From a8d9e51f57007d099ef2fa95630bad4d546ef3a9 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sat, 6 Sep 2025 12:44:32 +0530 Subject: [PATCH 01/16] Performance centric refactor. --- RTLBenchmarkApp/src/BenchMark.cpp | 25 ++++++------ ReflectionTemplateLib/access/inc/Function.h | 2 +- ReflectionTemplateLib/access/inc/Function.hpp | 38 +++++++++--------- ReflectionTemplateLib/common/Constants.h | 9 ++++- ReflectionTemplateLib/common/rtl_traits.h | 8 ++-- .../detail/inc/FunctionCaller.hpp | 2 +- .../detail/inc/RObjectBuilder.h | 12 +++--- .../detail/inc/RObjectBuilder.hpp | 39 ++++++++++++------- ReflectionTemplateLib/detail/inc/RObjectId.h | 10 ++--- .../detail/inc/SetupConstructor.hpp | 12 +++--- .../detail/inc/SetupFunction.hpp | 11 +++--- .../detail/inc/SetupMethod.hpp | 18 +++++---- ReflectionTemplateLib/detail/inc/TypeId.h | 2 +- 13 files changed, 108 insertions(+), 80 deletions(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index 6fc25be5..349796a3 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -1,5 +1,4 @@ -#include #include #include "BenchMark.h" @@ -13,6 +12,11 @@ # define NOINLINE #endif +static const std::string LONG_STR = +"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; namespace { @@ -33,7 +37,7 @@ namespace { { NOINLINE void sendMessage(const char* pMsg) { - g_msg = pMsg; + g_msg = pMsg; } NOINLINE std::string getMessage(const char* pMsg) @@ -68,7 +72,7 @@ namespace rtl_bench { for (auto _ : state) { - sendMessage("direct"); + sendMessage(LONG_STR.c_str()); benchmark::DoNotOptimize(g_msg); } } @@ -82,7 +86,7 @@ namespace rtl_bench for (auto _ : state) { - sendMsg("lambda"); + sendMsg(LONG_STR.c_str()); benchmark::DoNotOptimize(g_msg); } } @@ -91,10 +95,9 @@ namespace rtl_bench void BenchMark::reflectedCall_noReturn(benchmark::State& state) { static rtl::Function sendMsg = cxx_mirror().getFunction("sendMessage").value(); - static auto sendMsgCall = sendMsg.bind(); for (auto _ : state) { - benchmark::DoNotOptimize(sendMsgCall.call("reflected")); + benchmark::DoNotOptimize(sendMsg.bind().call(LONG_STR.c_str())); } } @@ -107,7 +110,7 @@ namespace rtl_bench for (auto _ : state) { - benchmark::DoNotOptimize(sendMsg.bind(robj).call("reflected")); + benchmark::DoNotOptimize(sendMsg.bind(robj).call(LONG_STR.c_str())); } } @@ -116,7 +119,7 @@ namespace rtl_bench { for (auto _ : state) { - benchmark::DoNotOptimize(getMessage("direct")); + benchmark::DoNotOptimize(getMessage(LONG_STR.c_str())); } } @@ -129,7 +132,7 @@ namespace rtl_bench for (auto _ : state) { - benchmark::DoNotOptimize(getMsg("lambda")); + benchmark::DoNotOptimize(getMsg(LONG_STR.c_str())); } } @@ -139,7 +142,7 @@ namespace rtl_bench static rtl::Function getMsg = cxx_mirror().getFunction("getMessage").value(); for (auto _ : state) { - benchmark::DoNotOptimize(getMsg.bind().call("reflected")); + benchmark::DoNotOptimize(getMsg.bind().call(LONG_STR.c_str())); } } @@ -152,7 +155,7 @@ namespace rtl_bench for (auto _ : state) { - benchmark::DoNotOptimize(getMsg.bind(robj).call("reflected")); + benchmark::DoNotOptimize(getMsg.bind(robj).call(LONG_STR.c_str())); } } } \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/Function.h b/ReflectionTemplateLib/access/inc/Function.h index f8ffdec2..94675923 100644 --- a/ReflectionTemplateLib/access/inc/Function.h +++ b/ReflectionTemplateLib/access/inc/Function.h @@ -67,7 +67,7 @@ namespace rtl { Function(const Function& pOther, const detail::FunctorId& pFunctorId, const std::string_view pFunctorName); - std::size_t hasSignatureId(const std::size_t pSignatureId) const; + const std::size_t hasSignatureId(const std::size_t pSignatureId) const; GETTER(detail::methodQ, Qualifier, m_qualifier); diff --git a/ReflectionTemplateLib/access/inc/Function.hpp b/ReflectionTemplateLib/access/inc/Function.hpp index 033db291..02aadb33 100644 --- a/ReflectionTemplateLib/access/inc/Function.hpp +++ b/ReflectionTemplateLib/access/inc/Function.hpp @@ -22,12 +22,12 @@ namespace rtl return detail::FunctionCaller<_signature...>(*this); } - /* @method: hasSignature<...>() - @param: set of arguments, explicitly specified as template parameter. - @return: bool, if the functor associated with this object is of certain signature or not. - * a single 'Function' object can be associated with multiple overloads of same function. - * the set of arguments passed is checked agains all registered overloads, returns true if matched with any one. - */ template +/* @method: hasSignature<...>() + @param: set of arguments, explicitly specified as template parameter. + @return: bool, if the functor associated with this object is of certain signature or not. + * a single 'Function' object can be associated with multiple overloads of same function. + * the set of arguments passed is checked agains all registered overloads, returns true if matched with any one. +*/ template inline bool Function::hasSignature() const { //hasSignatureId() returns the index of the 'lambda' in functor-container, which cannot be '-1'. @@ -35,25 +35,25 @@ namespace rtl } - /* @method: operator()() - @param: variadic arguments. - @return: Return, possible error & return value of from the reflected call. - * if the arguments did not match with any overload, returns RObject with error::SignatureMismatch - * providing optional syntax, Function::call() does the exact same thing. - */ template +/* @method: operator()() + @param: variadic arguments. + @return: Return, possible error & return value of from the reflected call. + * if the arguments did not match with any overload, returns RObject with error::SignatureMismatch + * providing optional syntax, Function::call() does the exact same thing. +*/ template inline Return Function::operator()(_args&& ...params) const noexcept { return bind().call(std::forward<_args>(params)...); } - /* @method: hasSignatureId() - @param: const std::size_t& (signatureId to be found) - @return: the index of the functor in the functor-table. - * a 'Function' object may be associated with multiple functors in case of overloads. - * every overload will have unique 'FunctorId', contained by one 'Function' object. - * given signatureId is compared against the signatureId of all overloads registered. - */ inline std::size_t Function::hasSignatureId(const std::size_t pSignatureId) const +/* @method: hasSignatureId() + @param: const std::size_t& (signatureId to be found) + @return: the index of the functor in the functor-table. + * a 'Function' object may be associated with multiple functors in case of overloads. + * every overload will have unique 'FunctorId', contained by one 'Function' object. + * given signatureId is compared against the signatureId of all overloads registered. +*/ inline const std::size_t Function::hasSignatureId(const std::size_t pSignatureId) const { //simple linear-search, efficient for small set of elements. for (const auto& functorId : m_functorIds) { diff --git a/ReflectionTemplateLib/common/Constants.h b/ReflectionTemplateLib/common/Constants.h index 24d47ddd..145cd01c 100644 --- a/ReflectionTemplateLib/common/Constants.h +++ b/ReflectionTemplateLib/common/Constants.h @@ -131,6 +131,7 @@ namespace rtl::detail NonConst // Non-const instance method }; + constexpr const std::string_view NAMESPACE_GLOBAL = "global"; inline static const std::string ctor_name(const std::string_view pRecordName = "") { // [critical] Must not change. Constructors are identified using this format. @@ -157,5 +158,11 @@ namespace rtl::detail return _var; \ } - constexpr const std::string_view NAMESPACE_GLOBAL = "global"; +#if defined(_MSC_VER) +#define FORCE_INLINE __forceinline +#elif defined(__GNUC__) || defined(__clang__) +#define FORCE_INLINE inline __attribute__((always_inline)) +#else +#define FORCE_INLINE inline +#endif } \ No newline at end of file diff --git a/ReflectionTemplateLib/common/rtl_traits.h b/ReflectionTemplateLib/common/rtl_traits.h index 25a42d2b..d5bc1f89 100644 --- a/ReflectionTemplateLib/common/rtl_traits.h +++ b/ReflectionTemplateLib/common/rtl_traits.h @@ -70,7 +70,7 @@ namespace rtl { using value_type = std::nullptr_t; static constexpr const auto type = detail::Wrapper::None; - static auto id() { return detail::TypeId<>::None; } + static constexpr std::size_t id() { return detail::TypeId<>::None; } }; @@ -79,7 +79,7 @@ namespace rtl { using value_type = T; static constexpr const auto type = detail::Wrapper::Shared; - static auto id() { return detail::TypeId>::get(); } + static constexpr std::size_t id() { return detail::TypeId>::get(); } }; @@ -88,7 +88,7 @@ namespace rtl { using value_type = T; static constexpr const auto type = detail::Wrapper::Unique; - static auto id() { return detail::TypeId>::get(); } + static constexpr std::size_t id() { return detail::TypeId>::get(); } }; @@ -97,7 +97,7 @@ namespace rtl { using value_type = T; static constexpr const auto type = detail::Wrapper::Weak; - static auto id() { return detail::TypeId>::get(); } + static constexpr std::size_t id() { return detail::TypeId>::get(); } }; template diff --git a/ReflectionTemplateLib/detail/inc/FunctionCaller.hpp b/ReflectionTemplateLib/detail/inc/FunctionCaller.hpp index 4fdfbde7..3abe2eab 100644 --- a/ReflectionTemplateLib/detail/inc/FunctionCaller.hpp +++ b/ReflectionTemplateLib/detail/inc/FunctionCaller.hpp @@ -36,6 +36,6 @@ namespace rtl::detail if (index != rtl::index_none) { return Container::template forwardCall<_args...>(index, std::forward<_args>(params)...); } - return { error::SignatureMismatch, RObject{ } }; + return { error::SignatureMismatch, RObject{} }; } } \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/RObjectBuilder.h b/ReflectionTemplateLib/detail/inc/RObjectBuilder.h index 17e0f08c..00fa53e1 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectBuilder.h +++ b/ReflectionTemplateLib/detail/inc/RObjectBuilder.h @@ -37,8 +37,8 @@ namespace rtl::detail static const std::size_t rtlManagedInstanceCount(); - template - static RObject build(T&& pVal, const bool pIsConstCastSafe); + template + static RObject build(T&& pVal); }; } @@ -55,10 +55,10 @@ namespace rtl inline RObject reflect(T(&pArr)[N]) { if constexpr (std::is_same_v, char>) { - return detail::RObjectBuilder::build(std::string_view(pArr, N - 1), !traits::is_const_v); + return detail::RObjectBuilder::build>(std::string_view(pArr, N - 1)); } else { - return detail::RObjectBuilder::build, alloc::Stack>(std::vector(pArr, pArr + N), !traits::is_const_v); + return detail::RObjectBuilder::build, alloc::Stack, !traits::is_const_v>(std::vector(pArr, pArr + N)); } } @@ -69,12 +69,12 @@ namespace rtl using _T = traits::raw_t; if constexpr (traits::std_wrapper<_T>::type == detail::Wrapper::None) { - return detail::RObjectBuilder::build(std::forward(pVal), !traits::is_const_v); + return detail::RObjectBuilder::build>(std::forward(pVal)); } else { constexpr bool isConstCastSafe = !traits::is_const_v::value_type>; - return detail::RObjectBuilder::build(std::forward(pVal), isConstCastSafe); + return detail::RObjectBuilder::build(std::forward(pVal)); } } } \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp index 68fa56e0..20af995d 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp +++ b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp @@ -49,11 +49,13 @@ namespace rtl::detail { { case alloc::Stack: return { error::None, - RObjectBuilder::template build<_T, alloc::Stack>(_T(srcObj), true) }; + RObjectBuilder::template build<_T, alloc::Stack, true>(_T(srcObj)) + }; case alloc::Heap: return { error::None, - RObjectBuilder::template build<_T*, alloc::Heap>(new _T(srcObj), true) }; + RObjectBuilder::template build<_T*, alloc::Heap, true>(new _T(srcObj)) + }; default: return { error::EmptyRObject, RObject{} }; @@ -72,8 +74,8 @@ namespace rtl::detail { - template - inline RObject RObjectBuilder::build(T&& pVal, const bool pIsConstCastSafe) + template + inline RObject RObjectBuilder::build(T&& pVal) { using _T = traits::raw_t; constexpr bool isRawPointer = std::is_pointer_v>; @@ -81,8 +83,11 @@ namespace rtl::detail { if constexpr (_allocOn == alloc::Heap) { static_assert(isRawPointer, "Invalid 'alloc' specified for non-pointer-type 'T'"); - return RObject(RObjectId::create, _allocOn>(pIsConstCastSafe), - std::any(RObjectUPtr<_T>(std::unique_ptr<_T>(static_cast<_T*>(pVal)))), + return RObject(RObjectId::create, _allocOn, _isConstCastSafe>(), + std::any { + std::in_place_type>, + RObjectUPtr<_T>(std::unique_ptr<_T>(static_cast<_T*>(pVal))) + }, buildCloner<_T>(), getConverters>()); } @@ -90,8 +95,10 @@ namespace rtl::detail { { if constexpr (isRawPointer) { - return RObject(RObjectId::create(pIsConstCastSafe), - std::any(static_cast(pVal)), + return RObject(RObjectId::create(), + std::any { + static_cast(pVal) + }, buildCloner<_T>(), getConverters()); } @@ -100,16 +107,22 @@ namespace rtl::detail { if constexpr (traits::std_wrapper<_T>::type == Wrapper::Unique) { using U = traits::std_wrapper<_T>::value_type; - return RObject(RObjectId::create(pIsConstCastSafe), - std::any(RObjectUPtr(std::move(pVal))), + return RObject(RObjectId::create(), + std::any { + std::in_place_type>, + RObjectUPtr(std::move(pVal)) + }, buildCloner<_T>(), getConverters()); } - else + else { static_assert(std::is_copy_constructible_v<_T>, "T must be copy-constructible (std::any requires this)."); - return RObject(RObjectId::create(pIsConstCastSafe), - std::any(std::forward(pVal)), + return RObject(RObjectId::create(), + std::any { + std::in_place_type, + std::forward(pVal) + }, buildCloner<_T>(), getConverters()); } diff --git a/ReflectionTemplateLib/detail/inc/RObjectId.h b/ReflectionTemplateLib/detail/inc/RObjectId.h index 4dd628c8..7ee8dbf4 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectId.h +++ b/ReflectionTemplateLib/detail/inc/RObjectId.h @@ -37,7 +37,7 @@ namespace rtl::detail GETTER(EntityKind, ContainedAs, m_containsAs) template - static constexpr EntityKind getEntityKind() + FORCE_INLINE static constexpr EntityKind getEntityKind() { using W = traits::std_wrapper>; using _T = traits::raw_t>; @@ -56,8 +56,8 @@ namespace rtl::detail } - template - static RObjectId create(bool pIsConstCastSafe) + template + FORCE_INLINE static RObjectId create() { // extract wrapper info. using _W = traits::std_wrapper>; @@ -67,8 +67,8 @@ namespace rtl::detail const std::size_t wrapperId = _W::id(); const std::size_t typeId = rtl::detail::TypeId<_T>::get(); - const bool isWrappingConst = (_W::type != Wrapper::None && traits::is_const_v); - return RObjectId{ isWrappingConst, pIsConstCastSafe, typeId, wrapperId, _allocOn, _W::type, entityKind }; + constexpr bool isWrappingConst = (_W::type != Wrapper::None && traits::is_const_v); + return RObjectId{ isWrappingConst, _isConstCastSafe, typeId, wrapperId, _allocOn, _W::type, entityKind }; } }; } \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp b/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp index a5d78f4b..bbde6efe 100644 --- a/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp @@ -37,14 +37,16 @@ namespace rtl::detail } else { return { error::None, - RObjectBuilder::build<_recordType, alloc::Stack>(_recordType(std::forward<_signature>(params)...), - true) }; + RObjectBuilder::build<_recordType, alloc::Stack, true>( + _recordType(std::forward<_signature>(params)...)) + }; } } else if (pAllocType == alloc::Heap) { - return {error::None, - RObjectBuilder::build<_recordType*, alloc::Heap>(new _recordType(std::forward<_signature>(params)...), - true) }; + return { error::None, + RObjectBuilder::build<_recordType*, alloc::Heap, true>( + new _recordType(std::forward<_signature>(params)...)) + }; } } return { error::EmptyRObject, RObject{} }; //dead code. compiler warning omitted. diff --git a/ReflectionTemplateLib/detail/inc/SetupFunction.hpp b/ReflectionTemplateLib/detail/inc/SetupFunction.hpp index ade7baec..9908808d 100644 --- a/ReflectionTemplateLib/detail/inc/SetupFunction.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupFunction.hpp @@ -40,14 +40,15 @@ namespace rtl */ using _rawRetType = traits::raw_t<_returnType>; const _rawRetType& retObj = (*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj, - isConstCastSafe) }; + RObjectBuilder::build(&retObj) + }; } else { //if the function returns anything (not refrence), this block will be retained by compiler. - return { error::None, - RObjectBuilder::build<_returnType, rtl::alloc::Stack>((*pFunctor)(std::forward<_signature>(params)...), - isConstCastSafe) }; + return { error::None, + RObjectBuilder::build<_returnType, rtl::alloc::Stack, isConstCastSafe>( + (*pFunctor)(std::forward<_signature>(params)...)) + }; } }; } diff --git a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp index b0ca559e..117460be 100644 --- a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp @@ -48,13 +48,14 @@ namespace rtl */ using _rawRetType = traits::raw_t<_returnType>; const _rawRetType& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj, - isConstCastSafe) }; + RObjectBuilder::build(&retObj) + }; } else { return { error::None, - RObjectBuilder::build<_returnType, alloc::Stack>((target.*pFunctor)(std::forward<_signature>(params)...), - isConstCastSafe) }; + RObjectBuilder::build<_returnType, alloc::Stack, isConstCastSafe>( + (target.*pFunctor)(std::forward<_signature>(params)...)) + }; } }; } @@ -84,13 +85,14 @@ namespace rtl */ using _rawRetType = traits::raw_t<_returnType>; const _rawRetType& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj, - isConstCastSafe) }; + RObjectBuilder::build(&retObj) + }; } else { return { error::None, - RObjectBuilder::build<_returnType, alloc::Stack>((target.*pFunctor)(std::forward<_signature>(params)...), - isConstCastSafe) }; + RObjectBuilder::build<_returnType, alloc::Stack, isConstCastSafe>( + (target.*pFunctor)(std::forward<_signature>(params)...)) + }; } }; } diff --git a/ReflectionTemplateLib/detail/inc/TypeId.h b/ReflectionTemplateLib/detail/inc/TypeId.h index 2cc571ca..09f4dce6 100644 --- a/ReflectionTemplateLib/detail/inc/TypeId.h +++ b/ReflectionTemplateLib/detail/inc/TypeId.h @@ -35,7 +35,7 @@ namespace rtl { //'0' represents no type. [Never change, critical.] static constexpr const std::size_t None = 0; - static std::size_t get() + static const std::size_t get() { //statically initialize a unique-id. static const std::size_t typeId = generate_unique_id(); From c1f6fd5c153a3e7eed413aa5c37430b7329a848f Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 7 Sep 2025 00:52:06 +0530 Subject: [PATCH 02/16] benchmark code updated, rtl:minor_refactor --- RTLBenchmarkApp/src/BenchMark.cpp | 321 ++++++++++-------- RTLBenchmarkApp/src/BenchMark.h | 64 +++- RTLBenchmarkApp/src/main.cpp | 8 +- ReflectionTemplateLib/access/inc/RObject.h | 4 +- ReflectionTemplateLib/access/inc/RObject.hpp | 8 +- .../detail/inc/RObjectBuilder.hpp | 64 ++-- 6 files changed, 284 insertions(+), 185 deletions(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index 349796a3..909419b5 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -1,161 +1,190 @@ +#include #include -#include "BenchMark.h" -#include "RTLibInterface.h" - -#if defined(_MSC_VER) -# define NOINLINE __declspec(noinline) -#elif defined(__GNUC__) -# define NOINLINE __attribute__((noinline)) -#else -# define NOINLINE -#endif - -static const std::string LONG_STR = -"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " -"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " -"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " -"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; - -namespace { - - static std::optional g_msg; +#include - NOINLINE static void sendMessage(const char* pMsg) - { - g_msg = pMsg; - } - - NOINLINE static std::string getMessage(const char* pMsg) - { - g_msg = pMsg; - return std::string(pMsg); - } - - struct Node - { - NOINLINE void sendMessage(const char* pMsg) - { - g_msg = pMsg; - } +#include "BenchMark.h" - NOINLINE std::string getMessage(const char* pMsg) - { - g_msg = pMsg; - return std::string(pMsg); - } - }; - const rtl::CxxMirror& cxx_mirror() - { - static auto m = rtl::CxxMirror({ +namespace { - rtl::type().record("node").build(), + static const char* LONG_STR = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do" + "do aeiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis" + "nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure" + "dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Except" + "eur ssint occaecat cupidatat nnon proident, sunt in culpa qui officia deserunt mollit anim id"; - rtl::type().function("sendMessage").build(sendMessage), + // Pre-created string to isolate call overhead + static const std::string g_longStr(LONG_STR); +} - rtl::type().member().method("sendMessage").build(&Node::sendMessage), - rtl::type().function("getMessage").build(getMessage), +namespace rtl_bench +{ + void BenchMark::directCall_noReturn(benchmark::State& state) + { + for (auto _ : state) + { + sendMessage(g_longStr); + benchmark::DoNotOptimize(g_msg); + } + } + + + void BenchMark::autoLambdaCall_noReturn(benchmark::State& state) + { + auto sendMsg = [](const str_type& pMsg) { + sendMessage(pMsg); + }; + + for (auto _ : state) + { + sendMsg(g_longStr); + benchmark::DoNotOptimize(g_msg); + } + } + + + void BenchMark::stdFunctionCall_noReturn(benchmark::State& state) + { + static std::function sendMsg = [](const str_type& pMsg) { + sendMessage(pMsg); + }; + + for (auto _ : state) + { + sendMsg(g_longStr); + benchmark::DoNotOptimize(g_msg); + } + } + + void BenchMark::directCall_withReturn(benchmark::State& state) + { + static auto _ = []() { + std::cout << "--------------------------------------------------" + "---------------------------------------------" << std::endl; + return 0; + }(); + + for (auto _ : state) + { + benchmark::DoNotOptimize(getMessage(g_longStr)); + } + } + + + void BenchMark::autoLambdaCall_withReturn(benchmark::State& state) + { + auto getMsg = [](const str_type& pMsg) { + return getMessage(pMsg); + }; + + for (auto _ : state) + { + benchmark::DoNotOptimize(getMsg(g_longStr)); + } + } + + + void BenchMark::stdFunctionCall_withReturn(benchmark::State& state) + { + static std::function getMsg = [](const str_type& pMsg) { + return getMessage(pMsg); + }; + + for (auto _ : state) + { + benchmark::DoNotOptimize(getMsg(g_longStr)); + } + } - rtl::type().member().method("getMessage").build(&Node::getMessage) - }); - return m; - } } -namespace rtl_bench +namespace rtl_bench { - void BenchMark::directCall_noReturn(benchmark::State& state) - { - for (auto _ : state) - { - sendMessage(LONG_STR.c_str()); - benchmark::DoNotOptimize(g_msg); - } - } - - - void BenchMark::lambdaCall_noReturn(benchmark::State& state) - { - static std::function sendMsg = [](const char* pMsg) { - sendMessage(pMsg); - }; - - for (auto _ : state) - { - sendMsg(LONG_STR.c_str()); - benchmark::DoNotOptimize(g_msg); - } - } - - - void BenchMark::reflectedCall_noReturn(benchmark::State& state) - { - static rtl::Function sendMsg = cxx_mirror().getFunction("sendMessage").value(); - for (auto _ : state) - { - benchmark::DoNotOptimize(sendMsg.bind().call(LONG_STR.c_str())); - } - } - - - void BenchMark::reflectedMethodCall_noReturn(benchmark::State& state) - { - static rtl::Record rNode = cxx_mirror().getRecord("node").value(); - static rtl::Method sendMsg = rNode.getMethod("sendMessage").value(); - static rtl::RObject robj = rNode.create().rObject; - - for (auto _ : state) - { - benchmark::DoNotOptimize(sendMsg.bind(robj).call(LONG_STR.c_str())); - } - } - - - void BenchMark::directCall_withReturn(benchmark::State& state) - { - for (auto _ : state) - { - benchmark::DoNotOptimize(getMessage(LONG_STR.c_str())); - } - } - - - void BenchMark::lambdaCall_withReturn(benchmark::State& state) - { - static std::function getMsg = [](const char* pMsg) { - return getMessage(pMsg); - }; - - for (auto _ : state) - { - benchmark::DoNotOptimize(getMsg(LONG_STR.c_str())); - } - } - - - void BenchMark::reflectedCall_withReturn(benchmark::State& state) - { - static rtl::Function getMsg = cxx_mirror().getFunction("getMessage").value(); - for (auto _ : state) - { - benchmark::DoNotOptimize(getMsg.bind().call(LONG_STR.c_str())); - } - } - - - void BenchMark::reflectedMethodCall_withReturn(benchmark::State& state) - { - static rtl::Record rNode = cxx_mirror().getRecord("node").value(); - static rtl::Method getMsg = rNode.getMethod("getMessage").value(); - static rtl::RObject robj = rNode.create().rObject; - - for (auto _ : state) - { - benchmark::DoNotOptimize(getMsg.bind(robj).call(LONG_STR.c_str())); - } - } -} \ No newline at end of file + void BenchMark::reflectedCall_noReturn(benchmark::State& state) + { + static rtl::Function sendMsg = cxx_mirror().getFunction("sendMessage").value(); + + static auto _ = []() { + if (sendMsg.bind().call(g_longStr).err == rtl::error::None) { + std::cout << "[rtl:0] call success.\n"; + } + else { + std::cout << "[rtl:0] call failed.\n"; + } + return 0; + }(); + + for (auto _ : state) + { + benchmark::DoNotOptimize(sendMsg.bind().call(g_longStr)); + } + } + + + void BenchMark::reflectedMethodCall_noReturn(benchmark::State& state) + { + static rtl::Record rNode = cxx_mirror().getRecord("Node").value(); + static rtl::Method sendMsg = rNode.getMethod("sendMessage").value(); + static rtl::RObject robj = rNode.create().rObject; + static auto _ = []() { + if (sendMsg.bind(robj).call(g_longStr).err == rtl::error::None) { + std::cout << "[rtl:1] call success.\n"; + } + else { + std::cout << "[rtl:1] call failed.\n"; + } + return 0; + }(); + + for (auto _ : state) + { + benchmark::DoNotOptimize(sendMsg.bind(robj).call(g_longStr)); + } + } + + + void BenchMark::reflectedCall_withReturn(benchmark::State& state) + { + static rtl::Function getMsg = cxx_mirror().getFunction("getMessage").value(); + static auto _ = []() { + if (getMsg.bind().call(g_longStr).err == rtl::error::None) { + std::cout << "[rtl:2] call success.\n"; + } + else { + std::cout << "[rtl:2] call failed.\n"; + } + return 0; + }(); + + for (auto _ : state) + { + benchmark::DoNotOptimize(getMsg.bind().call(g_longStr)); + } + } + + + void BenchMark::reflectedMethodCall_withReturn(benchmark::State& state) + { + static rtl::Record rNode = cxx_mirror().getRecord("Node").value(); + static rtl::Method getMsg = rNode.getMethod("getMessage").value(); + static rtl::RObject robj = rNode.create().rObject; + static auto _ = []() { + if (getMsg.bind(robj).call(g_longStr).err == rtl::error::None) { + std::cout << "[rtl:3] call success.\n"; + } + else { + std::cout << "[rtl:3] call failed.\n"; + } + return 0; + }(); + + for (auto _ : state) + { + benchmark::DoNotOptimize(getMsg.bind(robj).call(g_longStr)); + } + } +} diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index c744ba0d..d485f971 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -2,13 +2,71 @@ #include +#include "RTLibInterface.h" + +#include + +#if defined(_MSC_VER) +# define NOINLINE __declspec(noinline) +#elif defined(__GNUC__) +# define NOINLINE __attribute__((noinline)) +#else +# define NOINLINE +#endif + +using str_type = std::string; //*/ std::string_view; + namespace rtl_bench { + static std::optional g_msg; + + NOINLINE static void sendMessage(str_type pMsg) { + g_msg = pMsg; + } + + NOINLINE static str_type getMessage(str_type pMsg) { + g_msg = pMsg; + return str_type(pMsg); + } + + struct Node + { + NOINLINE void sendMessage(str_type pMsg) { + g_msg = pMsg; + } + + NOINLINE str_type getMessage(str_type pMsg) { + g_msg = pMsg; + return str_type(pMsg); + } + }; + + + static const rtl::CxxMirror& cxx_mirror() + { + static auto m = rtl::CxxMirror({ + + rtl::type().record("Node").build(), + + rtl::type().function("sendMessage").build(sendMessage), + + rtl::type().member().method("sendMessage").build(&Node::sendMessage), + + rtl::type().function("getMessage").build(getMessage), + + rtl::type().member().method("getMessage").build(&Node::getMessage) + }); + return m; + } + + struct BenchMark { static void directCall_noReturn(benchmark::State& state); - static void lambdaCall_noReturn(benchmark::State& state); + static void autoLambdaCall_noReturn(benchmark::State& state); + + static void stdFunctionCall_noReturn(benchmark::State& state); static void reflectedCall_noReturn(benchmark::State& state); @@ -16,7 +74,9 @@ namespace rtl_bench static void directCall_withReturn(benchmark::State& state); - static void lambdaCall_withReturn(benchmark::State& state); + static void autoLambdaCall_withReturn(benchmark::State& state); + + static void stdFunctionCall_withReturn(benchmark::State& state); static void reflectedCall_withReturn(benchmark::State& state); diff --git a/RTLBenchmarkApp/src/main.cpp b/RTLBenchmarkApp/src/main.cpp index f0a27601..a7eb54ec 100644 --- a/RTLBenchmarkApp/src/main.cpp +++ b/RTLBenchmarkApp/src/main.cpp @@ -9,11 +9,15 @@ // ------------------------------------------------------------ BENCHMARK(rtl_bench::BenchMark::directCall_noReturn); -BENCHMARK(rtl_bench::BenchMark::lambdaCall_noReturn); +BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_noReturn); +BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_noReturn); BENCHMARK(rtl_bench::BenchMark::reflectedCall_noReturn); BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_noReturn); + BENCHMARK(rtl_bench::BenchMark::directCall_withReturn); -BENCHMARK(rtl_bench::BenchMark::lambdaCall_withReturn); +BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_withReturn); +BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_withReturn); BENCHMARK(rtl_bench::BenchMark::reflectedCall_withReturn); BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_withReturn); + BENCHMARK_MAIN(); diff --git a/ReflectionTemplateLib/access/inc/RObject.h b/ReflectionTemplateLib/access/inc/RObject.h index 6a446112..9555a61c 100644 --- a/ReflectionTemplateLib/access/inc/RObject.h +++ b/ReflectionTemplateLib/access/inc/RObject.h @@ -49,8 +49,8 @@ namespace rtl mutable const std::vector* m_converters; RObject(const RObject&) = default; - RObject(const detail::RObjectId& pRObjId, std::any&& pObject, const Cloner& pCloner, - const std::vector& pConverters); + RObject(detail::RObjectId&& pRObjId, std::any&& pObject, const Cloner* pCloner, + const std::vector* pConverters); static std::atomic& getInstanceCounter(); diff --git a/ReflectionTemplateLib/access/inc/RObject.hpp b/ReflectionTemplateLib/access/inc/RObject.hpp index c478a320..fefa64ff 100644 --- a/ReflectionTemplateLib/access/inc/RObject.hpp +++ b/ReflectionTemplateLib/access/inc/RObject.hpp @@ -24,12 +24,12 @@ namespace rtl { - inline RObject::RObject(const detail::RObjectId& pRObjId, std::any&& pObject, const Cloner& pCloner, - const std::vector& pConverters) + inline RObject::RObject(detail::RObjectId&& pRObjId, std::any&& pObject, const Cloner* pCloner, + const std::vector* pConverters) : m_objectId(pRObjId) , m_object(std::forward(pObject)) - , m_getClone(&pCloner) - , m_converters(&pConverters) + , m_getClone(pCloner) + , m_converters(pConverters) { } inline RObject::RObject(RObject&& pOther) noexcept diff --git a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp index 20af995d..35d8453f 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp +++ b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp @@ -48,17 +48,20 @@ namespace rtl::detail { switch (pAllocOn) { case alloc::Stack: - return { error::None, - RObjectBuilder::template build<_T, alloc::Stack, true>(_T(srcObj)) + return { + error::None, + RObjectBuilder::template build<_T, alloc::Stack, true>(_T(srcObj)) }; - case alloc::Heap: - return { error::None, - RObjectBuilder::template build<_T*, alloc::Heap, true>(new _T(srcObj)) + return { + error::None, + RObjectBuilder::template build<_T*, alloc::Heap, true>(new _T(srcObj)) }; - default: - return { error::EmptyRObject, RObject{} }; + return { + error::EmptyRObject, + RObject{} + }; } }; return cloner; @@ -66,7 +69,10 @@ namespace rtl::detail { else { static const Cloner cloner = [](const RObject&, alloc) -> Return { - return { error::TypeNotCopyConstructible, RObject{} }; + return { + error::TypeNotCopyConstructible, + RObject{} + }; }; return cloner; } @@ -85,22 +91,22 @@ namespace rtl::detail { static_assert(isRawPointer, "Invalid 'alloc' specified for non-pointer-type 'T'"); return RObject(RObjectId::create, _allocOn, _isConstCastSafe>(), std::any { - std::in_place_type>, - RObjectUPtr<_T>(std::unique_ptr<_T>(static_cast<_T*>(pVal))) - }, - buildCloner<_T>(), - getConverters>()); + std::in_place_type>, + RObjectUPtr<_T>(std::unique_ptr<_T>(static_cast<_T*>(pVal))) + }, + &buildCloner<_T>(), + &getConverters>()); } else if constexpr (_allocOn == alloc::Stack) { if constexpr (isRawPointer) { return RObject(RObjectId::create(), - std::any { - static_cast(pVal) - }, - buildCloner<_T>(), - getConverters()); + std::any { + static_cast(pVal) + }, + &buildCloner<_T>(), + &getConverters()); } else { @@ -109,22 +115,22 @@ namespace rtl::detail { using U = traits::std_wrapper<_T>::value_type; return RObject(RObjectId::create(), std::any { - std::in_place_type>, - RObjectUPtr(std::move(pVal)) - }, - buildCloner<_T>(), - getConverters()); + std::in_place_type>, + RObjectUPtr(std::move(pVal)) + }, + &buildCloner<_T>(), + &getConverters()); } else { static_assert(std::is_copy_constructible_v<_T>, "T must be copy-constructible (std::any requires this)."); return RObject(RObjectId::create(), - std::any { - std::in_place_type, - std::forward(pVal) - }, - buildCloner<_T>(), - getConverters()); + std::any { + std::in_place_type, + std::forward(pVal) + }, + &buildCloner<_T>(), + &getConverters()); } } } From e458d9e486f9a916714931c0c34b64f3d2352f58 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 7 Sep 2025 08:24:13 +0530 Subject: [PATCH 03/16] benchmarking std::any/std::function --- RTLBenchmarkApp/src/BenchMark.cpp | 32 +++++++++++++++++++++++++++---- RTLBenchmarkApp/src/BenchMark.h | 3 +++ RTLBenchmarkApp/src/main.cpp | 27 +++++++++++++------------- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index 909419b5..27a66626 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -34,9 +34,9 @@ namespace rtl_bench void BenchMark::autoLambdaCall_noReturn(benchmark::State& state) { - auto sendMsg = [](const str_type& pMsg) { + static auto sendMsg = [](const str_type& pMsg) { sendMessage(pMsg); - }; + }; for (auto _ : state) { @@ -50,7 +50,7 @@ namespace rtl_bench { static std::function sendMsg = [](const str_type& pMsg) { sendMessage(pMsg); - }; + }; for (auto _ : state) { @@ -91,7 +91,7 @@ namespace rtl_bench { static std::function getMsg = [](const str_type& pMsg) { return getMessage(pMsg); - }; + }; for (auto _ : state) { @@ -102,6 +102,30 @@ namespace rtl_bench } +namespace rtl_bench +{ + void BenchMark::BM_FunctionCall(benchmark::State& state) + { + static std::function func = [](const str_type& pMsg) { + return getMessage(pMsg); + }; + + for (auto _ : state) { + benchmark::DoNotOptimize(func(g_longStr)); + } + } + + void BenchMark::BM_AnyCast(benchmark::State& state) + { + std::any a = getMessage; + for (auto _ : state) { + auto anyfunc = std::any_cast(a); + benchmark::DoNotOptimize(anyfunc(g_longStr)); + } + } +} + + namespace rtl_bench { void BenchMark::reflectedCall_noReturn(benchmark::State& state) diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index d485f971..ef8e032a 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -81,5 +81,8 @@ namespace rtl_bench static void reflectedCall_withReturn(benchmark::State& state); static void reflectedMethodCall_withReturn(benchmark::State& state); + + static void BM_FunctionCall(benchmark::State& state); + static void BM_AnyCast(benchmark::State& state); }; } \ No newline at end of file diff --git a/RTLBenchmarkApp/src/main.cpp b/RTLBenchmarkApp/src/main.cpp index a7eb54ec..18029fb7 100644 --- a/RTLBenchmarkApp/src/main.cpp +++ b/RTLBenchmarkApp/src/main.cpp @@ -4,20 +4,19 @@ #include "BenchMark.h" -// ------------------------------------------------------------ -// Register benchmarks -// ------------------------------------------------------------ +BENCHMARK(rtl_bench::BenchMark::BM_FunctionCall); +BENCHMARK(rtl_bench::BenchMark::BM_AnyCast); -BENCHMARK(rtl_bench::BenchMark::directCall_noReturn); -BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_noReturn); -BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_noReturn); -BENCHMARK(rtl_bench::BenchMark::reflectedCall_noReturn); -BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_noReturn); - -BENCHMARK(rtl_bench::BenchMark::directCall_withReturn); -BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_withReturn); -BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_withReturn); -BENCHMARK(rtl_bench::BenchMark::reflectedCall_withReturn); -BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_withReturn); +//BENCHMARK(rtl_bench::BenchMark::directCall_noReturn); +//BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_noReturn); +//BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_noReturn); +//BENCHMARK(rtl_bench::BenchMark::reflectedCall_noReturn); +//BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_noReturn); +// +//BENCHMARK(rtl_bench::BenchMark::directCall_withReturn); +//BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_withReturn); +//BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_withReturn); +//BENCHMARK(rtl_bench::BenchMark::reflectedCall_withReturn); +//BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_withReturn); BENCHMARK_MAIN(); From 524adff3c3730295f4bdd557f756f67ee23c070c Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 7 Sep 2025 16:12:02 +0530 Subject: [PATCH 04/16] introducing rtl::LambdaFunction --- RTLBenchmarkApp/src/BenchMark.cpp | 36 +++++++++------- RTLBenchmarkApp/src/BenchMark.h | 21 ++++++++-- RTLBenchmarkApp/src/main.cpp | 27 ++++++------ .../detail/inc/LambdaFunction.h | 41 +++++++++++++++++++ .../detail/src/CMakeLists.txt | 1 + 5 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 ReflectionTemplateLib/detail/inc/LambdaFunction.h diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index 27a66626..ef5822c9 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -6,6 +6,8 @@ #include "BenchMark.h" +#include "LambdaFunction.h" + namespace { @@ -14,11 +16,10 @@ namespace { "nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure" "dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Except" "eur ssint occaecat cupidatat nnon proident, sunt in culpa qui officia deserunt mollit anim id"; - - // Pre-created string to isolate call overhead - static const std::string g_longStr(LONG_STR); } +// Pre-created string to isolate call overhead +static const std::string g_longStr(LONG_STR); namespace rtl_bench { @@ -78,7 +79,7 @@ namespace rtl_bench { auto getMsg = [](const str_type& pMsg) { return getMessage(pMsg); - }; + }; for (auto _ : state) { @@ -98,7 +99,6 @@ namespace rtl_bench benchmark::DoNotOptimize(getMsg(g_longStr)); } } - } @@ -106,21 +106,27 @@ namespace rtl_bench { void BenchMark::BM_FunctionCall(benchmark::State& state) { - static std::function func = [](const str_type& pMsg) { + static std::function getMsg = [](const str_type& pMsg) { return getMessage(pMsg); }; - - for (auto _ : state) { - benchmark::DoNotOptimize(func(g_longStr)); + + for (auto _ : state) + { + benchmark::DoNotOptimize(getMsg(g_longStr)); } } - void BenchMark::BM_AnyCast(benchmark::State& state) + void BenchMark::BM_LambdaFunc(benchmark::State& state) { - std::any a = getMessage; + static rtl::detail::LambdaFunction obj; + + static auto _ = []() { + obj.init(getMessage); + return 0; + }(); + for (auto _ : state) { - auto anyfunc = std::any_cast(a); - benchmark::DoNotOptimize(anyfunc(g_longStr)); + benchmark::DoNotOptimize(obj(g_longStr)); } } } @@ -195,7 +201,7 @@ namespace rtl_bench { static rtl::Record rNode = cxx_mirror().getRecord("Node").value(); static rtl::Method getMsg = rNode.getMethod("getMessage").value(); - static rtl::RObject robj = rNode.create().rObject; + static rtl::RObject robj = rNode.create().rObject; static auto _ = []() { if (getMsg.bind(robj).call(g_longStr).err == rtl::error::None) { std::cout << "[rtl:3] call success.\n"; @@ -211,4 +217,4 @@ namespace rtl_bench benchmark::DoNotOptimize(getMsg.bind(robj).call(g_longStr)); } } -} +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index ef8e032a..a79f7a2e 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -21,10 +21,16 @@ namespace rtl_bench static std::optional g_msg; NOINLINE static void sendMessage(str_type pMsg) { + std::string result = pMsg + pMsg; + result = result + result; + result = result + result; g_msg = pMsg; } NOINLINE static str_type getMessage(str_type pMsg) { + std::string result = pMsg + pMsg; + result = result + result; + result = result + result; g_msg = pMsg; return str_type(pMsg); } @@ -32,12 +38,20 @@ namespace rtl_bench struct Node { NOINLINE void sendMessage(str_type pMsg) { + std::string result = pMsg + pMsg; + result = result + result; + result = result + result; + g_msg = pMsg; g_msg = pMsg; } - NOINLINE str_type getMessage(str_type pMsg) { + NOINLINE str_type getMessage(str_type pMsg) + { + std::string result = pMsg + pMsg; + result = result + result; + result = result + result; g_msg = pMsg; - return str_type(pMsg); + return pMsg; } }; @@ -83,6 +97,7 @@ namespace rtl_bench static void reflectedMethodCall_withReturn(benchmark::State& state); static void BM_FunctionCall(benchmark::State& state); - static void BM_AnyCast(benchmark::State& state); + + static void BM_LambdaFunc(benchmark::State& state); }; } \ No newline at end of file diff --git a/RTLBenchmarkApp/src/main.cpp b/RTLBenchmarkApp/src/main.cpp index 18029fb7..e074a5db 100644 --- a/RTLBenchmarkApp/src/main.cpp +++ b/RTLBenchmarkApp/src/main.cpp @@ -4,19 +4,20 @@ #include "BenchMark.h" -BENCHMARK(rtl_bench::BenchMark::BM_FunctionCall); -BENCHMARK(rtl_bench::BenchMark::BM_AnyCast); -//BENCHMARK(rtl_bench::BenchMark::directCall_noReturn); -//BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_noReturn); -//BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_noReturn); -//BENCHMARK(rtl_bench::BenchMark::reflectedCall_noReturn); -//BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_noReturn); -// -//BENCHMARK(rtl_bench::BenchMark::directCall_withReturn); -//BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_withReturn); -//BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_withReturn); -//BENCHMARK(rtl_bench::BenchMark::reflectedCall_withReturn); -//BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_withReturn); +BENCHMARK(rtl_bench::BenchMark::directCall_noReturn); +BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_noReturn); +BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_noReturn); +BENCHMARK(rtl_bench::BenchMark::reflectedCall_noReturn); +BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_noReturn); + +BENCHMARK(rtl_bench::BenchMark::directCall_withReturn); +BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_withReturn); +BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_withReturn); +BENCHMARK(rtl_bench::BenchMark::reflectedCall_withReturn); +BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_withReturn); + +BENCHMARK(rtl_bench::BenchMark::BM_LambdaFunc); +BENCHMARK(rtl_bench::BenchMark::BM_FunctionCall); BENCHMARK_MAIN(); diff --git a/ReflectionTemplateLib/detail/inc/LambdaFunction.h b/ReflectionTemplateLib/detail/inc/LambdaFunction.h new file mode 100644 index 00000000..1b1f3845 --- /dev/null +++ b/ReflectionTemplateLib/detail/inc/LambdaFunction.h @@ -0,0 +1,41 @@ +#pragma once + +#include "RObjectBuilder.hpp" + +namespace rtl::detail +{ + template + struct LambdaFunction + { + using Invoker = std::string(*)(void* , _signature&...); + + Invoker m_invoker = nullptr; + void* m_storage = nullptr; + + template + void init(_returnType(*pFunctor)(_signature...)) + { + struct Holder { + + using Functor = decltype(pFunctor); + Functor m_functor; + + Holder(Functor pFptr) : m_functor(pFptr) { } + }; + + static auto holder = Holder{ pFunctor }; + m_storage = &holder; + + m_invoker = +[](void* stor, _signature&... params) -> std::string { + + auto h = static_cast(stor); + return (h->m_functor)(params...); + }; + } + + std::string operator()(_signature&... params) + { + return m_invoker(m_storage, params...); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/src/CMakeLists.txt b/ReflectionTemplateLib/detail/src/CMakeLists.txt index d7be430f..da4ba808 100644 --- a/ReflectionTemplateLib/detail/src/CMakeLists.txt +++ b/ReflectionTemplateLib/detail/src/CMakeLists.txt @@ -9,6 +9,7 @@ set(LOCAL_SOURCES SET(LOCAL_HEADERS + "${PROJECT_SOURCE_DIR}/detail/inc/LambdaFunction.h" "${PROJECT_SOURCE_DIR}/detail/inc/CallReflector.h" "${PROJECT_SOURCE_DIR}/detail/inc/CxxReflection.h" "${PROJECT_SOURCE_DIR}/detail/inc/FunctionCaller.h" From ded495c9eb11baf956f85f80f9b2e2f4a744ad54 Mon Sep 17 00:00:00 2001 From: neeraj Date: Sun, 7 Sep 2025 16:46:22 +0530 Subject: [PATCH 05/16] refactor --- RTLBenchmarkApp/src/BenchMark.cpp | 7 ++-- RTLBenchmarkApp/src/BenchMark.h | 33 +++++++++---------- .../detail/inc/LambdaFunction.h | 8 ++--- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index ef5822c9..260bc548 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -118,15 +118,16 @@ namespace rtl_bench void BenchMark::BM_LambdaFunc(benchmark::State& state) { - static rtl::detail::LambdaFunction obj; - + static rtl::detail::LambdaFunction obj; + static str_type str = std::string_view(g_longStr.c_str()); static auto _ = []() { obj.init(getMessage); return 0; }(); for (auto _ : state) { - benchmark::DoNotOptimize(obj(g_longStr)); + + benchmark::DoNotOptimize(obj(str)); } } } diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index a79f7a2e..447ca6f9 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -4,8 +4,6 @@ #include "RTLibInterface.h" -#include - #if defined(_MSC_VER) # define NOINLINE __declspec(noinline) #elif defined(__GNUC__) @@ -14,44 +12,43 @@ # define NOINLINE #endif -using str_type = std::string; //*/ std::string_view; +using str_type = /*std::string; //*/ std::string_view; namespace rtl_bench { static std::optional g_msg; NOINLINE static void sendMessage(str_type pMsg) { - std::string result = pMsg + pMsg; - result = result + result; - result = result + result; + // std::string result = pMsg + pMsg; + // result = result + result; + // result = result + result; g_msg = pMsg; } NOINLINE static str_type getMessage(str_type pMsg) { - std::string result = pMsg + pMsg; - result = result + result; - result = result + result; + // std::string result = pMsg + pMsg; + // result = result + result; + // result = result + result; g_msg = pMsg; - return str_type(pMsg); + return str_type(g_msg->c_str()); } struct Node { NOINLINE void sendMessage(str_type pMsg) { - std::string result = pMsg + pMsg; - result = result + result; - result = result + result; - g_msg = pMsg; + // std::string result = pMsg + pMsg; + // result = result + result; + // result = result + result; g_msg = pMsg; } NOINLINE str_type getMessage(str_type pMsg) { - std::string result = pMsg + pMsg; - result = result + result; - result = result + result; + // std::string result = pMsg + pMsg; + // result = result + result; + // result = result + result; g_msg = pMsg; - return pMsg; + return str_type(g_msg->c_str()); } }; diff --git a/ReflectionTemplateLib/detail/inc/LambdaFunction.h b/ReflectionTemplateLib/detail/inc/LambdaFunction.h index 1b1f3845..14413017 100644 --- a/ReflectionTemplateLib/detail/inc/LambdaFunction.h +++ b/ReflectionTemplateLib/detail/inc/LambdaFunction.h @@ -4,10 +4,10 @@ namespace rtl::detail { - template + template struct LambdaFunction { - using Invoker = std::string(*)(void* , _signature&...); + using Invoker = _retT(*)(void* , _signature&...); Invoker m_invoker = nullptr; void* m_storage = nullptr; @@ -26,14 +26,14 @@ namespace rtl::detail static auto holder = Holder{ pFunctor }; m_storage = &holder; - m_invoker = +[](void* stor, _signature&... params) -> std::string { + m_invoker = +[](void* stor, _signature&... params) -> _retT { auto h = static_cast(stor); return (h->m_functor)(params...); }; } - std::string operator()(_signature&... params) + _retT operator()(_signature&... params) { return m_invoker(m_storage, params...); } From 52b5fb7708feb47c0ca5d85bcfeaa7677b90678b Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 7 Sep 2025 18:11:46 +0530 Subject: [PATCH 06/16] cleanup. --- RTLBenchmarkApp/src/BenchMark.cpp | 30 -------------- RTLBenchmarkApp/src/BenchMark.h | 14 +++---- RTLBenchmarkApp/src/main.cpp | 3 -- .../detail/inc/LambdaFunction.h | 41 ------------------- .../detail/src/CMakeLists.txt | 1 - 5 files changed, 5 insertions(+), 84 deletions(-) delete mode 100644 ReflectionTemplateLib/detail/inc/LambdaFunction.h diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index ef5822c9..a18759e0 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -102,36 +102,6 @@ namespace rtl_bench } -namespace rtl_bench -{ - void BenchMark::BM_FunctionCall(benchmark::State& state) - { - static std::function getMsg = [](const str_type& pMsg) { - return getMessage(pMsg); - }; - - for (auto _ : state) - { - benchmark::DoNotOptimize(getMsg(g_longStr)); - } - } - - void BenchMark::BM_LambdaFunc(benchmark::State& state) - { - static rtl::detail::LambdaFunction obj; - - static auto _ = []() { - obj.init(getMessage); - return 0; - }(); - - for (auto _ : state) { - benchmark::DoNotOptimize(obj(g_longStr)); - } - } -} - - namespace rtl_bench { void BenchMark::reflectedCall_noReturn(benchmark::State& state) diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index a79f7a2e..f009aa6a 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -14,21 +14,21 @@ # define NOINLINE #endif -using str_type = std::string; //*/ std::string_view; +using str_type = /*std::string; //*/ std::string_view; namespace rtl_bench { static std::optional g_msg; NOINLINE static void sendMessage(str_type pMsg) { - std::string result = pMsg + pMsg; + std::string result = std::string(pMsg) + std::string(pMsg); result = result + result; result = result + result; g_msg = pMsg; } NOINLINE static str_type getMessage(str_type pMsg) { - std::string result = pMsg + pMsg; + std::string result = std::string(pMsg) + std::string(pMsg); result = result + result; result = result + result; g_msg = pMsg; @@ -38,7 +38,7 @@ namespace rtl_bench struct Node { NOINLINE void sendMessage(str_type pMsg) { - std::string result = pMsg + pMsg; + std::string result = std::string(pMsg) + std::string(pMsg); result = result + result; result = result + result; g_msg = pMsg; @@ -47,7 +47,7 @@ namespace rtl_bench NOINLINE str_type getMessage(str_type pMsg) { - std::string result = pMsg + pMsg; + std::string result = std::string(pMsg) + std::string(pMsg); result = result + result; result = result + result; g_msg = pMsg; @@ -95,9 +95,5 @@ namespace rtl_bench static void reflectedCall_withReturn(benchmark::State& state); static void reflectedMethodCall_withReturn(benchmark::State& state); - - static void BM_FunctionCall(benchmark::State& state); - - static void BM_LambdaFunc(benchmark::State& state); }; } \ No newline at end of file diff --git a/RTLBenchmarkApp/src/main.cpp b/RTLBenchmarkApp/src/main.cpp index e074a5db..673364f8 100644 --- a/RTLBenchmarkApp/src/main.cpp +++ b/RTLBenchmarkApp/src/main.cpp @@ -17,7 +17,4 @@ BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_withReturn); BENCHMARK(rtl_bench::BenchMark::reflectedCall_withReturn); BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_withReturn); -BENCHMARK(rtl_bench::BenchMark::BM_LambdaFunc); -BENCHMARK(rtl_bench::BenchMark::BM_FunctionCall); - BENCHMARK_MAIN(); diff --git a/ReflectionTemplateLib/detail/inc/LambdaFunction.h b/ReflectionTemplateLib/detail/inc/LambdaFunction.h deleted file mode 100644 index 1b1f3845..00000000 --- a/ReflectionTemplateLib/detail/inc/LambdaFunction.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "RObjectBuilder.hpp" - -namespace rtl::detail -{ - template - struct LambdaFunction - { - using Invoker = std::string(*)(void* , _signature&...); - - Invoker m_invoker = nullptr; - void* m_storage = nullptr; - - template - void init(_returnType(*pFunctor)(_signature...)) - { - struct Holder { - - using Functor = decltype(pFunctor); - Functor m_functor; - - Holder(Functor pFptr) : m_functor(pFptr) { } - }; - - static auto holder = Holder{ pFunctor }; - m_storage = &holder; - - m_invoker = +[](void* stor, _signature&... params) -> std::string { - - auto h = static_cast(stor); - return (h->m_functor)(params...); - }; - } - - std::string operator()(_signature&... params) - { - return m_invoker(m_storage, params...); - } - }; -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/src/CMakeLists.txt b/ReflectionTemplateLib/detail/src/CMakeLists.txt index da4ba808..d7be430f 100644 --- a/ReflectionTemplateLib/detail/src/CMakeLists.txt +++ b/ReflectionTemplateLib/detail/src/CMakeLists.txt @@ -9,7 +9,6 @@ set(LOCAL_SOURCES SET(LOCAL_HEADERS - "${PROJECT_SOURCE_DIR}/detail/inc/LambdaFunction.h" "${PROJECT_SOURCE_DIR}/detail/inc/CallReflector.h" "${PROJECT_SOURCE_DIR}/detail/inc/CxxReflection.h" "${PROJECT_SOURCE_DIR}/detail/inc/FunctionCaller.h" From 8752880572247403cb6c673c495c1c391aa20a1e Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Mon, 8 Sep 2025 02:15:26 +0530 Subject: [PATCH 07/16] RObjectBuilder optimized. --- .../inc/TestMirrorProvider.h | 2 +- .../src/TestMirrorProvider.cpp | 10 +- RTLBenchmarkApp/src/BenchMark.cpp | 66 ++++------ RTLBenchmarkApp/src/BenchMark.h | 36 ++---- RTLBenchmarkApp/src/main.cpp | 2 - .../CxxMirrorTests/CxxMirrorObjectTest.cpp | 7 -- .../CxxMirrorTests/CxxMirrorThreadingTest.cpp | 2 - .../MoveConstructorTests.cpp | 4 - ReflectionTemplateLib/access/inc/RObject.h | 25 ++-- ReflectionTemplateLib/access/inc/RObject.hpp | 30 ++--- .../detail/inc/LambdaFunction.h | 41 ------- .../detail/inc/RObjExtracter.h | 18 +-- .../detail/inc/RObjectBuilder.h | 34 ++--- .../detail/inc/RObjectBuilder.hpp | 101 +++++++-------- ReflectionTemplateLib/detail/inc/RObjectId.h | 8 +- .../detail/inc/SetupConstructor.hpp | 8 +- .../detail/inc/SetupFunction.h | 3 + .../detail/inc/SetupFunction.hpp | 29 +++-- .../detail/inc/SetupMethod.h | 6 + .../detail/inc/SetupMethod.hpp | 116 +++++++++++++----- 20 files changed, 258 insertions(+), 290 deletions(-) delete mode 100644 ReflectionTemplateLib/detail/inc/LambdaFunction.h diff --git a/CxxRTLTypeRegistration/inc/TestMirrorProvider.h b/CxxRTLTypeRegistration/inc/TestMirrorProvider.h index 9900dac5..42072a54 100644 --- a/CxxRTLTypeRegistration/inc/TestMirrorProvider.h +++ b/CxxRTLTypeRegistration/inc/TestMirrorProvider.h @@ -22,7 +22,7 @@ namespace test_mirror static std::size_t calender; static std::size_t char_t; - static std::size_t void_t; + static std::size_t int_t; static std::size_t std_string; static std::size_t std_string_view; diff --git a/CxxRTLTypeRegistration/src/TestMirrorProvider.cpp b/CxxRTLTypeRegistration/src/TestMirrorProvider.cpp index 980c4456..dd2ac277 100644 --- a/CxxRTLTypeRegistration/src/TestMirrorProvider.cpp +++ b/CxxRTLTypeRegistration/src/TestMirrorProvider.cpp @@ -37,15 +37,15 @@ namespace test_mirror --------------------------------- */ // Registering void, valid but not useful at all. - rtl::type().record("void").build(), + rtl::type().record("int").build(), // Registering type 'void' again, ignored & emits- // [WARNING] Multiple registrations of the same type detected. - rtl::type().record("void").build(), + rtl::type().record("int").build(), // Registering type 'void' again, but with different name. ignored & emits- // [WARNING] Multiple registrations of the same type detected. - rtl::type().record("ccvoid").build(), + rtl::type().record("ccint").build(), // Registering pod, reflecting- constructor, copy-constructor & destructor. rtl::type().record("char").build(), @@ -266,7 +266,7 @@ namespace test_mirror std::size_t reflected_id::event = rtl::detail::TypeId::get(); std::size_t reflected_id::calender = rtl::detail::TypeId::get(); - std::size_t reflected_id::void_t = rtl::detail::TypeId::get(); + std::size_t reflected_id::int_t = rtl::detail::TypeId::get(); std::size_t reflected_id::char_t = rtl::detail::TypeId::get(); std::size_t reflected_id::std_string = rtl::detail::TypeId::get(); std::size_t reflected_id::std_string_view = rtl::detail::TypeId::get(); @@ -277,7 +277,7 @@ namespace test_mirror static std::unordered_map nameIdMap( { { "char", char_t }, - { "void", void_t }, + { "int", int_t }, { "string", std_string }, { "string_view", std_string_view }, diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index a18759e0..db703b0e 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -11,15 +11,15 @@ namespace { - static const char* LONG_STR = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do" - "do aeiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis" - "nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure" - "dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Except" - "eur ssint occaecat cupidatat nnon proident, sunt in culpa qui officia deserunt mollit anim id"; + static const char* LONG_STR = "Lorem ipsum";// dolor sit amet, consectetur adipiscing elit, sed do"; + //"do aeiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis" + //"nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure" + //"dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Except" + //"eur ssint occaecat cupidatat nnon proident, sunt in culpa qui officia deserunt mollit anim id"; } // Pre-created string to isolate call overhead -static const std::string g_longStr(LONG_STR); +static argStr_t g_longStr(LONG_STR); namespace rtl_bench { @@ -33,23 +33,9 @@ namespace rtl_bench } - void BenchMark::autoLambdaCall_noReturn(benchmark::State& state) - { - static auto sendMsg = [](const str_type& pMsg) { - sendMessage(pMsg); - }; - - for (auto _ : state) - { - sendMsg(g_longStr); - benchmark::DoNotOptimize(g_msg); - } - } - - void BenchMark::stdFunctionCall_noReturn(benchmark::State& state) { - static std::function sendMsg = [](const str_type& pMsg) { + static std::function sendMsg = [](argStr_t& pMsg) { sendMessage(pMsg); }; @@ -60,6 +46,7 @@ namespace rtl_bench } } + void BenchMark::directCall_withReturn(benchmark::State& state) { static auto _ = []() { @@ -70,33 +57,22 @@ namespace rtl_bench for (auto _ : state) { - benchmark::DoNotOptimize(getMessage(g_longStr)); - } - } - - - void BenchMark::autoLambdaCall_withReturn(benchmark::State& state) - { - auto getMsg = [](const str_type& pMsg) { - return getMessage(pMsg); - }; - - for (auto _ : state) - { - benchmark::DoNotOptimize(getMsg(g_longStr)); + volatile std::string forced = std::move(getMessage(g_longStr)); // ensures real move + benchmark::DoNotOptimize(forced); } } void BenchMark::stdFunctionCall_withReturn(benchmark::State& state) { - static std::function getMsg = [](const str_type& pMsg) { + static std::function getMsg = [](argStr_t& pMsg) { return getMessage(pMsg); }; for (auto _ : state) { - benchmark::DoNotOptimize(getMsg(g_longStr)); + volatile std::string forced = std::move(getMsg(g_longStr)); // ensures real move + benchmark::DoNotOptimize(forced); } } } @@ -109,7 +85,7 @@ namespace rtl_bench static rtl::Function sendMsg = cxx_mirror().getFunction("sendMessage").value(); static auto _ = []() { - if (sendMsg.bind().call(g_longStr).err == rtl::error::None) { + if (sendMsg.bind().call(g_longStr).err == rtl::error::None) { std::cout << "[rtl:0] call success.\n"; } else { @@ -120,7 +96,7 @@ namespace rtl_bench for (auto _ : state) { - benchmark::DoNotOptimize(sendMsg.bind().call(g_longStr)); + benchmark::DoNotOptimize(sendMsg.bind().call(g_longStr)); } } @@ -131,7 +107,7 @@ namespace rtl_bench static rtl::Method sendMsg = rNode.getMethod("sendMessage").value(); static rtl::RObject robj = rNode.create().rObject; static auto _ = []() { - if (sendMsg.bind(robj).call(g_longStr).err == rtl::error::None) { + if (sendMsg.bind(robj).call(g_longStr).err == rtl::error::None) { std::cout << "[rtl:1] call success.\n"; } else { @@ -142,7 +118,7 @@ namespace rtl_bench for (auto _ : state) { - benchmark::DoNotOptimize(sendMsg.bind(robj).call(g_longStr)); + benchmark::DoNotOptimize(sendMsg.bind(robj).call(g_longStr)); } } @@ -151,7 +127,7 @@ namespace rtl_bench { static rtl::Function getMsg = cxx_mirror().getFunction("getMessage").value(); static auto _ = []() { - if (getMsg.bind().call(g_longStr).err == rtl::error::None) { + if (getMsg.bind().call(g_longStr).err == rtl::error::None) { std::cout << "[rtl:2] call success.\n"; } else { @@ -162,7 +138,7 @@ namespace rtl_bench for (auto _ : state) { - benchmark::DoNotOptimize(getMsg.bind().call(g_longStr)); + benchmark::DoNotOptimize(getMsg.bind().call(g_longStr)); } } @@ -173,7 +149,7 @@ namespace rtl_bench static rtl::Method getMsg = rNode.getMethod("getMessage").value(); static rtl::RObject robj = rNode.create().rObject; static auto _ = []() { - if (getMsg.bind(robj).call(g_longStr).err == rtl::error::None) { + if (getMsg.bind(robj).call(g_longStr).err == rtl::error::None) { std::cout << "[rtl:3] call success.\n"; } else { @@ -184,7 +160,7 @@ namespace rtl_bench for (auto _ : state) { - benchmark::DoNotOptimize(getMsg.bind(robj).call(g_longStr)); + benchmark::DoNotOptimize(getMsg.bind(robj).call(g_longStr)); } } } \ No newline at end of file diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index acb9689c..141d01a4 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -12,44 +12,30 @@ # define NOINLINE #endif -using str_type = /*std::string; //*/ std::string_view; +using argStr_t = std::string_view; +using retStr_t = std::string; namespace rtl_bench { static std::optional g_msg; - NOINLINE static void sendMessage(str_type pMsg) { - std::string result = std::string(pMsg) + std::string(pMsg); - result = result + result; - result = result + result; + NOINLINE static void sendMessage(argStr_t pMsg) { g_msg = pMsg; } - NOINLINE static str_type getMessage(str_type pMsg) { - std::string result = std::string(pMsg) + std::string(pMsg); - result = result + result; - result = result + result; - g_msg = pMsg; - return str_type(g_msg->c_str()); + NOINLINE static retStr_t getMessage(argStr_t pMsg) { + return retStr_t(pMsg); } struct Node { - NOINLINE void sendMessage(str_type pMsg) { - std::string result = std::string(pMsg) + std::string(pMsg); - result = result + result; - result = result + result; - g_msg = pMsg; + NOINLINE void sendMessage(argStr_t pMsg) { g_msg = pMsg; } - NOINLINE str_type getMessage(str_type pMsg) + NOINLINE retStr_t getMessage(argStr_t pMsg) { - std::string result = std::string(pMsg) + std::string(pMsg); - result = result + result; - result = result + result; - g_msg = pMsg; - return str_type(g_msg->c_str()); + return retStr_t(pMsg); } }; @@ -60,7 +46,7 @@ namespace rtl_bench rtl::type().record("Node").build(), - rtl::type().function("sendMessage").build(sendMessage), + rtl::type().function("sendMessage").build(sendMessage), rtl::type().member().method("sendMessage").build(&Node::sendMessage), @@ -76,8 +62,6 @@ namespace rtl_bench { static void directCall_noReturn(benchmark::State& state); - static void autoLambdaCall_noReturn(benchmark::State& state); - static void stdFunctionCall_noReturn(benchmark::State& state); static void reflectedCall_noReturn(benchmark::State& state); @@ -86,8 +70,6 @@ namespace rtl_bench static void directCall_withReturn(benchmark::State& state); - static void autoLambdaCall_withReturn(benchmark::State& state); - static void stdFunctionCall_withReturn(benchmark::State& state); static void reflectedCall_withReturn(benchmark::State& state); diff --git a/RTLBenchmarkApp/src/main.cpp b/RTLBenchmarkApp/src/main.cpp index 673364f8..1d4d8488 100644 --- a/RTLBenchmarkApp/src/main.cpp +++ b/RTLBenchmarkApp/src/main.cpp @@ -6,13 +6,11 @@ BENCHMARK(rtl_bench::BenchMark::directCall_noReturn); -BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_noReturn); BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_noReturn); BENCHMARK(rtl_bench::BenchMark::reflectedCall_noReturn); BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_noReturn); BENCHMARK(rtl_bench::BenchMark::directCall_withReturn); -BENCHMARK(rtl_bench::BenchMark::autoLambdaCall_withReturn); BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_withReturn); BENCHMARK(rtl_bench::BenchMark::reflectedCall_withReturn); BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_withReturn); diff --git a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp index 570a8d33..d98723d4 100644 --- a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp +++ b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp @@ -11,13 +11,6 @@ namespace const rtl::CxxMirror cxx_mirror() { return rtl::CxxMirror({ - - // Registering void as a record type (valid type but has no members/constructors). - // Demonstrates that RTL can explicitly represent even fundamental non-instantiable types. - rtl::type().record("void").build(), - - // Example of compile-time safety: constructors for void are invalid, RTL enforces this. - // rtl::type().member().constructor().build(), // <- will not compile // Register char as a record type (fundamental but instantiable). rtl::type().record("char").build(), diff --git a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.cpp b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.cpp index 99460e54..b340a9c0 100644 --- a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.cpp +++ b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.cpp @@ -99,8 +99,6 @@ namespace rtl_tests rtl::type().function("strlen").build(std::strlen), - rtl::type().record("void").build(), - rtl::type().record("char").build(), rtl::type().record>("vector_int").build(), diff --git a/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp b/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp index 245dee72..19c0dd68 100644 --- a/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp +++ b/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp @@ -49,7 +49,6 @@ namespace rtl_tests // 'calander0' must be empty now. ASSERT_TRUE(calender0.isEmpty()); - EXPECT_NE(calender0.getTypeId(), calender1.getTypeId()); // After move, these instance count must remain same. EXPECT_TRUE(calender::get_instance_count() == 1); @@ -114,7 +113,6 @@ namespace rtl_tests // 'calander0' must be empty now. ASSERT_TRUE(calender0.isEmpty()); - EXPECT_NE(calender0.getTypeId(), calender1.getTypeId()); // After move, these instance count must remain same. EXPECT_TRUE(calender::get_instance_count() == 1); @@ -184,7 +182,6 @@ namespace rtl_tests // 'event0' must be empty now. ASSERT_TRUE(event0.isEmpty()); - EXPECT_NE(event0.getTypeId(), event1.getTypeId()); { // Event::reset() is a non-const method. can't be called on const-object. optional eventReset = classEvent->getMethod(event::str_reset); @@ -257,7 +254,6 @@ namespace rtl_tests // 'calander0' must be empty now. ASSERT_TRUE(calender0.isEmpty()); - EXPECT_NE(calender0.getTypeId(), calender1.getTypeId()); // After move, these instance count must remain same. EXPECT_TRUE(calender::get_instance_count() == 1); diff --git a/ReflectionTemplateLib/access/inc/RObject.h b/ReflectionTemplateLib/access/inc/RObject.h index 9555a61c..d3e64d60 100644 --- a/ReflectionTemplateLib/access/inc/RObject.h +++ b/ReflectionTemplateLib/access/inc/RObject.h @@ -28,6 +28,7 @@ namespace rtl::detail class RObjExtractor; + template struct RObjectBuilder; } @@ -42,17 +43,15 @@ namespace rtl { using Cloner = std::function< Return(const RObject&, rtl::alloc) >; - mutable detail::RObjectId m_objectId; - mutable std::any m_object; + mutable const Cloner* m_getClone; + mutable const detail::RObjectId* m_objectId; mutable const std::vector* m_converters; RObject(const RObject&) = default; - RObject(detail::RObjectId&& pRObjId, std::any&& pObject, const Cloner* pCloner, - const std::vector* pConverters); - - static std::atomic& getInstanceCounter(); + RObject(const detail::RObjectId* pRObjId, std::any&& pObject, const Cloner* pCloner, + const std::vector* pConverters) noexcept; std::size_t getConverterIndex(const std::size_t pToTypeId) const; @@ -70,16 +69,16 @@ namespace rtl RObject& operator=(RObject&&) = delete; RObject& operator=(const RObject&) = delete; - GETTER(std::size_t, TypeId, m_objectId.m_typeId) GETTER_BOOL(Empty, (m_object.has_value() == false)) - GETTER_BOOL(OnHeap, (m_objectId.m_allocatedOn == alloc::Heap)) - GETTER_BOOL(AllocatedByRtl, (m_objectId.m_allocatedOn == alloc::Heap)) + GETTER_BOOL(OnHeap, (m_objectId && m_objectId->m_allocatedOn == alloc::Heap)) + GETTER_BOOL(AllocatedByRtl, (m_objectId && m_objectId->m_allocatedOn == alloc::Heap)) + GETTER(std::size_t, TypeId, (m_objectId ? m_objectId->m_typeId : detail::TypeId<>::None)) /* Reflection Const Semantics: * - All reflected objects default to mutable internally; API enforces logical constness. * - RTL may 'const_cast' its own objects(allocated via RTL) but preserves logical constness. * - External objects (e.g. returned via Reflected call) keep original qualifier; if const, then const_cast is unsafe. - */ GETTER_BOOL(ConstCastSafe, m_objectId.m_isConstCastSafe) + */ GETTER_BOOL(ConstCastSafe, (m_objectId && m_objectId->m_isConstCastSafe)) template bool canViewAs() const; @@ -96,11 +95,15 @@ namespace rtl template, int> = 0> std::optional> view() const; + static std::atomic& getInstanceCounter(); + //friends :) template friend struct detail::RObjectUPtr; friend detail::RObjExtractor; - friend detail::RObjectBuilder; + + template + friend struct detail::RObjectBuilder; }; struct [[nodiscard]] Return { diff --git a/ReflectionTemplateLib/access/inc/RObject.hpp b/ReflectionTemplateLib/access/inc/RObject.hpp index fefa64ff..f7ddbf5c 100644 --- a/ReflectionTemplateLib/access/inc/RObject.hpp +++ b/ReflectionTemplateLib/access/inc/RObject.hpp @@ -24,11 +24,11 @@ namespace rtl { - inline RObject::RObject(detail::RObjectId&& pRObjId, std::any&& pObject, const Cloner* pCloner, - const std::vector* pConverters) - : m_objectId(pRObjId) - , m_object(std::forward(pObject)) + inline RObject::RObject(const detail::RObjectId* pRObjId, std::any&& pObject, const Cloner* pCloner, + const std::vector* pConverters) noexcept + : m_object(std::forward(pObject)) , m_getClone(pCloner) + , m_objectId(pRObjId) , m_converters(pConverters) { } @@ -40,7 +40,7 @@ namespace rtl { // Explicitly clear moved-from source pOther.m_object.reset(); - pOther.m_objectId = {}; + pOther.m_objectId = nullptr; pOther.m_getClone = nullptr; pOther.m_converters = nullptr; } @@ -54,7 +54,7 @@ namespace rtl inline std::size_t RObject::getConverterIndex(const std::size_t pToTypeId) const { - if (m_objectId.m_containsAs != detail::EntityKind::None) { + if (m_objectId->m_containsAs != detail::EntityKind::None) { for (std::size_t index = 0; index < m_converters->size(); index++) { if ((*m_converters)[index].first == pToTypeId) { return index; @@ -70,12 +70,12 @@ namespace rtl { if constexpr (traits::is_bare_type()) { if constexpr (traits::std_wrapper::type != detail::Wrapper::None) { - if (m_objectId.m_wrapperTypeId == traits::std_wrapper::id()) { + if (m_objectId->m_wrapperTypeId == traits::std_wrapper::id()) { return true; } } const auto& typeId = detail::TypeId::get(); - return (m_objectId.m_typeId == typeId || getConverterIndex(typeId) != index_none); + return (m_objectId->m_typeId == typeId || getConverterIndex(typeId) != index_none); } } @@ -85,7 +85,7 @@ namespace rtl { detail::EntityKind newKind = detail::EntityKind::None; const traits::Converter& convert = (*m_converters)[pIndex].second; - const std::any& viewObj = convert(m_object, m_objectId.m_containsAs, newKind); + const std::any& viewObj = convert(m_object, m_objectId->m_containsAs, newKind); const T* viewRef = detail::RObjExtractor::getPointer(viewObj, newKind); if (viewRef != nullptr && newKind == detail::EntityKind::Ref) { @@ -105,7 +105,7 @@ namespace rtl { if constexpr (traits::is_bare_type()) { - if (detail::TypeId::get() == m_objectId.m_wrapperTypeId) + if (detail::TypeId::get() == m_objectId->m_wrapperTypeId) { using U = detail::RObjectUPtr::value_type>; const U& uptrRef = *(detail::RObjExtractor(this).getWrapper()); @@ -121,7 +121,7 @@ namespace rtl { if constexpr (traits::is_bare_type()) { - if (detail::TypeId::get() == m_objectId.m_wrapperTypeId) + if (detail::TypeId::get() == m_objectId->m_wrapperTypeId) { const T& sptrRef = *(detail::RObjExtractor(this).getWrapper()); return std::optional>(std::in_place, const_cast(sptrRef)); @@ -137,7 +137,7 @@ namespace rtl if constexpr (traits::is_bare_type()) { const std::size_t asTypeId = detail::TypeId::get(); - if (asTypeId == m_objectId.m_typeId) + if (asTypeId == m_objectId->m_typeId) { const T* valRef = detail::RObjExtractor(this).getPointer(); if (valRef != nullptr) { @@ -184,10 +184,10 @@ namespace rtl template<> inline Return RObject::createCopy() const { - if (m_objectId.m_wrapperType == detail::Wrapper::None) { + if (m_objectId->m_wrapperType == detail::Wrapper::None) { return { error::NotWrapperType, RObject{} }; } - else if (m_objectId.m_wrapperType == detail::Wrapper::Unique) + else if (m_objectId->m_wrapperType == detail::Wrapper::Unique) { return { error::TypeNotCopyConstructible, RObject{} }; } @@ -212,7 +212,7 @@ namespace rtl else if constexpr (_copyTarget == copy::Auto) { // RTL wraps the objects allocated on heap in 'std::unique_ptr'. Which by default is transparent to RTL itself. // 'std::unique_ptr' acquired via any other source, (e.g. return value) are not transparent. hence the second condition. - if (m_objectId.m_wrapperType != detail::Wrapper::None && !isAllocatedByRtl()) + if (m_objectId->m_wrapperType != detail::Wrapper::None && !isAllocatedByRtl()) { return createCopy<_allocOn, detail::EntityKind::Wrapper>(); } diff --git a/ReflectionTemplateLib/detail/inc/LambdaFunction.h b/ReflectionTemplateLib/detail/inc/LambdaFunction.h deleted file mode 100644 index 14413017..00000000 --- a/ReflectionTemplateLib/detail/inc/LambdaFunction.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "RObjectBuilder.hpp" - -namespace rtl::detail -{ - template - struct LambdaFunction - { - using Invoker = _retT(*)(void* , _signature&...); - - Invoker m_invoker = nullptr; - void* m_storage = nullptr; - - template - void init(_returnType(*pFunctor)(_signature...)) - { - struct Holder { - - using Functor = decltype(pFunctor); - Functor m_functor; - - Holder(Functor pFptr) : m_functor(pFptr) { } - }; - - static auto holder = Holder{ pFunctor }; - m_storage = &holder; - - m_invoker = +[](void* stor, _signature&... params) -> _retT { - - auto h = static_cast(stor); - return (h->m_functor)(params...); - }; - } - - _retT operator()(_signature&... params) - { - return m_invoker(m_storage, params...); - } - }; -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/RObjExtracter.h b/ReflectionTemplateLib/detail/inc/RObjExtracter.h index c805f9d6..97a89d83 100644 --- a/ReflectionTemplateLib/detail/inc/RObjExtracter.h +++ b/ReflectionTemplateLib/detail/inc/RObjExtracter.h @@ -48,7 +48,7 @@ namespace rtl::detail const T* getPointer() const { try { - switch (m_rObj.m_objectId.m_containsAs) + switch (m_rObj.m_objectId->m_containsAs) { case EntityKind::Ref: { return std::any_cast(m_rObj.m_object); @@ -72,12 +72,12 @@ namespace rtl::detail auto getWrapper() const -> const RObjectUPtr::value_type>* { try { - if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Unique) + if (m_rObj.m_objectId->m_wrapperType == detail::Wrapper::Unique) { using _T = traits::std_wrapper::value_type; if constexpr (traits::is_const_v<_T>) { - if (m_rObj.m_objectId.m_isWrappingConst) + if (m_rObj.m_objectId->m_isWrappingConst) { using U = detail::RObjectUPtr; const U& uptrRef = std::any_cast(m_rObj.m_object); @@ -101,12 +101,12 @@ namespace rtl::detail const T* getWrapper() const { try { - if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Shared) + if (m_rObj.m_objectId->m_wrapperType == detail::Wrapper::Shared) { using _T = traits::std_wrapper::value_type; if constexpr (traits::is_const_v<_T>) { - if (m_rObj.m_objectId.m_isWrappingConst) { + if (m_rObj.m_objectId->m_isWrappingConst) { using U = std::shared_ptr; const U& sptrRef = std::any_cast(m_rObj.m_object); return static_cast(&sptrRef); @@ -131,9 +131,9 @@ namespace rtl::detail try { if constexpr (std::is_destructible_v) { - if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Unique) + if (m_rObj.m_objectId->m_wrapperType == detail::Wrapper::Unique) { - if (m_rObj.m_objectId.m_isWrappingConst) { + if (m_rObj.m_objectId->m_isWrappingConst) { using U = detail::RObjectUPtr; const U& uptrRef = std::any_cast(m_rObj.m_object); return static_cast(uptrRef.get()); @@ -144,9 +144,9 @@ namespace rtl::detail return static_cast(uptrRef.get()); } } - if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Shared) + if (m_rObj.m_objectId->m_wrapperType == detail::Wrapper::Shared) { - if (m_rObj.m_objectId.m_isWrappingConst) { + if (m_rObj.m_objectId->m_isWrappingConst) { using U = std::shared_ptr; const auto& sptrRef = std::any_cast(m_rObj.m_object); return static_cast(sptrRef.get()); diff --git a/ReflectionTemplateLib/detail/inc/RObjectBuilder.h b/ReflectionTemplateLib/detail/inc/RObjectBuilder.h index 00fa53e1..86612b89 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectBuilder.h +++ b/ReflectionTemplateLib/detail/inc/RObjectBuilder.h @@ -20,25 +20,17 @@ namespace rtl { namespace rtl::detail { - class RObjectBuilder + template + struct RObjectBuilder { - using Cloner = std::function< Return(const RObject&, rtl::alloc) >; - - template - static const Cloner& buildCloner(); - - template - static const std::vector& getConverters(); - - public: - RObjectBuilder() = delete; RObjectBuilder(const RObjectBuilder&) = delete; - static const std::size_t rtlManagedInstanceCount(); + template requires (_allocOn == alloc::Heap) + static RObject build(T&& pVal, bool pIsConstCastSafe) noexcept; - template - static RObject build(T&& pVal); + template requires (_allocOn == alloc::Stack) + static RObject build(T&& pVal, bool pIsConstCastSafe) noexcept; }; } @@ -47,34 +39,34 @@ namespace rtl { inline const std::size_t getRtlManagedHeapInstanceCount() { - return detail::RObjectBuilder::rtlManagedInstanceCount(); + return RObject::getInstanceCounter(); } template - inline RObject reflect(T(&pArr)[N]) + inline RObject reflect(T(&pArr)[N]) noexcept { if constexpr (std::is_same_v, char>) { - return detail::RObjectBuilder::build>(std::string_view(pArr, N - 1)); + return detail::RObjectBuilder::build(std::string_view(pArr, N - 1), !traits::is_const_v); } else { - return detail::RObjectBuilder::build, alloc::Stack, !traits::is_const_v>(std::vector(pArr, pArr + N)); + return detail::RObjectBuilder>::build(std::vector(pArr, pArr + N), !traits::is_const_v); } } template - inline RObject reflect(T&& pVal) + inline RObject reflect(T&& pVal) noexcept { using _T = traits::raw_t; if constexpr (traits::std_wrapper<_T>::type == detail::Wrapper::None) { - return detail::RObjectBuilder::build>(std::forward(pVal)); + return detail::RObjectBuilder::build(std::forward(pVal), !traits::is_const_v); } else { constexpr bool isConstCastSafe = !traits::is_const_v::value_type>; - return detail::RObjectBuilder::build(std::forward(pVal)); + return detail::RObjectBuilder::build(std::forward(pVal), isConstCastSafe); } } } \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp index 35d8453f..397d1270 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp +++ b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp @@ -18,14 +18,11 @@ #include "RObjectBuilder.h" namespace rtl::detail { - - inline const std::size_t RObjectBuilder::rtlManagedInstanceCount() - { - return RObject::getInstanceCounter(); - } + using Cloner = std::function< Return(const RObject&, rtl::alloc) >; + template - inline const std::vector& RObjectBuilder::getConverters() + FORCE_INLINE const std::vector& getConverters() noexcept { // extract wrapper info. using _W = traits::std_wrapper>; @@ -35,7 +32,7 @@ namespace rtl::detail { } template - inline const RObjectBuilder::Cloner& RObjectBuilder::buildCloner() + FORCE_INLINE const Cloner& buildCloner() noexcept { using W = traits::std_wrapper; using _T = std::conditional_t; @@ -50,12 +47,12 @@ namespace rtl::detail { case alloc::Stack: return { error::None, - RObjectBuilder::template build<_T, alloc::Stack, true>(_T(srcObj)) + RObjectBuilder<_T>::template build(_T(srcObj), true) }; case alloc::Heap: return { error::None, - RObjectBuilder::template build<_T*, alloc::Heap, true>(new _T(srcObj)) + RObjectBuilder<_T*>::template build(new _T(srcObj), true) }; default: return { @@ -79,59 +76,63 @@ namespace rtl::detail { } + template + template requires (_allocOn == alloc::Heap) + RObject RObjectBuilder::build(T&& pVal, bool pIsConstCastSafe) noexcept + { + using _T = traits::raw_t; + static const RObjectId robjId = RObjectId::create, _allocOn>(pIsConstCastSafe); + + return RObject( &robjId, + std::any{ + std::in_place_type>, + RObjectUPtr<_T>(std::unique_ptr<_T>(static_cast<_T*>(pVal))) + }, + &buildCloner<_T>(), + &getConverters>()); + } - template - inline RObject RObjectBuilder::build(T&& pVal) + + template + template requires (_allocOn == alloc::Stack) + RObject RObjectBuilder::build(T&& pVal, bool pIsConstCastSafe) noexcept { using _T = traits::raw_t; constexpr bool isRawPointer = std::is_pointer_v>; - if constexpr (_allocOn == alloc::Heap) + if constexpr (isRawPointer) { - static_assert(isRawPointer, "Invalid 'alloc' specified for non-pointer-type 'T'"); - return RObject(RObjectId::create, _allocOn, _isConstCastSafe>(), - std::any { - std::in_place_type>, - RObjectUPtr<_T>(std::unique_ptr<_T>(static_cast<_T*>(pVal))) - }, - &buildCloner<_T>(), - &getConverters>()); + static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); + return RObject( &robjId, + std::any { static_cast(pVal) }, + &buildCloner<_T>(), + &getConverters() ); } - else if constexpr (_allocOn == alloc::Stack) + else { - if constexpr (isRawPointer) + if constexpr (traits::std_wrapper<_T>::type == Wrapper::Unique) { - return RObject(RObjectId::create(), - std::any { - static_cast(pVal) - }, - &buildCloner<_T>(), - &getConverters()); + using U = traits::std_wrapper<_T>::value_type; + static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); + return RObject( &robjId, + std::any { + std::in_place_type>, + RObjectUPtr(std::move(pVal)) + }, + &buildCloner<_T>(), + &getConverters() ); } else { - if constexpr (traits::std_wrapper<_T>::type == Wrapper::Unique) - { - using U = traits::std_wrapper<_T>::value_type; - return RObject(RObjectId::create(), - std::any { - std::in_place_type>, - RObjectUPtr(std::move(pVal)) - }, - &buildCloner<_T>(), - &getConverters()); - } - else - { - static_assert(std::is_copy_constructible_v<_T>, "T must be copy-constructible (std::any requires this)."); - return RObject(RObjectId::create(), - std::any { - std::in_place_type, - std::forward(pVal) - }, - &buildCloner<_T>(), - &getConverters()); - } + static_assert(std::is_copy_constructible_v<_T>, "T must be copy-constructible (std::any requires this)."); + static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); + return RObject( &robjId, + std::any { + std::in_place_type, + std::forward(pVal) + }, + &buildCloner<_T>(), + &getConverters() ); } } } diff --git a/ReflectionTemplateLib/detail/inc/RObjectId.h b/ReflectionTemplateLib/detail/inc/RObjectId.h index 7ee8dbf4..a5d5decc 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectId.h +++ b/ReflectionTemplateLib/detail/inc/RObjectId.h @@ -37,7 +37,7 @@ namespace rtl::detail GETTER(EntityKind, ContainedAs, m_containsAs) template - FORCE_INLINE static constexpr EntityKind getEntityKind() + FORCE_INLINE static constexpr EntityKind getEntityKind() noexcept { using W = traits::std_wrapper>; using _T = traits::raw_t>; @@ -56,8 +56,8 @@ namespace rtl::detail } - template - FORCE_INLINE static RObjectId create() + template + FORCE_INLINE static RObjectId create(bool pIsConstCastSafe) noexcept { // extract wrapper info. using _W = traits::std_wrapper>; @@ -68,7 +68,7 @@ namespace rtl::detail const std::size_t wrapperId = _W::id(); const std::size_t typeId = rtl::detail::TypeId<_T>::get(); constexpr bool isWrappingConst = (_W::type != Wrapper::None && traits::is_const_v); - return RObjectId{ isWrappingConst, _isConstCastSafe, typeId, wrapperId, _allocOn, _W::type, entityKind }; + return RObjectId{ isWrappingConst, pIsConstCastSafe, typeId, wrapperId, _allocOn, _W::type, entityKind }; } }; } \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp b/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp index bbde6efe..79935663 100644 --- a/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp @@ -37,15 +37,15 @@ namespace rtl::detail } else { return { error::None, - RObjectBuilder::build<_recordType, alloc::Stack, true>( - _recordType(std::forward<_signature>(params)...)) + RObjectBuilder<_recordType>::build( + _recordType(std::forward<_signature>(params)...), true) }; } } else if (pAllocType == alloc::Heap) { return { error::None, - RObjectBuilder::build<_recordType*, alloc::Heap, true>( - new _recordType(std::forward<_signature>(params)...)) + RObjectBuilder<_recordType*>::build( + new _recordType(std::forward<_signature>(params)...), true) }; } } diff --git a/ReflectionTemplateLib/detail/inc/SetupFunction.h b/ReflectionTemplateLib/detail/inc/SetupFunction.h index 131a1f62..493aa4a9 100644 --- a/ReflectionTemplateLib/detail/inc/SetupFunction.h +++ b/ReflectionTemplateLib/detail/inc/SetupFunction.h @@ -35,6 +35,9 @@ namespace rtl { template using FunctionLambda = std::function < Return(_signature...) >; + template + static FunctionLambda<_signature...> getCaller(void(*pFunctor)(_signature...)); + template static FunctionLambda<_signature...> getCaller(_returnType(*pFunctor)(_signature...)); diff --git a/ReflectionTemplateLib/detail/inc/SetupFunction.hpp b/ReflectionTemplateLib/detail/inc/SetupFunction.hpp index 9908808d..0246805e 100644 --- a/ReflectionTemplateLib/detail/inc/SetupFunction.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupFunction.hpp @@ -18,6 +18,19 @@ namespace rtl { namespace detail { + template + template + inline SetupFunction<_derivedType>::FunctionLambda<_signature...> + SetupFunction<_derivedType>::getCaller(void(*pFunctor)(_signature...)) + { + return [=](_signature&&... params) -> Return + { + pFunctor(std::forward<_signature>(params)...); + return { error::None, RObject{} }; + }; + } + + template template inline SetupFunction<_derivedType>::FunctionLambda<_signature...> @@ -29,25 +42,21 @@ namespace rtl { constexpr bool isConstCastSafe = (!traits::is_const_v<_returnType>); - if constexpr (std::is_same_v<_returnType, void>) { - //if the function do not returns anything, this block will be retained by compiler. - (*pFunctor)(std::forward<_signature>(params)...); - return { error::None, RObject{} }; - } - else if constexpr (std::is_reference_v<_returnType>) { + if constexpr (std::is_reference_v<_returnType>) { /* if the function returns reference, this block will be retained by compiler. Note: reference to temporary or dangling is not checked here. */ using _rawRetType = traits::raw_t<_returnType>; - const _rawRetType& retObj = (*pFunctor)(std::forward<_signature>(params)...); + const _rawRetType& retObj = pFunctor(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj) + RObjectBuilder::build(&retObj, isConstCastSafe) }; } else { //if the function returns anything (not refrence), this block will be retained by compiler. + _returnType&& retObj = std::move(pFunctor(std::forward<_signature>(params)...)); return { error::None, - RObjectBuilder::build<_returnType, rtl::alloc::Stack, isConstCastSafe>( - (*pFunctor)(std::forward<_signature>(params)...)) + RObjectBuilder<_returnType>::build( + std::forward<_returnType>(retObj), isConstCastSafe) }; } }; diff --git a/ReflectionTemplateLib/detail/inc/SetupMethod.h b/ReflectionTemplateLib/detail/inc/SetupMethod.h index 8456aa6e..2aea8dfe 100644 --- a/ReflectionTemplateLib/detail/inc/SetupMethod.h +++ b/ReflectionTemplateLib/detail/inc/SetupMethod.h @@ -41,6 +41,12 @@ namespace rtl { template static MethodLambda<_signature...> getMethodCaller(_returnType(_recordType::* pFunctor)(_signature...) const); + + template + static MethodLambda<_signature...> getVoidMethodCaller(_returnType(_recordType::* pFunctor)(_signature...)); + + template + static MethodLambda<_signature...> getVoidMethodCaller(_returnType(_recordType::* pFunctor)(_signature...) const); protected: diff --git a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp index 117460be..498f2bf5 100644 --- a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp @@ -20,6 +20,27 @@ namespace rtl { namespace detail { + + template + template + inline SetupMethod<_derivedType>::MethodLambda<_signature...> + SetupMethod<_derivedType>::getVoidMethodCaller(_returnType(_recordType::* pFunctor)(_signature...)) + { + /* a variable arguments lambda, which finally calls the 'pFunctor' with 'params...'. + this is stored in _derivedType's (MethodContainer) vector holding lambda's. + */ return [=](const RObject& pTargetObj, _signature&&...params)-> Return + { + if (!pTargetObj.isConstCastSafe()) { + return { error::IllegalConstCast, RObject{} }; + } + + _recordType& target = const_cast<_recordType&>(pTargetObj.view<_recordType>()->get()); + (target.*pFunctor)(std::forward<_signature>(params)...); + return { error::None, RObject{} }; + }; + } + + template template inline SetupMethod<_derivedType>::MethodLambda<_signature...> @@ -29,38 +50,52 @@ namespace rtl this is stored in _derivedType's (MethodContainer) vector holding lambda's. */ return [=](const RObject& pTargetObj, _signature&&...params)-> Return { - if (!pTargetObj.isConstCastSafe()) - { + if (!pTargetObj.isConstCastSafe()) { return { error::IllegalConstCast, RObject{} }; } constexpr bool isConstCastSafe = (!traits::is_const_v<_returnType>); //'target' needs const_cast, since the functor is non-const-member-function. _recordType& target = const_cast<_recordType&>(pTargetObj.view<_recordType>()->get()); - if constexpr (std::is_same_v<_returnType, void>) { - //if the function do not returns anything, this block will be retained by compiler. - (target.*pFunctor)(std::forward<_signature>(params)...); - return { error::None, RObject{} }; - } - else if constexpr (std::is_reference_v<_returnType>) { + if constexpr (std::is_reference_v<_returnType>) + { /* if the function returns reference, this block will be retained by compiler. Note: reference to temporary or dangling is not checked here. */ using _rawRetType = traits::raw_t<_returnType>; const _rawRetType& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj) + RObjectBuilder::build(&retObj, isConstCastSafe) }; } else { + + _returnType&& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build<_returnType, alloc::Stack, isConstCastSafe>( - (target.*pFunctor)(std::forward<_signature>(params)...)) + RObjectBuilder<_returnType>::build( + std::forward<_returnType>(retObj), isConstCastSafe) }; } }; } + + template + template + inline SetupMethod<_derivedType>::MethodLambda<_signature...> + SetupMethod<_derivedType>::getVoidMethodCaller(_returnType(_recordType::* pFunctor)(_signature...) const) + { + /* a variable arguments lambda, which finally calls the 'pFunctor' with 'params...'. + this is stored in _derivedType's (MethodContainer) vector holding lambda's. + */ return [=](const RObject& pTargetObj, _signature&&...params)-> Return + { + const _recordType& target = pTargetObj.view<_recordType>()->get(); + (target.*pFunctor)(std::forward<_signature>(params)...); + return { error::None, RObject{} }; + }; + } + + template template inline SetupMethod<_derivedType>::MethodLambda<_signature...> @@ -73,25 +108,20 @@ namespace rtl constexpr bool isConstCastSafe = (!traits::is_const_v<_returnType>); //'target' is const and 'pFunctor' is const-member-function. const _recordType& target = pTargetObj.view<_recordType>()->get(); - - if constexpr (std::is_same_v<_returnType, void>) { - //if the function do not returns anything, this block will be retained by compiler. - (target.*pFunctor)(std::forward<_signature>(params)...); - return { error::None, RObject{} }; - } - else if constexpr (std::is_reference_v<_returnType>) { - /* if the function returns reference, this block will be retained by compiler. - Note: reference to temporary or dangling is not checked here. - */ using _rawRetType = traits::raw_t<_returnType>; + if constexpr (std::is_reference_v<_returnType>) { + /* if the function returns reference, this block will be retained by compiler. + Note: reference to temporary or dangling is not checked here. + */ using _rawRetType = traits::raw_t<_returnType>; const _rawRetType& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj) + RObjectBuilder::build(&retObj, isConstCastSafe) }; } else { + _returnType&& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build<_returnType, alloc::Stack, isConstCastSafe>( - (target.*pFunctor)(std::forward<_signature>(params)...)) + RObjectBuilder<_returnType>::build( + std::forward<_returnType>(retObj), isConstCastSafe) }; } }; @@ -139,10 +169,21 @@ namespace rtl //generate a type-id of '_returnType'. const std::size_t retTypeId = TypeId>::get(); //finally add the lambda 'functor' in 'MethodContainer' lambda vector and get the index. - const std::size_t index = _derivedType::pushBack(getMethodCaller(pFunctor), getIndex, updateIndex); - //construct the hash-key 'FunctorId' and return. - return detail::FunctorId(index, retTypeId, TypeId<_recordType>::get(), _derivedType::getContainerId(), - _derivedType::template getSignatureStr<_recordType, _returnType>()); + + if constexpr (std::is_same_v<_returnType, void>) + { + const std::size_t index = _derivedType::pushBack(getVoidMethodCaller(pFunctor), getIndex, updateIndex); + //construct the hash-key 'FunctorId' and return. + return detail::FunctorId(index, retTypeId, TypeId<_recordType>::get(), _derivedType::getContainerId(), + _derivedType::template getSignatureStr<_recordType, _returnType>()); + } + else + { + const std::size_t index = _derivedType::pushBack(getMethodCaller(pFunctor), getIndex, updateIndex); + //construct the hash-key 'FunctorId' and return. + return detail::FunctorId(index, retTypeId, TypeId<_recordType>::get(), _derivedType::getContainerId(), + _derivedType::template getSignatureStr<_recordType, _returnType>()); + } } @@ -184,10 +225,21 @@ namespace rtl //generate a type-id of '_returnType'. const std::size_t retTypeId = TypeId>::get(); //finally add the lambda 'functor' in 'MethodContainer' lambda vector and get the index. - const std::size_t index = _derivedType::pushBack(getMethodCaller(pFunctor), getIndex, updateIndex); - //construct the hash-key 'FunctorId' and return. - return detail::FunctorId(index, retTypeId, TypeId<_recordType>::get(), _derivedType::getContainerId(), - _derivedType::template getSignatureStr<_recordType, _returnType>()); + + if constexpr (std::is_same_v<_returnType, void>) + { + const std::size_t index = _derivedType::pushBack(getVoidMethodCaller(pFunctor), getIndex, updateIndex); + //construct the hash-key 'FunctorId' and return. + return detail::FunctorId(index, retTypeId, TypeId<_recordType>::get(), _derivedType::getContainerId(), + _derivedType::template getSignatureStr<_recordType, _returnType>()); + } + else + { + const std::size_t index = _derivedType::pushBack(getMethodCaller(pFunctor), getIndex, updateIndex); + //construct the hash-key 'FunctorId' and return. + return detail::FunctorId(index, retTypeId, TypeId<_recordType>::get(), _derivedType::getContainerId(), + _derivedType::template getSignatureStr<_recordType, _returnType>()); + } } } } \ No newline at end of file From e444ba13d7ffc258f890f3d66a8c4f68afbec65e Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Mon, 8 Sep 2025 02:19:14 +0530 Subject: [PATCH 08/16] removed deleted header include. --- RTLBenchmarkApp/src/BenchMark.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index db703b0e..d8599051 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -6,9 +6,6 @@ #include "BenchMark.h" -#include "LambdaFunction.h" - - namespace { static const char* LONG_STR = "Lorem ipsum";// dolor sit amet, consectetur adipiscing elit, sed do"; From d0f226d5955438c60154ce03fc14ec0abfa5242c Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Mon, 8 Sep 2025 03:11:38 +0530 Subject: [PATCH 09/16] benchmark baseline setup final. --- RTLBenchmarkApp/src/BenchMark.cpp | 6 ++---- RTLBenchmarkApp/src/BenchMark.h | 8 +++++--- ReflectionTemplateLib/detail/inc/SetupMethod.hpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index d8599051..f7becc51 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -54,8 +54,7 @@ namespace rtl_bench for (auto _ : state) { - volatile std::string forced = std::move(getMessage(g_longStr)); // ensures real move - benchmark::DoNotOptimize(forced); + benchmark::DoNotOptimize(getMessage(g_longStr)); } } @@ -68,8 +67,7 @@ namespace rtl_bench for (auto _ : state) { - volatile std::string forced = std::move(getMsg(g_longStr)); // ensures real move - benchmark::DoNotOptimize(forced); + benchmark::DoNotOptimize(getMsg(g_longStr)); } } } diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index 141d01a4..5e82482c 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -13,7 +13,7 @@ #endif using argStr_t = std::string_view; -using retStr_t = std::string; +using retStr_t = std::string_view; namespace rtl_bench { @@ -24,7 +24,8 @@ namespace rtl_bench } NOINLINE static retStr_t getMessage(argStr_t pMsg) { - return retStr_t(pMsg); + g_msg = pMsg; + return retStr_t(g_msg->c_str()); } struct Node @@ -35,7 +36,8 @@ namespace rtl_bench NOINLINE retStr_t getMessage(argStr_t pMsg) { - return retStr_t(pMsg); + g_msg = pMsg; + return retStr_t(g_msg->c_str()); } }; diff --git a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp index 498f2bf5..bad3bf8f 100644 --- a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp @@ -69,7 +69,7 @@ namespace rtl } else { - _returnType&& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); + _returnType&& retObj = std::move((target.*pFunctor)(std::forward<_signature>(params)...)); return { error::None, RObjectBuilder<_returnType>::build( std::forward<_returnType>(retObj), isConstCastSafe) @@ -118,7 +118,7 @@ namespace rtl }; } else { - _returnType&& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); + _returnType&& retObj = std::move((target.*pFunctor)(std::forward<_signature>(params)...)); return { error::None, RObjectBuilder<_returnType>::build( std::forward<_returnType>(retObj), isConstCastSafe) From b811508814db7eab2b89e27decb63e5a5586a0a9 Mon Sep 17 00:00:00 2001 From: neeraj Date: Mon, 8 Sep 2025 10:31:28 +0530 Subject: [PATCH 10/16] gcc/clang compile error fix. --- .../detail/inc/RObjectBuilder.h | 12 ++++++---- .../detail/inc/SetupConstructor.hpp | 8 +++---- .../detail/inc/SetupFunction.hpp | 11 +++++---- .../detail/inc/SetupMethod.hpp | 23 ++++++++++++------- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/ReflectionTemplateLib/detail/inc/RObjectBuilder.h b/ReflectionTemplateLib/detail/inc/RObjectBuilder.h index 86612b89..5ea9619e 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectBuilder.h +++ b/ReflectionTemplateLib/detail/inc/RObjectBuilder.h @@ -47,10 +47,12 @@ namespace rtl inline RObject reflect(T(&pArr)[N]) noexcept { if constexpr (std::is_same_v, char>) { - return detail::RObjectBuilder::build(std::string_view(pArr, N - 1), !traits::is_const_v); + return detail::RObjectBuilder::template + build(std::string_view(pArr, N - 1), !traits::is_const_v); } else { - return detail::RObjectBuilder>::build(std::vector(pArr, pArr + N), !traits::is_const_v); + return detail::RObjectBuilder>::template + build(std::vector(pArr, pArr + N), !traits::is_const_v); } } @@ -61,12 +63,14 @@ namespace rtl using _T = traits::raw_t; if constexpr (traits::std_wrapper<_T>::type == detail::Wrapper::None) { - return detail::RObjectBuilder::build(std::forward(pVal), !traits::is_const_v); + return detail::RObjectBuilder::template + build(std::forward(pVal), !traits::is_const_v); } else { constexpr bool isConstCastSafe = !traits::is_const_v::value_type>; - return detail::RObjectBuilder::build(std::forward(pVal), isConstCastSafe); + return detail::RObjectBuilder::template + build(std::forward(pVal), isConstCastSafe); } } } \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp b/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp index 79935663..a84ff3ea 100644 --- a/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp @@ -37,15 +37,15 @@ namespace rtl::detail } else { return { error::None, - RObjectBuilder<_recordType>::build( - _recordType(std::forward<_signature>(params)...), true) + RObjectBuilder<_recordType>::template + build(_recordType(std::forward<_signature>(params)...), true) }; } } else if (pAllocType == alloc::Heap) { return { error::None, - RObjectBuilder<_recordType*>::build( - new _recordType(std::forward<_signature>(params)...), true) + RObjectBuilder<_recordType*>::template + build(new _recordType(std::forward<_signature>(params)...), true) }; } } diff --git a/ReflectionTemplateLib/detail/inc/SetupFunction.hpp b/ReflectionTemplateLib/detail/inc/SetupFunction.hpp index 0246805e..f76bbbf4 100644 --- a/ReflectionTemplateLib/detail/inc/SetupFunction.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupFunction.hpp @@ -48,15 +48,18 @@ namespace rtl */ using _rawRetType = traits::raw_t<_returnType>; const _rawRetType& retObj = pFunctor(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj, isConstCastSafe) + RObjectBuilder::template + build(&retObj, isConstCastSafe) }; } else { //if the function returns anything (not refrence), this block will be retained by compiler. - _returnType&& retObj = std::move(pFunctor(std::forward<_signature>(params)...)); + auto&& retObj = pFunctor(std::forward<_signature>(params)...); + using T = std::remove_cvref_t; + return { error::None, - RObjectBuilder<_returnType>::build( - std::forward<_returnType>(retObj), isConstCastSafe) + RObjectBuilder::template + build(std::forward(retObj), isConstCastSafe) }; } }; diff --git a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp index bad3bf8f..4f64ee7a 100644 --- a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp +++ b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp @@ -64,15 +64,18 @@ namespace rtl */ using _rawRetType = traits::raw_t<_returnType>; const _rawRetType& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj, isConstCastSafe) + RObjectBuilder::template + build(&retObj, isConstCastSafe) }; } else { - _returnType&& retObj = std::move((target.*pFunctor)(std::forward<_signature>(params)...)); + auto&& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); + using T = std::remove_cvref_t; + return { error::None, - RObjectBuilder<_returnType>::build( - std::forward<_returnType>(retObj), isConstCastSafe) + RObjectBuilder::template + build(std::forward(retObj), isConstCastSafe) }; } }; @@ -114,14 +117,18 @@ namespace rtl */ using _rawRetType = traits::raw_t<_returnType>; const _rawRetType& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); return { error::None, - RObjectBuilder::build(&retObj, isConstCastSafe) + RObjectBuilder::template + build(&retObj, isConstCastSafe) }; } else { - _returnType&& retObj = std::move((target.*pFunctor)(std::forward<_signature>(params)...)); + + auto&& retObj = (target.*pFunctor)(std::forward<_signature>(params)...); + using T = std::remove_cvref_t; + return { error::None, - RObjectBuilder<_returnType>::build( - std::forward<_returnType>(retObj), isConstCastSafe) + RObjectBuilder::template + build(std::forward(retObj), isConstCastSafe) }; } }; From 999ea24dfe99adfdadbdacd00abcd7775cfe48fc Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Mon, 8 Sep 2025 13:56:44 +0530 Subject: [PATCH 11/16] posible inlining. --- RTLBenchmarkApp/src/BenchMark.cpp | 37 +++++++------------ ReflectionTemplateLib/access/inc/RObject.hpp | 6 +-- .../detail/inc/RObjectBuilder.hpp | 12 +++--- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index f7becc51..feb45f77 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -78,16 +78,13 @@ namespace rtl_bench void BenchMark::reflectedCall_noReturn(benchmark::State& state) { static rtl::Function sendMsg = cxx_mirror().getFunction("sendMessage").value(); - static auto _ = []() { - if (sendMsg.bind().call(g_longStr).err == rtl::error::None) { - std::cout << "[rtl:0] call success.\n"; - } - else { - std::cout << "[rtl:0] call failed.\n"; + auto err = sendMsg.bind().call(g_longStr).err; + if (err != rtl::error::None) { + std::cout << "[rtl:0] err: "<< rtl::to_string(err)<<"\n"; } return 0; - }(); + }(); for (auto _ : state) { @@ -102,14 +99,12 @@ namespace rtl_bench static rtl::Method sendMsg = rNode.getMethod("sendMessage").value(); static rtl::RObject robj = rNode.create().rObject; static auto _ = []() { - if (sendMsg.bind(robj).call(g_longStr).err == rtl::error::None) { - std::cout << "[rtl:1] call success.\n"; - } - else { - std::cout << "[rtl:1] call failed.\n"; + auto err = sendMsg.bind(robj).call(g_longStr).err; + if (err != rtl::error::None) { + std::cout << "[rtl:1] err: " << rtl::to_string(err) << "\n"; } return 0; - }(); + }(); for (auto _ : state) { @@ -122,11 +117,9 @@ namespace rtl_bench { static rtl::Function getMsg = cxx_mirror().getFunction("getMessage").value(); static auto _ = []() { - if (getMsg.bind().call(g_longStr).err == rtl::error::None) { - std::cout << "[rtl:2] call success.\n"; - } - else { - std::cout << "[rtl:2] call failed.\n"; + auto err = getMsg.bind().call(g_longStr).err; + if (err != rtl::error::None) { + std::cout << "[rtl:2] err: " << rtl::to_string(err) << "\n"; } return 0; }(); @@ -144,11 +137,9 @@ namespace rtl_bench static rtl::Method getMsg = rNode.getMethod("getMessage").value(); static rtl::RObject robj = rNode.create().rObject; static auto _ = []() { - if (getMsg.bind(robj).call(g_longStr).err == rtl::error::None) { - std::cout << "[rtl:3] call success.\n"; - } - else { - std::cout << "[rtl:3] call failed.\n"; + auto err = getMsg.bind(robj).call(g_longStr).err; + if (err != rtl::error::None) { + std::cout << "[rtl:3] err: " << rtl::to_string(err) << "\n"; } return 0; }(); diff --git a/ReflectionTemplateLib/access/inc/RObject.hpp b/ReflectionTemplateLib/access/inc/RObject.hpp index f7ddbf5c..fdf19ee1 100644 --- a/ReflectionTemplateLib/access/inc/RObject.hpp +++ b/ReflectionTemplateLib/access/inc/RObject.hpp @@ -24,15 +24,15 @@ namespace rtl { - inline RObject::RObject(const detail::RObjectId* pRObjId, std::any&& pObject, const Cloner* pCloner, - const std::vector* pConverters) noexcept + FORCE_INLINE RObject::RObject(const detail::RObjectId* pRObjId, std::any&& pObject, const Cloner* pCloner, + const std::vector* pConverters) noexcept : m_object(std::forward(pObject)) , m_getClone(pCloner) , m_objectId(pRObjId) , m_converters(pConverters) { } - inline RObject::RObject(RObject&& pOther) noexcept + FORCE_INLINE RObject::RObject(RObject&& pOther) noexcept : m_object(std::move(pOther.m_object)) , m_getClone(pOther.m_getClone) , m_objectId(pOther.m_objectId) diff --git a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp index 397d1270..4b447d34 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp +++ b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp @@ -78,10 +78,10 @@ namespace rtl::detail { template template requires (_allocOn == alloc::Heap) - RObject RObjectBuilder::build(T&& pVal, bool pIsConstCastSafe) noexcept + FORCE_INLINE RObject RObjectBuilder::build(T&& pVal, bool pIsConstCastSafe) noexcept { using _T = traits::raw_t; - static const RObjectId robjId = RObjectId::create, _allocOn>(pIsConstCastSafe); + static const RObjectId robjId = RObjectId::create, alloc::Heap>(pIsConstCastSafe); return RObject( &robjId, std::any{ @@ -95,14 +95,14 @@ namespace rtl::detail { template template requires (_allocOn == alloc::Stack) - RObject RObjectBuilder::build(T&& pVal, bool pIsConstCastSafe) noexcept + FORCE_INLINE RObject RObjectBuilder::build(T&& pVal, bool pIsConstCastSafe) noexcept { using _T = traits::raw_t; constexpr bool isRawPointer = std::is_pointer_v>; if constexpr (isRawPointer) { - static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); + static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); return RObject( &robjId, std::any { static_cast(pVal) }, &buildCloner<_T>(), @@ -113,7 +113,7 @@ namespace rtl::detail { if constexpr (traits::std_wrapper<_T>::type == Wrapper::Unique) { using U = traits::std_wrapper<_T>::value_type; - static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); + static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); return RObject( &robjId, std::any { std::in_place_type>, @@ -125,7 +125,7 @@ namespace rtl::detail { else { static_assert(std::is_copy_constructible_v<_T>, "T must be copy-constructible (std::any requires this)."); - static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); + static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); return RObject( &robjId, std::any { std::in_place_type, From 11fad817ddf5dc2bc8f481351fcaf77a999d77f2 Mon Sep 17 00:00:00 2001 From: neeraj Date: Mon, 8 Sep 2025 15:01:45 +0530 Subject: [PATCH 12/16] added volatile, blocks nrvo. --- RTLBenchmarkApp/src/BenchMark.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index feb45f77..1cd25d5b 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -62,7 +62,9 @@ namespace rtl_bench void BenchMark::stdFunctionCall_withReturn(benchmark::State& state) { static std::function getMsg = [](argStr_t& pMsg) { - return getMessage(pMsg); + retStr_t retMsg = getMessage(pMsg); + volatile auto *msg = &retMsg; + return retMsg; }; for (auto _ : state) From 214085c71e33f094eaf7dde6e874bc5b46a4d42a Mon Sep 17 00:00:00 2001 From: neeraj Date: Mon, 8 Sep 2025 15:35:26 +0530 Subject: [PATCH 13/16] removed static RObjectId. clean-up. --- ReflectionTemplateLib/access/inc/RObject.h | 12 ++++---- ReflectionTemplateLib/access/inc/RObject.hpp | 28 +++++++++---------- .../detail/inc/RObjExtracter.h | 18 ++++++------ .../detail/inc/RObjectBuilder.hpp | 21 ++++++-------- 4 files changed, 37 insertions(+), 42 deletions(-) diff --git a/ReflectionTemplateLib/access/inc/RObject.h b/ReflectionTemplateLib/access/inc/RObject.h index d3e64d60..07d3f594 100644 --- a/ReflectionTemplateLib/access/inc/RObject.h +++ b/ReflectionTemplateLib/access/inc/RObject.h @@ -44,13 +44,13 @@ namespace rtl using Cloner = std::function< Return(const RObject&, rtl::alloc) >; mutable std::any m_object; + mutable detail::RObjectId m_objectId; mutable const Cloner* m_getClone; - mutable const detail::RObjectId* m_objectId; mutable const std::vector* m_converters; RObject(const RObject&) = default; - RObject(const detail::RObjectId* pRObjId, std::any&& pObject, const Cloner* pCloner, + RObject(std::any&& pObject, const detail::RObjectId pRObjId, const Cloner* pCloner, const std::vector* pConverters) noexcept; std::size_t getConverterIndex(const std::size_t pToTypeId) const; @@ -70,15 +70,15 @@ namespace rtl RObject& operator=(const RObject&) = delete; GETTER_BOOL(Empty, (m_object.has_value() == false)) - GETTER_BOOL(OnHeap, (m_objectId && m_objectId->m_allocatedOn == alloc::Heap)) - GETTER_BOOL(AllocatedByRtl, (m_objectId && m_objectId->m_allocatedOn == alloc::Heap)) - GETTER(std::size_t, TypeId, (m_objectId ? m_objectId->m_typeId : detail::TypeId<>::None)) + GETTER_BOOL(OnHeap, (m_objectId.m_allocatedOn == alloc::Heap)) + GETTER_BOOL(AllocatedByRtl, (m_objectId.m_allocatedOn == alloc::Heap)) + GETTER(std::size_t, TypeId, m_objectId.m_typeId) /* Reflection Const Semantics: * - All reflected objects default to mutable internally; API enforces logical constness. * - RTL may 'const_cast' its own objects(allocated via RTL) but preserves logical constness. * - External objects (e.g. returned via Reflected call) keep original qualifier; if const, then const_cast is unsafe. - */ GETTER_BOOL(ConstCastSafe, (m_objectId && m_objectId->m_isConstCastSafe)) + */ GETTER_BOOL(ConstCastSafe, m_objectId.m_isConstCastSafe) template bool canViewAs() const; diff --git a/ReflectionTemplateLib/access/inc/RObject.hpp b/ReflectionTemplateLib/access/inc/RObject.hpp index fdf19ee1..ee3bb532 100644 --- a/ReflectionTemplateLib/access/inc/RObject.hpp +++ b/ReflectionTemplateLib/access/inc/RObject.hpp @@ -24,23 +24,23 @@ namespace rtl { - FORCE_INLINE RObject::RObject(const detail::RObjectId* pRObjId, std::any&& pObject, const Cloner* pCloner, + FORCE_INLINE RObject::RObject(std::any&& pObject, const detail::RObjectId pRObjId, const Cloner* pCloner, const std::vector* pConverters) noexcept : m_object(std::forward(pObject)) - , m_getClone(pCloner) , m_objectId(pRObjId) + , m_getClone(pCloner) , m_converters(pConverters) { } FORCE_INLINE RObject::RObject(RObject&& pOther) noexcept : m_object(std::move(pOther.m_object)) - , m_getClone(pOther.m_getClone) , m_objectId(pOther.m_objectId) + , m_getClone(pOther.m_getClone) , m_converters(pOther.m_converters) { // Explicitly clear moved-from source pOther.m_object.reset(); - pOther.m_objectId = nullptr; + pOther.m_objectId = {}; pOther.m_getClone = nullptr; pOther.m_converters = nullptr; } @@ -54,7 +54,7 @@ namespace rtl inline std::size_t RObject::getConverterIndex(const std::size_t pToTypeId) const { - if (m_objectId->m_containsAs != detail::EntityKind::None) { + if (m_objectId.m_containsAs != detail::EntityKind::None) { for (std::size_t index = 0; index < m_converters->size(); index++) { if ((*m_converters)[index].first == pToTypeId) { return index; @@ -70,12 +70,12 @@ namespace rtl { if constexpr (traits::is_bare_type()) { if constexpr (traits::std_wrapper::type != detail::Wrapper::None) { - if (m_objectId->m_wrapperTypeId == traits::std_wrapper::id()) { + if (m_objectId.m_wrapperTypeId == traits::std_wrapper::id()) { return true; } } const auto& typeId = detail::TypeId::get(); - return (m_objectId->m_typeId == typeId || getConverterIndex(typeId) != index_none); + return (m_objectId.m_typeId == typeId || getConverterIndex(typeId) != index_none); } } @@ -85,7 +85,7 @@ namespace rtl { detail::EntityKind newKind = detail::EntityKind::None; const traits::Converter& convert = (*m_converters)[pIndex].second; - const std::any& viewObj = convert(m_object, m_objectId->m_containsAs, newKind); + const std::any& viewObj = convert(m_object, m_objectId.m_containsAs, newKind); const T* viewRef = detail::RObjExtractor::getPointer(viewObj, newKind); if (viewRef != nullptr && newKind == detail::EntityKind::Ref) { @@ -105,7 +105,7 @@ namespace rtl { if constexpr (traits::is_bare_type()) { - if (detail::TypeId::get() == m_objectId->m_wrapperTypeId) + if (detail::TypeId::get() == m_objectId.m_wrapperTypeId) { using U = detail::RObjectUPtr::value_type>; const U& uptrRef = *(detail::RObjExtractor(this).getWrapper()); @@ -121,7 +121,7 @@ namespace rtl { if constexpr (traits::is_bare_type()) { - if (detail::TypeId::get() == m_objectId->m_wrapperTypeId) + if (detail::TypeId::get() == m_objectId.m_wrapperTypeId) { const T& sptrRef = *(detail::RObjExtractor(this).getWrapper()); return std::optional>(std::in_place, const_cast(sptrRef)); @@ -137,7 +137,7 @@ namespace rtl if constexpr (traits::is_bare_type()) { const std::size_t asTypeId = detail::TypeId::get(); - if (asTypeId == m_objectId->m_typeId) + if (asTypeId == m_objectId.m_typeId) { const T* valRef = detail::RObjExtractor(this).getPointer(); if (valRef != nullptr) { @@ -184,10 +184,10 @@ namespace rtl template<> inline Return RObject::createCopy() const { - if (m_objectId->m_wrapperType == detail::Wrapper::None) { + if (m_objectId.m_wrapperType == detail::Wrapper::None) { return { error::NotWrapperType, RObject{} }; } - else if (m_objectId->m_wrapperType == detail::Wrapper::Unique) + else if (m_objectId.m_wrapperType == detail::Wrapper::Unique) { return { error::TypeNotCopyConstructible, RObject{} }; } @@ -212,7 +212,7 @@ namespace rtl else if constexpr (_copyTarget == copy::Auto) { // RTL wraps the objects allocated on heap in 'std::unique_ptr'. Which by default is transparent to RTL itself. // 'std::unique_ptr' acquired via any other source, (e.g. return value) are not transparent. hence the second condition. - if (m_objectId->m_wrapperType != detail::Wrapper::None && !isAllocatedByRtl()) + if (m_objectId.m_wrapperType != detail::Wrapper::None && !isAllocatedByRtl()) { return createCopy<_allocOn, detail::EntityKind::Wrapper>(); } diff --git a/ReflectionTemplateLib/detail/inc/RObjExtracter.h b/ReflectionTemplateLib/detail/inc/RObjExtracter.h index 97a89d83..c805f9d6 100644 --- a/ReflectionTemplateLib/detail/inc/RObjExtracter.h +++ b/ReflectionTemplateLib/detail/inc/RObjExtracter.h @@ -48,7 +48,7 @@ namespace rtl::detail const T* getPointer() const { try { - switch (m_rObj.m_objectId->m_containsAs) + switch (m_rObj.m_objectId.m_containsAs) { case EntityKind::Ref: { return std::any_cast(m_rObj.m_object); @@ -72,12 +72,12 @@ namespace rtl::detail auto getWrapper() const -> const RObjectUPtr::value_type>* { try { - if (m_rObj.m_objectId->m_wrapperType == detail::Wrapper::Unique) + if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Unique) { using _T = traits::std_wrapper::value_type; if constexpr (traits::is_const_v<_T>) { - if (m_rObj.m_objectId->m_isWrappingConst) + if (m_rObj.m_objectId.m_isWrappingConst) { using U = detail::RObjectUPtr; const U& uptrRef = std::any_cast(m_rObj.m_object); @@ -101,12 +101,12 @@ namespace rtl::detail const T* getWrapper() const { try { - if (m_rObj.m_objectId->m_wrapperType == detail::Wrapper::Shared) + if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Shared) { using _T = traits::std_wrapper::value_type; if constexpr (traits::is_const_v<_T>) { - if (m_rObj.m_objectId->m_isWrappingConst) { + if (m_rObj.m_objectId.m_isWrappingConst) { using U = std::shared_ptr; const U& sptrRef = std::any_cast(m_rObj.m_object); return static_cast(&sptrRef); @@ -131,9 +131,9 @@ namespace rtl::detail try { if constexpr (std::is_destructible_v) { - if (m_rObj.m_objectId->m_wrapperType == detail::Wrapper::Unique) + if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Unique) { - if (m_rObj.m_objectId->m_isWrappingConst) { + if (m_rObj.m_objectId.m_isWrappingConst) { using U = detail::RObjectUPtr; const U& uptrRef = std::any_cast(m_rObj.m_object); return static_cast(uptrRef.get()); @@ -144,9 +144,9 @@ namespace rtl::detail return static_cast(uptrRef.get()); } } - if (m_rObj.m_objectId->m_wrapperType == detail::Wrapper::Shared) + if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Shared) { - if (m_rObj.m_objectId->m_isWrappingConst) { + if (m_rObj.m_objectId.m_isWrappingConst) { using U = std::shared_ptr; const auto& sptrRef = std::any_cast(m_rObj.m_object); return static_cast(sptrRef.get()); diff --git a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp index 4b447d34..6c0f3e48 100644 --- a/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp +++ b/ReflectionTemplateLib/detail/inc/RObjectBuilder.hpp @@ -81,13 +81,11 @@ namespace rtl::detail { FORCE_INLINE RObject RObjectBuilder::build(T&& pVal, bool pIsConstCastSafe) noexcept { using _T = traits::raw_t; - static const RObjectId robjId = RObjectId::create, alloc::Heap>(pIsConstCastSafe); - - return RObject( &robjId, - std::any{ + return RObject( std::any{ std::in_place_type>, RObjectUPtr<_T>(std::unique_ptr<_T>(static_cast<_T*>(pVal))) }, + RObjectId::create, alloc::Heap>(pIsConstCastSafe), &buildCloner<_T>(), &getConverters>()); } @@ -102,9 +100,8 @@ namespace rtl::detail { if constexpr (isRawPointer) { - static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); - return RObject( &robjId, - std::any { static_cast(pVal) }, + return RObject( std::any { static_cast(pVal) }, + RObjectId::create(pIsConstCastSafe), &buildCloner<_T>(), &getConverters() ); } @@ -113,24 +110,22 @@ namespace rtl::detail { if constexpr (traits::std_wrapper<_T>::type == Wrapper::Unique) { using U = traits::std_wrapper<_T>::value_type; - static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); - return RObject( &robjId, - std::any { + return RObject( std::any { std::in_place_type>, RObjectUPtr(std::move(pVal)) }, + RObjectId::create(pIsConstCastSafe), &buildCloner<_T>(), &getConverters() ); } else { static_assert(std::is_copy_constructible_v<_T>, "T must be copy-constructible (std::any requires this)."); - static const RObjectId robjId = RObjectId::create(pIsConstCastSafe); - return RObject( &robjId, - std::any { + return RObject( std::any { std::in_place_type, std::forward(pVal) }, + RObjectId::create(pIsConstCastSafe), &buildCloner<_T>(), &getConverters() ); } From 891e7abf721febc836dd1d122d914725753fda8a Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Mon, 8 Sep 2025 21:42:18 +0530 Subject: [PATCH 14/16] removed unnecessory try-catch. --- RTLBenchmarkApp/src/BenchMark.cpp | 42 ++++- RTLBenchmarkApp/src/BenchMark.h | 4 + RTLBenchmarkApp/src/main.cpp | 2 + .../MoveConstructorTests.cpp | 10 +- ReflectionTemplateLib/access/inc/RObject.h | 8 +- ReflectionTemplateLib/access/inc/RObject.hpp | 16 +- .../detail/inc/RObjExtracter.h | 149 ++++++++---------- 7 files changed, 128 insertions(+), 103 deletions(-) diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index 1cd25d5b..cc557620 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -1,5 +1,5 @@ -#include + #include #include @@ -8,11 +8,12 @@ namespace { - static const char* LONG_STR = "Lorem ipsum";// dolor sit amet, consectetur adipiscing elit, sed do"; + static const char* LONG_STR = "Lorem ipsum";// dolor sit amet, consectetur adipiscing elit, sed do" //"do aeiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis" //"nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure" //"dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Except" - //"eur ssint occaecat cupidatat nnon proident, sunt in culpa qui officia deserunt mollit anim id"; + //"eur ssint occaecat cupidatat nnon proident, sunt in culpa qui officia deserunt mollit anim id" + //"Lorem ipsum dolor sit amet laboris nisi ut aliquip ex ea commodo"; } // Pre-created string to isolate call overhead @@ -44,6 +45,21 @@ namespace rtl_bench } + void BenchMark::stdFunctionMethodCall_noReturn(benchmark::State& state) + { + Node* node = new Node(); + static std::function sendMsg = [=](argStr_t& pMsg) { + node->sendMessage(pMsg); + }; + + for (auto _ : state) + { + sendMsg(g_longStr); + benchmark::DoNotOptimize(g_msg); + } + } + + void BenchMark::directCall_withReturn(benchmark::State& state) { static auto _ = []() { @@ -62,9 +78,21 @@ namespace rtl_bench void BenchMark::stdFunctionCall_withReturn(benchmark::State& state) { static std::function getMsg = [](argStr_t& pMsg) { - retStr_t retMsg = getMessage(pMsg); - volatile auto *msg = &retMsg; - return retMsg; + return getMessage(pMsg); + }; + + for (auto _ : state) + { + benchmark::DoNotOptimize(getMsg(g_longStr)); + } + } + + + void BenchMark::stdFunctionMethodCall_withReturn(benchmark::State& state) + { + static Node* node = new Node(); + static std::function getMsg = [=](argStr_t& pMsg) { + return node->getMessage(pMsg); }; for (auto _ : state) @@ -99,7 +127,7 @@ namespace rtl_bench { static rtl::Record rNode = cxx_mirror().getRecord("Node").value(); static rtl::Method sendMsg = rNode.getMethod("sendMessage").value(); - static rtl::RObject robj = rNode.create().rObject; + static rtl::RObject robj = rNode.create().rObject; static auto _ = []() { auto err = sendMsg.bind(robj).call(g_longStr).err; if (err != rtl::error::None) { diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index 5e82482c..7658acf3 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -68,12 +68,16 @@ namespace rtl_bench static void reflectedCall_noReturn(benchmark::State& state); + static void stdFunctionMethodCall_noReturn(benchmark::State& state); + static void reflectedMethodCall_noReturn(benchmark::State& state); static void directCall_withReturn(benchmark::State& state); static void stdFunctionCall_withReturn(benchmark::State& state); + static void stdFunctionMethodCall_withReturn(benchmark::State& state); + static void reflectedCall_withReturn(benchmark::State& state); static void reflectedMethodCall_withReturn(benchmark::State& state); diff --git a/RTLBenchmarkApp/src/main.cpp b/RTLBenchmarkApp/src/main.cpp index 1d4d8488..dc55ee28 100644 --- a/RTLBenchmarkApp/src/main.cpp +++ b/RTLBenchmarkApp/src/main.cpp @@ -7,11 +7,13 @@ BENCHMARK(rtl_bench::BenchMark::directCall_noReturn); BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_noReturn); +BENCHMARK(rtl_bench::BenchMark::stdFunctionMethodCall_noReturn); BENCHMARK(rtl_bench::BenchMark::reflectedCall_noReturn); BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_noReturn); BENCHMARK(rtl_bench::BenchMark::directCall_withReturn); BENCHMARK(rtl_bench::BenchMark::stdFunctionCall_withReturn); +BENCHMARK(rtl_bench::BenchMark::stdFunctionMethodCall_withReturn); BENCHMARK(rtl_bench::BenchMark::reflectedCall_withReturn); BENCHMARK(rtl_bench::BenchMark::reflectedMethodCall_withReturn); diff --git a/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp b/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp index 19c0dd68..d4c07bc0 100644 --- a/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp +++ b/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp @@ -7,7 +7,7 @@ using namespace std; using namespace rtl; -using namespace test_utils; +using namespace test_utils; using namespace test_mirror; namespace rtl_tests @@ -38,7 +38,7 @@ namespace rtl_tests // Moving a RObject created via alloc::Stack, invokes Calender's move constructor. RObject calender1 = std::move(calender0); - + //TODO: Fails on linux, differently optimized away from windows? // Calender's move-constructor called once. // EXPECT_TRUE(calender::get_move_ops_count() == 1); @@ -49,6 +49,7 @@ namespace rtl_tests // 'calander0' must be empty now. ASSERT_TRUE(calender0.isEmpty()); + EXPECT_NE(calender0.getTypeId(), calender1.getTypeId()); // After move, these instance count must remain same. EXPECT_TRUE(calender::get_instance_count() == 1); @@ -113,6 +114,7 @@ namespace rtl_tests // 'calander0' must be empty now. ASSERT_TRUE(calender0.isEmpty()); + EXPECT_NE(calender0.getTypeId(), calender1.getTypeId()); // After move, these instance count must remain same. EXPECT_TRUE(calender::get_instance_count() == 1); @@ -182,6 +184,7 @@ namespace rtl_tests // 'event0' must be empty now. ASSERT_TRUE(event0.isEmpty()); + EXPECT_NE(event0.getTypeId(), event1.getTypeId()); { // Event::reset() is a non-const method. can't be called on const-object. optional eventReset = classEvent->getMethod(event::str_reset); @@ -244,7 +247,7 @@ namespace rtl_tests // Moving a RObject created via alloc::Stack, invokes Calender's move constructor. RObject calender1 = std::move(calender0); - //TODO: Fails on linux, differently optimized away from windows? + //TODO: Works on windows, fails on linux, differently optimized away for windows? // Calender's move-constructor called once. // EXPECT_TRUE(calender::get_move_ops_count() == 1); @@ -254,6 +257,7 @@ namespace rtl_tests // 'calander0' must be empty now. ASSERT_TRUE(calender0.isEmpty()); + EXPECT_NE(calender0.getTypeId(), calender1.getTypeId()); // After move, these instance count must remain same. EXPECT_TRUE(calender::get_instance_count() == 1); diff --git a/ReflectionTemplateLib/access/inc/RObject.h b/ReflectionTemplateLib/access/inc/RObject.h index 07d3f594..208e2c59 100644 --- a/ReflectionTemplateLib/access/inc/RObject.h +++ b/ReflectionTemplateLib/access/inc/RObject.h @@ -43,11 +43,11 @@ namespace rtl { using Cloner = std::function< Return(const RObject&, rtl::alloc) >; - mutable std::any m_object; - mutable detail::RObjectId m_objectId; + std::any m_object; + detail::RObjectId m_objectId; - mutable const Cloner* m_getClone; - mutable const std::vector* m_converters; + const Cloner* m_getClone = nullptr; + const std::vector* m_converters = nullptr; RObject(const RObject&) = default; RObject(std::any&& pObject, const detail::RObjectId pRObjId, const Cloner* pCloner, diff --git a/ReflectionTemplateLib/access/inc/RObject.hpp b/ReflectionTemplateLib/access/inc/RObject.hpp index ee3bb532..f55d6dda 100644 --- a/ReflectionTemplateLib/access/inc/RObject.hpp +++ b/ReflectionTemplateLib/access/inc/RObject.hpp @@ -26,13 +26,13 @@ namespace rtl { FORCE_INLINE RObject::RObject(std::any&& pObject, const detail::RObjectId pRObjId, const Cloner* pCloner, const std::vector* pConverters) noexcept - : m_object(std::forward(pObject)) + : m_object(std::move(pObject)) , m_objectId(pRObjId) , m_getClone(pCloner) , m_converters(pConverters) { } - FORCE_INLINE RObject::RObject(RObject&& pOther) noexcept + inline RObject::RObject(RObject&& pOther) noexcept : m_object(std::move(pOther.m_object)) , m_objectId(pOther.m_objectId) , m_getClone(pOther.m_getClone) @@ -101,7 +101,7 @@ namespace rtl template , int>> - std::optional> RObject::view() const + FORCE_INLINE std::optional> RObject::view() const { if constexpr (traits::is_bare_type()) { @@ -117,14 +117,16 @@ namespace rtl template , int>> - std::optional> RObject::view() const + FORCE_INLINE std::optional> RObject::view() const { if constexpr (traits::is_bare_type()) { if (detail::TypeId::get() == m_objectId.m_wrapperTypeId) { - const T& sptrRef = *(detail::RObjExtractor(this).getWrapper()); - return std::optional>(std::in_place, const_cast(sptrRef)); + const T* sptrRef = detail::RObjExtractor(this).getWrapper(); + if (sptrRef != nullptr) { + return std::optional>(std::in_place, const_cast(*sptrRef)); + } } } return std::nullopt; @@ -132,7 +134,7 @@ namespace rtl template , int>> - inline std::optional> RObject::view() const + FORCE_INLINE std::optional> RObject::view() const { if constexpr (traits::is_bare_type()) { diff --git a/ReflectionTemplateLib/detail/inc/RObjExtracter.h b/ReflectionTemplateLib/detail/inc/RObjExtracter.h index c805f9d6..723a4075 100644 --- a/ReflectionTemplateLib/detail/inc/RObjExtracter.h +++ b/ReflectionTemplateLib/detail/inc/RObjExtracter.h @@ -24,11 +24,10 @@ namespace rtl::detail RObjExtractor(const RObject* pRObj) : m_rObj(*pRObj) { } template - static const T* getPointer(const std::any& pObject, const EntityKind pEntityKind) + FORCE_INLINE static const T* getPointer(const std::any& pObject, const EntityKind pEntityKind) { - try { - switch (pEntityKind) - { + switch (pEntityKind) + { case EntityKind::Ref: { return std::any_cast(pObject); } @@ -37,129 +36,115 @@ namespace rtl::detail return static_cast(&valueRef); } default: return nullptr; - } } - catch (const std::bad_any_cast&) { /*TODO: log the failure. */ } return nullptr; } template - const T* getPointer() const + FORCE_INLINE const T* getPointer() const { - try { - switch (m_rObj.m_objectId.m_containsAs) - { - case EntityKind::Ref: { - return std::any_cast(m_rObj.m_object); - } - case EntityKind::Wrapper: { - return getFromWrapper(); - } - case EntityKind::Value: { - const T& valueRef = std::any_cast(m_rObj.m_object); - return static_cast(&valueRef); - } - default: return nullptr; + switch (m_rObj.m_objectId.m_containsAs) + { + case EntityKind::Ref: { + return std::any_cast(m_rObj.m_object); } + case EntityKind::Wrapper: { + return getFromWrapper(); + } + case EntityKind::Value: { + const T& valueRef = std::any_cast(m_rObj.m_object); + return static_cast(&valueRef); + } + default: return nullptr; } - catch (const std::bad_any_cast&) { /*TODO: log the failure. */ } return nullptr; } template = 0> - auto getWrapper() const -> const RObjectUPtr::value_type>* + FORCE_INLINE auto getWrapper() const -> const RObjectUPtr::value_type>* { - try { - if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Unique) + if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Unique) + { + using _T = traits::std_wrapper::value_type; + if constexpr (traits::is_const_v<_T>) { - using _T = traits::std_wrapper::value_type; - if constexpr (traits::is_const_v<_T>) + if (m_rObj.m_objectId.m_isWrappingConst) { - if (m_rObj.m_objectId.m_isWrappingConst) - { - using U = detail::RObjectUPtr; - const U& uptrRef = std::any_cast(m_rObj.m_object); - return static_cast(&uptrRef); - } - } - else - { - using U = detail::RObjectUPtr<_T>; + using U = detail::RObjectUPtr; const U& uptrRef = std::any_cast(m_rObj.m_object); return static_cast(&uptrRef); } } + else + { + using U = detail::RObjectUPtr<_T>; + const U& uptrRef = std::any_cast(m_rObj.m_object); + return static_cast(&uptrRef); + } } - catch (const std::bad_any_cast&) { /*TODO: log the failure. */ } return nullptr; } template = 0> - const T* getWrapper() const + FORCE_INLINE const T* getWrapper() const { - try { - if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Shared) + if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Shared) + { + using _T = traits::std_wrapper::value_type; + if constexpr (traits::is_const_v<_T>) { - using _T = traits::std_wrapper::value_type; - if constexpr (traits::is_const_v<_T>) - { - if (m_rObj.m_objectId.m_isWrappingConst) { - using U = std::shared_ptr; - const U& sptrRef = std::any_cast(m_rObj.m_object); - return static_cast(&sptrRef); - } - } - else - { - using U = std::shared_ptr<_T>; + if (m_rObj.m_objectId.m_isWrappingConst) { + using U = std::shared_ptr; const U& sptrRef = std::any_cast(m_rObj.m_object); return static_cast(&sptrRef); } } + else + { + using U = std::shared_ptr<_T>; + const U& sptrRef = std::any_cast(m_rObj.m_object); + return static_cast(&sptrRef); + } } - catch (const std::bad_any_cast&) { /*TODO: log the failure. */ } return nullptr; } template - const T* getFromWrapper() const + FORCE_INLINE const T* getFromWrapper() const { - try { - if constexpr (std::is_destructible_v) + if constexpr (std::is_destructible_v) + { + if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Unique) { - if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Unique) - { - if (m_rObj.m_objectId.m_isWrappingConst) { - using U = detail::RObjectUPtr; - const U& uptrRef = std::any_cast(m_rObj.m_object); - return static_cast(uptrRef.get()); - } - else { - using U = detail::RObjectUPtr; - const U& uptrRef = std::any_cast(m_rObj.m_object); - return static_cast(uptrRef.get()); - } + if (m_rObj.m_objectId.m_isWrappingConst) { + using U = detail::RObjectUPtr; + const U& uptrRef = std::any_cast(m_rObj.m_object); + return static_cast(uptrRef.get()); } - if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Shared) - { - if (m_rObj.m_objectId.m_isWrappingConst) { - using U = std::shared_ptr; - const auto& sptrRef = std::any_cast(m_rObj.m_object); - return static_cast(sptrRef.get()); - } - else { - using U = std::shared_ptr; - const auto& sptrRef = std::any_cast(m_rObj.m_object); - return static_cast(sptrRef.get()); - } + else { + using U = detail::RObjectUPtr; + const U& uptrRef = std::any_cast(m_rObj.m_object); + return static_cast(uptrRef.get()); + } + } + if (m_rObj.m_objectId.m_wrapperType == detail::Wrapper::Shared) + { + if (m_rObj.m_objectId.m_isWrappingConst) { + using U = std::shared_ptr; + const auto& sptrRef = std::any_cast(m_rObj.m_object); + return static_cast(sptrRef.get()); + } + else { + using U = std::shared_ptr; + const auto& sptrRef = std::any_cast(m_rObj.m_object); + return static_cast(sptrRef.get()); } } } - catch (const std::bad_any_cast&) { /*TODO: log the failure. */ } return nullptr; } }; From 815e41755efedaa85046c8c97df74c64b92388b9 Mon Sep 17 00:00:00 2001 From: neeraj Date: Mon, 8 Sep 2025 23:19:45 +0530 Subject: [PATCH 15/16] benchmark, workload, initial report added. --- BenchMarkReport_0.md | 68 +++++++++++++++++++++++++++++++ RTLBenchmarkApp/src/BenchMark.cpp | 24 +++++++---- RTLBenchmarkApp/src/BenchMark.h | 10 +++-- 3 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 BenchMarkReport_0.md diff --git a/BenchMarkReport_0.md b/BenchMarkReport_0.md new file mode 100644 index 00000000..8ae266c9 --- /dev/null +++ b/BenchMarkReport_0.md @@ -0,0 +1,68 @@ +# Reflection Template Library (RTL) — Benchmark Report + +This document presents benchmark results for the **Reflection Template Library (RTL)**. +The goal was to measure the runtime overhead of reflective function calls compared to direct calls and `std::function`, under increasing workloads. + +--- + +## Benchmark Setup + +We tested: + +- **Direct calls** (baseline). +- **`std::function` calls** and method calls. +- **RTL reflective calls** (free functions and member methods, with and without return values). + +Each benchmark was repeated across workloads of increasing complexity, with times measured in nanoseconds. + +--- + +## Results Summary + +| Workload | Direct Call (ns) | Reflected Call Overhead (ns) | Reflected Method Overhead (ns) | Notes (With Return) | +|-----------------|------------------|------------------------------|--------------------------------|---------------------| +| baseline_40ns | 39.0 / 44.7 | +2.5 | +6.6 | +10.6 / +14.3 | +| workload_80ns | 82.4 / 82.5 | ~0 | ~0 | +12.5 / +15.6 | +| workload_100ns | 94.2 / 100.0 | +1.4 | +8.8 | +12.0 / +16.0 | +| workload_150ns* | 139.0 / 158.0 | +2–3 | +14–17 | +12–13 / +17–19 | + +\*Three independent runs were recorded at ~150 ns workload; numbers are consistent. + +--- + +## Insights + +- **Constant Overhead** + Reflection overhead remains almost constant across workloads: + - No-return functions: **+2–6 ns**. + - Return-value functions: **+10–20 ns**. + +- **Percentage Overhead Shrinks** + - At the 40 ns baseline, overhead was ~25%. + - By ~150 ns workloads, overhead dropped below 10%. + +- **No Scaling Penalty** + The overhead does not grow with function complexity. + This indicates that RTL adds only a fixed, predictable cost per call, with no hidden allocations or RTTI-like penalties. + +- **Performance-Culture Friendly** + This aligns with C++’s ethos: *you only pay a small, predictable cost when you use reflection*. + +--- + +## Conclusion + +The Reflection Template Library (RTL) demonstrates: + +- **Runtime reflection with constant, minimal overhead**. +- **Predictable cost model**: ~10–20 ns for reflective calls with returns. +- **Competitive performance**: far faster than existing C++ or mainstream language reflection systems. + +This makes RTL practical for domains traditionally wary of reflection: +- Serialization +- RPC / networking +- GUI bindings +- Scripting integrations +- Tooling + +RTL shows that reflection in C++ can finally be **both expressive and performant**. diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp index cc557620..97afd4dd 100644 --- a/RTLBenchmarkApp/src/BenchMark.cpp +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -8,12 +8,12 @@ namespace { - static const char* LONG_STR = "Lorem ipsum";// dolor sit amet, consectetur adipiscing elit, sed do" - //"do aeiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis" - //"nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure" - //"dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Except" - //"eur ssint occaecat cupidatat nnon proident, sunt in culpa qui officia deserunt mollit anim id" - //"Lorem ipsum dolor sit amet laboris nisi ut aliquip ex ea commodo"; + static const char* LONG_STR = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do" + "do aeiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis" + "nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure" + "dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Except" + "eur ssint occaecat cupidatat nnon proident, sunt in culpa qui officia deserunt mollit anim id" + "Lorem ipsum dolor sit amet laboris nisi ut aliquip ex ea commodo"; } // Pre-created string to isolate call overhead @@ -64,7 +64,7 @@ namespace rtl_bench { static auto _ = []() { std::cout << "--------------------------------------------------" - "---------------------------------------------" << std::endl; + "-----------------------------------------------" << std::endl; return 0; }(); @@ -78,7 +78,10 @@ namespace rtl_bench void BenchMark::stdFunctionCall_withReturn(benchmark::State& state) { static std::function getMsg = [](argStr_t& pMsg) { - return getMessage(pMsg); + auto msgStr = getMessage(pMsg); + volatile auto* p = &msgStr; + static_cast(p); + return msgStr; }; for (auto _ : state) @@ -92,7 +95,10 @@ namespace rtl_bench { static Node* node = new Node(); static std::function getMsg = [=](argStr_t& pMsg) { - return node->getMessage(pMsg); + auto msgStr = node->getMessage(pMsg); + volatile auto* p = &msgStr; + static_cast(p); + return msgStr; }; for (auto _ : state) diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h index 7658acf3..31b14437 100644 --- a/RTLBenchmarkApp/src/BenchMark.h +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -15,28 +15,30 @@ using argStr_t = std::string_view; using retStr_t = std::string_view; +#define WORK_LOAD(S) (std::string(S) + std::string(S) + std::string(S) + std::string(S)) + namespace rtl_bench { static std::optional g_msg; NOINLINE static void sendMessage(argStr_t pMsg) { - g_msg = pMsg; + g_msg = WORK_LOAD(pMsg); } NOINLINE static retStr_t getMessage(argStr_t pMsg) { - g_msg = pMsg; + g_msg = WORK_LOAD(pMsg); return retStr_t(g_msg->c_str()); } struct Node { NOINLINE void sendMessage(argStr_t pMsg) { - g_msg = pMsg; + g_msg = WORK_LOAD(pMsg); } NOINLINE retStr_t getMessage(argStr_t pMsg) { - g_msg = pMsg; + g_msg = WORK_LOAD(pMsg); return retStr_t(g_msg->c_str()); } }; From 4e15904ffafd885b5d17c0a47fde551f4911029b Mon Sep 17 00:00:00 2001 From: Neeraj Date: Mon, 8 Sep 2025 23:28:04 +0530 Subject: [PATCH 16/16] Update BenchMarkReport_0.md --- BenchMarkReport_0.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/BenchMarkReport_0.md b/BenchMarkReport_0.md index 8ae266c9..d56ab3cb 100644 --- a/BenchMarkReport_0.md +++ b/BenchMarkReport_0.md @@ -43,7 +43,7 @@ Each benchmark was repeated across workloads of increasing complexity, with time - **No Scaling Penalty** The overhead does not grow with function complexity. - This indicates that RTL adds only a fixed, predictable cost per call, with no hidden allocations or RTTI-like penalties. + This indicates that RTL adds only a fixed, predictable cost per call, with no hidden allocations. - **Performance-Culture Friendly** This aligns with C++’s ethos: *you only pay a small, predictable cost when you use reflection*. @@ -56,13 +56,3 @@ The Reflection Template Library (RTL) demonstrates: - **Runtime reflection with constant, minimal overhead**. - **Predictable cost model**: ~10–20 ns for reflective calls with returns. -- **Competitive performance**: far faster than existing C++ or mainstream language reflection systems. - -This makes RTL practical for domains traditionally wary of reflection: -- Serialization -- RPC / networking -- GUI bindings -- Scripting integrations -- Tooling - -RTL shows that reflection in C++ can finally be **both expressive and performant**.