From 4ab57bbafac8716acf3b8dde0d633975df39f4a4 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 18 Jan 2026 11:27:59 +0530 Subject: [PATCH 1/5] CxxMirror: disabled implicit copy-ctor. --- RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp | 2 +- .../src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp | 2 +- ReflectionTemplateLib/rtl/inc/CxxMirror.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp index 6e7b5dbc..1b013ec7 100644 --- a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp +++ b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp @@ -47,7 +47,7 @@ namespace rtl_tests // Two mirrors constructed from same set of registrations must serialize identically. // Confirms stability of metadata and deterministic JSON output. rtl::CxxMirror mirror = cxx_mirror(); - rtl::CxxMirror mirror0 = mirror; + rtl::CxxMirror mirror0(mirror); mirrorStr0 = rtl::CxxMirrorToJson::toJson(mirror0); } std::string mirrorStr1; diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp index 42b5c736..0c7bab1a 100644 --- a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp @@ -13,7 +13,7 @@ using namespace rtl; namespace { - static rtl::CxxMirror cxx_mirror() + static const rtl::CxxMirror& cxx_mirror() { static rtl::CxxMirror m = rtl::CxxMirror({ rtl::type().record("int").build(), diff --git a/ReflectionTemplateLib/rtl/inc/CxxMirror.h b/ReflectionTemplateLib/rtl/inc/CxxMirror.h index 8b8ab9dd..8ea8b18d 100644 --- a/ReflectionTemplateLib/rtl/inc/CxxMirror.h +++ b/ReflectionTemplateLib/rtl/inc/CxxMirror.h @@ -42,8 +42,8 @@ namespace rtl { public: - CxxMirror(CxxMirror&&) = default; - CxxMirror(const CxxMirror&) = default; + explicit CxxMirror(CxxMirror&&) = default; + explicit CxxMirror(const CxxMirror&) = default; // Constructs CxxMirror using a set of Function objects. All other constructors are disabled. explicit CxxMirror(const std::vector& pFunctions); From e22eeb5bb54c3695d77ee972a4807044e0c829a1 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 18 Jan 2026 11:38:24 +0530 Subject: [PATCH 2/5] cleanup. --- .../RObjectTests/RObjectReflecting_stdSharedPtr.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp index 0c7bab1a..fb913a99 100644 --- a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp @@ -11,17 +11,6 @@ using namespace test_utils; using namespace rtl; -namespace { - - static const rtl::CxxMirror& cxx_mirror() - { - static rtl::CxxMirror m = rtl::CxxMirror({ - rtl::type().record("int").build(), - rtl::type().record("Node").build() - }); - return m; - } -} namespace rtl::unit_test { From 0fdb5a818722a6d7bf7807cff9a2389684887984 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 18 Jan 2026 13:43:19 +0530 Subject: [PATCH 3/5] CxxMirror: polished comments. --- README.md | 4 + ReflectionTemplateLib/rtl/inc/CxxMirror.h | 55 ++++++----- ReflectionTemplateLib/rtl/src/CxxMirror.cpp | 101 ++++++++++++-------- 3 files changed, 94 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 04d6f28d..5b495114 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,10 @@ rtl::CxxMirror& cxx::mirror() { return cxx_mirror; } ``` +`cxx_mirror` is a immutable, stack-allocated, value-type object and is safe to copy. +However, when used as a singleton (as shown above), implicit copies (e.g., `auto mirror = cxx::mirror();`) can unintentionally violate the singleton semantics. +To prevent this, the copy constructor is restricted to avoid such unintended duplication. + ### RTL in action: **[Explore the demo code](https://github.com/ReflectCxx/RTL-Demo)** diff --git a/ReflectionTemplateLib/rtl/inc/CxxMirror.h b/ReflectionTemplateLib/rtl/inc/CxxMirror.h index 8ea8b18d..a7982ab3 100644 --- a/ReflectionTemplateLib/rtl/inc/CxxMirror.h +++ b/ReflectionTemplateLib/rtl/inc/CxxMirror.h @@ -15,52 +15,57 @@ namespace rtl { -/* @class CxxMirror - * Provides the primary interface to access registered functions and methods by name. - * This is the single point of access to the entire reflection system. + /** + * @class CxxMirror * - * All type registrations happen during object construction. + * @brief Primary interface for accessing all registered types, functions, and methods by name. * - * Objects of this class are regular stack-allocated objects (non-singleton) and are destroyed automatically when they go out of scope. - * Copy constructor and assignment operator are deleted, instances can only be passed by reference or wrapped in a smart pointer. + * CxxMirror serves as the single point of entry to the entire reflection system. + * All type, function, and method registrations occur during object construction. * - * All inherited members are properly destroyed when the object is destroyed, except for the *functor containers*. + * Instances of this class are regular, stack-allocated value-type objects. + * The copy constructor is explicit, and the assignment operator is deleted. * - * Notes on Functor Storage: - * - Functor containers have static lifetime and are not part of this class or its base class. - * - This class (and its base) store only `Function` objects, which serve as hash-keys to look up actual functors. - * - Registering the same functor multiple times across different `CxxMirror` instances will not duplicate the functor in the container. - * - However, each `CxxMirror` instance will maintain its own unique `Function` hash-keys, even for the same functor. - * - Within a single `CxxMirror` object, registering the same functor multiple times is ignored (no duplicate `Function` hash-keys). + * The class stores only metadata in the form of strings and PODs. + * It does not own or manage any heap-allocated or static-lifetime resources. * - * Summary: - * - Functor objects are shared and static. - * - `Function` keys are per-instance. - * - Functor storage remains unaffected by the number of `CxxMirror` instances. -*/ + * Function pointers provided during registration are cached separately and are + * decoupled from this class. Each CxxMirror instance maintains its own metadata + * that references the registered function pointers. + * + * As a result, the same function pointer may be associated with different string + * keys across different CxxMirror instances without duplicating the underlying + * function pointer storage. + * + * Within a single CxxMirror instance, attempting to register the same functor + * multiple times is ignored, and a warning is emitted to the console. + */ class CxxMirror : public detail::CxxReflection { public: + // avoids implicit move. explicit CxxMirror(CxxMirror&&) = default; + + // avoids implicit copy. explicit CxxMirror(const CxxMirror&) = default; - // Constructs CxxMirror using a set of Function objects. All other constructors are disabled. + // Constructs CxxMirror using a set of Function objects. explicit CxxMirror(const std::vector& pFunctions); - // Returns a Record containing function hash-keys for the given record ID. - std::optional getRecord(const std::size_t pRecordId) const; + // Returns a valid Record if the type is found by id; otherwise, std::nullopt. + std::optional getRecord(const traits::uid_t pRecordId) const; - // Returns a Record containing function hash-keys for the given record name. + // Returns a valid Record if the type is found by name in default namespace group; otherwise, std::nullopt. std::optional getRecord(const std::string& pRecordName) const; - // Returns a Record containing function hash-keys for the given record name (overloaded for namespace support). + // Returns a valid Record if the type is found by name in the given namespace group; otherwise, std::nullopt. std::optional getRecord(const std::string& pNameSpaceName, const std::string& pRecordName) const; - // Returns a Function object for the given function name (non-member function). + // Returns a valid Function if found by name in default namespace group; otherwise, std::nullopt. std::optional getFunction(const std::string& pFunctionName) const; - // Returns a Function object for the given function name, within the specified namespace. + // Returns a valid Function if found by name in the given namespace group; otherwise, std::nullopt. std::optional getFunction(const std::string& pNameSpaceName, const std::string& pFunctionName) const; }; } \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/src/CxxMirror.cpp b/ReflectionTemplateLib/rtl/src/CxxMirror.cpp index 090c8d3a..7ab2b0b6 100644 --- a/ReflectionTemplateLib/rtl/src/CxxMirror.cpp +++ b/ReflectionTemplateLib/rtl/src/CxxMirror.cpp @@ -15,60 +15,75 @@ namespace rtl { -/* @Constructor: CxxMirror - @params: 'const std::vector&' - * accepts vector of 'Function' objects, which are hash-key to lookup a functor. - * the only constructor to construct 'CxxMirror' object. - * Syntax for constructing - CxxMirror({ type().function("func_name").build(), ..., ... }) - * '.build()' function will return a 'Function' object, and passed to std::vector initializer list. - * the vector is simply forwarded to the base class constructor. -*/ CxxMirror::CxxMirror(const std::vector& pFunctions) : detail::CxxReflection(pFunctions) + CxxMirror::CxxMirror(const std::vector& pFunctions) : detail::CxxReflection(pFunctions) { rtl::detail::ReflectedConversions::init(); } -/* @method: getRecord - @param: const std::string& (name of the class/struct) - @return: std::optional - * if the class/struct isn't found by the given name, std::nullopt is returned. - * every class/struct's is grouped under a namespace. - * if no namespace is specified while registration, NAMESPACE_GLOBAL is used. -*/ std::optional CxxMirror::getRecord(const std::string& pRecord) const + /** + * @method getRecord + * + * @param pRecordName The name of the class or struct to look up. + * @return std::optional + * Returns a valid Record if the type is found by name in default namespace group; otherwise, std::nullopt. + * + * All registered classes and structs are grouped under a namespace. + * If no namespace is specified during registration, NAMESPACE_GLOBAL(the default) is used. */ + std::optional CxxMirror::getRecord(const std::string& pRecordName) const { - return getRecord(std::string(detail::NAMESPACE_GLOBAL), pRecord); + return getRecord(std::string(detail::NAMESPACE_GLOBAL), pRecordName); } -/* @method: getFunction - @param: const std::string& (name of the non-member function) - @return: std::optional - * if the function isn't found by the given name, std::nullopt is returned. - * every function is grouped under a namespace. - * if no namespace is specified while registration, NAMESPACE_GLOBAL is used. -*/ std::optional CxxMirror::getFunction(const std::string& pFunction) const + /** + * @method getFunction + * + * @param pFunctionName The name of the non-member function to look up. + * @return std::optional + * Returns a valid Function if found by name in default namespace group; otherwise, std::nullopt. + * + * All registered non-member functions are grouped under a namespace. + * If no namespace is specified during registration, NAMESPACE_GLOBAL(the default) is used. */ + std::optional CxxMirror::getFunction(const std::string& pFunctionName) const { - return getFunction(std::string(detail::NAMESPACE_GLOBAL), pFunction); + return getFunction(std::string(detail::NAMESPACE_GLOBAL), pFunctionName); } - std::optional CxxMirror::getRecord(const std::size_t pRecordId) const + /** + * @method getRecord + * + * @param pRecordId The RTL-specific unique type identifier. + * @return std::optional + * Returns a valid Record if the type is found; otherwise, std::nullopt. + * + * Every registered type `T` is assigned a unique integer type ID, which can be + * obtained via `rtl::traits::uid::value` and cached for efficient lookup. + * + * The primary benefit of using a type ID is that it avoids the need to provide + * the namespace and type name as strings during lookup. */ + std::optional CxxMirror::getRecord(const traits::uid_t pRecordId) const { const auto& recordMap = getRecordIdMap(); const auto& itr = recordMap.find(pRecordId); return (itr == recordMap.end() ? std::nullopt : std::make_optional(itr->second)); } -/* @method: getRecord - @param: std::string (namespace name), std::string (class/struct name) - @return: std::optional - * retrieves the class/struct (as Record) registered under the given namespace. - * if the class/struct isn't found by the given name, std::nullopt is returned. -*/ std::optional CxxMirror::getRecord(const std::string& pNameSpace, const std::string& pRecord) const + /** + * @method getRecord + * + * @param pNameSpaceName The namespace under which the type was registered. + * @param pRecordName The name of the type to look up. + * @return std::optional + * Returns a valid Record if the type is found by name in the given namespace group; otherwise, std::nullopt. + * + * Retrieves the class or struct registered under the specified namespace. */ + std::optional CxxMirror::getRecord(const std::string& pNameSpaceName, const std::string& pRecordName) const { const auto& nsRecordMap = getNamespaceRecordMap(); - const auto& itr = nsRecordMap.find(pNameSpace); + const auto& itr = nsRecordMap.find(pNameSpaceName); if (itr != nsRecordMap.end()) { const auto& recordMap = itr->second; - const auto& itr0 = recordMap.find(pRecord); + const auto& itr0 = recordMap.find(pRecordName); if (itr0 != recordMap.end()) { return std::make_optional(itr0->second); } @@ -76,19 +91,23 @@ namespace rtl return std::nullopt; } -/* @method: getFunction - @param: namespace name (std::string), non-mermber function name (std::string) - @return: std::optional - * retrieves the function (as 'Function' object) registered under the given namespace. - * if the function isn't found by the given name, std::nullopt is returned. -*/ std::optional CxxMirror::getFunction(const std::string& pNameSpace, const std::string& pFunction) const + /** + * @method getFunction + * + * @param pNameSpaceName The namespace under which the function was registered. + * @param pFunctionName The name of the function to look up. + * @return std::optional + * Returns a valid Function if found by name in the given namespace group; otherwise, std::nullopt. + * + * Retrieves the non-member function registered under the specified namespace. */ + std::optional CxxMirror::getFunction(const std::string& pNameSpaceName, const std::string& pFunctionName) const { const auto& nsFunctionMap = getNamespaceFunctionsMap(); - const auto& itr = nsFunctionMap.find(pNameSpace); + const auto& itr = nsFunctionMap.find(pNameSpaceName); if (itr != nsFunctionMap.end()) { const auto& functionMap = itr->second; - const auto& itr0 = functionMap.find(pFunction); + const auto& itr0 = functionMap.find(pFunctionName); if (itr0 != functionMap.end()) { return std::make_optional(itr0->second); } From bc597b5405dfbaf01a665439fdb53d1d98655617 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 18 Jan 2026 13:53:45 +0530 Subject: [PATCH 4/5] ignore actions for .md file edits. --- .github/workflows/build.yml | 2 ++ .github/workflows/coverage.yml | 2 ++ README.md | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 674c3d7c..21e114f9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,8 @@ on: - '**/*.md' push: branches: [ release ] + paths-ignore: + - '**/*.md' workflow_dispatch: jobs: diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index fcf5b9b8..55f63f9d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -7,6 +7,8 @@ on: - '**/*.md' push: branches: [ release ] + paths-ignore: + - '**/*.md' workflow_dispatch: jobs: diff --git a/README.md b/README.md index 5b495114..f77ccf16 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,8 @@ rtl::CxxMirror& cxx::mirror() { } ``` `cxx_mirror` is a immutable, stack-allocated, value-type object and is safe to copy. -However, when used as a singleton (as shown above), implicit copies (e.g., `auto mirror = cxx::mirror();`) can unintentionally violate the singleton semantics. -To prevent this, the copy constructor is restricted to avoid such unintended duplication. +However, when used as a singleton (as shown above), implicit copies (e.g., `auto mirror = cxx::mirror()`) can unintentionally violate the singleton semantics. +To prevent this, the `CxxMirror`'s copy constructor is restricted to avoid such unintended duplication. ### RTL in action: From 76066cd8af5dc92495afad2e53641ea9d0ee1ef5 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 18 Jan 2026 13:58:40 +0530 Subject: [PATCH 5/5] readme update. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f77ccf16..58871b56 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ rtl::CxxMirror& cxx::mirror() { ``` `cxx_mirror` is a immutable, stack-allocated, value-type object and is safe to copy. However, when used as a singleton (as shown above), implicit copies (e.g., `auto mirror = cxx::mirror()`) can unintentionally violate the singleton semantics. -To prevent this, the `CxxMirror`'s copy constructor is restricted to avoid such unintended duplication. +To prevent this, the `rtl::CxxMirror`'s copy constructor is restricted to avoid such unintended duplication. ### RTL in action: