diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 00000000..1d20178a --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,19 @@ +coverage: + status: + project: + rtl: + paths: + - ReflectionTemplateLib/rtl + target: 85% + informational: true + +comment: + layout: "diff, flags, files" + behavior: default + +ignore: + - "CxxTestProps/**" + - "CxxTestUtils/**" + - "RTLTestRunApp/**" + - "RTLBenchmarkApp/**" + - "ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp" \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..c9b598cc --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +# These are supported funding model platforms +github: cpphighnrj diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..21e114f9 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,95 @@ +name: RTL Build + +permissions: + contents: write + +on: + pull_request: + branches: [ release, develop ] + paths-ignore: + - '**/*.md' + push: + branches: [ release ] + paths-ignore: + - '**/*.md' + workflow_dispatch: + +jobs: + build: + name: Build (${{ matrix.os }} / ${{ matrix.compiler }}) + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + compiler: [gcc, clang, msvc] + exclude: + - os: windows-latest + compiler: gcc + - os: windows-latest + compiler: clang + - os: ubuntu-latest + compiler: msvc + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + # Linux dependencies + - name: Install dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt update + sudo apt install -y ninja-build g++ clang + + # Configure (Linux) + - name: Configure (Linux) + if: runner.os == 'Linux' + run: | + if [ "${{ matrix.compiler }}" = "gcc" ]; then + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++; + else + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++; + fi + + # Configure (Windows / MSVC) + - name: Configure (Windows / MSVC) + if: runner.os == 'Windows' + run: cmake -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release + + # Build + - name: Build + run: cmake --build build --config Release --parallel + + # Rename binaries (Linux) + - name: Rename binaries (Linux) + if: runner.os == 'Linux' + run: | + mv bin/RTLTestRunApp bin/RTLTestRunApp-${{ matrix.compiler }} + mv bin/RTLBenchmarkApp bin/RTLBenchmarkApp-${{ matrix.compiler }} + + # Rename binaries (Windows / MSVC) + - name: Rename binaries (Windows) + if: runner.os == 'Windows' + run: | + ren bin\Release\RTLTestRunApp.exe RTLTestRunApp-msvc.exe + ren bin\Release\RTLBenchmarkApp.exe RTLBenchmarkApp-msvc.exe + + # Upload artifacts (all builds) + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: rtl-test-binaries-${{ matrix.compiler }} + path: bin/ + + # Publish to GitHub Release (release branch only) + - name: Publish to GitHub Release (All binaries) + if: github.ref == 'refs/heads/release' + uses: softprops/action-gh-release@v2 + with: + tag_name: latest + name: Latest RTL Build + files: | + bin/** + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..55f63f9d --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,71 @@ +name: RTL Coverage + +on: + pull_request: + branches: [ release, develop ] + paths-ignore: + - '**/*.md' + push: + branches: [ release ] + paths-ignore: + - '**/*.md' + workflow_dispatch: + +jobs: + coverage: + name: RTL Coverage (Linux / GCC) + runs-on: ubuntu-latest + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Install coverage tools + run: | + sudo apt update + sudo apt install -y lcov gcovr ninja-build g++ + + - name: Configure (Coverage) + run: | + cmake -B build -G Ninja \ + -DENABLE_COVERAGE=ON \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_CXX_COMPILER=g++ + + - name: Build + run: cmake --build build --parallel + + - name: Run tests + run: | + ./bin/RTLTestRunApp + + - name: Capture RTL coverage + run: | + lcov --capture --directory . \ + --output-file coverage.info \ + --ignore-errors=inconsistent,negative,mismatch + + lcov --extract coverage.info \ + '*ReflectionTemplateLib/rtl/*' \ + -o coverage_rtl.info + + - name: Generate HTML report + run: | + genhtml coverage_rtl.info \ + --output-directory coverage_rtl \ + --ignore-errors inconsistent,corrupt + + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: rtl-coverage-report + path: coverage_rtl + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + files: coverage_rtl.info + flags: rtl + name: RTL-Core-Coverage + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ae7d28bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/build +/bin +/.vscode \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 012c1041..3451819f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,25 @@ -# CMakeLists.txt for the entire project cmake_minimum_required(VERSION 3.20) -# Set the project name project(CxxReflectionProject) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin") -# Add the subdirectories -add_subdirectory(CxxTestProject) +# ---------------------------- +# Coverage Support (Linux) +# ---------------------------- +option(ENABLE_COVERAGE "Enable code coverage" OFF) + +if(ENABLE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + message(STATUS "Code coverage enabled") + add_compile_options(--coverage -O0 -g) + add_link_options(--coverage) +endif() + +# ---------------------------- +# Subdirectories +# ---------------------------- add_subdirectory(ReflectionTemplateLib) -add_subdirectory(CxxTypeRegistration) -add_subdirectory(CxxReflectionTests) \ No newline at end of file +add_subdirectory(CxxTestRegistration) +add_subdirectory(CxxTestProps) +add_subdirectory(CxxTestUtils) +add_subdirectory(RTLTestRunApp) +add_subdirectory(RTLBenchmarkApp) diff --git a/CxxReflectionTests/CMakeLists.txt b/CxxReflectionTests/CMakeLists.txt deleted file mode 100644 index 7c7ec00a..00000000 --- a/CxxReflectionTests/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -# CMakeLists.txt for CxxReflectionTests -cmake_minimum_required(VERSION 3.20) - -set(CMAKE_CXX_STANDARD 20) - -project(CxxReflectionTests) - -set(CXX_EXE_NAME CxxReflectionTests) -add_executable(${CXX_EXE_NAME} "") - - -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip -) -# For Windows: Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) - -include_directories(inc) -include_directories("${CMAKE_SOURCE_DIR}/CxxTypeRegistration/inc") -include_directories("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib/common") -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib/detail/inc") -include_directories("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib/access/inc") -include_directories("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib/builder/inc") - -target_link_libraries(${CXX_EXE_NAME} GTest::gtest_main) -target_link_libraries(${CXX_EXE_NAME} CxxTypeRegistration) -target_link_libraries(${CXX_EXE_NAME} ReflectionTemplateLib) - -# Add the source directory -include(src/CMakeLists.txt) - -include(GoogleTest) -gtest_discover_tests(${CXX_EXE_NAME}) diff --git a/CxxReflectionTests/src/CMakeLists.txt b/CxxReflectionTests/src/CMakeLists.txt deleted file mode 100644 index 0fc63a9b..00000000 --- a/CxxReflectionTests/src/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -# CMakeLists.txt for CxxReflectionTests -cmake_minimum_required(VERSION 3.20) - -project(CxxReflectionTests) - -# Create a variable containing the source files for your target -set(LOCAL_SOURCES - "${CMAKE_CURRENT_LIST_DIR}/ClassMethodsTests.cpp" - "${CMAKE_CURRENT_LIST_DIR}/ConstMethodOverloadTests.cpp" - "${CMAKE_CURRENT_LIST_DIR}/ConstructorTests.cpp" - "${CMAKE_CURRENT_LIST_DIR}/CopyConstructorTests.cpp" - "${CMAKE_CURRENT_LIST_DIR}/NameSpaceGlobalsTests.cpp" - "${CMAKE_CURRENT_LIST_DIR}/ReflectedCallStatusErrTests.cpp" - "${CMAKE_CURRENT_LIST_DIR}/StaticMethodTests.cpp" -) - -# Add any additional source files if needed -target_sources(CxxReflectionTests - PUBLIC - "${LOCAL_SOURCES}" -) \ No newline at end of file diff --git a/CxxReflectionTests/src/ClassMethodsTests.cpp b/CxxReflectionTests/src/ClassMethodsTests.cpp deleted file mode 100644 index adf38aad..00000000 --- a/CxxReflectionTests/src/ClassMethodsTests.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include - -#include "MyReflection.h" -#include "TestUtilsBook.h" - -using namespace std; -using namespace rtl; -using namespace rtl::access; -using namespace test_utils; - -namespace rtl_tests -{ - TEST(RTLInterfaceCxxMirror, get_class_methods_with_wrong_names) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional badMethod = classBook->getMethod("no_method"); - EXPECT_FALSE(badMethod.has_value()); - } - - - TEST(ReflectionMethodCall, wrong_args) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional setAuthor = classBook->getMethod(book::str_setAuthor); - ASSERT_TRUE(setAuthor); - - auto [status, bookObj] = classBook->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(bookObj.isEmpty()); - ASSERT_FALSE(setAuthor->hasSignature()); - - RStatus rStatus = (*setAuthor)(bookObj)(book::AUTHOR); - - ASSERT_TRUE(rStatus == rtl::Error::SignatureMismatch); - ASSERT_FALSE(rStatus.getReturn().has_value()); - EXPECT_FALSE(book::test_method_setAuthor(bookObj.get())); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ClassBookMethod, args_void) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional getPublishedOn = classBook->getMethod(book::str_getPublishedOn); - ASSERT_TRUE(getPublishedOn); - - auto [status, bookObj] = classBook->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(bookObj.isEmpty()); - ASSERT_TRUE(getPublishedOn->hasSignature()); - - RStatus rStatus = (*getPublishedOn)(bookObj)(); - - ASSERT_TRUE(rStatus); - ASSERT_TRUE(rStatus.getReturn().has_value()); - ASSERT_TRUE(rStatus.isOfType()); - - const std::string& retStr = any_cast(rStatus.getReturn()); - EXPECT_TRUE(book::test_method_getPublishedOn_return(retStr)); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ClassBookMethod, args_string) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional setAuthor = classBook->getMethod(book::str_setAuthor); - ASSERT_TRUE(setAuthor); - - auto [status, bookObj] = classBook->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(bookObj.isEmpty()); - ASSERT_TRUE(setAuthor->hasSignature()); - - RStatus rStatus = (*setAuthor)(bookObj)(std::string(book::AUTHOR)); - - ASSERT_TRUE(rStatus); - ASSERT_FALSE(rStatus.getReturn().has_value()); - - EXPECT_TRUE(book::test_method_setAuthor(bookObj.get())); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ClassBookMethodOverload, args_void) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional updateBookInfo = classBook->getMethod(book::str_updateBookInfo); - ASSERT_TRUE(updateBookInfo); - - auto [status, bookObj] = classBook->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(bookObj.isEmpty()); - ASSERT_TRUE(updateBookInfo->hasSignature()); - - RStatus rStatus = (*updateBookInfo)(bookObj)(); - - ASSERT_TRUE(rStatus); - ASSERT_FALSE(rStatus.getReturn().has_value()); - EXPECT_TRUE(book::test_method_updateBookInfo(bookObj.get())); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ClassBookMethodOverload, args_string_double_charPtr) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional updateBookInfo = classBook->getMethod(book::str_updateBookInfo); - ASSERT_TRUE(updateBookInfo); - - auto [status, bookObj] = classBook->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(bookObj.isEmpty()); - const bool signatureValid = updateBookInfo->hasSignature(); - ASSERT_TRUE(signatureValid); - - RStatus rStatus = (*updateBookInfo)(bookObj)(string(book::AUTHOR), book::PRICE, book::TITLE); - - ASSERT_TRUE(rStatus); - ASSERT_FALSE(rStatus.getReturn().has_value()); - const bool isSuccess = book::test_method_updateBookInfo(bookObj.get()); - EXPECT_TRUE(isSuccess); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ClassBookMethodOverload, args_charPtr_double_string) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional updateBookInfo = classBook->getMethod(book::str_updateBookInfo); - ASSERT_TRUE(updateBookInfo); - - auto [status, bookObj] = classBook->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(bookObj.isEmpty()); - const bool signatureValid = updateBookInfo->hasSignature(); - ASSERT_TRUE(signatureValid); - - RStatus rStatus = (*updateBookInfo)(bookObj)(book::TITLE, book::PRICE, string(book::AUTHOR)); - - ASSERT_TRUE(rStatus); - ASSERT_FALSE(rStatus.getReturn().has_value()); - const bool isSuccess = book::test_method_updateBookInfo(bookObj.get()); - EXPECT_TRUE(isSuccess); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } -} \ No newline at end of file diff --git a/CxxReflectionTests/src/ConstMethodOverloadTests.cpp b/CxxReflectionTests/src/ConstMethodOverloadTests.cpp deleted file mode 100644 index f6d80fd7..00000000 --- a/CxxReflectionTests/src/ConstMethodOverloadTests.cpp +++ /dev/null @@ -1,226 +0,0 @@ -#include - -#include "MyReflection.h" -#include "TestUtilsPerson.h" - -using namespace std; -using namespace rtl::access; -using namespace test_utils; - -namespace rtl_tests -{ - TEST(ConstMethodOverload, const_method_no_overload_call_on_non_const_target) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional recOpt = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(recOpt.has_value()); - - const Record& classPerson = recOpt.value(); - optional updateLastName = classPerson.getMethod(person::str_updateLastName); - ASSERT_TRUE(updateLastName); - - auto [status, personObj] = classPerson.instance(string(person::FIRST_NAME)); - - ASSERT_TRUE(status); - ASSERT_FALSE(personObj.isEmpty()); - ASSERT_FALSE(personObj.isConst()); - ASSERT_TRUE(updateLastName->hasSignature()); - - const RStatus& rStatus = (*updateLastName)(personObj)(string(person::LAST_NAME)); - - ASSERT_TRUE(rStatus); - EXPECT_TRUE(person::test_method_updateLastName(personObj.get())); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ConstMethodOverload, const_method_no_overload_call_on_const_target) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional recOpt = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(recOpt.has_value()); - - const Record& classPerson = recOpt.value(); - optional updateLastName = classPerson.getMethod(person::str_updateLastName); - ASSERT_TRUE(updateLastName); - - auto [status, personObj] = classPerson.instance(string(person::FIRST_NAME)); - - ASSERT_TRUE(status); - ASSERT_FALSE(personObj.isEmpty()); - - personObj.makeConst(); - ASSERT_TRUE(personObj.isConst()); - ASSERT_TRUE(updateLastName->hasSignature()); - - const RStatus& rStatus = (*updateLastName)(personObj)(string(person::LAST_NAME)); - - ASSERT_TRUE(rStatus); - EXPECT_TRUE(person::test_method_updateLastName_const(personObj.get())); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ConstMethodOverload, const_method_no_overload_call_on_const_target_returns_string) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional recOpt = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(recOpt.has_value()); - - const Record& classPerson = recOpt.value(); - optional updateLastName = classPerson.getMethod(person::str_updateLastName); - ASSERT_TRUE(updateLastName); - - const std::string firstName = person::FIRST_NAME; - auto [status, personObj] = classPerson.instance(firstName); - - ASSERT_TRUE(status); - ASSERT_FALSE(personObj.isEmpty()); - - personObj.makeConst(); - ASSERT_TRUE(personObj.isConst()); - - optional getFirstName = classPerson.getMethod(person::str_getFirstName); - ASSERT_TRUE(getFirstName); - - const RStatus& rstatus = getFirstName->on(personObj).call(); - ASSERT_TRUE(rstatus); - ASSERT_TRUE(rstatus.isOfType()); - - const std::string retStr = std::any_cast(rstatus.getReturn()); - ASSERT_EQ(retStr, firstName); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ConstMethodOverload, const_method_string_call_on_const_target) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional updateAddress = classPerson->getMethod(person::str_updateAddress); - ASSERT_TRUE(updateAddress); - - string fnameStr = person::FIRST_NAME; - auto [status, personObj] = classPerson->instance(fnameStr); - - ASSERT_TRUE(status); - ASSERT_FALSE(personObj.isEmpty()); - - personObj.makeConst(); - ASSERT_TRUE(personObj.isConst()); - ASSERT_TRUE(updateAddress->hasSignature()); - - const RStatus& rStatus = (*updateAddress)(personObj)(string(person::ADDRESS)); - - ASSERT_TRUE(rStatus); - EXPECT_TRUE(person::test_method_updateAddress_const(personObj.get())); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ConstMethodOverload, const_method_string_call_on_non_const_target) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional updateAddress = classPerson->getMethod(person::str_updateAddress); - ASSERT_TRUE(updateAddress); - - auto [status, personObj] = classPerson->instance(string(person::FIRST_NAME)); - - ASSERT_TRUE(status); - ASSERT_FALSE(personObj.isEmpty()); - ASSERT_FALSE(personObj.isConst()); - ASSERT_TRUE(updateAddress->hasSignature()); - - const RStatus& rStatus = (*updateAddress)(personObj)(string(person::ADDRESS)); - - ASSERT_TRUE(rStatus); - EXPECT_TRUE(person::test_method_updateAddress(personObj.get())); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ConstMethodOverload, const_method_no_args_call_on_const_target) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional recOpt = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(recOpt.has_value()); - - const Record& classPerson = recOpt.value(); - optional updateAddress = classPerson.getMethod(person::str_updateAddress); - ASSERT_TRUE(updateAddress); - - auto [status, personObj] = classPerson.instance(string(person::FIRST_NAME)); - - ASSERT_TRUE(status); - ASSERT_FALSE(personObj.isEmpty()); - ASSERT_FALSE(personObj.isConst()); - - personObj.makeConst(); - ASSERT_TRUE(personObj.isConst()); - ASSERT_TRUE(updateAddress->hasSignature()); - - const RStatus& rStatus = (*updateAddress)(personObj)(); - - ASSERT_TRUE(rStatus); - EXPECT_TRUE(person::test_method_updateAddress_const(personObj.get())); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ConstMethodOverload, const_method_no_args_call_on_non_const_target) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional updateAddress = classPerson->getMethod(person::str_updateAddress); - ASSERT_TRUE(updateAddress); - - string fnameStr = person::FIRST_NAME; - auto [status, personObj] = classPerson->instance(fnameStr); - - ASSERT_TRUE(status); - ASSERT_FALSE(personObj.isEmpty()); - ASSERT_FALSE(personObj.isConst()); - ASSERT_TRUE(updateAddress->hasSignature()); - - const RStatus& rStatus = (*updateAddress)(personObj)(); - - ASSERT_TRUE(rStatus); - EXPECT_TRUE(person::test_method_updateAddress(personObj.get())); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } -} \ No newline at end of file diff --git a/CxxReflectionTests/src/ConstructorTests.cpp b/CxxReflectionTests/src/ConstructorTests.cpp deleted file mode 100644 index e4210a32..00000000 --- a/CxxReflectionTests/src/ConstructorTests.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include - -#include "MyReflection.h" -#include "TestUtilsBook.h" -#include "TestUtilsDate.h" - -using namespace std; -using namespace rtl; -using namespace rtl::access; -using namespace test_utils; - -namespace rtl_tests -{ - TEST(RTLInterfaceCxxMirror, get_record_types_with_wrong_names) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional badFunc = cxxMirror.getFunction(date::ns, "wrong_date_struct"); - EXPECT_FALSE(badFunc); - - optional badRec = cxxMirror.getRecord(date::ns, "wrong" + std::string(date::struct_)); - EXPECT_FALSE(badRec); - } - - - TEST(DynamicAllocConstructorDate, wrong_args) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classDate = cxxMirror.getRecord(date::ns, date::struct_); - ASSERT_TRUE(classDate); - - auto [status, instance] = classDate->instance("wrong", "args0", 10); - - ASSERT_TRUE(status == Error::SignatureMismatch); - ASSERT_TRUE(instance.isEmpty()); - } - EXPECT_TRUE(date::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(DynamicAllocConstructorDate, args_void) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classDate = cxxMirror.getRecord(date::ns, date::struct_); - ASSERT_TRUE(classDate); - - auto [status, instance] = classDate->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(instance.isEmpty()); - EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor<>(instance.get())); - } - EXPECT_TRUE(date::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(DynamicAllocConstructorDate, args_string) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classDate = cxxMirror.getRecord(date::ns, date::struct_); - ASSERT_TRUE(classDate); - - const string& dateStr = date::DATE_STR; - auto [status, instance] = classDate->instance(dateStr); - - ASSERT_TRUE(status); - ASSERT_FALSE(instance.isEmpty()); - EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor(instance.get())); - } - EXPECT_TRUE(date::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(DynamicAllocConstructorDate, args_unsigned_unsigned_unsigned) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classDate = cxxMirror.getRecord(date::ns, date::struct_); - ASSERT_TRUE(classDate); - - auto [status, instance] = classDate->instance(date::DAY, date::MONTH, date::YEAR); - - ASSERT_TRUE(status); - ASSERT_FALSE(instance.isEmpty()); - - const bool isPassed = date::test_dynamic_alloc_instance_ctor(instance.get()); - EXPECT_TRUE(isPassed); - } - EXPECT_TRUE(date::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(DestructorDate, non_virtual) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classDate = cxxMirror.getRecord(date::ns, date::struct_); - ASSERT_TRUE(classDate); - - auto [status, instance] = classDate->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(instance.isEmpty()); - EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor<>(instance.get())); - } - EXPECT_TRUE(date::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(DynamicAllocConstructorBook, wrong_args) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - auto [status, instance] = classBook->instance(19.0, 87.5); - - ASSERT_TRUE(status == Error::SignatureMismatch); - ASSERT_TRUE(instance.isEmpty()); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(DynamicAllocConstructorBook, args_default) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - auto [status, instance] = classBook->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(instance.isEmpty()); - EXPECT_TRUE(book::test_dynamic_alloc_instance_ctor(instance.get())); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(DynamicAllocConstructorBook, args_double_string) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - double price = book::PRICE; - string title = book::TITLE; - auto [status, instance] = classBook->instance(price, title); - - ASSERT_TRUE(status); - ASSERT_FALSE(instance.isEmpty()); - - const bool isPassed = book::test_dynamic_alloc_instance_ctor(instance.get()); - EXPECT_TRUE(isPassed); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(DestructorBook, non_virtual) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - auto [status, instance] = classBook->instance(); - - ASSERT_TRUE(status); - ASSERT_FALSE(instance.isEmpty()); - EXPECT_TRUE(book::test_dynamic_alloc_instance_ctor(instance.get())); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } -} \ No newline at end of file diff --git a/CxxReflectionTests/src/CopyConstructorTests.cpp b/CxxReflectionTests/src/CopyConstructorTests.cpp deleted file mode 100644 index 9f867a04..00000000 --- a/CxxReflectionTests/src/CopyConstructorTests.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include - -#include "MyReflection.h" -#include "TestUtilsBook.h" -#include "TestUtilsPerson.h" - -using namespace std; -using namespace rtl; -using namespace rtl::access; -using namespace test_utils; - -namespace rtl_tests -{ - - TEST(CopyConstructor, call_copy_ctor_of_PERSON_with_BOOK_instance) - { - { - optional classPerson = MyReflection::instance().getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional classBook = MyReflection::instance().getRecord(book::class_); - ASSERT_TRUE(classBook); - - auto [status, bookObj] = classBook->instance(); - ASSERT_TRUE(status); - ASSERT_FALSE(bookObj.isEmpty()); - - auto [retStatus, badObj] = classPerson->clone(bookObj); - - ASSERT_TRUE(retStatus == Error::InstanceTypeMismatch); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(CopyConstructor, copy_ctor_arg_const_ref___src_instance_non_const) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional setAuthor = classBook->getMethod(book::str_setAuthor); - ASSERT_TRUE(setAuthor); - - optional setDecription = classBook->getMethod(book::str_setDescription); - ASSERT_TRUE(setDecription); - - double price = book::PRICE; - string title = book::TITLE; - string author = book::AUTHOR; - string description = book::DESCRIPTION; - - auto [status, srcObj] = classBook->instance(price, title); - ASSERT_TRUE(status); - ASSERT_FALSE(srcObj.isEmpty()); - - (*setAuthor)(srcObj)(author); - (*setDecription)(srcObj)(description); - - auto [ret, copyObj] = classBook->clone(srcObj); - ASSERT_TRUE(ret); - ASSERT_FALSE(copyObj.isEmpty()); - - const bool isPassed = book::test_unique_copy_ctor_const_ref(copyObj.get()); - EXPECT_TRUE(isPassed); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(CopyConstructor, copy_ctor_arg_const_ref___src_instance_const) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classBook = cxxMirror.getRecord(book::class_); - ASSERT_TRUE(classBook); - - optional setAuthor = classBook->getMethod(book::str_setAuthor); - ASSERT_TRUE(setAuthor); - - optional setDecription = classBook->getMethod(book::str_setDescription); - ASSERT_TRUE(setDecription); - - double price = book::PRICE; - string title = book::TITLE; - string author = book::AUTHOR; - string description = book::DESCRIPTION; - - auto [status, srcObj] = classBook->instance(price, title); - ASSERT_TRUE(status); - ASSERT_FALSE(srcObj.isEmpty()); - - (*setAuthor)(srcObj)(author); - (*setDecription)(srcObj)(description); - - //make this instance const. - srcObj.makeConst(); - - auto [ret, copyObj] = classBook->clone(srcObj); - ASSERT_TRUE(ret); - ASSERT_FALSE(copyObj.isEmpty()); - - const bool isPassed = book::test_unique_copy_ctor_const_ref(copyObj.get()); - EXPECT_TRUE(isPassed); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(CopyConstructor, copy_ctor_arg_const_ref_overload___src_instance_const) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - auto [status, srcObj] = classPerson->instance(); - ASSERT_TRUE(status); - ASSERT_FALSE(srcObj.isEmpty()); - - srcObj.makeConst(); - - auto [ret, copyObj] = classPerson->clone(srcObj); - ASSERT_TRUE(ret); - ASSERT_FALSE(copyObj.isEmpty()); - - const bool isPassed = person::test_copy_constructor_overload_src_const_obj(copyObj.get()); - EXPECT_TRUE(isPassed); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(CopyConstructor, copy_ctor_arg_non_const_ref_overload___src_instance_non_const) - { - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - auto [status, srcObj] = classPerson->instance(); - ASSERT_TRUE(status); - ASSERT_FALSE(srcObj.isEmpty()); - - auto [ret, copyObj] = classPerson->clone(srcObj); - ASSERT_TRUE(ret); - ASSERT_FALSE(copyObj.isEmpty()); - - const bool isPassed = person::test_copy_constructor_overload_src_non_const_obj(copyObj.get()); - EXPECT_TRUE(isPassed); - } - EXPECT_TRUE(book::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } -} \ No newline at end of file diff --git a/CxxReflectionTests/src/NameSpaceGlobalsTests.cpp b/CxxReflectionTests/src/NameSpaceGlobalsTests.cpp deleted file mode 100644 index 05019476..00000000 --- a/CxxReflectionTests/src/NameSpaceGlobalsTests.cpp +++ /dev/null @@ -1,149 +0,0 @@ - -#include -#include - -#include "MyReflection.h" -#include "TestUtilsGlobals.h" - -using namespace std; -using namespace test_utils; -using namespace rtl::access; - -namespace rtl_tests -{ - TEST(RTLInterfaceCxxMirror, get_global_functions_with_wrong_names) - { - CxxMirror& cxxMirror = MyReflection::instance(); - { - optional badFunc = cxxMirror.getFunction("wrong_namespace", "wrong_function"); - EXPECT_FALSE(badFunc); - } { - optional badFunc = cxxMirror.getFunction(str_complex, "wrong_function"); - EXPECT_FALSE(badFunc); - } { - optional badFunc = cxxMirror.getFunction("wrong_getComplexNumAsString"); - EXPECT_FALSE(badFunc); - } - } - - - TEST(FunctionInNameSpace, get_namespace_function_types) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional setReal = cxxMirror.getFunction(str_complex, str_setReal); - ASSERT_TRUE(setReal); - - optional setImaginary = cxxMirror.getFunction(str_complex, str_setImaginary); - ASSERT_TRUE(setImaginary); - - EXPECT_TRUE(setReal->getNamespace() == str_complex); - EXPECT_TRUE(setReal->getFunctionName() == str_setReal); - EXPECT_TRUE(setImaginary->getNamespace() == str_complex); - EXPECT_TRUE(setImaginary->getFunctionName() == str_setImaginary); - } - - - TEST(FunctionInNameSpace, namespace_function_execute_return) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional getMagnitude = cxxMirror.getFunction(str_complex, str_getMagnitude); - ASSERT_TRUE(getMagnitude); - - optional setReal = cxxMirror.getFunction(str_complex, str_setReal); - ASSERT_TRUE(setReal); - - optional setImaginary = cxxMirror.getFunction(str_complex, str_setImaginary); - ASSERT_TRUE(setImaginary); - - EXPECT_TRUE(setReal->hasSignature()); - (*setReal)(g_real); - - EXPECT_TRUE(setImaginary->hasSignature()); - (*setImaginary)(g_imaginary); - - EXPECT_TRUE(getMagnitude->hasSignature()); - - RStatus status = (*getMagnitude)(); - - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - double retVal = std::any_cast(status.getReturn()); - double magnitude = abs(complex(g_real, g_imaginary)); - EXPECT_DOUBLE_EQ(magnitude, retVal); - } - - - TEST(FunctionInNameSpace, execute_with_wrong_signature) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional setReal = cxxMirror.getFunction(str_complex, str_setReal); - ASSERT_TRUE(setReal); - EXPECT_TRUE(setReal->hasSignature()); - - EXPECT_FALSE(setReal->hasSignature()); - - //different syntax, other than (*setReal)(float(g_real)) - RStatus status = setReal->call(float(g_real)); - - ASSERT_FALSE(status); - ASSERT_FALSE(status.getReturn().has_value()); - } - - - TEST(GlobalFunction, get_function_execute_return) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional getComplexNumAsString = cxxMirror.getFunction(str_getComplexNumAsString); - ASSERT_TRUE(getComplexNumAsString); - - RStatus status = (*getComplexNumAsString)(); - - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - string retVal = std::any_cast(status.getReturn()); - string comlexNumStr = to_string(g_real) + "i" + to_string(g_imaginary); - EXPECT_TRUE(comlexNumStr == retVal); - } - - - TEST(GlobalFunction, overloaded_function_execute_return) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional reverseString = cxxMirror.getFunction(str_reverseString); - ASSERT_TRUE(reverseString); - { - RStatus status = (*reverseString)(string(STRA)); - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - string retVal = std::any_cast(status.getReturn()); - EXPECT_TRUE(retVal == STRA_REVERSE); - } { - RStatus status = reverseString->call(string(STRB)); - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - string retVal = std::any_cast(status.getReturn()); - EXPECT_TRUE(retVal == STRB_REVERSE); - } { - RStatus status = (*reverseString)(); - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - string retVal = std::any_cast(status.getReturn()); - EXPECT_TRUE(retVal == REV_STR_VOID_RET); - } - } -} \ No newline at end of file diff --git a/CxxReflectionTests/src/ReflectedCallStatusErrTests.cpp b/CxxReflectionTests/src/ReflectedCallStatusErrTests.cpp deleted file mode 100644 index 0b72ef1d..00000000 --- a/CxxReflectionTests/src/ReflectedCallStatusErrTests.cpp +++ /dev/null @@ -1,169 +0,0 @@ - -#include - -#include "MyReflection.h" -#include "TestUtilsBook.h" -#include "TestUtilsDate.h" -#include "TestUtilsPerson.h" - -using namespace std; -using namespace rtl; -using namespace rtl::access; -using namespace test_utils; - -namespace rtl_tests -{ - TEST(ReflectedCallStatusError, unregistered_constructor___error_ConstructorNotFound) - { - optional classLibrary = MyReflection::instance().getRecord(library::class_); - ASSERT_TRUE(classLibrary); - - auto [status, instance] = classLibrary->instance(); - - ASSERT_TRUE(status == Error::ConstructorNotFound); - ASSERT_TRUE(instance.isEmpty()); - } - - - TEST(ReflectedCallStatusError, unregistered_constructor___error_CopyConstructorNotFound) - { - { - optional classCalender = MyReflection::instance().getRecord(calender::ns, calender::struct_); - ASSERT_TRUE(classCalender); - - auto [ret, srcObj] = classCalender->instance(); - ASSERT_TRUE(ret); - ASSERT_FALSE(srcObj.isEmpty()); - - auto [status, instance] = classCalender->clone(srcObj); - - ASSERT_TRUE(status == Error::CopyConstructorNotFound); - ASSERT_TRUE(instance.isEmpty()); - } - EXPECT_TRUE(calender::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ReflectedCallStatusError, static_method_call_wrong_args___error_SignatureMismatch) - { - optional classPerson = MyReflection::instance().getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional getProfile = classPerson->getMethod(person::str_getProfile); - ASSERT_TRUE(getProfile); - ASSERT_TRUE(getProfile->hasSignature()); - - const RStatus& status = getProfile->on().call(std::string()); - - ASSERT_TRUE(status == Error::SignatureMismatch); - } - - - TEST(ReflectedCallStatusError, copy_ctor_on_empty_instance___error_EmptyInstance) - { - optional classLibrary = MyReflection::instance().getRecord(library::class_); - ASSERT_TRUE(classLibrary); - - auto [status, emptyObj] = classLibrary->instance(); - - ASSERT_TRUE(status == Error::ConstructorNotFound); - ASSERT_TRUE(emptyObj.isEmpty()); - - optional classPerson = MyReflection::instance().getRecord(person::class_); - ASSERT_TRUE(classPerson); - - auto [retStatus, personObj] = classPerson->clone(emptyObj); - - ASSERT_TRUE(retStatus == Error::EmptyInstance); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ReflectedCallStatusError, method_call_on_empty_instance___error_EmptyInstance) - { - optional classLibrary = MyReflection::instance().getRecord(library::class_); - ASSERT_TRUE(classLibrary); - - auto [ret, emptyObj] = classLibrary->instance(); - - ASSERT_TRUE(ret == Error::ConstructorNotFound); - ASSERT_TRUE(emptyObj.isEmpty()); - - optional classBook = MyReflection::instance().getRecord(book::class_); - ASSERT_TRUE(classBook); - - RStatus retStatus = classBook->getMethod(book::str_getPublishedOn)->on(emptyObj).call(); - ASSERT_TRUE(retStatus == Error::EmptyInstance); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ReflectedCallStatusError, unregistered_constructor___error_ConstCopyConstructorNotFound) - { - { - optional classDate = MyReflection::instance().getRecord(date::ns, date::struct_); - ASSERT_TRUE(classDate); - - auto [ret, srcObj] = classDate->instance(); - ASSERT_TRUE(ret); - ASSERT_FALSE(srcObj.isEmpty()); - - srcObj.makeConst(); - - auto [status, instance] = classDate->clone(srcObj); - - ASSERT_TRUE(status == Error::ConstCopyConstructorNotFound); - ASSERT_TRUE(instance.isEmpty()); - } - EXPECT_TRUE(date::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ReflectedCallStatusError, method_on_wrong_instance___error_InstanceTypeMismatch) - { - { - optional classPerson = MyReflection::instance().getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional classBook = MyReflection::instance().getRecord(book::class_); - ASSERT_TRUE(classBook); - - auto [status, personObj] = classPerson->instance(); - ASSERT_TRUE(status); - ASSERT_FALSE(personObj.isEmpty()); - - optional getPublishedOn = classBook->getMethod(book::str_getPublishedOn); - ASSERT_TRUE(getPublishedOn); - - RStatus retStatus = getPublishedOn->on(personObj).call(); - ASSERT_TRUE(retStatus == Error::InstanceTypeMismatch); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } - - - TEST(ReflectedCallStatusError, non_const_method_on_const_Instance__error_InstanceConstMismatch) - { - { - optional classBook = MyReflection::instance().getRecord(book::class_); - ASSERT_TRUE(classBook); - - auto [status, bookObj] = classBook->instance(); - ASSERT_TRUE(status); - ASSERT_FALSE(bookObj.isEmpty()); - - optional getPublishedOn = classBook->getMethod(book::str_getPublishedOn); - ASSERT_TRUE(getPublishedOn); - - bookObj.makeConst(); - RStatus retStatus = getPublishedOn->on(bookObj).call(); - - ASSERT_TRUE(retStatus == Error::InstanceConstMismatch); - } - EXPECT_TRUE(person::assert_zero_instance_count()); - EXPECT_TRUE(Instance::getInstanceCount() == 0); - } -} \ No newline at end of file diff --git a/CxxReflectionTests/src/StaticMethodTests.cpp b/CxxReflectionTests/src/StaticMethodTests.cpp deleted file mode 100644 index 083b0115..00000000 --- a/CxxReflectionTests/src/StaticMethodTests.cpp +++ /dev/null @@ -1,135 +0,0 @@ - -#include - -#include "MyReflection.h" -#include "TestUtilsPerson.h" - -using namespace std; -using namespace rtl::access; -using namespace test_utils; - -namespace rtl_tests -{ - TEST(StaticMethods, unique_method_call) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional getDefaults = classPerson->getMethod(person::str_getDefaults); - ASSERT_TRUE(getDefaults); - ASSERT_TRUE(getDefaults->hasSignature()); - - const RStatus& status = (*getDefaults)()(); - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - const string& retStr = any_cast(status.getReturn()); - EXPECT_EQ(retStr, person::get_str_returned_on_call_getDefaults()); - } - - - TEST(StaticMethods, overload_method_void_call) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional getProfile = classPerson->getMethod(person::str_getProfile); - ASSERT_TRUE(getProfile); - ASSERT_TRUE(getProfile->hasSignature()); - - const RStatus& status = getProfile->on().call(); - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - const string& retStr = any_cast(status.getReturn()); - EXPECT_EQ(retStr, person::get_str_returned_on_call_getProfile()); - } - - - TEST(StaticMethods, overload_method_args_bool_call) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional getProfile = classPerson->getMethod(person::str_getProfile); - ASSERT_TRUE(getProfile); - ASSERT_TRUE(getProfile->hasSignature()); - { - const RStatus& status = (*getProfile)()(true); - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - const string& retStr = any_cast(status.getReturn()); - EXPECT_EQ(retStr, person::get_str_returned_on_call_getProfile(true)); - } { - //different syntax of calling. - const RStatus& status = getProfile->on().call(false); - - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - const string& retStr = any_cast(status.getReturn()); - EXPECT_EQ(retStr, person::get_str_returned_on_call_getProfile(false)); - } - } - - - TEST(StaticMethods, overload_method_args_string_size_t_call) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional recOpt = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(recOpt.has_value()); - - const Record& classPerson = recOpt.value(); - optional methOpt = classPerson.getMethod(person::str_getProfile); - ASSERT_TRUE(methOpt.has_value()); - - const Method& getProfile = methOpt.value(); - const bool& signValid = getProfile.hasSignature(); - ASSERT_TRUE(signValid); - - const RStatus& status = getProfile.on().call(string(person::OCCUPATION), person::AGE); - - ASSERT_TRUE(status); - ASSERT_TRUE(status.getReturn().has_value()); - ASSERT_TRUE(status.isOfType()); - - const string& retStr = any_cast(status.getReturn()); - const string& checkStr = person::get_str_returned_on_call_getProfile(); - - EXPECT_EQ(retStr, checkStr); - } - - - TEST(StaticMethods, static_method_call_on_target_instance) - { - CxxMirror& cxxMirror = MyReflection::instance(); - - optional classPerson = cxxMirror.getRecord(person::class_); - ASSERT_TRUE(classPerson); - - optional getDefaults = classPerson->getMethod(person::str_getDefaults); - ASSERT_TRUE(getDefaults); - ASSERT_TRUE(getDefaults->hasSignature()); - - auto [isSuccess, personObj] = classPerson->instance(); - - ASSERT_TRUE(isSuccess); - ASSERT_FALSE(personObj.isEmpty()); - - //TODO: handle this test case with appropriate error or make successful call as its valid to call static method on objects. - const RStatus& status = (*getDefaults)(personObj)(); - ASSERT_TRUE(status == rtl::Error::InstanceTypeMismatch); - } -} \ No newline at end of file diff --git a/CxxTestProject/inc/Date.h b/CxxTestProject/inc/Date.h deleted file mode 100644 index e0dd018b..00000000 --- a/CxxTestProject/inc/Date.h +++ /dev/null @@ -1,43 +0,0 @@ - -#pragma once - -#include - -namespace nsdate -{ - struct Date - { - Date(); - Date(Date& pOther); - Date(const std::string& pDateStr); - Date(unsigned dd, unsigned mm, unsigned yy); - - const bool operator==(const Date& pOther) const; - - ~Date(); - - static unsigned instanceCount(); - - std::string getAsString(); - - private: - - unsigned m_day; - unsigned m_month; - unsigned m_year; - static unsigned m_instanceCount; - }; - - - //for testing 'copy constructor found' - struct Calender - { - Calender(); - ~Calender(); - - static unsigned instanceCount(); - - private: - static unsigned m_instanceCount; - }; -} \ No newline at end of file diff --git a/CxxTestProject/src/CMakeLists.txt b/CxxTestProject/src/CMakeLists.txt deleted file mode 100644 index 1d1b6e60..00000000 --- a/CxxTestProject/src/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -# Create a variable containing the source files for your target -set(LOCAL_SOURCES - "${CMAKE_CURRENT_LIST_DIR}/Book.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Complex.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Date.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Person.cpp" -) - -SET(LOCAL_HEADERS - "${PROJECT_SOURCE_DIR}/inc/Book.h" - "${PROJECT_SOURCE_DIR}/inc/Complex.h" - "${PROJECT_SOURCE_DIR}/inc/Date.h" - "${PROJECT_SOURCE_DIR}/inc/Person.h" -) - -# Add any additional source files if needed -target_sources(CxxTestProject - PRIVATE - "${LOCAL_HEADERS}" - "${LOCAL_SOURCES}" -) \ No newline at end of file diff --git a/CxxTestProject/src/Date.cpp b/CxxTestProject/src/Date.cpp deleted file mode 100644 index d7ebe59e..00000000 --- a/CxxTestProject/src/Date.cpp +++ /dev/null @@ -1,93 +0,0 @@ - -#include -#include -#include "Date.h" - -using namespace std; - -static int g_dateObjCount = 0; -static int g_calenderObjCount = 0; - -namespace nsdate -{ - unsigned int Date::m_instanceCount = 0; - unsigned int Calender::m_instanceCount = 0; - - Calender::Calender() - { - m_instanceCount++; - } - - Calender::~Calender() - { - m_instanceCount--; - } - - unsigned Calender::instanceCount() - { - return g_calenderObjCount; - } - - - Date::~Date() { - m_instanceCount--; - } - - unsigned Date::instanceCount() - { - return m_instanceCount; - } - - - std::string Date::getAsString() - { - return (to_string(m_day) + "/" + to_string(m_month) + "/" + to_string(m_year)); - } - - - Date::Date() - : m_day(1) - , m_month(1) - , m_year(2000) { - m_instanceCount++; - } - - Date::Date(Date& pOther) - : m_day(pOther.m_day) - , m_month(pOther.m_month) - , m_year(pOther.m_year) { - m_instanceCount++; - } - - Date::Date(unsigned dd, unsigned mm, unsigned yy) - : m_day(dd) - , m_month(mm) - , m_year(yy) { - m_instanceCount++; - } - - const bool Date::operator==(const Date& pOther) const - { - return (m_day == pOther.m_day && m_month == pOther.m_month && m_year == pOther.m_year); - } - - Date::Date(const string& pDateStr) - { - m_instanceCount++; - string strBuf; - vector date; - for (size_t i = 0; i < pDateStr.length(); i++) - { - if (pDateStr.at(i) == '/') { - date.push_back(strBuf); - strBuf.clear(); - } - else { - strBuf.push_back(pDateStr.at(i)); - } - } - m_day = stoi(date[0]); - m_month = stoi(date[1]); - m_year = stoi(strBuf); - } -} \ No newline at end of file diff --git a/CxxTestProject/CMakeLists.txt b/CxxTestProps/CMakeLists.txt similarity index 80% rename from CxxTestProject/CMakeLists.txt rename to CxxTestProps/CMakeLists.txt index 21ddfcfa..4d9a99a0 100644 --- a/CxxTestProject/CMakeLists.txt +++ b/CxxTestProps/CMakeLists.txt @@ -1,10 +1,10 @@ -# CMakeLists.txt for CxxTestProject +# CMakeLists.txt for CxxTestProps # Set the minimum required CMake version cmake_minimum_required(VERSION 3.20) # Set the project name -project(CxxTestProject) +project(CxxTestProps) set(CMAKE_CXX_STANDARD 20) diff --git a/CxxTestProps/inc/Animal.h b/CxxTestProps/inc/Animal.h new file mode 100644 index 00000000..685509e2 --- /dev/null +++ b/CxxTestProps/inc/Animal.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +class Animal +{ + mutable std::string m_name; + std::string m_familyName; + + static std::string m_zooKeeper; + static unsigned m_instanceCount; + +public: + + Animal(); + ~Animal(); + Animal(const std::string& pFamilyName); + + Animal(Animal&& pOther) noexcept; + + Animal& operator=(Animal&& pOther) noexcept; + + Animal(const Animal& pOther); + + Animal& operator=(const Animal& pOther); + + const bool operator==(const Animal& pOther) const; + + void setFamilyName(const std::string pName); + + std::string getFamilyName() const; + + void setAnimalName(std::string& pName); + + void setAnimalName(std::string&& pName); + + void setAnimalName(const std::string& pName); + + void setAnimalName(const std::string& pName) const; + + static std::string updateZooKeeper(std::string& pZooKeeper); + + static std::string updateZooKeeper(std::string&& pZooKeeper); + + static std::string updateZooKeeper(const std::string& pZooKeeper); + + static unsigned getInstanceCount(); +}; \ No newline at end of file diff --git a/CxxTestProject/inc/Book.h b/CxxTestProps/inc/Book.h similarity index 65% rename from CxxTestProject/inc/Book.h rename to CxxTestProps/inc/Book.h index f743a226..8c8c1ce3 100644 --- a/CxxTestProject/inc/Book.h +++ b/CxxTestProps/inc/Book.h @@ -1,3 +1,4 @@ +#pragma once #include #include "Date.h" @@ -12,35 +13,31 @@ class Book std::string m_author; std::string m_description; - static unsigned m_instanceCount; + static int m_instanceCount; public: Book(); Book(const Book& pOther); + Book(Book&& pOther) noexcept; Book(double pPrice, std::string pTitle); ~Book(); + std::string getTitle() const; std::string getPublishedOn(); - void setAuthor(std::string pAuthor); void setDescription(std::string pDesc); + void addCopyrightTag(const std::string pPubInfo); void updateBookInfo(); void updateBookInfo(const char* pTitle, double pPrice, std::string pAuthor); void updateBookInfo(std::string pAuthor, double pPrice, const char* pTitle); - const bool operator==(const Book& pOther) const; - - static unsigned getInstanceCount(); -}; + void addPreface(const std::string pAcknowledgements, const std::string& pPreface); + Book& operator=(const Book& pOther) = default; + const bool operator==(const Book& pOther) const; -class Library -{ -public: - //for testing 'no constructor found' only. - Library() { } - static void addBook(Book pBook) { } -}; + static int getInstanceCount(); +}; \ No newline at end of file diff --git a/CxxTestProject/inc/Complex.h b/CxxTestProps/inc/Complex.h similarity index 58% rename from CxxTestProject/inc/Complex.h rename to CxxTestProps/inc/Complex.h index d3065400..808a270f 100644 --- a/CxxTestProject/inc/Complex.h +++ b/CxxTestProps/inc/Complex.h @@ -2,14 +2,9 @@ #include +// C-style/free-functions. std::string getComplexNumAsString(); -std::string reverseString(); - -std::string reverseString(std::string pStr); - -std::string reverseString(const char* pStr); - namespace complex { double getMagnitude(); @@ -17,5 +12,4 @@ namespace complex void setReal(double pNum); void setImaginary(double pNum); -} - +} \ No newline at end of file diff --git a/CxxTestProps/inc/Date.h b/CxxTestProps/inc/Date.h new file mode 100644 index 00000000..343bc927 --- /dev/null +++ b/CxxTestProps/inc/Date.h @@ -0,0 +1,105 @@ + +#pragma once + +#include +#include + +namespace nsdate +{ + struct Date + { + Date(); + Date(const Date& pOther); + Date(const std::string& pDateStr); + Date(unsigned dd, unsigned mm, unsigned yy); + Date(Date&&) noexcept; + + Date& operator=(Date&&) = default; + Date& operator=(const Date&) = default; + + const bool operator==(const Date& pOther) const; + + ~Date(); + + static std::size_t instanceCount(); + + std::string getAsString() const; + + void updateDate(std::string pDateStr); + + private: + + unsigned m_day; + unsigned m_month; + unsigned m_year; + static std::size_t m_instanceCount; + }; + + + struct Event; + + struct Calender + { + Calender(); + ~Calender(); + Calender(Calender&&) noexcept; + Calender(const Calender&); + + Calender& operator=(Calender&&) = delete; + Calender& operator=(const Calender&) = delete; + + Date& getTheDate(); + Date& getSavedDate(); + + const Event& getTheEvent(); + const Event& getSavedEvent(); + + static void resetMoveOpsCounter(); + static std::size_t instanceCount(); + static std::size_t getMoveOpsCount(); + + static Calender create(); + + private: + + std::shared_ptr m_theEvent; + + std::unique_ptr m_savedEvent; + + static std::size_t m_instanceCount; + + static std::size_t m_moveOpsCount; + }; + + + struct Event + { + ~Event(); + + Event(Event&&) = delete; + + static std::size_t instanceCount(); + + const Date& getEventDate(); + + void reset(); + + private: + + Event(); + Event(const Event& pOther); + + std::unique_ptr m_date; + + static std::size_t m_instanceCount; + + static Event* create(); + static Event* createCopy(const Event& pOther); + + //friends :) + friend Calender; + + Event& operator=(Event&&) = delete; + Event& operator=(const Event&) = delete; + }; +} diff --git a/CxxTestProps/inc/Library.h b/CxxTestProps/inc/Library.h new file mode 100644 index 00000000..4e4e71dc --- /dev/null +++ b/CxxTestProps/inc/Library.h @@ -0,0 +1,25 @@ + +#pragma once +#include + +class Book; + +class Library +{ + static std::unordered_map m_booksByTitle; + +public: + + Library(); + ~Library(); + + Library(const Library&) = delete; + + static int getBooksCount(); + + static std::size_t getInstanceCount(); + + static void addBook(const Book& pBook); + + static Book getBookByTitle(const std::string& pTitle); +}; \ No newline at end of file diff --git a/CxxTestProject/inc/Person.h b/CxxTestProps/inc/Person.h similarity index 80% rename from CxxTestProject/inc/Person.h rename to CxxTestProps/inc/Person.h index b429b6d1..a534b5f8 100644 --- a/CxxTestProject/inc/Person.h +++ b/CxxTestProps/inc/Person.h @@ -10,19 +10,17 @@ class Person public: - ~Person(); Person(); - Person(const std::string& pName); - - Person(Person& pOther); - + ~Person(); + Person(Person&&) noexcept; Person(const Person& pOther); + Person(const std::string& pName); void updateAddress(); void updateAddress() const; - std::string getFirstName() const; + std::string getFirstName(); void updateAddress(std::string pAddress); @@ -40,5 +38,11 @@ class Person static std::string getProfile(std::string pOccupation, std::size_t pAge); + static const Person createConst(); + + static const Person* createPtr(); + + static void deletePtr(const Person* ptr); + static unsigned getInstanceCount(); }; \ No newline at end of file diff --git a/CxxTestProps/inc/StringConst.h b/CxxTestProps/inc/StringConst.h new file mode 100644 index 00000000..ab038ede --- /dev/null +++ b/CxxTestProps/inc/StringConst.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +// 'StrConst' - String-Const, all methods are const. +struct StrConst +{ + constexpr static const char* struct_ = "StrConst"; + + std::string reverseString() const; + + std::string reverseString(const char* pStr) const; + + std::string reverseString(std::string pStr) const; // (1) by value + + std::string reverseString(std::string& pStr) const; // (2) lvalue ref + + std::string reverseString(const std::string& pStr) const; // (3) const lvalue ref + + std::string reverseString(std::string&& pStr) const; // (4) rvalue ref + + std::string reverseString(std::string* pStr) const; // (5) pointer + + std::string reverseString(const std::string* pStr) const; // (6) pointer to const + + std::string revStrConstRefArg(const std::string_view& pStr) const; + + std::string revStrNonConstRefArg(std::string_view& pStr) const; + + std::string revStrRValueRefArg(std::string_view&& pStr) const; + + std::string revStrOverloadValRef(std::string_view pStr) const; + + std::string revStrOverloadValRef(std::string_view& pStr) const; + + std::string revStrOverloadValCRef(std::string_view pStr) const; + + std::string revStrOverloadValCRef(const std::string_view& pStr) const; + + std::string revStrOverloadRefAndCRef(std::string_view& pStr) const; + + std::string revStrOverloadRefAndCRef(const std::string_view& pStr) const; +}; \ No newline at end of file diff --git a/CxxTestProps/inc/StringConstOverload.h b/CxxTestProps/inc/StringConstOverload.h new file mode 100644 index 00000000..fdb844f8 --- /dev/null +++ b/CxxTestProps/inc/StringConstOverload.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct StrConstOverload +{ + constexpr static const char* struct_ = "StrConstOverload"; + + std::string reverseString(); + + std::string reverseString() const; +}; \ No newline at end of file diff --git a/CxxTestProps/inc/StringMute.h b/CxxTestProps/inc/StringMute.h new file mode 100644 index 00000000..4b71c00d --- /dev/null +++ b/CxxTestProps/inc/StringMute.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +// 'StrMute' - String-Mutable, all methods are non-const. +struct StrMute +{ + constexpr static const char* struct_ = "StrMute"; + + std::string reverseString(); + + std::string reverseString(const char* pStr); + + std::string reverseString(std::string pStr); // (1) by value + + std::string reverseString(std::string& pStr); // (2) lvalue ref + + std::string reverseString(const std::string& pStr); // (3) const lvalue ref + + std::string reverseString(std::string&& pStr); // (4) rvalue ref + + std::string reverseString(std::string* pStr); // (5) pointer + + std::string reverseString(const std::string* pStr); // (6) pointer to const + + std::string revStrConstRefArg(const std::string_view& pStr); + + std::string revStrNonConstRefArg(std::string_view& pStr); + + std::string revStrRValueRefArg(std::string_view&& pStr); + + std::string revStrOverloadValRef(std::string_view pStr); + + std::string revStrOverloadValRef(std::string_view& pStr); + + std::string revStrOverloadValCRef(std::string_view pStr); + + std::string revStrOverloadValCRef(const std::string_view& pStr); + + std::string revStrOverloadRefAndCRef(std::string_view& pStr); + + std::string revStrOverloadRefAndCRef(const std::string_view& pStr); +}; \ No newline at end of file diff --git a/CxxTestProps/inc/StringOps.h b/CxxTestProps/inc/StringOps.h new file mode 100644 index 00000000..c45c85da --- /dev/null +++ b/CxxTestProps/inc/StringOps.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +std::string reverseString(); + +std::string reverseString(const char* pStr); + +std::string reverseString(std::string pStr); // (1) by value + +std::string reverseString(std::string& pStr); // (2) lvalue ref + +std::string reverseString(const std::string& pStr); // (3) const lvalue ref + +std::string reverseString(std::string&& pStr); // (4) rvalue ref + +std::string reverseString(std::string* pStr); // (5) pointer + +std::string reverseString(const std::string* pStr); // (6) pointer to const + +std::string revStrConstRefArg(const std::string_view& pStr); + +std::string revStrNonConstRefArg(std::string_view& pStr); + +std::string revStrRValueRefArg(std::string_view&& pStr); + +std::string revStrOverloadValRef(std::string_view pStr); + +std::string revStrOverloadValRef(std::string_view& pStr); + +std::string revStrOverloadValCRef(std::string_view pStr); + +std::string revStrOverloadValCRef(const std::string_view& pStr); + +std::string revStrOverloadRefAndCRef(std::string_view& pStr); + +std::string revStrOverloadRefAndCRef(const std::string_view& pStr); \ No newline at end of file diff --git a/CxxTestProps/inc/StringStatic.h b/CxxTestProps/inc/StringStatic.h new file mode 100644 index 00000000..88bfece5 --- /dev/null +++ b/CxxTestProps/inc/StringStatic.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +// 'StrStatic' - String-Static, all methods are static. +struct StrStatic +{ + constexpr static const char* struct_ = "StrStatic"; + + static std::string reverseString(); + + static std::string reverseString(const char* pStr); + + static std::string reverseString(std::string pStr); // (1) by value + + static std::string reverseString(std::string& pStr); // (2) lvalue ref + + static std::string reverseString(const std::string& pStr); // (3) const lvalue ref + + static std::string reverseString(std::string&& pStr); // (4) rvalue ref + + static std::string reverseString(std::string* pStr); // (5) pointer + + static std::string reverseString(const std::string* pStr); // (6) pointer to const + + static std::string revStrConstRefArg(const std::string_view& pStr); + + static std::string revStrNonConstRefArg(std::string_view& pStr); + + static std::string revStrRValueRefArg(std::string_view&& pStr); + + static std::string revStrOverloadValRef(std::string_view pStr); + + static std::string revStrOverloadValRef(std::string_view& pStr); + + static std::string revStrOverloadValCRef(std::string_view pStr); + + static std::string revStrOverloadValCRef(const std::string_view& pStr); + + static std::string revStrOverloadRefAndCRef(std::string_view& pStr); + + static std::string revStrOverloadRefAndCRef(const std::string_view& pStr); +}; \ No newline at end of file diff --git a/CxxTestProps/inc/StringWrap.h b/CxxTestProps/inc/StringWrap.h new file mode 100644 index 00000000..443295c6 --- /dev/null +++ b/CxxTestProps/inc/StringWrap.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +struct StrWrap +{ + const std::string m_str; + const std::string& sstr() const; + + StrWrap(const std::string& pStr); +}; + +// 'StrWrapA' - String-Wrapper, only constructors for testing. +struct StrWrapA : public StrWrap +{ + constexpr static const char* struct_ = "StrWrapA"; + + StrWrapA(); + + StrWrapA(std::string_view pStr); // (1) by value + + StrWrapA(std::string& pStr); // (2) lvalue ref + + StrWrapA(const std::string& pStr); // (3) const lvalue ref + + StrWrapA(std::string&& pStr); // (4) rvalue ref + + StrWrapA(const char* pStr); // (5) pointer +}; + + +// 'StrWrapB' - String-Wrapper, only constructors for testing. +struct StrWrapB : public StrWrap +{ + constexpr static const char* struct_ = "StrWrapB"; + StrWrapB(std::string& pStr); + StrWrapB(const std::string& pStr); +}; + + +// 'StrWrapC' - String-Wrapper, only constructors for testing. +struct StrWrapC : public StrWrap +{ + constexpr static const char* struct_ = "StrWrapC"; + StrWrapC(std::string& pStr); +}; + + +// 'StrWrapD' - String-Wrapper, only constructors for testing. +struct StrWrapD : public StrWrap +{ + constexpr static const char* struct_ = "StrWrapD"; + StrWrapD(const std::string& pStr); +}; \ No newline at end of file diff --git a/CxxTestProps/src/Animal.cpp b/CxxTestProps/src/Animal.cpp new file mode 100644 index 00000000..2456338c --- /dev/null +++ b/CxxTestProps/src/Animal.cpp @@ -0,0 +1,145 @@ + +#include "Animal.h" + +unsigned Animal::m_instanceCount = 0; +std::string Animal::m_zooKeeper = "__no_zookeeper.."; + + +Animal::Animal() + : m_name("__no_name..") + , m_familyName("__no_family_ :( ") +{ + m_instanceCount++; +} + + +Animal::~Animal() +{ + m_instanceCount--; +} + + +Animal::Animal(const std::string& pFamilyName) + : m_name("__no_name..") + , m_familyName(pFamilyName) +{ + m_instanceCount++; +} + + +Animal::Animal(const Animal& pOther) + : m_name(pOther.m_name) + , m_familyName(pOther.m_familyName) +{ + m_instanceCount++; +} + + +Animal& Animal::operator=(const Animal& pOther) +{ + if (this == &pOther) + return *this; + m_name = pOther.m_name; + m_familyName = pOther.m_familyName; + return *this; +} + + +Animal::Animal(Animal&& pOther) noexcept + : m_name(pOther.m_name) + , m_familyName(pOther.m_familyName) +{ + m_instanceCount++; + pOther.m_name.clear(); + pOther.m_familyName.clear(); +} + + +Animal& Animal::operator=(Animal&& pOther) noexcept +{ + if (this == &pOther) + return *this; + + m_name = pOther.m_name + "__move_assignment"; + m_familyName = pOther.m_familyName + "__move_assignment"; + + pOther.m_name.clear(); + pOther.m_familyName.clear(); + return *this; +} + + +void Animal::setAnimalName(std::string& pName) +{ + m_name = pName + "__args_non_const_lvalue_ref..."; +} + + +void Animal::setFamilyName(const std::string pName) +{ + m_familyName = pName; +} + + +std::string Animal::getFamilyName() const +{ + return m_familyName; +} + + +void Animal::setAnimalName(std::string&& pName) +{ + m_name = pName + "__args_rvalue_ref..."; +} + + +unsigned Animal::getInstanceCount() +{ + return m_instanceCount; +} + + +void Animal::setAnimalName(const std::string& pName) +{ + m_name = pName + "__args_const_lvalue_ref..."; +} + + +void Animal::setAnimalName(const std::string& pName) const +{ + m_name = pName + "__args_const_lvalue_ref_method_const..."; +} + + +std::string Animal::updateZooKeeper(std::string& pZooKeeper) +{ + m_zooKeeper = pZooKeeper + "__args_non_const_lvalue_ref..."; + return m_zooKeeper; +} + + +std::string Animal::updateZooKeeper(std::string&& pZooKeeper) +{ + m_zooKeeper = pZooKeeper + "__args_rvalue_ref..."; + return m_zooKeeper; +} + + +std::string Animal::updateZooKeeper(const std::string& pZooKeeper) +{ + m_zooKeeper = pZooKeeper + "__args_const_lvalue_ref..."; + return m_zooKeeper; +} + + +const bool Animal::operator==(const Animal& pOther) const +{ + if (this == &pOther) + return true; + + if (m_name != pOther.m_name || m_familyName != pOther.m_familyName) { + return false; + } + + return true; +} \ No newline at end of file diff --git a/CxxTestProject/src/Book.cpp b/CxxTestProps/src/Book.cpp similarity index 67% rename from CxxTestProject/src/Book.cpp rename to CxxTestProps/src/Book.cpp index ff2998d4..e9a0b4e9 100644 --- a/CxxTestProject/src/Book.cpp +++ b/CxxTestProps/src/Book.cpp @@ -1,10 +1,9 @@ #include "Book.h" -using namespace std; using namespace nsdate; -unsigned Book::m_instanceCount = 0; +int Book::m_instanceCount = 0; Book::~Book() { m_instanceCount--; @@ -28,8 +27,17 @@ Book::Book(const Book& pOther) m_instanceCount++; } +Book::Book(Book&& pOther) noexcept + : m_price(pOther.m_price) + , m_title(pOther.m_title) + , m_date(pOther.m_date) + , m_author(pOther.m_author) + , m_description(pOther.m_description) { + m_instanceCount++; +} + -Book::Book(double pPrice, string pTitle) +Book::Book(double pPrice, std::string pTitle) : m_price(pPrice) , m_title(pTitle) , m_author("no_author_ctor_double_string") @@ -39,7 +47,7 @@ Book::Book(double pPrice, string pTitle) } -void Book::setAuthor(string pAuthor) { +void Book::setAuthor(std::string pAuthor) { m_author = pAuthor; } @@ -49,6 +57,11 @@ void Book::setDescription(std::string pDesc) m_description = pDesc; } +void Book::addCopyrightTag(const std::string pPubInfo) +{ + m_description += pPubInfo; +} + const bool Book::operator==(const Book& pOther) const { return (m_price == pOther.m_price && m_author == pOther.m_author && m_date == pOther.m_date && @@ -56,13 +69,18 @@ const bool Book::operator==(const Book& pOther) const { } -string Book::getPublishedOn() { +std::string Book::getTitle() const +{ + return m_title; +} + +std::string Book::getPublishedOn() { return m_date.getAsString(); } -unsigned Book::getInstanceCount() { +int Book::getInstanceCount() { return m_instanceCount; } @@ -79,7 +97,7 @@ void Book::updateBookInfo(const char* pTitle, double pPrice, std::string pAuthor { m_price = pPrice; m_date = nsdate::Date(9, 10, 2020); - m_title = string(pTitle) + "[Discontinued]"; + m_title = std::string(pTitle) + "[Discontinued]"; m_author = pAuthor + " (Retired)"; } @@ -88,6 +106,11 @@ void Book::updateBookInfo(std::string pAuthor, double pPrice, const char* pTitle { m_price = pPrice; m_date = nsdate::Date(6, 12, 1999); - m_title = string(pTitle) + "[BestSeller]"; + m_title = std::string(pTitle) + "[BestSeller]"; m_author = pAuthor + " (Independent)"; -} \ No newline at end of file +} + +void Book::addPreface(const std::string pAcknowledgements, const std::string& pPreface) +{ + m_description += pPreface + " " + pAcknowledgements; +} diff --git a/CxxTestProps/src/CMakeLists.txt b/CxxTestProps/src/CMakeLists.txt new file mode 100644 index 00000000..d8bb7ff8 --- /dev/null +++ b/CxxTestProps/src/CMakeLists.txt @@ -0,0 +1,37 @@ +# Create a variable containing the source files for your target +set(LOCAL_SOURCES + "${CMAKE_CURRENT_LIST_DIR}/Book.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Date.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Person.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Animal.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Library.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Complex.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StringOps.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StringWrap.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StringMute.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StringConst.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StringStatic.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StringConstOverload.cpp" +) + +SET(LOCAL_HEADERS + "${PROJECT_SOURCE_DIR}/inc/Book.h" + "${PROJECT_SOURCE_DIR}/inc/Date.h" + "${PROJECT_SOURCE_DIR}/inc/Animal.h" + "${PROJECT_SOURCE_DIR}/inc/Person.h" + "${PROJECT_SOURCE_DIR}/inc/Library.h" + "${PROJECT_SOURCE_DIR}/inc/Complex.h" + "${PROJECT_SOURCE_DIR}/inc/StringOps.h" + "${PROJECT_SOURCE_DIR}/inc/StringWrap.h" + "${PROJECT_SOURCE_DIR}/inc/StringMute.h" + "${PROJECT_SOURCE_DIR}/inc/StringConst.h" + "${PROJECT_SOURCE_DIR}/inc/StringStatic.h" + "${PROJECT_SOURCE_DIR}/inc/StringConstOverload.h" +) + +# Add any additional source files if needed +target_sources(CxxTestProps + PRIVATE + "${LOCAL_HEADERS}" + "${LOCAL_SOURCES}" +) \ No newline at end of file diff --git a/CxxTestProject/src/Complex.cpp b/CxxTestProps/src/Complex.cpp similarity index 51% rename from CxxTestProject/src/Complex.cpp rename to CxxTestProps/src/Complex.cpp index 1f337752..d70b4ad3 100644 --- a/CxxTestProject/src/Complex.cpp +++ b/CxxTestProps/src/Complex.cpp @@ -3,33 +3,6 @@ #include "Complex.h" -namespace test_utils { - - const char* REV_STR_VOID_RET = "func_reverseString(void)->[return_str]"; -} - -std::string reverseString() -{ - return test_utils::REV_STR_VOID_RET; -} - - -std::string reverseString(std::string pStr) -{ - std::string retStr = pStr; - std::reverse(retStr.begin(), retStr.end()); - return retStr; -} - - -std::string reverseString(const char* pStr) -{ - std::string retStr = pStr; - std::reverse(retStr.begin(), retStr.end()); - return retStr; -} - - namespace complex { static double g_imgNumber; @@ -50,7 +23,6 @@ namespace complex } } - std::string getComplexNumAsString() { return std::to_string(complex::g_realNumber) + "i" + (std::to_string(complex::g_imgNumber)); diff --git a/CxxTestProps/src/Complex.h b/CxxTestProps/src/Complex.h new file mode 100644 index 00000000..e69de29b diff --git a/CxxTestProps/src/Date.cpp b/CxxTestProps/src/Date.cpp new file mode 100644 index 00000000..a3b76538 --- /dev/null +++ b/CxxTestProps/src/Date.cpp @@ -0,0 +1,223 @@ +#include "Date.h" + +#include +#include "Date.h" + +using namespace std; + +namespace nsdate +{ + std::size_t Date::m_instanceCount = 0; + std::size_t Event::m_instanceCount = 0; + std::size_t Calender::m_instanceCount = 0; + std::size_t Calender::m_moveOpsCount = 0; + + Calender::~Calender() + { + m_instanceCount--; + } + + Calender::Calender() + : m_theEvent(std::shared_ptr(Event::create())) + , m_savedEvent(std::unique_ptr(Event::create())) + { + m_instanceCount++; + } + + Calender::Calender(const Calender& pOther) + : m_theEvent(pOther.m_theEvent) + , m_savedEvent(pOther.m_savedEvent ? std::unique_ptr(Event::createCopy(*pOther.m_savedEvent)) : nullptr) + { + m_instanceCount++; + } + + Calender::Calender(Calender&& pOther) noexcept + : m_theEvent(std::move(pOther.m_theEvent)) + , m_savedEvent(std::move(pOther.m_savedEvent)) + { + m_moveOpsCount++; + m_instanceCount++; + } + + Calender Calender::create() + { + return Calender(); + } + + const Event& Calender::getTheEvent() + { + return *m_theEvent; + } + + const Event& Calender::getSavedEvent() + { + return *m_savedEvent; + } + + Date& Calender::getTheDate() + { + return *(m_theEvent->m_date); + } + + Date& Calender::getSavedDate() + { + return *(m_savedEvent->m_date); + } + + std::size_t Calender::instanceCount() + { + return m_instanceCount; + } + + std::size_t Calender::getMoveOpsCount() + { + return m_moveOpsCount; + } + + void Calender::resetMoveOpsCounter() + { + m_moveOpsCount = 0; + } +} + +namespace nsdate +{ + Event::~Event() + { + m_instanceCount--; + } + + Event::Event() + : m_date(std::make_unique()) + { + m_instanceCount++; + } + + Event::Event(const Event& pOther) + : m_date(pOther.m_date ? std::make_unique(*pOther.m_date) : nullptr) + { + m_instanceCount++; + } + + const Date& Event::getEventDate() + { + return *m_date; + } + + + void Event::reset() + { + //does nothing yet. + } + + + std::size_t Event::instanceCount() + { + return m_instanceCount; + } + + Event* Event::create() + { + return new Event(); + } + + Event* Event::createCopy(const Event& pOther) + { + return new Event(pOther); + } +} + + +namespace nsdate +{ + Date::~Date() { + m_instanceCount--; + } + + std::size_t Date::instanceCount() + { + return m_instanceCount; + } + + std::string Date::getAsString() const + { + return (to_string(m_day) + "/" + to_string(m_month) + "/" + to_string(m_year)); + } + + + void Date::updateDate(std::string pDateStr) + { + string strBuf; + vector date; + for (size_t i = 0; i < pDateStr.length(); i++) + { + if (pDateStr[i] == '/') { + date.push_back(strBuf); + strBuf.clear(); + } + else { + strBuf.push_back(pDateStr[i]); + } + } + m_day = stoi(date[0]); + m_month = stoi(date[1]); + m_year = stoi(strBuf); + } + + Date::Date() + : m_day(1) + , m_month(1) + , m_year(2000) + { + m_instanceCount++; + } + + Date::Date(const Date& pOther) + : m_day(pOther.m_day) + , m_month(pOther.m_month) + , m_year(pOther.m_year) + { + m_instanceCount++; + } + + Date::Date(unsigned dd, unsigned mm, unsigned yy) + : m_day(dd) + , m_month(mm) + , m_year(yy) + { + m_instanceCount++; + } + + Date::Date(Date&& pOther) noexcept + : m_day(pOther.m_day) + , m_month(pOther.m_month) + , m_year(pOther.m_year) + { + m_instanceCount++; + } + + const bool Date::operator==(const Date& pOther) const + { + return (m_day == pOther.m_day && m_month == pOther.m_month && m_year == pOther.m_year); + } + + Date::Date(const string& pDateStr) + { + m_instanceCount++; + string strBuf; + vector date; + for (size_t i = 0; i < pDateStr.length(); i++) + { + if (pDateStr[i] == '/') { + date.push_back(strBuf); + strBuf.clear(); + } + else { + strBuf.push_back(pDateStr[i]); + } + } + m_day = stoi(date[0]); + m_month = stoi(date[1]); + m_year = stoi(strBuf); + } +} \ No newline at end of file diff --git a/CxxTestProps/src/Library.cpp b/CxxTestProps/src/Library.cpp new file mode 100644 index 00000000..a7d117d8 --- /dev/null +++ b/CxxTestProps/src/Library.cpp @@ -0,0 +1,37 @@ + +#include "Book.h" +#include "Library.h" + +std::size_t g_instanceCount = 0; + +std::unordered_map Library::m_booksByTitle; + +Library::Library() +{ + g_instanceCount++; +} + +Library::~Library() +{ + g_instanceCount--; +} + +std::size_t Library::getInstanceCount() +{ + return g_instanceCount; +} + +int Library::getBooksCount() +{ + return m_booksByTitle.size(); +} + +void Library::addBook(const Book& pBook) +{ + m_booksByTitle[pBook.getTitle()] = pBook; +} + +Book Library::getBookByTitle(const std::string& pTitle) +{ + return m_booksByTitle[pTitle]; +} \ No newline at end of file diff --git a/CxxTestProject/src/Person.cpp b/CxxTestProps/src/Person.cpp similarity index 86% rename from CxxTestProject/src/Person.cpp rename to CxxTestProps/src/Person.cpp index ab5ebefd..e074471d 100644 --- a/CxxTestProject/src/Person.cpp +++ b/CxxTestProps/src/Person.cpp @@ -1,5 +1,7 @@ + #include #include + #include "Person.h" static long g_instanceCount = 0; @@ -12,6 +14,16 @@ Person::~Person() } } +Person::Person(Person&& pOther) noexcept + : m_address(pOther.m_address) + , m_lastName(pOther.m_lastName) + , m_firstName(pOther.m_firstName) +{ + g_instanceCount++; + pOther.m_address.clear(); + pOther.m_lastName.clear(); +} + Person::Person() : m_address("182 st. Westoros, Dune.") , m_lastName("Doe") @@ -28,13 +40,6 @@ Person::Person(const std::string& pName) g_instanceCount++; } -Person::Person(Person& pOther) - : m_address(pOther.m_address + ".__Person::Person(Person&)") - , m_lastName(pOther.m_lastName + ".__Person::Person(Person&)") - , m_firstName(pOther.m_firstName + ".__Person::Person(Person&)") -{ - g_instanceCount++; -} Person::Person(const Person& pOther) : m_address(pOther.m_address + ".__Person::Person(const Person&)") @@ -62,7 +67,7 @@ void Person::updateAddress() const } -std::string Person::getFirstName() const +std::string Person::getFirstName() { return m_firstName; } @@ -95,6 +100,21 @@ std::string Person::getProfile(std::string pOccupation, std::size_t pAge) "\nAge: " + std::to_string(pAge) + "\n[__Person::getProfile(string, size_t)]"); } +const Person Person::createConst() +{ + return Person(); +} + +const Person* Person::createPtr() +{ + return new Person(); +} + +void Person::deletePtr(const Person* ptr) +{ + delete ptr; +} + std::string Person::getProfile(bool pNoAddress) { diff --git a/CxxTestProps/src/StringConst.cpp b/CxxTestProps/src/StringConst.cpp new file mode 100644 index 00000000..666a1475 --- /dev/null +++ b/CxxTestProps/src/StringConst.cpp @@ -0,0 +1,142 @@ + +#include + +#include "StringConst.h" +#include "../../CxxTestUtils/inc/GlobalTestUtils.h" + +using namespace test_utils; + +//---------------------------StrConst-------------------------------- + +std::string StrConst::reverseString() const +{ + return std::string(struct_) + REV_STR_VOID_RET + SUFFIX_void + SUFFIX_const; +} + + +std::string StrConst::reverseString(const char* pStr) const +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_const_char_ptr + SUFFIX_const; +} + + +std::string StrConst::reverseString(std::string pStr) const +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string + SUFFIX_const; +} + + +std::string StrConst::reverseString(std::string& pStr) const +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_lvref + SUFFIX_const; +} + + +std::string StrConst::reverseString(std::string&& pStr) const +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_rvref + SUFFIX_const; +} + + +std::string StrConst::reverseString(const std::string& pStr) const +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_clvref + SUFFIX_const; +} + + +std::string StrConst::reverseString(std::string* pStr) const +{ + std::string retStr = *pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_ptr + SUFFIX_const; +} + + +std::string StrConst::reverseString(const std::string* pStr) const +{ + std::string retStr = *pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_cptr + SUFFIX_const; +} + + +std::string StrConst::revStrConstRefArg(const std::string_view& pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref + SUFFIX_const; +} + + +std::string StrConst::revStrRValueRefArg(std::string_view&& pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_rvref + SUFFIX_const; +} + + +std::string StrConst::revStrNonConstRefArg(std::string_view& pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref + SUFFIX_const; +} + + +std::string StrConst::revStrOverloadValCRef(std::string_view pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view + SUFFIX_const; +} + + +std::string StrConst::revStrOverloadValCRef(const std::string_view& pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref + SUFFIX_const; +} + + +std::string StrConst::revStrOverloadValRef(std::string_view pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view + SUFFIX_const; +} + + +std::string StrConst::revStrOverloadValRef(std::string_view& pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref + SUFFIX_const; +} + + +std::string StrConst::revStrOverloadRefAndCRef(std::string_view& pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref + SUFFIX_const; +} + + +std::string StrConst::revStrOverloadRefAndCRef(const std::string_view& pStr) const +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref + SUFFIX_const; +} \ No newline at end of file diff --git a/CxxTestProps/src/StringConstOverload.cpp b/CxxTestProps/src/StringConstOverload.cpp new file mode 100644 index 00000000..75c75b63 --- /dev/null +++ b/CxxTestProps/src/StringConstOverload.cpp @@ -0,0 +1,20 @@ + +#include + +#include "StringConstOverload.h" +#include "../../CxxTestUtils/inc/GlobalTestUtils.h" + +using namespace test_utils; + +//---------------------------StrConstOverload-------------------------------- + +std::string StrConstOverload::reverseString() +{ + return std::string(struct_) + REV_STR_VOID_RET + SUFFIX_void; +} + + +std::string StrConstOverload::reverseString() const +{ + return std::string(struct_) + REV_STR_VOID_RET + SUFFIX_void + SUFFIX_const; +} \ No newline at end of file diff --git a/CxxTestProps/src/StringMute.cpp b/CxxTestProps/src/StringMute.cpp new file mode 100644 index 00000000..21d54fbd --- /dev/null +++ b/CxxTestProps/src/StringMute.cpp @@ -0,0 +1,142 @@ + +#include + +#include "StringMute.h" +#include "../../CxxTestUtils/inc/GlobalTestUtils.h" + +using namespace test_utils; + +//---------------------------StrMute-------------------------------- + +std::string StrMute::reverseString() +{ + return std::string(struct_) + REV_STR_VOID_RET + SUFFIX_void; +} + + +std::string StrMute::reverseString(const char* pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_const_char_ptr; +} + + +std::string StrMute::reverseString(std::string pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string; +} + + +std::string StrMute::reverseString(std::string& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_lvref; +} + + +std::string StrMute::reverseString(std::string&& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_rvref; +} + + +std::string StrMute::reverseString(const std::string& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_clvref; +} + + +std::string StrMute::reverseString(std::string* pStr) +{ + std::string retStr = *pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_ptr; +} + + +std::string StrMute::reverseString(const std::string* pStr) +{ + std::string retStr = *pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_cptr; +} + + +std::string StrMute::revStrConstRefArg(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref; +} + + +std::string StrMute::revStrRValueRefArg(std::string_view&& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_rvref; +} + + +std::string StrMute::revStrNonConstRefArg(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref; +} + + +std::string StrMute::revStrOverloadValCRef(std::string_view pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view; +} + + +std::string StrMute::revStrOverloadValCRef(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref; +} + + +std::string StrMute::revStrOverloadValRef(std::string_view pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view; +} + + +std::string StrMute::revStrOverloadValRef(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref; +} + + +std::string StrMute::revStrOverloadRefAndCRef(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref; +} + + +std::string StrMute::revStrOverloadRefAndCRef(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref; +} \ No newline at end of file diff --git a/CxxTestProps/src/StringOps.cpp b/CxxTestProps/src/StringOps.cpp new file mode 100644 index 00000000..3bafb6f4 --- /dev/null +++ b/CxxTestProps/src/StringOps.cpp @@ -0,0 +1,140 @@ + +#include + +#include "StringOps.h" +#include "../../CxxTestUtils/inc/GlobalTestUtils.h" + +using namespace test_utils; + +std::string reverseString() +{ + return std::string(REV_STR_VOID_RET) + SUFFIX_void; +} + + +std::string reverseString(const char* pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_const_char_ptr; +} + + +std::string reverseString(std::string pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string; +} + + +std::string reverseString(std::string& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_lvref; +} + + +std::string reverseString(std::string&& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_rvref; +} + + +std::string reverseString(const std::string& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_clvref; +} + + +std::string reverseString(std::string* pStr) +{ + std::string retStr = *pStr; + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_ptr; +} + + +std::string reverseString(const std::string* pStr) +{ + std::string retStr = *pStr; + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_cptr; +} + + +std::string revStrConstRefArg(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view_clvref; +} + + +std::string revStrRValueRefArg(std::string_view&& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view_rvref; +} + + +std::string revStrNonConstRefArg(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view_lvref; +} + + +std::string revStrOverloadValCRef(std::string_view pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view; +} + + +std::string revStrOverloadValCRef(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view_clvref; +} + + +std::string revStrOverloadValRef(std::string_view pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view; +} + + +std::string revStrOverloadValRef(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view_lvref; +} + + +std::string revStrOverloadRefAndCRef(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view_lvref; +} + + +std::string revStrOverloadRefAndCRef(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return retStr + SUFFIX_std_string_view_clvref; +} \ No newline at end of file diff --git a/CxxTestProps/src/StringStatic.cpp b/CxxTestProps/src/StringStatic.cpp new file mode 100644 index 00000000..8aa092af --- /dev/null +++ b/CxxTestProps/src/StringStatic.cpp @@ -0,0 +1,142 @@ + +#include + +#include "StringStatic.h" +#include "../../CxxTestUtils/inc/GlobalTestUtils.h" + +using namespace test_utils; + +//---------------------------StrStatic-------------------------------- + +std::string StrStatic::reverseString() +{ + return std::string(struct_) + (REV_STR_VOID_RET) + SUFFIX_void + SUFFIX_static; +} + + +std::string StrStatic::reverseString(const char* pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_const_char_ptr + SUFFIX_static; +} + + +std::string StrStatic::reverseString(std::string pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string + SUFFIX_static; +} + + +std::string StrStatic::reverseString(std::string& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_lvref + SUFFIX_static; +} + + +std::string StrStatic::reverseString(std::string&& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_rvref + SUFFIX_static; +} + + +std::string StrStatic::reverseString(const std::string& pStr) +{ + std::string retStr = pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_clvref + SUFFIX_static; +} + + +std::string StrStatic::reverseString(std::string* pStr) +{ + std::string retStr = *pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_ptr + SUFFIX_static; +} + + +std::string StrStatic::reverseString(const std::string* pStr) +{ + std::string retStr = *pStr; + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_cptr + SUFFIX_static; +} + + +std::string StrStatic::revStrConstRefArg(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref + SUFFIX_static; +} + + +std::string StrStatic::revStrRValueRefArg(std::string_view&& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_rvref + SUFFIX_static; +} + + +std::string StrStatic::revStrNonConstRefArg(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref + SUFFIX_static; +} + + +std::string StrStatic::revStrOverloadValCRef(std::string_view pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view + SUFFIX_static; +} + + +std::string StrStatic::revStrOverloadValCRef(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref + SUFFIX_static; +} + + +std::string StrStatic::revStrOverloadValRef(std::string_view pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view + SUFFIX_static; +} + + +std::string StrStatic::revStrOverloadValRef(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref + SUFFIX_static; +} + + +std::string StrStatic::revStrOverloadRefAndCRef(std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_lvref + SUFFIX_static; +} + + +std::string StrStatic::revStrOverloadRefAndCRef(const std::string_view& pStr) +{ + std::string retStr(pStr); + std::reverse(retStr.begin(), retStr.end()); + return std::string(struct_) + retStr + SUFFIX_std_string_view_clvref + SUFFIX_static; +} \ No newline at end of file diff --git a/CxxTestProps/src/StringWrap.cpp b/CxxTestProps/src/StringWrap.cpp new file mode 100644 index 00000000..a295235a --- /dev/null +++ b/CxxTestProps/src/StringWrap.cpp @@ -0,0 +1,53 @@ + +#include "StringWrap.h" +#include "../../CxxTestUtils/inc/GlobalTestUtils.h" + +using namespace test_utils; + +const std::string& StrWrap::sstr() const { + return m_str; +} + +StrWrap::StrWrap(const std::string& pStr) + :m_str(pStr) +{ } + +StrWrapA::StrWrapA() + :StrWrap(std::string(struct_) + SUFFIX_ctor) +{ } + +StrWrapA::StrWrapA(std::string_view pStr) + :StrWrap(std::string(struct_) + std::string(pStr) + SUFFIX_std_string_view + SUFFIX_ctor) +{ } + +StrWrapA::StrWrapA(std::string& pStr) + :StrWrap(std::string(struct_) + pStr + SUFFIX_std_string_lvref + SUFFIX_ctor) +{ } + +StrWrapA::StrWrapA(const std::string& pStr) + :StrWrap(std::string(struct_) + pStr + SUFFIX_std_string_clvref + SUFFIX_ctor) +{ } + +StrWrapA::StrWrapA(std::string&& pStr) + :StrWrap(std::string(struct_) + pStr + SUFFIX_std_string_rvref + SUFFIX_ctor) +{ } + +StrWrapA::StrWrapA(const char* pStr) + :StrWrap(std::string(struct_) + std::string(pStr) + SUFFIX_const_char_ptr + SUFFIX_ctor) +{ } + +StrWrapB::StrWrapB(const std::string& pStr) + :StrWrap(std::string(struct_) + pStr + SUFFIX_std_string_clvref + SUFFIX_ctor) +{ } + +StrWrapB::StrWrapB(std::string& pStr) + :StrWrap(std::string(struct_) + pStr + SUFFIX_std_string_lvref + SUFFIX_ctor) +{ } + +StrWrapC::StrWrapC(std::string& pStr) + :StrWrap(std::string(struct_) + pStr + SUFFIX_std_string_lvref + SUFFIX_ctor) +{ } + +StrWrapD::StrWrapD(const std::string& pStr) + :StrWrap(std::string(struct_) + pStr + SUFFIX_std_string_clvref + SUFFIX_ctor) +{ } \ No newline at end of file diff --git a/CxxTestRegistration/CMakeLists.txt b/CxxTestRegistration/CMakeLists.txt new file mode 100644 index 00000000..433c7c8f --- /dev/null +++ b/CxxTestRegistration/CMakeLists.txt @@ -0,0 +1,24 @@ +# CMakeLists.txt for ReflectionTypeRegistration + +# Set the minimum required CMake version +cmake_minimum_required(VERSION 3.20) + +# Set the project name +project(CxxTestRegistration) + +set(CMAKE_CXX_STANDARD 20) + +SET(CXX_LIB_NAME CxxTestRegistration) + +ADD_LIBRARY(${PROJECT_NAME} STATIC "") + +INCLUDE_DIRECTORIES(inc) +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/CxxTestUtils/inc") +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/CxxTestProps/inc") +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib") + +TARGET_LINK_LIBRARIES(${CXX_LIB_NAME} CxxTestProps) +TARGET_LINK_LIBRARIES(${CXX_LIB_NAME} ReflectionTemplateLib) + +# Add the source directory +INCLUDE(src/CMakeLists.txt) \ No newline at end of file diff --git a/CxxTestRegistration/inc/Registration.h b/CxxTestRegistration/inc/Registration.h new file mode 100644 index 00000000..f7b6e830 --- /dev/null +++ b/CxxTestRegistration/inc/Registration.h @@ -0,0 +1,70 @@ +#pragma once + +#include + +namespace rtl { + class Function; +} + +namespace test_mirror +{ + struct Register + { + static void stdTypes(std::vector&); + + static void typeComplex(std::vector&); + + static void typeDate(std::vector&); + + static void typeEvent(std::vector&); + + static void typeCalender(std::vector&); + + static void typePerson(std::vector&); + + static void typeBook(std::vector&); + + static void typeLibrary(std::vector&); + + static void typeAnimal(std::vector&); + + static void typeStringFuncs(std::vector&); + + static void typeStringWrap(std::vector&); + + static void typeStringMute(std::vector&); + + static void typeStringConst(std::vector&); + + static void typeStringStatic(std::vector&); + + static void typeStringConstOverload(std::vector&); + + //--------------------------------------------------------------------------------- + static void typeIdPodStd(std::unordered_map&); + + static void typeIdDate(std::unordered_map&); + + static void typeIdEvent(std::unordered_map&); + + static void typeIdCalender(std::unordered_map&); + + static void typeIdPerson(std::unordered_map&); + + static void typeIdBook(std::unordered_map&); + + static void typeIdLibrary(std::unordered_map&); + + static void typeIdAnimal(std::unordered_map&); + + static void typeIdStringWrap(std::unordered_map&); + + static void typeIdStringMute(std::unordered_map&); + + static void typeIdStringConst(std::unordered_map&); + + static void typeIdStringStatic(std::unordered_map&); + + static void typeIdStringConstOverload(std::unordered_map& id); + }; +} \ No newline at end of file diff --git a/CxxTestRegistration/inc/TestMirrorProvider.h b/CxxTestRegistration/inc/TestMirrorProvider.h new file mode 100644 index 00000000..f908b031 --- /dev/null +++ b/CxxTestRegistration/inc/TestMirrorProvider.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace rtl { + class CxxMirror; +} + +namespace test_mirror +{ + struct cxx { + + static const rtl::CxxMirror& mirror(); + + static const rtl::traits::uid_t reflected_id(const std::string& pRecordName); + }; +} \ No newline at end of file diff --git a/CxxTestRegistration/src/AnimalRegistration.cpp b/CxxTestRegistration/src/AnimalRegistration.cpp new file mode 100644 index 00000000..99eb56d6 --- /dev/null +++ b/CxxTestRegistration/src/AnimalRegistration.cpp @@ -0,0 +1,92 @@ + +#include + +#include "Animal.h" +#include "Registration.h" +#include "TestUtilsAnimal.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdAnimal(std::unordered_map& id) + { + id.insert(std::make_pair(animal::class_, rtl::traits::uid::value)); + } + + void Register::typeAnimal(std::vector& fns) + { + // class 'Animal', methods & constructors. + fns.push_back(rtl::type().record(animal::class_) + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); //overloaded constructor. + + fns.push_back(rtl::type().member() + .method(animal::str_setFamilyName) + .build(&Animal::setFamilyName)); //unique method, no overloads. + + // Unique const-method, no overloads. + fns.push_back(rtl::type().member() + .methodConst(animal::str_getFamilyName) + .build(&Animal::getFamilyName)); + + // Overloaded method, taking const-ref as argument. + fns.push_back(rtl::type().member() + .method(animal::str_setAnimalName) + .build(&Animal::setAnimalName)); + + // Overloaded const-method, taking const-ref as argument. + fns.push_back(rtl::type().member() + .methodConst(animal::str_setAnimalName) + .build(&Animal::setAnimalName)); + + // Static method, taking const-ref as argument. + fns.push_back(rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(&Animal::updateZooKeeper)); + +#if defined(__GNUC__) && !defined(__clang__) +/* + GCC here fails to automatically resolve the correct overloaded functor + when both a lvalue reference and an rvalue overload exist. + To disambiguate, explicitly cast the member function pointer, e.g.: + + static_cast(&Animal::setAnimalName) +*/ + fns.push_back(rtl::type().member() + .method(animal::str_setAnimalName) + .build(static_cast(&Animal::setAnimalName))); //overloaded method, taking non-const lvalue reference as argument. + + fns.push_back(rtl::type().member() + .method(animal::str_setAnimalName) + .build(static_cast(&Animal::setAnimalName))); //overloaded method, taking rvalue reference as argument. + + fns.push_back(rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(static_cast(&Animal::updateZooKeeper))); //static method, taking non-const lvalue reference as argument. + + fns.push_back(rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(static_cast(&Animal::updateZooKeeper))); //static method, taking rvalue reference as argument. +#else + fns.push_back(rtl::type().member() + .method(animal::str_setAnimalName) + .build(&Animal::setAnimalName)); //overloaded method, taking non-const lvalue reference as argument. + + fns.push_back(rtl::type().member() + .method(animal::str_setAnimalName) + .build(&Animal::setAnimalName)); //overloaded method, taking rvalue reference as argument. + + fns.push_back(rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(&Animal::updateZooKeeper)); //static method, taking non-const lvalue reference as argument. + + fns.push_back(rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(&Animal::updateZooKeeper)); //static method, taking rvalue reference as argument. +#endif + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/BookRegistration.cpp b/CxxTestRegistration/src/BookRegistration.cpp new file mode 100644 index 00000000..f6321ad6 --- /dev/null +++ b/CxxTestRegistration/src/BookRegistration.cpp @@ -0,0 +1,65 @@ + +#include + +#include "Book.h" +#include "Registration.h" +#include "TestUtilsBook.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdBook(std::unordered_map& id) + { + id.insert(std::make_pair(book::class_, rtl::traits::uid::value)); + } + + void Register::typeBook(std::vector& fns) + { + // class 'Book', methods & constructors. + // Registering default constructor. + fns.push_back(rtl::type().record(book::class_) + .build()); + + // Registering overloaded constructor, signature must be specified as template parameter. + fns.push_back(rtl::type().member() + .constructor() + .build()); + + // Unique methods, no overloads. + fns.push_back(rtl::type().member() + .method(book::str_setAuthor) + .build(&Book::setAuthor)); + + // Unique method, taking 'std::string' & 'const std::string&' as argument, auto deduced via function-pointer. + fns.push_back(rtl::type().member() + .method(book::str_addPreface) + .build(&Book::addPreface)); + + // Furthur registrations of unique-menthods, signature auto-deduced via function pointer. + fns.push_back(rtl::type().member() + .method(book::str_setDescription) + .build(&Book::setDescription)); + + fns.push_back(rtl::type().member() + .method(book::str_getPublishedOn) + .build(&Book::getPublishedOn)); + + fns.push_back(rtl::type().member() + .method(book::str_addCopyrightTag) + .build(&Book::addCopyrightTag)); + + // Registering overloaded methods, signature must be specified as template params since other overloads exists, else compiler error. + fns.push_back(rtl::type().member() + .method(book::str_updateBookInfo) + .build(&Book::updateBookInfo)); + + fns.push_back(rtl::type().member() + .method(book::str_updateBookInfo) + .build(&Book::updateBookInfo)); + + fns.push_back(rtl::type().member() + .method(book::str_updateBookInfo) + .build(&Book::updateBookInfo)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/CMakeLists.txt b/CxxTestRegistration/src/CMakeLists.txt new file mode 100644 index 00000000..21cf3de4 --- /dev/null +++ b/CxxTestRegistration/src/CMakeLists.txt @@ -0,0 +1,38 @@ +# CMakeLists.txt for ReflectionTypeRegistration +cmake_minimum_required(VERSION 3.20) + +project(CxxTestRegistration) + +# Create a variable containing the source files for your target +set(LOCAL_SOURCES + "${CMAKE_CURRENT_LIST_DIR}/AnimalRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/BookRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/CalenderRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/ComplexRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/DateRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/EventRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/LibraryRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/PersonRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/PodStdRegistration.cpp" + + "${CMAKE_CURRENT_LIST_DIR}/StrWrapRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StrMuteRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StrConstRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StrFuncsRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StrStaticRegistration.cpp" + "${CMAKE_CURRENT_LIST_DIR}/StrConstOverloadRegistration.cpp" + + "${CMAKE_CURRENT_LIST_DIR}/TestMirrorProvider.cpp" +) + +SET(LOCAL_HEADERS + "${PROJECT_SOURCE_DIR}/inc/Registration.h" + "${PROJECT_SOURCE_DIR}/inc/TestMirrorProvider.h" +) + +# Add any additional source files if needed +target_sources(CxxTestRegistration + PRIVATE + "${LOCAL_SOURCES}" + "${LOCAL_HEADERS}" +) \ No newline at end of file diff --git a/CxxTestRegistration/src/CalenderRegistration.cpp b/CxxTestRegistration/src/CalenderRegistration.cpp new file mode 100644 index 00000000..bd8a688a --- /dev/null +++ b/CxxTestRegistration/src/CalenderRegistration.cpp @@ -0,0 +1,46 @@ + +#include + +#include "Date.h" +#include "Registration.h" +#include "TestUtilsDate.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdCalender(std::unordered_map& id) + { + id.insert(std::make_pair(calender::struct_, rtl::traits::uid::value)); + } + + void Register::typeCalender(std::vector& fns) + { + // Registring static-method, 'methodStatic()' function must be used. compiler error otherwise. + fns.push_back(rtl::type().member() + .methodStatic(calender::str_create) + .build(&nsdate::Calender::create)); + + // Registring unique methods of class Calender, no overloads. + fns.push_back(rtl::type().member() + .method(calender::str_getTheEvent) + .build(&nsdate::Calender::getTheEvent)); + + fns.push_back(rtl::type().member() + .method(calender::str_getTheDate) + .build(&nsdate::Calender::getTheDate)); + + fns.push_back(rtl::type().member() + .method(calender::str_getSavedEvent) + .build(&nsdate::Calender::getSavedEvent)); + + fns.push_back(rtl::type().member() + .method(calender::str_getSavedDate) + .build(&nsdate::Calender::getSavedDate)); + + // class Calender, registering after the methods. (order doesn't matter) + fns.push_back(rtl::type().ns(date::ns) + .record(calender::struct_) + .build()); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/ComplexRegistration.cpp b/CxxTestRegistration/src/ComplexRegistration.cpp new file mode 100644 index 00000000..26ed62c9 --- /dev/null +++ b/CxxTestRegistration/src/ComplexRegistration.cpp @@ -0,0 +1,33 @@ + +#include + +#include "Complex.h" +#include "Registration.h" +#include "GlobalTestUtils.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeComplex(std::vector& fns) + { + // Unique function, no overloads, no need to specify signature as template parameters. + fns.push_back(rtl::type().function(str_getComplexNumAsString) + .build(getComplexNumAsString)); + + /* Grouping functions under a namespace, which is optional. they can be registered without it as well. + but if registered under namspace, then to retrieve it from CxxMirror object, namespace name must be passed, + e.g. cxx::mirror().getFunction("namespace_name", "function_name") & cxx::mirror().getRecord("namespace_name", "record_name") */ + fns.push_back(rtl::type().ns(str_complex) + .function(str_setReal) + .build(complex::setReal)); + + fns.push_back(rtl::type().ns(str_complex) + .function(str_setImaginary) + .build(complex::setImaginary)); + + fns.push_back(rtl::type().ns(str_complex) + .function(str_getMagnitude) + .build(complex::getMagnitude)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/DateRegistration.cpp b/CxxTestRegistration/src/DateRegistration.cpp new file mode 100644 index 00000000..b5c152b3 --- /dev/null +++ b/CxxTestRegistration/src/DateRegistration.cpp @@ -0,0 +1,45 @@ + +#include + +#include "Date.h" +#include "Registration.h" +#include "TestUtilsDate.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdDate(std::unordered_map& id) + { + id.insert(std::make_pair(date::struct_, rtl::traits::uid::value)); + } + + void Register::typeDate(std::vector& fns) + { + // Constructors registration, class/struct name and type must be passed 'record("NAME")'. + // Registers default constructor with implicit registration of destructor & copy-constructor. + fns.push_back(rtl::type().ns(date::ns) + .record(date::struct_) + .build()); + + // Overloaded constructor, taking 'string' as argument, signature must be specified as template parameter. + fns.push_back(rtl::type().member() + .constructor() + .build()); + + // Again, register an overloaded constructor with diffeent signature. + fns.push_back(rtl::type().member() + .constructor() + .build()); + + // Registring, Unique method, no overloads. Taking param 'std::string', auto deduced via function-pointer. + fns.push_back(rtl::type().member() + .method(date::str_updateDate) + .build(&nsdate::Date::updateDate)); + + // Registring const-method, 'methodConst()' function must be used. compiler error otherwise. + fns.push_back(rtl::type().member() + .methodConst(date::str_getAsString) + .build(&nsdate::Date::getAsString)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/EventRegistration.cpp b/CxxTestRegistration/src/EventRegistration.cpp new file mode 100644 index 00000000..6fb5f45f --- /dev/null +++ b/CxxTestRegistration/src/EventRegistration.cpp @@ -0,0 +1,29 @@ + +#include + +#include "Date.h" +#include "Registration.h" +#include "TestUtilsDate.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdEvent(std::unordered_map& id) + { + id.insert(std::make_pair(event::struct_, rtl::traits::uid::value)); + } + + void Register::typeEvent(std::vector& fns) + { + // Registering 'Event' for reflection; instance creation via reflection fails since its default constructor is private or deleted. + // At least one member must be registered for RTL to recognize the type. be it property, member-function or constructor. + fns.push_back(rtl::type().ns(event::ns) + .record(event::struct_) + .build()); + + fns.push_back(rtl::type().member() + .method(event::str_reset) + .build(&nsdate::Event::reset)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/LibraryRegistration.cpp b/CxxTestRegistration/src/LibraryRegistration.cpp new file mode 100644 index 00000000..cf9c1c06 --- /dev/null +++ b/CxxTestRegistration/src/LibraryRegistration.cpp @@ -0,0 +1,35 @@ + +#include + +#include "Book.h" +#include "Library.h" +#include "Registration.h" +#include "TestUtilsBook.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdLibrary(std::unordered_map& id) + { + id.insert(std::make_pair(library::class_, rtl::traits::uid::value)); + } + + void Register::typeLibrary(std::vector& fns) + { + // Registering Library's constructor. Stack allocation (rtl::alloc::Stack) will fail since its copy constructor is deleted + // and its required by 'std::any' to store its object via copy-construction. But instance on heap (rtl::alloc::HEAP) can be + // constructed since, in that case, 'std::any' stores only the poiner which does not requires copy constructor to be called. + fns.push_back(rtl::type().record(library::class_) + .build()); + + // Registring static-method, 'methodStatic()' function must be used. compiler error otherwise. + fns.push_back(rtl::type().member() + .methodStatic(library::str_addBook) + .build(&Library::addBook)); + + fns.push_back(rtl::type().member() + .methodStatic(library::str_getBookByTitle) + .build(&Library::getBookByTitle)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/PersonRegistration.cpp b/CxxTestRegistration/src/PersonRegistration.cpp new file mode 100644 index 00000000..05594da8 --- /dev/null +++ b/CxxTestRegistration/src/PersonRegistration.cpp @@ -0,0 +1,77 @@ + +#include + +#include "Person.h" +#include "Registration.h" +#include "TestUtilsPerson.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdPerson(std::unordered_map& id) + { + id.insert(std::make_pair(person::class_, rtl::traits::uid::value)); + } + + void Register::typePerson(std::vector& fns) + { + // class 'Person', methods & constructors. + fns.push_back(rtl::type().record(person::class_) + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + fns.push_back(rtl::type().member() + .methodStatic(person::str_createPtr) + .build(&Person::createPtr)); + + fns.push_back(rtl::type().member() + .method(person::str_updateAddress) + .build(&Person::updateAddress)); + + fns.push_back(rtl::type().member() + .method(person::str_updateAddress) + .build(&Person::updateAddress)); + + fns.push_back(rtl::type().member() + .method(person::str_getFirstName) + .build(&Person::getFirstName)); + + // Registring const-method, 'methodConst()' function must be used. compiler error otherwise. + fns.push_back(rtl::type().member() + .methodConst(person::str_updateLastName) + .build(&Person::updateLastName)); + + // Registring const-method overload, non-const overloaded method already registered above. + fns.push_back(rtl::type().member() + .methodConst(person::str_updateAddress) + .build(&Person::updateAddress)); + + fns.push_back(rtl::type().member() + .methodConst(person::str_updateAddress) + .build(&Person::updateAddress)); + + fns.push_back(rtl::type().member() + .methodStatic(person::str_getDefaults) + .build(&Person::getDefaults)); + + fns.push_back(rtl::type().member() + .methodStatic(person::str_createConst) + .build(&Person::createConst)); + + fns.push_back(rtl::type().member() + .methodStatic(person::str_getProfile) + .build(&Person::getProfile)); + + fns.push_back(rtl::type().member() + .methodStatic(person::str_getProfile) + .build(&Person::getProfile)); + + fns.push_back(rtl::type().member() + .methodStatic(person::str_getProfile) + .build(&Person::getProfile)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/PodStdRegistration.cpp b/CxxTestRegistration/src/PodStdRegistration.cpp new file mode 100644 index 00000000..6ca0da33 --- /dev/null +++ b/CxxTestRegistration/src/PodStdRegistration.cpp @@ -0,0 +1,72 @@ + +#include + +#include "Registration.h" + +namespace test_mirror +{ + void Register::typeIdPodStd(std::unordered_map& id) + { + id.insert(std::make_pair("int", rtl::traits::uid::value)); + id.insert(std::make_pair("char", rtl::traits::uid::value)); + id.insert(std::make_pair("string", rtl::traits::uid::value)); + id.insert(std::make_pair("string_view", rtl::traits::uid::value)); + } + + void Register::stdTypes(std::vector& fns) + { + // Registering int. + fns.push_back(rtl::type().record("int") + .build()); + + // Registering type 'int' again, ignored & emits- + // [WARNING] Multiple registrations of the same type detected. + fns.push_back(rtl::type().record("int") + .build()); + + // Registering type 'int' again, but with different name. ignored & emits- + // [WARNING] Multiple registrations of the same type detected. + fns.push_back(rtl::type().record("ccint") + .build()); + + // Registering pod, reflecting- constructor, copy-constructor & destructor. + fns.push_back(rtl::type().record("char") + .build()); + + fns.push_back(rtl::type().ns("std") + .record("string_view") + .build()); + + // Registers std::string class + fns.push_back(rtl::type().member() + .methodConst("empty") + .build(&std::string::empty)); + + /* Attempting to register the same type(`std::string`) again under a different name. + * RTL will ignore this duplicate registration and retain the first one. Emits a warning on the console: + * "[WARNING] Multiple registrations of the same type with different names detected." + */ fns.push_back(rtl::type().member() + .methodConst("empty") + .build(&std::string::empty)); + + fns.push_back(rtl::type().ns("std") + .record("string") + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + /* Attempting to register std::string_view, but the provided member function pointer belongs to std::string. + * RTL will ignore this registration. Emits a warning on the console: + * "[WARNING] Member function pointer does not belong to the class being registered!" + */ fns.push_back(rtl::type().member() + .methodConst("empty") + .build(&std::string::empty)); + + // Finally, register std::string_view with correct member-function-pointer + fns.push_back(rtl::type().member() + .methodConst("empty") + .build(&std::string_view::empty)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/StrConstOverloadRegistration.cpp b/CxxTestRegistration/src/StrConstOverloadRegistration.cpp new file mode 100644 index 00000000..fdf9315a --- /dev/null +++ b/CxxTestRegistration/src/StrConstOverloadRegistration.cpp @@ -0,0 +1,33 @@ + +#include + +#include "StringConstOverload.h" +#include "Registration.h" +#include "GlobalTestUtils.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdStringConstOverload(std::unordered_map& id) + { + const StrConstOverload obj; + obj.reverseString(); + + id.insert(std::make_pair(StrConstOverload::struct_, rtl::traits::uid::value)); + } + + void Register::typeStringConstOverload(std::vector& fns) + { + fns.push_back(rtl::type().record(StrConstOverload::struct_) + .build()); + + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrConstOverload::reverseString)); + + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConstOverload::reverseString)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/StrConstRegistration.cpp b/CxxTestRegistration/src/StrConstRegistration.cpp new file mode 100644 index 00000000..00a6c635 --- /dev/null +++ b/CxxTestRegistration/src/StrConstRegistration.cpp @@ -0,0 +1,114 @@ + +#include + +#include "StringConst.h" +#include "Registration.h" +#include "GlobalTestUtils.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdStringConst(std::unordered_map& id) + { + id.insert(std::make_pair(StrConst::struct_, rtl::traits::uid::value)); + } + + void Register::typeStringConst(std::vector& fns) + { + fns.push_back(rtl::type().record(StrConst::struct_) + .build()); + + // Function taking no arguments. '' must be specified if other overload exists else not needed. compiler error otherwise. + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConst::reverseString)); + + // Overloaded function, takes 'string' arguments. '' must be specified as template parameter. + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConst::reverseString)); + + // Overloaded function, takes 'const char*' arguments. + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConst::reverseString)); + + // numereous other overloads. + #if defined(__GNUC__) && !defined(__clang__) + /* + GCC here fails to automatically resolve the correct overloaded functor + when both a lvalue reference and an rvalue overload exist. + To disambiguate, explicitly cast the function pointer, e.g.: + + static_cast(reverseString) + */ + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(static_cast(&StrConst::reverseString))); + + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(static_cast(&StrConst::reverseString))); + + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(static_cast(&StrConst::reverseString))); +#else + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConst::reverseString)); + + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConst::reverseString)); + + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConst::reverseString)); +#endif + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConst::reverseString)); + + fns.push_back(rtl::type().member() + .methodConst(str_reverseString) + .build(&StrConst::reverseString)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrNonConstRefArg) + .build(&StrConst::revStrNonConstRefArg)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrRValueRefArg) + .build(&StrConst::revStrRValueRefArg)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrConstRefArg) + .build(&StrConst::revStrConstRefArg)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrOverloadValRef) + .build(&StrConst::revStrOverloadValRef)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrOverloadValRef) + .build(&StrConst::revStrOverloadValRef)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrOverloadValCRef) + .build(&StrConst::revStrOverloadValCRef)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrOverloadValCRef) + .build(&StrConst::revStrOverloadValCRef)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrOverloadValRefAndCRef) + .build(&StrConst::revStrOverloadRefAndCRef)); + + fns.push_back(rtl::type().member() + .methodConst(str_revStrOverloadValRefAndCRef) + .build(&StrConst::revStrOverloadRefAndCRef)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/StrFuncsRegistration.cpp b/CxxTestRegistration/src/StrFuncsRegistration.cpp new file mode 100644 index 00000000..be339835 --- /dev/null +++ b/CxxTestRegistration/src/StrFuncsRegistration.cpp @@ -0,0 +1,85 @@ + +#include + +#include "StringOps.h" +#include "Registration.h" +#include "GlobalTestUtils.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeStringFuncs(std::vector& fns) + { + // Function taking no arguments. '' must be specified if other overload exists else not needed. compiler error otherwise. + fns.push_back(rtl::type().function(str_reverseString) + .build(reverseString)); + + // Overloaded function, takes 'string' arguments. '' must be specified as template parameter. + fns.push_back(rtl::type().function(str_reverseString) + .build(reverseString)); + + // Overloaded function, takes 'const char*' arguments. + fns.push_back(rtl::type().function(str_reverseString) + .build(reverseString)); + // numereous other overloads. + #if defined(__GNUC__) && !defined(__clang__) +/* + GCC here fails to automatically resolve the correct overloaded functor + when both a lvalue reference and an rvalue overload exist. + To disambiguate, explicitly cast the function pointer, e.g.: + + static_cast(reverseString) +*/ + fns.push_back(rtl::type().function(str_reverseString) + .build(static_cast(reverseString))); + + fns.push_back(rtl::type().function(str_reverseString) + .build(static_cast(reverseString))); + + fns.push_back(rtl::type().function(str_reverseString) + .build(static_cast(reverseString))); +#else + fns.push_back(rtl::type().function(str_reverseString) + .build(reverseString)); + + fns.push_back(rtl::type().function(str_reverseString) + .build(reverseString)); + + fns.push_back(rtl::type().function(str_reverseString) + .build(reverseString)); +#endif + fns.push_back(rtl::type().function(str_reverseString) + .build(reverseString)); + + fns.push_back(rtl::type().function(str_reverseString) + .build(reverseString)); + + fns.push_back(rtl::type().function(str_revStrNonConstRefArg) + .build(revStrNonConstRefArg)); + + fns.push_back(rtl::type().function(str_revStrRValueRefArg) + .build(revStrRValueRefArg)); + + fns.push_back(rtl::type().function(str_revStrConstRefArg) + .build(revStrConstRefArg)); + + fns.push_back(rtl::type().function(str_revStrOverloadValRef) + .build(revStrOverloadValRef)); + + fns.push_back(rtl::type().function(str_revStrOverloadValRef) + .build(revStrOverloadValRef)); + + fns.push_back(rtl::type().function(str_revStrOverloadValCRef) + .build(revStrOverloadValCRef)); + + fns.push_back(rtl::type().function(str_revStrOverloadValCRef) + .build(revStrOverloadValCRef)); + + fns.push_back(rtl::type().function(str_revStrOverloadValRefAndCRef) + .build(revStrOverloadRefAndCRef)); + + fns.push_back(rtl::type().function(str_revStrOverloadValRefAndCRef) + .build(revStrOverloadRefAndCRef)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/StrMuteRegistration.cpp b/CxxTestRegistration/src/StrMuteRegistration.cpp new file mode 100644 index 00000000..a6f7d548 --- /dev/null +++ b/CxxTestRegistration/src/StrMuteRegistration.cpp @@ -0,0 +1,114 @@ + +#include + +#include "StringMute.h" +#include "Registration.h" +#include "GlobalTestUtils.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdStringMute(std::unordered_map& id) + { + id.insert(std::make_pair(StrMute::struct_, rtl::traits::uid::value)); + } + + void Register::typeStringMute(std::vector& fns) + { + fns.push_back(rtl::type().record(StrMute::struct_) + .build()); + + // Function taking no arguments. '' must be specified if other overload exists else not needed. compiler error otherwise. + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrMute::reverseString)); + + // Overloaded function, takes 'string' arguments. '' must be specified as template parameter. + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrMute::reverseString)); + + // Overloaded function, takes 'const char*' arguments. + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrMute::reverseString)); + + // numereous other overloads. + #if defined(__GNUC__) && !defined(__clang__) + /* + GCC here fails to automatically resolve the correct overloaded functor + when both a lvalue reference and an rvalue overload exist. + To disambiguate, explicitly cast the function pointer, e.g.: + + static_cast(reverseString) + */ + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(static_cast(&StrMute::reverseString))); + + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(static_cast(&StrMute::reverseString))); + + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(static_cast(&StrMute::reverseString))); +#else + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrMute::reverseString)); + + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrMute::reverseString)); + + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrMute::reverseString)); +#endif + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrMute::reverseString)); + + fns.push_back(rtl::type().member() + .method(str_reverseString) + .build(&StrMute::reverseString)); + + fns.push_back(rtl::type().member() + .method(str_revStrNonConstRefArg) + .build(&StrMute::revStrNonConstRefArg)); + + fns.push_back(rtl::type().member() + .method(str_revStrRValueRefArg) + .build(&StrMute::revStrRValueRefArg)); + + fns.push_back(rtl::type().member() + .method(str_revStrConstRefArg) + .build(&StrMute::revStrConstRefArg)); + + fns.push_back(rtl::type().member() + .method(str_revStrOverloadValRef) + .build(&StrMute::revStrOverloadValRef)); + + fns.push_back(rtl::type().member() + .method(str_revStrOverloadValRef) + .build(&StrMute::revStrOverloadValRef)); + + fns.push_back(rtl::type().member() + .method(str_revStrOverloadValCRef) + .build(&StrMute::revStrOverloadValCRef)); + + fns.push_back(rtl::type().member() + .method(str_revStrOverloadValCRef) + .build(&StrMute::revStrOverloadValCRef)); + + fns.push_back(rtl::type().member() + .method(str_revStrOverloadValRefAndCRef) + .build(&StrMute::revStrOverloadRefAndCRef)); + + fns.push_back(rtl::type().member() + .method(str_revStrOverloadValRefAndCRef) + .build(&StrMute::revStrOverloadRefAndCRef)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/StrStaticRegistration.cpp b/CxxTestRegistration/src/StrStaticRegistration.cpp new file mode 100644 index 00000000..25f875cf --- /dev/null +++ b/CxxTestRegistration/src/StrStaticRegistration.cpp @@ -0,0 +1,114 @@ + +#include + +#include "StringStatic.h" +#include "Registration.h" +#include "GlobalTestUtils.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdStringStatic(std::unordered_map& id) + { + id.insert(std::make_pair(StrStatic::struct_, rtl::traits::uid::value)); + } + + void Register::typeStringStatic(std::vector& fns) + { + fns.push_back(rtl::type().record(StrStatic::struct_) + .build()); + + // Function taking no arguments. '' must be specified if other overload exists else not needed. compiler error otherwise. + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(&StrStatic::reverseString)); + + // Overloaded function, takes 'string' arguments. '' must be specified as template parameter. + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(&StrStatic::reverseString)); + + // Overloaded function, takes 'const char*' arguments. + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(&StrStatic::reverseString)); + + // numereous other overloads. + #if defined(__GNUC__) && !defined(__clang__) + /* + GCC here fails to automatically resolve the correct overloaded functor + when both a lvalue reference and an rvalue overload exist. + To disambiguate, explicitly cast the function pointer, e.g.: + + static_cast(reverseString) + */ + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(static_cast(&StrStatic::reverseString))); + + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(static_cast(&StrStatic::reverseString))); + + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(static_cast(&StrStatic::reverseString))); +#else + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(&StrStatic::reverseString)); + + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(&StrStatic::reverseString)); + + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(&StrStatic::reverseString)); +#endif + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(&StrStatic::reverseString)); + + fns.push_back(rtl::type().member() + .methodStatic(str_reverseString) + .build(&StrStatic::reverseString)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrNonConstRefArg) + .build(&StrStatic::revStrNonConstRefArg)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrRValueRefArg) + .build(&StrStatic::revStrRValueRefArg)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrConstRefArg) + .build(&StrStatic::revStrConstRefArg)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrOverloadValRef) + .build(&StrStatic::revStrOverloadValRef)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrOverloadValRef) + .build(&StrStatic::revStrOverloadValRef)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrOverloadValCRef) + .build(&StrStatic::revStrOverloadValCRef)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrOverloadValCRef) + .build(&StrStatic::revStrOverloadValCRef)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrOverloadValRefAndCRef) + .build(&StrStatic::revStrOverloadRefAndCRef)); + + fns.push_back(rtl::type().member() + .methodStatic(str_revStrOverloadValRefAndCRef) + .build(&StrStatic::revStrOverloadRefAndCRef)); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/StrWrapRegistration.cpp b/CxxTestRegistration/src/StrWrapRegistration.cpp new file mode 100644 index 00000000..128fe3b5 --- /dev/null +++ b/CxxTestRegistration/src/StrWrapRegistration.cpp @@ -0,0 +1,74 @@ + +#include + +#include "StringWrap.h" +#include "Registration.h" +#include "GlobalTestUtils.h" + +using namespace test_utils; + +namespace test_mirror +{ + void Register::typeIdStringWrap(std::unordered_map& id) + { + id.insert(std::make_pair(StrWrapA::struct_, rtl::traits::uid::value)); + id.insert(std::make_pair(StrWrapB::struct_, rtl::traits::uid::value)); + id.insert(std::make_pair(StrWrapC::struct_, rtl::traits::uid::value)); + id.insert(std::make_pair(StrWrapD::struct_, rtl::traits::uid::value)); + } + + void Register::typeStringWrap(std::vector& fns) + { + //------------------StrWrapA-------------------------------- + fns.push_back(rtl::type().record(StrWrapA::struct_) // Registers default constructor as well. + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + //------------------StrWrapB-------------------------------- + fns.push_back(rtl::type().record(StrWrapB::struct_) // Registers default constructor as well. + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + //------------------StrWrapC-------------------------------- + fns.push_back(rtl::type().record(StrWrapC::struct_) // Registers default constructor as well. + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + + //------------------StrWrapD-------------------------------- + fns.push_back(rtl::type().record(StrWrapD::struct_) // Registers default constructor as well. + .build()); + + fns.push_back(rtl::type().member() + .constructor() + .build()); + } +} \ No newline at end of file diff --git a/CxxTestRegistration/src/TestMirrorProvider.cpp b/CxxTestRegistration/src/TestMirrorProvider.cpp new file mode 100644 index 00000000..04dd7d86 --- /dev/null +++ b/CxxTestRegistration/src/TestMirrorProvider.cpp @@ -0,0 +1,79 @@ + +#include +#include + +#include +#include + +#include "Registration.h" +#include "TestMirrorProvider.h" + +namespace test_mirror +{ + const rtl::CxxMirror& cxx::mirror() + { + static auto cxx_mirror = rtl::CxxMirror( + []() { + + std::vector fns; + + Register::stdTypes(fns); + Register::typeBook(fns); + Register::typeDate(fns); + Register::typeEvent(fns); + Register::typePerson(fns); + Register::typeAnimal(fns); + Register::typeLibrary(fns); + Register::typeComplex(fns); + Register::typeCalender(fns); + + Register::typeStringWrap(fns); + Register::typeStringMute(fns); + Register::typeStringConst(fns); + Register::typeStringFuncs(fns); + Register::typeStringStatic(fns); + Register::typeStringConstOverload(fns); + + return fns; + }() + ); + + static const auto _= [&]() + { + const std::string pathStr = std::filesystem::current_path().string() + "/MyReflection.json"; + std::cout << "\n[ OUTPUT] test_mirror::cxx::mirror() ==> dumping 'CxxMirror' as JSON." + << "\n file path: " << pathStr << "\n" << std::endl; + rtl::CxxMirrorToJson::dump(cxx_mirror, pathStr); + return 0; + }(); + + return cxx_mirror; + } + + const rtl::traits::uid_t cxx::reflected_id(const std::string& pRecordName) + { + static std::unordered_map nameIdMap = []() + { + std::unordered_map ids; + + Register::typeIdBook(ids); + Register::typeIdDate(ids); + Register::typeIdEvent(ids); + Register::typeIdPerson(ids); + Register::typeIdPodStd(ids); + Register::typeIdAnimal(ids); + Register::typeIdLibrary(ids); + Register::typeIdCalender(ids); + Register::typeIdStringWrap(ids); + Register::typeIdStringMute(ids); + Register::typeIdStringConst(ids); + Register::typeIdStringStatic(ids); + Register::typeIdStringConstOverload(ids); + + return ids; + }(); + + const auto& itr = nameIdMap.find(pRecordName); + return (itr == nameIdMap.end() ? rtl::index_none : itr->second); + } +} \ No newline at end of file diff --git a/CxxTestUtils/CMakeLists.txt b/CxxTestUtils/CMakeLists.txt new file mode 100644 index 00000000..c92ffa61 --- /dev/null +++ b/CxxTestUtils/CMakeLists.txt @@ -0,0 +1,22 @@ +# CMakeLists.txt for CxxTestUtils + +# Set the minimum required CMake version +cmake_minimum_required(VERSION 3.20) + +# Set the project name +project(CxxTestUtils) + +set(CMAKE_CXX_STANDARD 20) + +SET(CXX_LIB_NAME CxxTestUtils) + +ADD_LIBRARY(${PROJECT_NAME} STATIC "") + +INCLUDE_DIRECTORIES(inc) +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/CxxTestProps/inc") + +TARGET_LINK_LIBRARIES(${CXX_LIB_NAME} CxxTestProps) +TARGET_LINK_LIBRARIES(${CXX_LIB_NAME} ReflectionTemplateLib) + +# Add the source directory +INCLUDE(src/CMakeLists.txt) \ No newline at end of file diff --git a/CxxTestUtils/inc/GlobalTestUtils.h b/CxxTestUtils/inc/GlobalTestUtils.h new file mode 100755 index 00000000..122dd9cd --- /dev/null +++ b/CxxTestUtils/inc/GlobalTestUtils.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +/* +TestUtils provide the interface to test/compare reflected type objects with actual objects (retrived/created using +strict Types) without exposing the actual type objects to "CxxReflectionTests" project. + +Provides interface for Testing/Comparing the global functions & types (may or not be in some namespace) without exposing their actual implementation. +*/ +namespace test_utils { + + static constexpr double g_real = 3.92; + static constexpr double g_imaginary = 9.27; + + static constexpr const char* STRA = "ReflectC++"; + static constexpr const char* STRA_REVERSE = "++CtcelfeR"; + + static constexpr const char* STRB = "cxxReflection"; + static constexpr const char* STRB_REVERSE = "noitcelfeRxxc"; + + static constexpr const char* str_reverseString = "reverseString"; + static constexpr const char* str_revStrConstRefArg = "revStrConstRefArg"; + static constexpr const char* str_revStrRValueRefArg = "revStrRValueRefArg"; + static constexpr const char* str_revStrNonConstRefArg = "revStrNonConstRefArg"; + static constexpr const char* str_revStrOverloadValRef = "revStrOverloadValRef"; + static constexpr const char* str_revStrOverloadValCRef = "revStrOverloadValCRef"; + static constexpr const char* str_revStrOverloadValRefAndCRef = "revStrOverloadValRefAndCRef"; + + static constexpr const char* str_getComplexNumAsString = "getComplexNumAsString"; + + static constexpr const char* str_complex = "complex"; + static constexpr const char* str_setReal = "setReal"; + + static constexpr const char* str_setImaginary = "setImaginary"; + static constexpr const char* str_getMagnitude = "getMagnitude"; + + static const char* SUFFIX_void = "_void"; + static const char* SUFFIX_ctor = "_ctor"; + static const char* SUFFIX_const = "_const"; + static const char* SUFFIX_static = "_static"; + static const char* SUFFIX_const_char_ptr = "_const_char_*"; + + static const char* SUFFIX_std_string = "_std::string"; + + static const char* SUFFIX_std_string_ptr = "_std::string*"; + static const char* SUFFIX_std_string_cptr = "_const_std::string*"; + + static const char* SUFFIX_std_string_lvref = "_std::string&"; + static const char* SUFFIX_std_string_clvref = "_const_std::string&"; + + static const char* SUFFIX_std_string_rvref = "_std::string&&"; + + static const char* REV_STR_VOID_RET = "func_reverseString(void)->[return_str]"; + + static const char* SUFFIX_std_string_view = "_std::string_view"; + static const char* SUFFIX_std_string_view_lvref = "_std::string_view&"; + static const char* SUFFIX_std_string_view_rvref = "_std::string_view&&"; + static const char* SUFFIX_std_string_view_clvref = "_const_std::string_view&"; +} \ No newline at end of file diff --git a/CxxTestUtils/inc/Node.h b/CxxTestUtils/inc/Node.h new file mode 100644 index 00000000..2571297c --- /dev/null +++ b/CxxTestUtils/inc/Node.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +namespace test_utils +{ + struct Node + { + ~Node(); + Node(int pData); + Node(Node&& pOther) noexcept = delete; + Node(const Node& pOther) = delete; + Node& operator=(Node&&) = delete; + Node& operator=(const Node&) = delete; + + int data() const; + static bool instanceCount(); + static bool assertResourcesReleased(); + static bool getMoveOpsCountAndReset(); + + private: + int* m_data; + std::function m_deleter; + }; + + + struct Edge + { + + private: + Node* m_data; + }; +} diff --git a/CxxTestUtils/inc/TestUtilsAnimal.h b/CxxTestUtils/inc/TestUtilsAnimal.h new file mode 100644 index 00000000..cab364e2 --- /dev/null +++ b/CxxTestUtils/inc/TestUtilsAnimal.h @@ -0,0 +1,46 @@ +#pragma once +/* +TestUtils provide the interface to test/compare reflected type objects with actual objects (retrived/created using +strict Types) without exposing the actual type objects to "CxxReflectionTests" project. + +Provides interface for Testing/Comparing the class "Animal" objects states/returns without exposing the actual type "Animal". +*/ + +#include + +namespace rtl { + class RObject; +} + + +namespace test_utils +{ + struct animal + { + static constexpr const int AGE = 0.0; + static constexpr const float WEIGHT = 0.0; + static constexpr const bool IS_MAMMAL = false; + static constexpr const char* NAME = "Orangutan"; + static constexpr const char* FAMILY_NAME = "Great Ape"; + static constexpr const char* ZOO_KEEPER = "Donald McAdams"; + + static constexpr const char* class_ = "Animal"; + static constexpr const char* str_updateZooKeeper = "updateZooKeeper"; + static constexpr const char* str_setAnimalName = "setAnimalName"; + static constexpr const char* str_setFamilyName = "setFamilyName"; + static constexpr const char* str_getFamilyName = "getFamilyName"; + + static const bool assert_zero_instance_count(); + + static const bool test_method_setAnimalName_rvalue_args(const rtl::RObject& pInstance); + + static const bool test_method_setAnimalName_const_lvalue_ref_args(const rtl::RObject& pInstance); + + static const bool test_method_const_setAnimalName_const_lvalue_ref_args(const rtl::RObject& pInstance); + + static const bool test_method_setAnimalName_non_const_lvalue_ref_args(const rtl::RObject& pInstance); + + template + static const bool test_method_updateZooKeeper(const std::string& pZooKeeper); + }; +} \ No newline at end of file diff --git a/CxxTypeRegistration/inc/TestUtilsBook.h b/CxxTestUtils/inc/TestUtilsBook.h similarity index 56% rename from CxxTypeRegistration/inc/TestUtilsBook.h rename to CxxTestUtils/inc/TestUtilsBook.h index ced1359b..1b380af2 100644 --- a/CxxTypeRegistration/inc/TestUtilsBook.h +++ b/CxxTestUtils/inc/TestUtilsBook.h @@ -1,19 +1,26 @@ #pragma once - -#include -#include /* TestUtils provide the interface to test/compare reflected type objects with actual objects (retrived/created using strict Types) without exposing the actual type objects to "CxxReflectionTests" project. Provides interface for Testing/Comparing the class "Book" objects states/returns without exposing the actual type "Book". */ + +#include + +namespace rtl { + class RObject; +} + namespace test_utils { struct library { static constexpr const char* class_ = "Library"; static constexpr const char* str_addBook = "addBook"; + static constexpr const char* str_getBookByTitle = "getBookByTitle"; + + static const bool assert_zero_instance_count(); }; struct book @@ -22,26 +29,37 @@ namespace test_utils static constexpr const char* TITLE = "Somehow, I manage."; static constexpr const char* AUTHOR = "Micheal G. Scott"; static constexpr const char* DESCRIPTION = "World's greatest boss Michael G. Scott, Regional Manager, shares his wisdom with you."; + static constexpr const char* COPYRIGHT_TAG = "Copyright (c) Micheal Scott Paper Company Pvt. Ltd."; + static constexpr const char* PREFACE = "This is a preface."; + static constexpr const char* ACKNOWLEDGEMENTS = "This is an acknowledgement."; static constexpr const char* class_ = "Book"; static constexpr const char* str_setAuthor = "setAuthor"; + static constexpr const char* str_addPreface = "addPreface"; static constexpr const char* str_setDescription = "setDescription"; static constexpr const char* str_getPublishedOn = "getPublishedOn"; static constexpr const char* str_setPublishedOn = "setPublishedOn"; static constexpr const char* str_updateBookInfo = "updateBookInfo"; + static constexpr const char* str_addCopyrightTag = "addCopyrightTag"; + + static const int get_book_instance_count(); static const bool assert_zero_instance_count(); - static const bool test_method_setAuthor(const std::any& pInstance); + static const bool test_method_setAuthor(const rtl::RObject& pInstance); + + static const bool test_method_addPreface(const rtl::RObject& pInstance); + + static const bool test_method_addCopyrightTag(const rtl::RObject& pInstance); static const bool test_method_getPublishedOn_return(const std::string& pRetStr); - template - static const bool test_method_updateBookInfo(const std::any& pInstance); + template + static const bool test_method_updateBookInfo(const rtl::RObject& pInstance); template - static const bool test_dynamic_alloc_instance_ctor(const std::any& pInstance); + static const bool test_dynamic_alloc_instance_ctor(const rtl::RObject& pInstance); - static const bool test_unique_copy_ctor_const_ref(const std::any& pInstance); + static const bool test_copy_ctor_with_mutated_object(const rtl::RObject& pInstance); }; } \ No newline at end of file diff --git a/CxxTestUtils/inc/TestUtilsDate.h b/CxxTestUtils/inc/TestUtilsDate.h new file mode 100644 index 00000000..8281dc5b --- /dev/null +++ b/CxxTestUtils/inc/TestUtilsDate.h @@ -0,0 +1,63 @@ +#pragma once + +/* +TestUtils provide the interface to test/compare reflected type objects with actual objects (retrived/created using +strict Types) without exposing the actual type objects to "CxxReflectionTests" project. + +Provides interface for Testing/Comparing the class "Date" objects states/returns without exposing the actual type "Date". +*/ + +namespace rtl { + class RObject; +} + +namespace test_utils +{ + struct event + { + static constexpr const char* ns = "nsdate"; + static constexpr const char* struct_ = "Event"; + static constexpr const char* str_getDate = "getDate"; + static constexpr const char* str_reset = "reset"; + + static const bool assert_zero_instance_count(); + static const std::size_t get_instance_count(); + }; + + struct calender + { + static constexpr const char* ns = "nsdate"; + static constexpr const char* struct_ = "Calender"; + static constexpr const char* str_create = "create"; + static constexpr const char* str_getTheDate = "getTheDate"; + static constexpr const char* str_getSavedDate = "getSavedDate"; + static constexpr const char* str_getTheEvent = "getTheEvent"; + static constexpr const char* str_getSavedEvent = "getSavedEvent"; + + static void reset_move_ops_counter(); + static const bool assert_zero_instance_count(); + static const std::size_t get_instance_count(); + static const std::size_t get_move_ops_count(); + }; + + struct date + { + static constexpr const unsigned DAY = 1; + static constexpr const unsigned MONTH = 1; + static constexpr const unsigned YEAR = 2000; + static constexpr const char* DATE_STR0 = "23/12/2024"; + static constexpr const char* DATE_STR1 = "04/05/2025"; + + static constexpr const char* ns = "nsdate"; + static constexpr const char* struct_ = "Date"; + static constexpr const char* str_updateDate = "updateDate"; + static constexpr const char* str_getAsString = "getAsString"; + + static const std::size_t get_instance_count(); + + static const bool test_if_obejcts_are_equal(const rtl::RObject& pInstance0, const rtl::RObject& pInstance1); + + template + static const bool test_dynamic_alloc_instance_ctor(const rtl::RObject& pInstance); + }; +} \ No newline at end of file diff --git a/CxxTypeRegistration/inc/TestUtilsPerson.h b/CxxTestUtils/inc/TestUtilsPerson.h similarity index 68% rename from CxxTypeRegistration/inc/TestUtilsPerson.h rename to CxxTestUtils/inc/TestUtilsPerson.h index 3098b716..dceac2ee 100644 --- a/CxxTypeRegistration/inc/TestUtilsPerson.h +++ b/CxxTestUtils/inc/TestUtilsPerson.h @@ -1,13 +1,17 @@ #pragma once - -#include -#include /* TestUtils provide the interface to test/compare reflected type objects with actual objects (retrived/created using strict Types) without exposing the actual type objects to "CxxReflectionTests" project. Provides interface for Testing/Comparing the class "Person" objects states/returns without exposing the actual type "Person". */ + +#include + +namespace rtl { + class RObject; +} + namespace test_utils { struct person @@ -19,7 +23,9 @@ namespace test_utils static constexpr const char* OCCUPATION = "Private Detective."; static constexpr const char* class_ = "Person"; + static constexpr const char* str_createPtr = "createPtr"; static constexpr const char* str_getProfile = "getProfile"; + static constexpr const char* str_createConst = "createConst"; static constexpr const char* str_getDefaults = "getDefaults"; static constexpr const char* str_getFirstName = "getFirstName"; static constexpr const char* str_updateAddress = "updateAddress"; @@ -29,21 +35,17 @@ namespace test_utils static const std::string get_str_returned_on_call_getDefaults(); - template - static const std::string get_str_returned_on_call_getProfile(const bool pNoAddress = false); - - static const bool test_method_updateLastName(const std::any& pInstance); + static const bool delete_unmanaged_person_instance_created_via_createPtr(const rtl::RObject& pInstance); - static const bool test_method_updateLastName_const(const std::any& pInstance); - - template - static const bool test_method_updateAddress(const std::any& pInstance); + template + static const std::string get_str_returned_on_call_getProfile(const bool pNoAddress = false); - template - static const bool test_method_updateAddress_const(const std::any& pInstance); + static const bool test_method_updateLastName_const(const rtl::RObject& pInstance); - static const bool test_copy_constructor_overload_src_const_obj(const std::any& pInstance); + template + static const bool test_method_updateAddress(const rtl::RObject& pInstance); - static const bool test_copy_constructor_overload_src_non_const_obj(const std::any& pInstance); + template + static const bool test_method_updateAddress_const(const rtl::RObject& pInstance); }; } \ No newline at end of file diff --git a/CxxTestUtils/src/CMakeLists.txt b/CxxTestUtils/src/CMakeLists.txt new file mode 100644 index 00000000..e68f9522 --- /dev/null +++ b/CxxTestUtils/src/CMakeLists.txt @@ -0,0 +1,29 @@ +# CMakeLists.txt for CxxTestUtils +cmake_minimum_required(VERSION 3.20) + +project(CxxTestUtils) + +# Create a variable containing the source files for your target +set(LOCAL_SOURCES + "${CMAKE_CURRENT_LIST_DIR}/Node.cpp" + "${CMAKE_CURRENT_LIST_DIR}/TestUtilsBook.cpp" + "${CMAKE_CURRENT_LIST_DIR}/TestUtilsDate.cpp" + "${CMAKE_CURRENT_LIST_DIR}/TestUtilsPerson.cpp" + "${CMAKE_CURRENT_LIST_DIR}/TestUtilsAnimal.cpp" +) + +SET(LOCAL_HEADERS + "${PROJECT_SOURCE_DIR}/inc/Node.h" + "${PROJECT_SOURCE_DIR}/inc/TestUtilsBook.h" + "${PROJECT_SOURCE_DIR}/inc/TestUtilsDate.h" + "${PROJECT_SOURCE_DIR}/inc/GlobalTestUtils.h" + "${PROJECT_SOURCE_DIR}/inc/TestUtilsPerson.h" + "${PROJECT_SOURCE_DIR}/inc/TestUtilsAnimal.h" +) + +# Add any additional source files if needed +target_sources(CxxTestUtils + PRIVATE + "${LOCAL_SOURCES}" + "${LOCAL_HEADERS}" +) \ No newline at end of file diff --git a/CxxTestUtils/src/Node.cpp b/CxxTestUtils/src/Node.cpp new file mode 100644 index 00000000..ef837b2e --- /dev/null +++ b/CxxTestUtils/src/Node.cpp @@ -0,0 +1,59 @@ + +#include "Node.h" + +namespace test_utils +{ + std::size_t _moveOpsCount = 0; + std::size_t _liveResourceCount = 0; + std::size_t _liveNodeCount = 0; + + Node::~Node() + { + _liveNodeCount--; + if (m_deleter && m_data) { + m_deleter(m_data); + m_data = nullptr; + m_deleter = nullptr; + } + } + + Node::Node(int pData) + : m_data([=]() { + _liveResourceCount++; + return new int(pData); + }()) + , m_deleter([](int* ptr) { + _liveResourceCount--; + delete ptr; + }) { + _liveNodeCount++; + } + + //Node::Node(Node&& pOther) noexcept + // : m_data(pOther.m_data) + // , m_deleter(std::move(pOther.m_deleter)) { + // pOther.m_data = nullptr; + // pOther.m_deleter = nullptr; + // _liveNodeCount++; + // _moveOpsCount++; + //} + + int Node::data() const { + return *m_data; + } + + bool Node::instanceCount() { + return _liveNodeCount; + } + + bool Node::assertResourcesReleased() { + return (_liveResourceCount == 0); + } + + bool Node::getMoveOpsCountAndReset() { + std::size_t count = _moveOpsCount; + _moveOpsCount = 0; + return count; + } +} + diff --git a/CxxTestUtils/src/TestUtilsAnimal.cpp b/CxxTestUtils/src/TestUtilsAnimal.cpp new file mode 100644 index 00000000..36c8e0c9 --- /dev/null +++ b/CxxTestUtils/src/TestUtilsAnimal.cpp @@ -0,0 +1,95 @@ + +#include + +#include "TestUtilsAnimal.h" +#include "Animal.h" +#include "Library.h" + +static auto _= Library::getBooksCount(); + +const bool test_utils::animal::assert_zero_instance_count() +{ + return (Animal::getInstanceCount() == 0); +} + + +template<> +const bool test_utils::animal::test_method_updateZooKeeper(const std::string& pZooKeeper) +{ + std::string zooKeeper = ZOO_KEEPER; + return (pZooKeeper == Animal::updateZooKeeper(zooKeeper)); +} + + +template<> +const bool test_utils::animal::test_method_updateZooKeeper(const std::string& pZooKeeper) +{ + return (pZooKeeper == Animal::updateZooKeeper(ZOO_KEEPER)); +} + + +template<> +const bool test_utils::animal::test_method_updateZooKeeper(const std::string& pZooKeeper) +{ + const std::string zooKeeper = ZOO_KEEPER; + return (pZooKeeper == Animal::updateZooKeeper(zooKeeper)); +} + + +const bool test_utils::animal::test_method_setAnimalName_rvalue_args(const rtl::RObject& pInstance) +{ + if (pInstance.canViewAs()) + { + Animal animal; + animal.setAnimalName(std::string(NAME)); + + const Animal& rAnimal = pInstance.view()->get(); + return (animal == rAnimal); + } + return false; +} + + +const bool test_utils::animal::test_method_setAnimalName_const_lvalue_ref_args(const rtl::RObject& pInstance) +{ + if (pInstance.canViewAs()) + { + Animal animal; + const auto& nameStr = std::string(NAME); + animal.setAnimalName(nameStr); + + const Animal& rAnimal = pInstance.view()->get(); + return (animal == rAnimal); + } + return false; +} + + +const bool test_utils::animal::test_method_setAnimalName_non_const_lvalue_ref_args(const rtl::RObject& pInstance) +{ + if (pInstance.canViewAs()) + { + Animal animal; + auto nameStr = std::string(NAME); + animal.setAnimalName(nameStr); + + const Animal& rAnimal = pInstance.view()->get(); + return (animal == rAnimal); + } + return false; +} + + +const bool test_utils::animal::test_method_const_setAnimalName_const_lvalue_ref_args(const rtl::RObject& pInstance) +{ + if (pInstance.canViewAs()) + { + const Animal animal; + auto nameStr = std::string(NAME); + animal.setAnimalName(nameStr); + + const Animal& rAnimal = pInstance.view()->get(); + return (animal == rAnimal); + } + return false; +} \ No newline at end of file diff --git a/CxxTestUtils/src/TestUtilsBook.cpp b/CxxTestUtils/src/TestUtilsBook.cpp new file mode 100644 index 00000000..771ebf28 --- /dev/null +++ b/CxxTestUtils/src/TestUtilsBook.cpp @@ -0,0 +1,155 @@ + +#include "TestUtilsBook.h" + +#include + +//User defined types. +#include "Book.h" +#include "Library.h" + +using namespace std; +using namespace nsdate; + +namespace test_utils +{ + const bool library::assert_zero_instance_count() + { + return (Library::getInstanceCount() == 0); + } + + const int book::get_book_instance_count() + { + return Book::getInstanceCount(); + } + + const bool book::assert_zero_instance_count() + { + return (Book::getInstanceCount() == 0); + } + + + const bool book::test_method_getPublishedOn_return(const std::string& pRetStr) + { + Book bookObj; + return (bookObj.getPublishedOn() == pRetStr); + } + + + template<> + const bool book::test_dynamic_alloc_instance_ctor<>(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + const auto& rbook = pInstance.view()->get(); + return (Book() == rbook); + } + return false; + } + + + template<> + const bool book::test_dynamic_alloc_instance_ctor(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + const auto& rbook = pInstance.view()->get(); + return (Book(PRICE, TITLE) == rbook); + } + return false; + } + + + const bool book::test_method_setAuthor(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Book book; + book.setAuthor(AUTHOR); + const auto& rbook = pInstance.view()->get(); + return (book == rbook); + } + return false; + } + + const bool book::test_method_addCopyrightTag(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Book book; + book.addCopyrightTag(COPYRIGHT_TAG); + const auto& rbook = pInstance.view()->get(); + return (book == rbook); + } + return false; + } + + + const bool book::test_method_addPreface(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Book book; + book.addPreface(ACKNOWLEDGEMENTS, PREFACE); + const auto& rbook = pInstance.view()->get(); + return (book == rbook); + } + return false; + } + + + template<> + const bool book::test_method_updateBookInfo<>(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Book book; + book.updateBookInfo(); + const auto& rbook = pInstance.view()->get(); + return (book == rbook); + } + return false; + } + + + template<> + const bool book::test_method_updateBookInfo(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Book book; + book.updateBookInfo(TITLE, PRICE, string(AUTHOR)); + const auto& rbook = pInstance.view()->get(); + return (book == rbook); + } + return false; + } + + + template<> + const bool book::test_method_updateBookInfo(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Book book; + book.updateBookInfo(string(AUTHOR), PRICE, TITLE); + const auto& rbook = pInstance.view()->get(); + return (book == rbook); + } + return false; + } + + + const bool test_utils::book::test_copy_ctor_with_mutated_object(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Book obj(PRICE, TITLE); + obj.setAuthor(AUTHOR); + obj.setDescription(DESCRIPTION); + Book copyObj(obj); + const auto& rbook = pInstance.view()->get(); + return (copyObj == rbook); + } + return false; + } +} \ No newline at end of file diff --git a/CxxTestUtils/src/TestUtilsDate.cpp b/CxxTestUtils/src/TestUtilsDate.cpp new file mode 100644 index 00000000..1864d55f --- /dev/null +++ b/CxxTestUtils/src/TestUtilsDate.cpp @@ -0,0 +1,89 @@ + +#include + +//User defined types. +#include "Date.h" +#include "TestUtilsDate.h" + +using namespace std; +using namespace nsdate; + +namespace test_utils +{ + const bool calender::assert_zero_instance_count() + { + return (Calender::instanceCount() == 0); + } + + const std::size_t calender::get_instance_count() + { + return Calender::instanceCount(); + } + + void calender::reset_move_ops_counter() + { + Calender::resetMoveOpsCounter(); + } + + const std::size_t calender::get_move_ops_count() + { + return Calender::getMoveOpsCount(); + } + + const bool event::assert_zero_instance_count() + { + return (Event::instanceCount() == 0); + } + + const std::size_t event::get_instance_count() + { + return Event::instanceCount(); + } + + const std::size_t date::get_instance_count() + { + return Date::instanceCount(); + } + + const bool date::test_if_obejcts_are_equal(const rtl::RObject& pInstance0, const rtl::RObject& pInstance1) + { + if (pInstance0.canViewAs() && pInstance1.canViewAs()) + { + const Date& rdate0 = pInstance0.view()->get(); + const Date& rdate1 = pInstance1.view()->get(); + return (rdate0 == rdate1); + } + return false; + } + + template<> + const bool date::test_dynamic_alloc_instance_ctor<>(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) { + const Date& rdate = pInstance.view()->get(); + return (Date() == rdate); + } + return false; + } + + template<> + const bool date::test_dynamic_alloc_instance_ctor(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) { + const Date& rdate = pInstance.view()->get(); + return (Date(DATE_STR0) == rdate); + } + return false; + } + + + template<> + const bool date::test_dynamic_alloc_instance_ctor(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) { + const Date& rdate = pInstance.view()->get(); + return (Date(DAY, MONTH, YEAR) == rdate); + } + return false; + } +} \ No newline at end of file diff --git a/CxxTestUtils/src/TestUtilsPerson.cpp b/CxxTestUtils/src/TestUtilsPerson.cpp new file mode 100644 index 00000000..eb4ab982 --- /dev/null +++ b/CxxTestUtils/src/TestUtilsPerson.cpp @@ -0,0 +1,125 @@ + +#include "TestUtilsPerson.h" + +#include + +//User defined types. +#include "Person.h" + +using namespace std; +namespace test_utils +{ + const bool person::assert_zero_instance_count() + { + return (Person::getInstanceCount() == 0); + } + + + const string person::get_str_returned_on_call_getDefaults() + { + return Person::getDefaults(); + } + + + template<> + const std::string person::get_str_returned_on_call_getProfile(const bool pNoAddress) + { + return Person::getProfile(); + } + + + template<> + const std::string person::get_str_returned_on_call_getProfile(const bool pNoAddress) + { + return Person::getProfile(pNoAddress); + } + + + template<> + const std::string person::get_str_returned_on_call_getProfile(const bool pNoAddress) + { + return Person::getProfile(OCCUPATION, AGE); + } + + + const bool person::test_method_updateLastName_const(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + const Person person(FIRST_NAME); + person.updateLastName(LAST_NAME); + const Person& rPerson = pInstance.view()->get(); + return (person == rPerson); + } + return false; + + } + + + template<> + const bool person::test_method_updateAddress(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Person person(FIRST_NAME); + person.updateAddress(ADDRESS); + const Person& rPerson = pInstance.view()->get(); + return (person == rPerson); + } + return false; + } + + + const bool person::delete_unmanaged_person_instance_created_via_createPtr(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + const Person& rPerson = pInstance.view()->get(); + Person::deletePtr(&rPerson); + return true; + } + return false; + } + + + template<> + const bool person::test_method_updateAddress_const(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + const Person person(FIRST_NAME); + person.updateAddress(ADDRESS); + const Person& rPerson = pInstance.view()->get(); + return (person == rPerson); + } + return false; + } + + + template<> + const bool person::test_method_updateAddress<>(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + Person person(FIRST_NAME); + person.updateAddress(); + const Person& rPerson = pInstance.view()->get(); + return (person == rPerson); + } + return false; + } + + + template<> + const bool person::test_method_updateAddress_const<>(const rtl::RObject& pInstance) + { + if (pInstance.canViewAs()) + { + const Person person(FIRST_NAME); + person.updateAddress(); + const Person& rPerson = pInstance.view()->get(); + return (person == rPerson); + } + return false; + } +} \ No newline at end of file diff --git a/CxxTypeRegistration/CMakeLists.txt b/CxxTypeRegistration/CMakeLists.txt deleted file mode 100644 index 51bfcbeb..00000000 --- a/CxxTypeRegistration/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# CMakeLists.txt for CxxTypeRegistration - -# Set the minimum required CMake version -cmake_minimum_required(VERSION 3.20) - -# Set the project name -project(CxxTypeRegistration) - -set(CMAKE_CXX_STANDARD 20) - -SET(CXX_LIB_NAME CxxTypeRegistration) - -ADD_LIBRARY(${PROJECT_NAME} STATIC "") - -INCLUDE_DIRECTORIES(inc) -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/CxxTestProject/inc") -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib/common") -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib/detail/inc") -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib/access/inc") -INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/ReflectionTemplateLib/builder/inc") - -#TARGET_LINK_LIBRARIES(${CXX_EXE_NAME} CxxTestProject) -TARGET_LINK_LIBRARIES(${CXX_EXE_NAME} ReflectionTemplateLib) - -# Add the source directory -INCLUDE(src/CMakeLists.txt) \ No newline at end of file diff --git a/CxxTypeRegistration/inc/MyReflection.h b/CxxTypeRegistration/inc/MyReflection.h deleted file mode 100644 index 9e594119..00000000 --- a/CxxTypeRegistration/inc/MyReflection.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "RTLibInterface.h" - -struct MyReflection -{ - static rtl::access::CxxMirror& instance(); -}; diff --git a/CxxTypeRegistration/inc/TestUtilsDate.h b/CxxTypeRegistration/inc/TestUtilsDate.h deleted file mode 100644 index 48e4dfb6..00000000 --- a/CxxTypeRegistration/inc/TestUtilsDate.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -/* -TestUtils provide the interface to test/compare reflected type objects with actual objects (retrived/created using -strict Types) without exposing the actual type objects to "CxxReflectionTests" project. - -Provides interface for Testing/Comparing the class "Date" objects states/returns without exposing the actual type "Date". -*/ -namespace test_utils -{ - struct calender - { - static constexpr const char* ns = "nsdate"; - static constexpr const char* struct_ = "Calender"; - static const bool assert_zero_instance_count(); - }; - - struct date - { - static constexpr const unsigned DAY = 1; - static constexpr const unsigned MONTH = 1; - static constexpr const unsigned YEAR = 2000; - static constexpr const char* DATE_STR = "23/12/2024"; - - static constexpr const char* ns = "nsdate"; - static constexpr const char* struct_ = "Date"; - - static const bool assert_zero_instance_count(); - - template - static const bool test_dynamic_alloc_instance_ctor(const std::any& pInstance); - }; -} \ No newline at end of file diff --git a/CxxTypeRegistration/inc/TestUtilsGlobals.h b/CxxTypeRegistration/inc/TestUtilsGlobals.h deleted file mode 100644 index 5cf78635..00000000 --- a/CxxTypeRegistration/inc/TestUtilsGlobals.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -/* -TestUtils provide the interface to test/compare reflected type objects with actual objects (retrived/created using -strict Types) without exposing the actual type objects to "CxxReflectionTests" project. - -Provides interface for Testing/Comparing the global functions & types (may or not be in some namespace) without exposing their actual implementation. -*/ -namespace test_utils { - - extern const char* REV_STR_VOID_RET; - - static constexpr double g_real = 3.92; - static constexpr double g_imaginary = 9.27; - - static constexpr const char* STRA = "ReflectC++"; - static constexpr const char* STRA_REVERSE = "++CtcelfeR"; - - static constexpr const char* STRB = "cxxReflection"; - static constexpr const char* STRB_REVERSE = "noitcelfeRxxc"; - - static constexpr const char* str_reverseString = "reverseString"; - static constexpr const char* str_getComplexNumAsString = "getComplexNumAsString"; - - static constexpr const char* str_complex = "complex"; - static constexpr const char* str_setReal = "setReal"; - static constexpr const char* str_setImaginary = "setImaginary"; - static constexpr const char* str_getMagnitude = "getMagnitude"; - -} \ No newline at end of file diff --git a/CxxTypeRegistration/src/CMakeLists.txt b/CxxTypeRegistration/src/CMakeLists.txt deleted file mode 100644 index b1803ca6..00000000 --- a/CxxTypeRegistration/src/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# CMakeLists.txt for CxxTypeRegistration -cmake_minimum_required(VERSION 3.20) - -project(CxxTypeRegistration) - -# Create a variable containing the source files for your target -set(LOCAL_SOURCES - "${CMAKE_CURRENT_LIST_DIR}/MyReflection.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TestUtilsBook.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TestUtilsDate.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TestUtilsPerson.cpp" - "${CMAKE_SOURCE_DIR}/CxxTestProject/src/Book.cpp" - "${CMAKE_SOURCE_DIR}/CxxTestProject/src/Complex.cpp" - "${CMAKE_SOURCE_DIR}/CxxTestProject/src/Date.cpp" - "${CMAKE_SOURCE_DIR}/CxxTestProject/src/Person.cpp" -) - -SET(LOCAL_HEADERS - "${PROJECT_SOURCE_DIR}/inc/MyReflection.h" - "${PROJECT_SOURCE_DIR}/inc/TestUtilsBook.h" - "${PROJECT_SOURCE_DIR}/inc/TestUtilsDate.h" - "${PROJECT_SOURCE_DIR}/inc/TestUtilsGlobals.h" - "${PROJECT_SOURCE_DIR}/inc/TestUtilsPerson.h" - "${CMAKE_SOURCE_DIR}/CxxTestProject/inc/Book.h" - "${CMAKE_SOURCE_DIR}/CxxTestProject/inc/Complex.h" - "${CMAKE_SOURCE_DIR}/CxxTestProject/inc/Date.h" - "${CMAKE_SOURCE_DIR}/CxxTestProject/inc/Person.h" -) - -# Add any additional source files if needed -target_sources(CxxTypeRegistration - PRIVATE - "${LOCAL_SOURCES}" - "${LOCAL_HEADERS}" -) \ No newline at end of file diff --git a/CxxTypeRegistration/src/MyReflection.cpp b/CxxTypeRegistration/src/MyReflection.cpp deleted file mode 100644 index 99d015d0..00000000 --- a/CxxTypeRegistration/src/MyReflection.cpp +++ /dev/null @@ -1,91 +0,0 @@ - -#include - -#include "MyReflection.h" -#include "CxxMirrorToJson.h" - -//User defined types to be reflected. -#include "Date.h" -#include "Book.h" -#include "Person.h" -#include "Complex.h" - -/* -TestUtils, provides the interface to test/compare reflected type objects with actual objects (created via strict typing) -without exposing the actual type objects to "CxxReflectionTests" project.*/ -#include "TestUtilsBook.h" -#include "TestUtilsDate.h" -#include "TestUtilsPerson.h" -#include "TestUtilsGlobals.h" - - -using namespace std; -using namespace test_utils; -using namespace rtl::access; -using namespace rtl::builder; - -CxxMirror& MyReflection::instance() -{ - static CxxMirror cxxMirror = CxxMirror({ - - //global functions, not contained in any namespace. - Reflect().function(str_reverseString).build(reverseString), //function taking no arguments. '' must be specified if other overload exists else not needed. compiler error otherwise. - Reflect().function(str_reverseString).build(reverseString), //overloaded function, takes 'string' arguments. '' must be specified as template parameter. - Reflect().function(str_reverseString).build(reverseString), //overloaded function, takes 'const char*' arguments. - Reflect().function(str_getComplexNumAsString).build(getComplexNumAsString), //unique function, no overloads, no need to specify signature as template parameters. - - /* Grouping functions under a namespace, which is optional. they can be registered without it as well. - but if registered under namspace, then to retrieve it from CxxMirror object, namespace name must be passed, - ex - cxxMirror.getFunction("namespace_name", "function_name") & cxxMirror.getRecord("namespace_name", "record_name") - */ Reflect().nameSpace(str_complex).function(str_setReal).build(complex::setReal), - Reflect().nameSpace(str_complex).function(str_setImaginary).build(complex::setImaginary), - Reflect().nameSpace(str_complex).function(str_getMagnitude).build(complex::getMagnitude), - - //Constructors registration, class/struct name and type must be passed 'record("NAME")'. - Reflect().nameSpace(date::ns).record(date::struct_).constructor().build(), //default constructor. Destructor gets registered automatically if any constructor is registered. - Reflect().nameSpace(date::ns).record(date::struct_).constructor().build(), //overloaded constructor, taking 'string' as argument, must be specified as template param. - Reflect().nameSpace(date::ns).record(date::struct_).constructor().build(), //again, the overloaded constructor. - Reflect().nameSpace(date::ns).record(date::struct_).constructor().build(), //Copy constructor, taking non-const ref as argument. - - //class Calender, default constructor. Instances will always be created on heap and managed using shared_ptr. - Reflect().nameSpace(calender::ns).record(calender::struct_).constructor().build(), - Reflect().record(library::class_).methodStatic(library::str_addBook).build(&Library::addBook), //Static method registration, 'methodStatic()' function must be used. compiler error otherwise. - - //class 'Book', methods & constructors. - Reflect().record(book::class_).constructor().build(), - Reflect().record(book::class_).constructor().build(), //copy constructor, taking const-ref. - Reflect().record(book::class_).constructor().build(), - Reflect().record(book::class_).method(book::str_setAuthor).build(&Book::setAuthor), //unique methods, no overloads. - Reflect().record(book::class_).method(book::str_setDescription).build(&Book::setDescription), - Reflect().record(book::class_).method(book::str_getPublishedOn).build(&Book::getPublishedOn), - Reflect().record(book::class_).method(book::str_updateBookInfo).build(&Book::updateBookInfo), //method overloading, '' must be specified since other overloads exists. - Reflect().record(book::class_).method(book::str_updateBookInfo).build(&Book::updateBookInfo), - Reflect().record(book::class_).method(book::str_updateBookInfo).build(&Book::updateBookInfo), - - //class 'Person', methods & constructors. - Reflect().record(person::class_).constructor().build(), - Reflect().record(person::class_).constructor().build(), - Reflect().record(person::class_).constructor().build(), //copy constructor taking non-const ref argument. - Reflect().record(person::class_).constructor().build(), //copy constructor taking const ref argument. - Reflect().record(person::class_).method(person::str_updateAddress).build(&Person::updateAddress), - Reflect().record(person::class_).method(person::str_updateAddress).build(&Person::updateAddress), - Reflect().record(person::class_).methodConst(person::str_getFirstName).build(&Person::getFirstName), - Reflect().record(person::class_).methodConst(person::str_updateLastName).build(&Person::updateLastName), //const method registration, 'methodConst()' function must be used. compiler error otherwise. - Reflect().record(person::class_).methodConst(person::str_updateAddress).build(&Person::updateAddress), - Reflect().record(person::class_).methodConst(person::str_updateAddress).build(&Person::updateAddress), //overloaded method based on 'const'. - Reflect().record(person::class_).methodStatic(person::str_getDefaults).build(&Person::getDefaults), - Reflect().record(person::class_).methodStatic(person::str_getProfile).build(&Person::getProfile), - Reflect().record(person::class_).methodStatic(person::str_getProfile).build(&Person::getProfile), - Reflect().record(person::class_).methodStatic(person::str_getProfile).build(&Person::getProfile) - }); - - - static bool dumped = false; - if (!dumped) { - const std::string pathStr = std::filesystem::current_path().string() + "/MyReflection.json"; - rtl::CxxMirrorToJson::dump(cxxMirror, pathStr); - dumped = true; - } - - return cxxMirror; -} \ No newline at end of file diff --git a/CxxTypeRegistration/src/TestUtils.cpp b/CxxTypeRegistration/src/TestUtils.cpp deleted file mode 100644 index 9c63bf44..00000000 --- a/CxxTypeRegistration/src/TestUtils.cpp +++ /dev/null @@ -1,99 +0,0 @@ - -#include - -#include "TestUtils.h" -#include "RObject.hpp" - -//User defined types. -#include "Date.h" -#include "Book.h" - -using namespace std; -using namespace nsdate; -using namespace rtl::access; - -namespace test_utils -{ - const bool date::assert_zero_instance_count() - { - return (Date::instanceCount() == 0); - } - - template<> - const bool date::test_new_instance_ctor(const unique_ptr& pInstance) - { - optional robj = pInstance->get(); - if (!robj.has_value()) { - return false; - } - - Date dateObj(DATE_STR); - Date& dateRObj = *(robj.value()); - - return (dateObj == dateRObj); - } - - template<> - const bool date::test_new_instance_ctor<>(const unique_ptr& pInstance) - { - optional robj = pInstance->get(); - if (!robj.has_value()) { - return false; - } - - Date dateObj; - Date& dateRObj = *(robj.value()); - - return (dateObj == dateRObj); - } - - template<> - const bool date::test_new_instance_ctor(const unique_ptr& pInstance) - { - optional robj = pInstance->get(); - if (!robj.has_value()) { - return false; - } - - Date dateObj(day, month, year); - Date& dateRObj = *(robj.value()); - - return (dateObj == dateRObj); - } - - - const bool book::assert_zero_instance_count() - { - return (Book::getInstanceCount() == 0); - } - - - template<> - const bool book::test_new_instance_ctor<>(const std::unique_ptr& pInstance) - { - optional robj = pInstance->get(); - if (!robj.has_value()) { - return false; - } - - Book bookObj; - Book& bookRObj = *(robj.value()); - - return (bookObj == bookRObj); - } - - - template<> - const bool book::test_new_instance_ctor(const std::unique_ptr& pInstance) - { - optional robj = pInstance->get(); - if (!robj.has_value()) { - return false; - } - - Book bookObj(PRICE, TITLE); - Book& bookRObj = *(robj.value()); - - return (bookObj == bookRObj); - } -} \ No newline at end of file diff --git a/CxxTypeRegistration/src/TestUtilsBook.cpp b/CxxTypeRegistration/src/TestUtilsBook.cpp deleted file mode 100644 index 329c4821..00000000 --- a/CxxTypeRegistration/src/TestUtilsBook.cpp +++ /dev/null @@ -1,116 +0,0 @@ - -#include "TestUtilsBook.h" - -//User defined types. -#include "Book.h" - -using namespace std; -using namespace nsdate; - -namespace test_utils -{ - const bool book::assert_zero_instance_count() - { - return (Book::getInstanceCount() == 0); - } - - - const bool book::test_method_getPublishedOn_return(const std::string& pRetStr) - { - Book bookObj; - return (bookObj.getPublishedOn() == pRetStr); - } - - - template<> - const bool book::test_dynamic_alloc_instance_ctor<>(const any& pInstance) - { - Book* rbook = any_cast(pInstance); - if (rbook == nullptr) { - return false; - } - return (Book() == *rbook); - } - - - template<> - const bool book::test_dynamic_alloc_instance_ctor(const any& pInstance) - { - Book* rbook = any_cast(pInstance); - if (rbook == nullptr) { - return false; - } - return (Book(PRICE, TITLE) == *rbook); - } - - - const bool book::test_method_setAuthor(const any& pInstance) - { - Book* rbook = any_cast(pInstance); - if (rbook == nullptr) { - return false; - } - - Book book; - book.setAuthor(AUTHOR); - return (book == *rbook); - } - - - template<> - const bool book::test_method_updateBookInfo<>(const any& pInstance) - { - Book* rbook = any_cast(pInstance); - if (rbook == nullptr) { - return false; - } - - Book book; - book.updateBookInfo(); - return (book == *rbook); - } - - - template<> - const bool book::test_method_updateBookInfo(const any& pInstance) - { - Book* rbook = any_cast(pInstance); - if (rbook == nullptr) { - return false; - } - - Book book; - book.updateBookInfo(TITLE, PRICE, string(AUTHOR)); - return (book == *rbook); - } - - - template<> - const bool book::test_method_updateBookInfo(const any& pInstance) - { - Book* rbook = any_cast(pInstance); - if (rbook == nullptr) { - return false; - } - - Book book; - book.updateBookInfo(string(AUTHOR), PRICE, TITLE); - return (book == *rbook); - } - - - const bool book::test_unique_copy_ctor_const_ref(const std::any& pInstance) - { - Book* rbook = any_cast(pInstance); - if (rbook == nullptr) { - return false; - } - - Book obj(PRICE, TITLE); - obj.setAuthor(AUTHOR); - obj.setDescription(DESCRIPTION); - - Book copyObj(obj); - return (copyObj == *rbook); - } -} \ No newline at end of file diff --git a/CxxTypeRegistration/src/TestUtilsDate.cpp b/CxxTypeRegistration/src/TestUtilsDate.cpp deleted file mode 100644 index bda51667..00000000 --- a/CxxTypeRegistration/src/TestUtilsDate.cpp +++ /dev/null @@ -1,53 +0,0 @@ - -#include "TestUtilsDate.h" - -//User defined types. -#include "Date.h" - -using namespace std; -using namespace nsdate; - -namespace test_utils -{ - const bool calender::assert_zero_instance_count() - { - return (Calender::instanceCount() == 0); - } - - const bool date::assert_zero_instance_count() - { - return (Date::instanceCount() == 0); - } - - template<> - const bool date::test_dynamic_alloc_instance_ctor<>(const any& pInstance) - { - Date* rdate = any_cast(pInstance); - if (rdate == nullptr) { - return false; - } - return (Date() == *rdate); - } - - - template<> - const bool date::test_dynamic_alloc_instance_ctor(const any& pInstance) - { - Date* rdate = any_cast(pInstance); - if (rdate == nullptr) { - return false; - } - return (Date(DATE_STR) == *rdate); - } - - - template<> - const bool date::test_dynamic_alloc_instance_ctor(const any& pInstance) - { - Date* rdate = any_cast(pInstance); - if (rdate == nullptr) { - return false; - } - return (Date(DAY, MONTH, YEAR) == *rdate); - } -} \ No newline at end of file diff --git a/CxxTypeRegistration/src/TestUtilsPerson.cpp b/CxxTypeRegistration/src/TestUtilsPerson.cpp deleted file mode 100644 index 002439df..00000000 --- a/CxxTypeRegistration/src/TestUtilsPerson.cpp +++ /dev/null @@ -1,154 +0,0 @@ - -#include "TestUtilsPerson.h" - -//User defined types. -#include "Person.h" - -using namespace std; -namespace test_utils -{ - const bool person::assert_zero_instance_count() - { - return (Person::getInstanceCount() == 0); - } - - - const string person::get_str_returned_on_call_getDefaults() - { - return Person::getDefaults(); - } - - - template<> - const std::string person::get_str_returned_on_call_getProfile(const bool pNoAddress) - { - return Person::getProfile(); - } - - - template<> - const std::string person::get_str_returned_on_call_getProfile(const bool pNoAddress) - { - return Person::getProfile(pNoAddress); - } - - - template<> - const std::string person::get_str_returned_on_call_getProfile(const bool pNoAddress) - { - return Person::getProfile(OCCUPATION, AGE); - } - - - const bool person::test_method_updateLastName(const std::any& pInstance) - { - Person* rPerson = any_cast(pInstance); - if (rPerson == nullptr) { - return false; - } - - Person person(FIRST_NAME); - person.updateLastName(LAST_NAME); - return (person == *rPerson); - } - - - const bool person::test_method_updateLastName_const(const std::any& pInstance) - { - //instance created via reflection will always hold non-const pointer only. const(or not) is maintained internally to call appropriate method. - Person* rPerson = any_cast(pInstance); - if (rPerson == nullptr) { - return false; - } - - const Person person(FIRST_NAME); - person.updateLastName(LAST_NAME); - return (person == *rPerson); - } - - const bool person::test_copy_constructor_overload_src_const_obj(const std::any& pInstance) - { - //instance created via reflection will always hold non-const pointer only. const(or not) is maintained internally to call appropriate method. - Person* rPerson = any_cast(pInstance); - if (rPerson == nullptr) { - return false; - } - - const Person personSrc; - Person person(personSrc); - return (person == *rPerson); - } - - const bool person::test_copy_constructor_overload_src_non_const_obj(const std::any& pInstance) - { - //instance created via reflection will always hold non-const pointer only. const(or not) is maintained internally to call appropriate method. - Person* rPerson = any_cast(pInstance); - if (rPerson == nullptr) { - return false; - } - - Person personSrc; - Person person(personSrc); - return (person == *rPerson); - } - - - template<> - const bool person::test_method_updateAddress(const std::any& pInstance) - { - //instance created via reflection will always hold non-const pointer only. const(or not) is maintained internally to call appropriate method. - Person* rPerson = any_cast(pInstance); - if (rPerson == nullptr) { - return false; - } - - Person person(FIRST_NAME); - person.updateAddress(ADDRESS); - return (person == *rPerson); - } - - - template<> - const bool person::test_method_updateAddress_const(const std::any& pInstance) - { - //instance created via reflection will always hold non-const pointer only. const(or not) is maintained internally to call appropriate method. - Person* rPerson = any_cast(pInstance); - if (rPerson == nullptr) { - return false; - } - - const Person person(FIRST_NAME); - person.updateAddress(ADDRESS); - return (person == *rPerson); - } - - - template<> - const bool person::test_method_updateAddress<>(const std::any& pInstance) - { - //instance created via reflection will always hold non-const pointer only. const(or not) is maintained internally to call appropriate method. - Person* rPerson = any_cast(pInstance); - if (rPerson == nullptr) { - return false; - } - - Person person(FIRST_NAME); - person.updateAddress(); - return (person == *rPerson); - } - - - template<> - const bool person::test_method_updateAddress_const<>(const std::any& pInstance) - { - //instance created via reflection will always hold non-const pointer only. const(or not) is maintained internally to call appropriate method. - Person* rPerson = any_cast(pInstance); - if (rPerson == nullptr) { - return false; - } - - const Person person(FIRST_NAME); - person.updateAddress(); - return (person == *rPerson); - } -} \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE similarity index 93% rename from LICENSE.txt rename to LICENSE index 6337bd93..32a642d9 100644 --- a/LICENSE.txt +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2024 Neeraj Singh (neeraj.singh31285@outlook.com) +Copyright (c) 2026 Neeraj Singh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/README.md b/README.md index 27d0ee54..b7d41f4a 100644 --- a/README.md +++ b/README.md @@ -1,162 +1,222 @@ -# Reflection Template Library C++ +# Reflection Template Library (RTL) – A Run-Time Reflection System for C++. + +[![License: MIT](https://img.shields.io/badge/License-MIT-2EA44F?logo=open-source-initiative&logoColor=white)](LICENSE) +  +[![CMake](https://img.shields.io/badge/CMake-Enabled-064F8C?logo=cmake&logoColor=white)](https://cmake.org) +  +[![C++20](https://img.shields.io/badge/C%2B%2B-20-00599C?logo=c%2B%2B&logoColor=white)](https://isocpp.org) +  +[![Build](https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP/actions/workflows/build.yml/badge.svg?branch=release)](https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP/actions/workflows/build.yml?query=branch%3Arelease) +  +[![Codecov](https://codecov.io/gh/ReflectCxx/ReflectionTemplateLibrary-CPP/branch/release/graph/badge.svg)](https://codecov.io/gh/ReflectCxx/ReflectionTemplateLibrary-CPP) +  +[![Try RTL Online](https://img.shields.io/badge/Try-RTL%20Online-f48024?logo=github&logoColor=white)](https://github.com/codespaces/new?repo=ReflectCxx/RTL-Demo&quickstart=1) + +RTL provides type-safe run-time reflection for C++, combining compile-time guarantees with run-time flexibility. + +It enables name-based discovery and invocation of functions, constructors, and object members through a non-intrusive, type-safe reflection system that follows modern C++ idioms. For example, consider the following function: +```c++ +std::string complexToStr(float real, float img); +``` +Using RTL, you can discover this function by name and call it dynamically: +```c++ +rtl::function cToStr = cxx::mirror().getFunction("complexToStr") + ->argsT() + .returnT(); +if(cToStr) { // Function materialized? + std::string result = cToStr(61, 35); // Works! +} +// cxx::mirror() returns an instance of 'rtl::CxxMirror' (explained in Quick-Preview section) +``` +> *No compile-time coupling to target symbols. No unsafe casting. No guesswork. Just run-time lookup and type-safe invocation.* -The **Reflection Template Library for C++** enables introspection of user-defined types, allowing modification of objects at runtime without needing to know their actual types at compile time. +⚡ **Performance** -Static library, the core design maintains several tables of function pointers(registered by the user) wrapped in lambdas and providing a mechanism to access at runtime. +RTL’s reflective calls are comparable to `std::function`, and achieve lower overhead when argument and return types are fully specified. -## Key Features +## Design Highlights -- **Builder Pattern**: Manual registration of types is simple and intuitive, with no mysterious macros involved. -- **Clean Code**: No reflection-related code needs to be added to class, struct, or function declarations or implementations— keeping your codebase clean and free of clutter. -- **Centralized Registration**: Manage all manual registrations in a single implementation unit, separate from the rest of your project code. -- **Simple Integration**: Just create an instance of `CxxMirror`, pass all type information to reflect as a constructor parameter, and you’re done! - ```c++ - rtl::CxxMirror cxxReflection({/*.. Pass all type information ..*/}); - ``` - The *cxxReflection* object provides interface to query and instantiate registered types. -- **Thread-Safe & Exception-Safe**: The library is designed to be thread-safe and exception-safe, providing error codes on possible failures to ensure robust operation. -- **Automatic Code Generation**: To generate manual registration code automatically, `clang-reflect` can be used. It is a work-in-progress tool available here: *https://github.com/ReflectCxx/clang-reflect*. This tool will generate registration code for any large project without requiring changes to your project’s code. +* ***Single Source of Truth*** – All reflection metadata can be centralized in a single immutable `rtl::CxxMirror`, providing a consistent, thread-safe, duplication-free, and deterministic view of reflected state. -## How To build (Windows/Linux), +* ***Non-Intrusive & Macro-Free*** – Reflection metadata is registered externally via a builder-style API, with no macros, base classes, or intrusive annotations required on user types. -Create a build directory in project root folder. -```sh - mkdir build && cd build -``` -Generate a build system using **Unix Makefiles** or **Visual Studio**, in CMake. (Use compiler with C++20) -```sh - cmake -G "" -``` -to build, any IDE applicable to the generator can be used or you can also just build straight from CMake. -```sh - cmake --build . +* ***Zero-Overhead by Design*** – Metadata can be registered and resolved lazily. Reflection introduces no runtime cost beyond the features explicitly exercised by the user. + +* ***Hot-Loop Ready*** – Typed reflection calls exhibit near-zero overhead and scale like direct calls, making RTL suitable for performance-critical and tight-loop workloads. *([Performance Summary](docs/benchmark_summary.md))* + +* ***Tooling-Friendly Architecture*** – Reflection metadata is encapsulated in a single immutable, lazily-initialized structure that can be shared with external tools and frameworks without compile-time type knowledge – suitable for serializers, debuggers, test frameworks, scripting engines, and editors. + +## A Quick Preview: Reflection That Looks and Feels Like C++ + +First, create an instance of `rtl::CxxMirror`: +```c++ +auto cxx_mirror = rtl::CxxMirror({ /* ...register all types here... */ }); ``` -Run **CxxReflectionTests** binary, generated in ../bin folder. *(tested on windows and Ubuntu-20)* -## How To Use, -In this example, we'll reflect a simple Person class. `Person.h`, +The `cxx_mirror` object provides access to the runtime reflection system. It references metadata for all registered entities and supports name-based lookup. The object may reside in any translation unit. To make it globally accessible while ensuring lazy initialization, a singleton access interface can be used: ```c++ -class Person { - int age; - std::string name; - -public: - Person(); - Person(std::string, int); - - void setAge(int); - void setName(std::string); - - int getAge() const; - std::string getName() const; -}; +// MyReflection.h +namespace rtl { class CxxMirror; } // Forward declaration, no includes here. +struct cxx { static rtl::CxxMirror& mirror(); }; // The singleton interface. ``` -### Step 1: Register the Class with 'CxxMirror' -Manually register the class and its members when creating a **`CxxMirror`** object. +define and register everything in an isolated translation unit: ```c++ -#include "CxxMirrorBuilder.h" // Provides registration interface. -#include "Person.h" // User-defined types to be reflected. - -using namespace rtl; - -const CxxMirror& MyReflection() -{ - static const CxxMirror cxxMirror({ - // Register member functions - Reflect().record("Person").method("setAge").build(&Person::setAge), - Reflect().record("Person").method("getAge").build(&Person::getAge), - Reflect().record("Person").method("setName").build(&Person::setName), - Reflect().record("Person").method("getName").build(&Person::getName), - - // Register constructors - Reflect().record("Person").constructor().build(), // Default constructor - Reflect().record("Person").constructor().build() // Constructor with parameters +// MyReflection.cpp +rtl::CxxMirror& cxx::mirror() { + static auto cxx_mirror = rtl::CxxMirror({ // Inherently thread safe. + // Register free(C-Style) function - + rtl::type().function("complexToStr").build(complexToStr), + // Register class 'Person' ('record' is general term used for 'struct/class') - + rtl::type().record("Person").build(), // Registers default/copy ctor as well. + // Register user defined ctor - + rtl::type().member().constructor().build(), + // Register method - + rtl::type().member().method("getName").build(&Person::getName) }); - - return cxxMirror; + return cxx_mirror; } ``` -Registration syntax, +### RTL in action: + +Lookup the `Person` class by its registered name: +```c++ +std::optional classPerson = cxx::mirror().getRecord("Person"); +if (!classPerson) { /* Class not registered. */ } +``` +`rtl::CxxMirror` returns two reflection metadata objects: `rtl::Record` for any registered type (class, struct, or POD) and `rtl::Function` for non-member functions. + +From `rtl::Record`, registered member functions can be obtained as `rtl::Method`. These are metadata descriptors (not callables). Callable entities are materialized by explicitly providing the argument types we intend to pass. + +For example, the overloaded constructor `Person(std::string, int)`: +```c++ +rtl::constructor personCtor = classPerson->ctorT(); +``` +Or the default constructor: +```c++ +rtl::constructor<> personCtor = classPerson->ctorT<>(); +``` +Instances can be created on the `Heap` or `Stack` with automatic lifetime management: +```c++ +auto [err, robj] = personCtor(rtl::alloc::Stack, "John", 42); +if (err != rtl::error::None) { std::cerr << rtl::to_string(err); } // Construction failed. +``` +The constructed object is returned as an `rtl::RObject` in the variable `robj`. + +Looking up a member function by name: +```c++ +std::optional oGetName = classPerson->getMethod("getName"); +if (!oGetName) { /* Member function not registered */ } +``` +And materialize a complete type-aware caller: ```c++ -Reflect().nameSpace("..") // Optional: specify namespace if the type is enclosed in one. - .record<..>("..") // Register class/struct type (template parameter) and its name (string). - .method("..") // Register function by name. - .build(*); // Pass function pointer. - -Reflect().nameSpace("..") - .record<..>("..") - .constructor<..>() // Register constructor with template parameters as signature. - .build<..>(); // No function pointer needed for constructors. +rtl::method getName = oGetName->targetT().argsT() + .returnT(); +if (!getName) { // Member function with expected signature not found. + std::cerr << rtl::to_string(getName.get_init_err()); +} +else { + Person person("Alex", 23); + std::string nameStr = getName(person)(); // Returns string 'Alex'. +} ``` -### Step 2: Use the 'Person' Class via Reflection -In main.cpp, use the **`Person`** class without directly exposing its type. +The above `getName` invocation is effectively a **native function-pointer hop**, since all types are known at compile time. + +If the concrete type `Person` is not accessible at the call site, its member functions can still be invoked by erasing the target type and using `rtl::RObject` instead. The previously constructed instance (`robj`) is passed as the target: ```c++ -#include "RTLibInterface.h" // Single header including reflection access interface. -extern const rtl::CxxMirror& MyReflection(); - -int main() -{ - // Get 'class Person', Returns 'Record' object associated with 'class Person' - std::optional classPerson = MyReflection().getClass("Person"); - - /* Create an instance of 'class Person' via reflection using the default constructor. - Returns 'RStatus' and 'Instance' objects. - */ auto [status, personObj] = classPerson->instance(); - +rtl::method getName = oGetName->targetT().argsT() + .returnT(); +auto [err, ret] = getName(robj)(); // Invoke and receive return as std::optional. +if (err == rtl::error::None && ret.has_value()) { + std::string nameStr = ret.value(); +} ``` -- `RStatus` provides an error code `(rtl::Error)` that indicates the success or failure of the reflection call, and it also contains the return value (if any) wrapped in `std::any`. -- `Instance` holds the created object (with its type erased), managed on the heap using `std::shared_ptr`. +If the return type is also not known at compile time,`rtl::Return` can be used: ```c++ +rtl::method getName = oGetName->targetT().argsT().returnT(); - /* Create an instance via reflection using a parameterized constructor. - Argument types/order must match else call will fail, returning error-code in 'status'. - */ auto [status, personObj] = classPerson->instance(std::string("John Doe"), int(42)); +auto [err, ret] = getName(robj)(); // Invoke and receive rtl::RObject as return, wrapping std::string underneath. +if (err == rtl::error::None && ret.canViewAs()) { + std::string nameStr = ret.view()->get(); // Safely view the returned std::string. +} +``` +**[Explore the demo code here](https://github.com/ReflectCxx/RTL-Demo)** - // Get method of 'class Person'. Returns a callable 'Method' object. - std::optional setAge = classPerson->getMethod("setAge"); +### How RTL Fits Together - // Call methods on the 'Person' object. returns 'RStatus'. - RStatus rst = setAge->on(personObj).call(int(42)); - // or with different syntax, - RStatus rst = (*setAge)(personObj)(int(42)); +At a high level, every registered C++ type is encapsulated as an `rtl::Record`. Callable entities (functions, member functions and constructors) are materialized through `rtl::Function`, `rtl::Method` and `rtl::Record`, all of which are discoverable via `rtl::CxxMirror`. - // Get method of 'class Person' that returns a value. - std::optional getName = classPerson->getMethod("getName"); +👉 Deep Dive - // Call method, returns 'RStatus' containing return value. - RStatus retName = getName->on(personObj).call(); - // or with different syntax, - RStatus retName = (*getName)(personObj)(); - - // Extract the return value. - std::string nameStr = std::any_cast(retName.getReturn()); -} +[![Design Traits](https://img.shields.io/badge/Doc-Design%20Traits-blue)](./docs/DESIGN_PRINCIPLES_AND_FEATURES.md) +  +[![RTL Syntax & Semantics](https://img.shields.io/badge/Doc-Syntax_&_Semantics-blueviolet)](./docs/RTL_SYNTAX_AND_SEMANTICS.md) +  +[![Benchmarks](https://img.shields.io/badge/Doc-Benchmarks-teal)](./docs/benchmark_summary.md) + +### How to Build (Windows / Linux) +```sh +mkdir build && cd build +cmake ../ -G "" # Use a C++20-compatible compiler +cmake --build . ``` -- `std::any_cast` will throw an exception if correct type is not specified. -- Check, `CxxTypeRegistration/src/MyReflection.cpp` for all sort of type registrations. -- Check, `CxxReflectionTests/src` for test cases. +Run the generated binaries from `bin/`: + +* `RTLTestRunApp` – Reflection tests and examples +* `RTLBenchmarkApp` – Performance benchmarks + +Additional resources: + +* `RTLTestRunApp/src` – Detailed test cases +* `RTLTestRunApp/src/MyReflectionTests/` – Tutorial example +* `RTLBenchmarkApp/src` – Benchmark implementations +* `run_benchmarks.sh` – Automated benchmark runs ## Reflection Features -- ✅ Register and invoke functions, supporting all overloads. -- ✅ Register classes/structs and reflect their methods, constructors, and destructors. -- ✅ Invoke the default constructor. -- ✅ Invoke the copy constructor with a non-const reference argument. -- ✅ Invoke the copy constructor with a const reference argument. -- ✅ Invoke any overloaded constructor. -- ✅ Invoke non-const member functions. -- ✅ Invoke const member functions. -- ✅ Invoke static member functions. -- ✅ Automatically invokes destructor for objects created on the heap via reflection. -- ❌ Reflect properties of classes/structs, providing getter/setter methods. -- ❌ Invoke functions with perfect forwarding. -- ❌ Reflect enums. -- ❌ Reflect classes with composite types that are also reflected. -- ❌ Support single, multiple, multilevel, and virtual inheritance. - -## License -This project is licensed under the MIT License. See the LICENSE file for more details. - -## Contributions -Contributions are welcome! If you find a bug, have a feature request, or want to contribute to the project, feel free to open an issue or submit a pull request on GitHub. - -## Contact -For any questions, suggestions, or feedback, you can reach out via GitHub or email at `neeraj.singh31285@outlook.com`. \ No newline at end of file + +* ✅ **Function Reflection** – Register and invoke C-style functions, supporting all kinds of overloads. +* ✅ **Class and Struct Reflection** – Register and dynamically reflect their methods, constructors, and destructors. +* ✅ **Complete Constructor Support** : + * Default construction. + * Copy/Move construction. + * Any overloaded constructor. + * Automatic destruction. + +* ✅ **Allocation Strategies & Ownership** : + * Choose between `Heap` or `Stack` allocation. + * Automatic move semantics for ownership transfers. + * Scope-based destruction for `Heap` allocated instances. + +* ✅ **Member Function Invocation** : + * Static methods. + * Const/Non-const methods. + * Any overloaded method, Const/Non-Const based as well. + +* ✅ **Perfect Forwarding** – Binds LValue/RValue to correct overload. +* ✅ **Zero Overhead Forwarding** – No temporaries or copies during dispatch and arguments forwarding. +* ✅ **Failure Semantics** – Explicit `rtl::error` diagnostics for all reflection operations (no exceptions, no silent failures). +* ✅ **Smart Pointer Reflection** – Reflect `std::shared_ptr` and `std::unique_ptr`, transparently access the underlying type, with full sharing and cloning semantics. +* 🟨 **Conservative Conversions** – Safely reinterpret reflected values. For example: treat an `int` as a `char`, or a `std::string` as a `std::string_view` / `const char*` *(In Progress)* +* 🚧 **STL Wrapper Support** – support for wrappers like `std::optional` and `std::reference_wrapper`. Return them, forward them as parameters, and access wrapped entities transparently. *(In Progress)* +* 🚧 **Relaxed Argument Matching** – Flexible parameter matching for reflective calls, enabling safe conversions (ex- base/derived) and overload resolution. *(In Progress)* +* ❌ **Inheritance Support**: Next in line. +* ❌ **Composition Support**: Planned. +* ❌ **Property Reflection**: Planned. +* ❌ **Enum Reflection**: Planned. +* ❌ **Metadata iterators**: Planned. + +## 💚 Support RTL’s Development + +RTL is an actively maintained, production-oriented C++ runtime reflection system focused on performance, type safety, and real-world usability. + +Sponsorship supports continued improvement of RTL’s core reflection capabilities, along with: + +* Production-ready examples +* Tooling and documentation +* Cross-platform CI and testing + +If you’re interested in advancing practical runtime reflection in C++ and supporting the continued evolution of RTL’s core capabilities, consider sponsoring the project. + +[![Sponsor RTL](https://img.shields.io/badge/Sponsor-RTL_Development-ea4aaa?logo=github)](https://github.com/sponsors/ReflectCxx) + +## + +***C++ joins the reflection party! – why should Java have all the fun?*** diff --git a/RTLBenchmarkApp/CMakeLists.txt b/RTLBenchmarkApp/CMakeLists.txt new file mode 100644 index 00000000..8141e308 --- /dev/null +++ b/RTLBenchmarkApp/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.20) +project(RTLBenchmarkApp LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# =============================== +# Dependencies (Google Benchmark) +# =============================== +include(FetchContent) + +FetchContent_Declare( + benchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG v1.8.3 +) + +# Prevent benchmark from adding extra projects +set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE) +set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) + +FetchContent_GetProperties(benchmark) +if(NOT benchmark_POPULATED) + FetchContent_Populate(benchmark) + add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR} EXCLUDE_FROM_ALL) +endif() + + +# =============================== +# Test Executable +# =============================== +set(CXX_EXE_NAME RTLBenchmarkApp) + +# =============================== +# Benchmarks (only target) +# =============================== +add_executable(${CXX_EXE_NAME} + src/main.cpp + src/BenchMark.h + src/BenchMark.cpp + src/StandardCall.h + src/StandardCall.cpp + src/StdFunction.cpp + src/ReflectedCallKnownReturn.h + src/ReflectedCallKnownReturn.cpp + src/ReflectedCallUnknownReturn.h + src/ReflectedCallUnknownReturn.cpp +) + + +target_link_libraries(${CXX_EXE_NAME} + PRIVATE + benchmark + ReflectionTemplateLib +) \ No newline at end of file diff --git a/RTLBenchmarkApp/src/BenchMark.cpp b/RTLBenchmarkApp/src/BenchMark.cpp new file mode 100644 index 00000000..268b356a --- /dev/null +++ b/RTLBenchmarkApp/src/BenchMark.cpp @@ -0,0 +1,75 @@ + + +#include +#include + +#include "BenchMark.h" + +namespace bm +{ + std::size_t g_work_load = 0; + + std::optional g_work_done = std::string(); + + extern std::string perform_work(const argStr_t& pMsg); +} + + +namespace bm +{ + void sendMessage(argStr_t pMsg) noexcept + { + if(g_work_load){ + g_work_done = perform_work(pMsg); + } + } + + void Node::sendMessage(argStr_t pMsg) noexcept + { + if(g_work_load){ + g_work_done = perform_work(pMsg); + } + } + + retStr_t getMessage(argStr_t pMsg) noexcept + { + retStr_t retStr = g_work_done->c_str(); + if(g_work_load){ + g_work_done = perform_work(pMsg); + retStr = g_work_done->c_str(); + } + return retStr; + } + + retStr_t Node::getMessage(argStr_t pMsg) noexcept + { + retStr_t retStr = g_work_done->c_str(); + if(g_work_load){ + g_work_done = perform_work(pMsg); + retStr = g_work_done->c_str(); + } + return retStr; + } +} + + +namespace cxx +{ + const rtl::CxxMirror& mirror() + { + static auto cxx_mirror = rtl::CxxMirror({ + + rtl::type().function("getMessage").build(bm::getMessage), + + rtl::type().function("sendMessage").build(bm::sendMessage), + + rtl::type().record("Node").build(), + + rtl::type().member().method("sendMessage").build(&bm::Node::sendMessage), + + rtl::type().member().method("getMessage").build(&bm::Node::getMessage) + }); + + return cxx_mirror; + } +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/BenchMark.h b/RTLBenchmarkApp/src/BenchMark.h new file mode 100644 index 00000000..a6bbc513 --- /dev/null +++ b/RTLBenchmarkApp/src/BenchMark.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +namespace bm +{ + using argStr_t = std::string_view; + using retStr_t = std::string_view; + + struct Node + { + void sendMessage(argStr_t) noexcept; + retStr_t getMessage(argStr_t) noexcept; + }; +} + + +namespace bm +{ + static argStr_t g_longStr = "Lorem ipsum" + "dolor sit amet, consectetur adipiscing elit, sed do" + "do aeiusmod tempor incididunt uth 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"; +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/ReflectedCallKnownReturn.cpp b/RTLBenchmarkApp/src/ReflectedCallKnownReturn.cpp new file mode 100644 index 00000000..d9755307 --- /dev/null +++ b/RTLBenchmarkApp/src/ReflectedCallKnownReturn.cpp @@ -0,0 +1,187 @@ + +#include +#include +#include +#include + +#include "BenchMark.h" +#include "ReflectedCallKnownReturn.h" + + +namespace bm +{ + extern std::optional g_work_done; +} + +namespace cxx +{ + extern const rtl::CxxMirror& mirror(); +} + +namespace +{ + static const rtl::function getMessage = []() + { + std::optional function = cxx::mirror().getFunction("getMessage"); + if(!function) + { + std::cerr << "[00] error: erase_function 'getMessage' not found."; + std::abort(); + } + return function->argsT().returnT(); + }(); + + static const rtl::function sendMessage = []() + { + std::optional function = cxx::mirror().getFunction("sendMessage"); + if(!function) + { + std::cerr << "[01] error: erase_function 'sendMessage' not found."; + std::abort(); + } + return function->argsT().returnT(); + }(); + + static const rtl::method getMessageNode = []() + { + std::optional Node = cxx::mirror().getRecord("Node"); + if (!Node) { + std::cerr << "[x] error: record 'Node' not found"; + std::abort(); + } + + std::optional method = Node->getMethod("getMessage"); + if (!method) { + std::cerr << "[02] error: method 'Node::getMessage' not found."; + std::abort(); + } + return method->targetT().argsT().returnT(); + }(); + + static const rtl::method sendMessageNode = []() + { + std::optional Node = cxx::mirror().getRecord("Node"); + if (!Node) { + std::cerr << "[x] error: record 'Node' not found."; + std::abort(); + } + + std::optional method = Node->getMethod("sendMessage"); + if (!method) { + std::cerr << "[3] error: method 'Node::sendMessage' not found."; + std::abort(); + } + return method->targetT().argsT().returnT(); + }(); +} + + +namespace +{ + static auto _new_line = []() { + std::cout << std::endl; + return 0; + }; + + template + static bool test(const T& to, int callerId) + { + if (!to) { + std::cerr << "[" << callerId << "] error: functor not valid, return-type or signature mismatch."; + std::abort(); + } + return true; + } +} + + +namespace bm_call +{ + void via_function_ptr__Function::get_string(benchmark::State& state) + { + static auto _ = _new_line(); + static auto is_ok = test(getMessage, 0); + for (auto _ : state) + { + benchmark::DoNotOptimize((getMessage.f_ptr())(bm::g_longStr)); + } + } + + void via_function_ptr____Method::get_string(benchmark::State& state) + { + static bm::Node nodeObj; + static auto is_ok = test(getMessageNode, 1); + for (auto _ : state) + { + benchmark::DoNotOptimize((nodeObj.*getMessageNode.f_ptr())(bm::g_longStr)); + } + } + + void via_function_ptr__Function::set_string(benchmark::State& state) + { + static auto _ = _new_line(); + static auto is_ok = test(sendMessage, 2); + for (auto _ : state) + { + (sendMessage.f_ptr())(bm::g_longStr); + benchmark::DoNotOptimize(bm::g_work_done->c_str()); + } + } + + void via_function_ptr____Method::set_string(benchmark::State& state) + { + static bm::Node nodeObj; + static auto is_ok = test(getMessageNode, 2); + for (auto _ : state) + { + (nodeObj.*sendMessageNode.f_ptr())(bm::g_longStr); + benchmark::DoNotOptimize(bm::g_work_done->c_str()); + } + } +} + + +namespace bm_rtl +{ + void function_calls__Function::get_string(benchmark::State& state) + { + static auto _ = _new_line(); + static auto is_ok = test(getMessage, 3); + for (auto _ : state) + { + benchmark::DoNotOptimize(getMessage(bm::g_longStr)); + } + } + + void function_calls__Function::set_string(benchmark::State& state) + { + static auto _ = _new_line(); + static auto is_ok = test(sendMessage, 0); + for (auto _ : state) + { + sendMessage(bm::g_longStr); + benchmark::DoNotOptimize(bm::g_work_done->c_str()); + } + } + + void method_calls______Method::get_string(benchmark::State& state) + { + static bm::Node nodeObj; + static auto is_ok = test(getMessageNode, 4); + for (auto _ : state) + { + benchmark::DoNotOptimize(getMessageNode(nodeObj)(bm::g_longStr)); + } + } + + void method_calls______Method::set_string(benchmark::State& state) + { + static bm::Node nodeObj; + static auto is_ok = test(sendMessageNode, 5); + for (auto _ : state) + { + sendMessageNode(nodeObj)(bm::g_longStr); + benchmark::DoNotOptimize(bm::g_work_done->c_str()); + } + } +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/ReflectedCallKnownReturn.h b/RTLBenchmarkApp/src/ReflectedCallKnownReturn.h new file mode 100644 index 00000000..c8dbea8f --- /dev/null +++ b/RTLBenchmarkApp/src/ReflectedCallKnownReturn.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace bm_call +{ + struct via_function_ptr__Function + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; + + struct via_function_ptr____Method + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; +} + +namespace bm_rtl +{ + struct function_calls__Function + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; + + struct method_calls______Method + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.cpp b/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.cpp new file mode 100644 index 00000000..83277116 --- /dev/null +++ b/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.cpp @@ -0,0 +1,340 @@ + +#include +#include +#include + +#include "BenchMark.h" +#include "ReflectedCallUnknownReturn.h" + +namespace bm +{ + extern std::optional g_work_done; +} + +namespace cxx +{ + extern const rtl::CxxMirror& mirror(); +} + +namespace +{ + static rtl::Record class_Node = []() + { + std::optional Node = cxx::mirror().getRecord("Node"); + if (!Node) { + std::cerr << "[x] error: record 'Node' not found.\n"; + std::abort(); + } + return Node.value(); + }(); + + static rtl::RObject nodeObj = []() + { + auto [err, robj] = class_Node.ctorT()(rtl::alloc::Stack); + if (robj.isEmpty()) { + std::cerr << "[x] error: " << rtl::to_string(err) << "\n"; + } + return std::move(robj); + }(); +} + +namespace +{ + static rtl::function ErasedReturnFn_GetMessage = []() + { + std::optional optFunction = cxx::mirror().getFunction("getMessage"); + if (!optFunction) { + std::cerr << "[0] error: function 'getMessage' not found.\n"; + std::abort(); + } + auto function = optFunction->argsT().returnT<>(); + if (!function) + { + std::cerr << "[0] error: invalid function caller.\n"; + std::abort(); + } + return function; + }(); + + static rtl::function ErasedReturnFn_SendMessage = []() + { + std::optional optFunction = cxx::mirror().getFunction("sendMessage"); + if (!optFunction) { + std::cerr << "[1] error: function 'sendMessage' not found.\n"; + std::abort(); + } + auto function = optFunction->argsT().returnT<>(); + if (!function) + { + std::cerr << "[1] error: invalid function caller.\n"; + std::abort(); + } + return function; + }(); +} + +namespace +{ + //---------------------------------------------------------------------------- + static rtl::method ErasedReturnAwareTarget_SendMessage = []() + { + std::optional optMethod = class_Node.getMethod("sendMessage"); + if (!optMethod) { + std::cerr << "[2] error: method 'Node::sendMessage' not found.\n"; + std::abort(); + } + auto method = optMethod->targetT().argsT().returnT<>(); + if (!method) { + std::cerr << "[2] error: invalid method caller.\n"; + std::abort(); + } + return method; + }(); + + static rtl::method ErasedTargetAwareReturn_SendMessage = []() + { + std::optional optMethod = class_Node.getMethod("sendMessage"); + if (!optMethod) { + std::cerr << "[3] error: method 'Node::sendMessage' not found.\n"; + std::abort(); + } + auto method = optMethod->targetT<>().argsT().returnT(); + if (!method) { + std::cerr << "[3] error: invalid method caller.\n"; + std::abort(); + } + return method; + }(); + + static rtl::method ErasedReturnAndTarget_SendMessage = []() + { + std::optional optMethod = class_Node.getMethod("sendMessage"); + if (!optMethod) { + std::cerr << "[4] error: method 'Node::sendMessage' not found.\n"; + std::abort(); + } + auto method = optMethod->targetT<>().argsT().returnT<>(); + if (!method) { + std::cerr << "[4] error: invalid method caller.\n"; + std::abort(); + } + return method; + }(); + + //---------------------------------------------------------------------------- + static rtl::method ErasedReturnAwareTarget_GetMessage = []() + { + std::optional optMethod = class_Node.getMethod("getMessage"); + if (!optMethod) { + std::cerr << "[5] error: method 'Node::getMessage' not found.\n"; + std::abort(); + } + auto method = optMethod->targetT().argsT().returnT<>(); + if (!method) { + std::cerr << "[5] error: invalid method caller.\n"; + std::abort(); + } + return method; + }(); + + static rtl::method ErasedTargetAwareReturn_GetMessage = []() + { + std::optional optMethod = class_Node.getMethod("getMessage"); + if (!optMethod) { + std::cerr << "[6] error: method 'Node::getMessage' not found.\n"; + std::abort(); + } + auto method = optMethod->targetT<>().argsT().returnT(); + if (!method) { + std::cerr << "[6] error: invalid method caller.\n"; + std::abort(); + } + return method; + }(); + + static rtl::method ErasedReturnAndTarget_GetMessage = []() + { + std::optional optMethod = class_Node.getMethod("getMessage"); + if (!optMethod) { + std::cerr << "[7] error: method 'Node::getMessage' not found.\n"; + std::abort(); + } + auto method = optMethod->targetT<>().argsT().returnT<>(); + if (!method) { + std::cerr << "[7] error: invalid method caller.\n"; + std::abort(); + } + return method; + }(); +} + +namespace +{ + static auto _test0 = []() + { + auto err = ErasedReturnFn_SendMessage(bm::g_longStr).err; + if (err != rtl::error::None) { + std::cerr << "[00] error: " << rtl::to_string(err) << "\n"; + } + return 0; + }; + + static auto _test1 = []() + { + auto err = ErasedReturnFn_GetMessage(bm::g_longStr).err; + if (err != rtl::error::None) { + std::cerr << "[01] error: " << rtl::to_string(err) << "\n"; + } + return 0; + }; +} + +namespace +{ + static auto _test2 = []() + { + auto err = ErasedReturnAwareTarget_SendMessage(bm::Node())(bm::g_longStr).err; + if (err != rtl::error::None) { + std::cerr << "[02] error: " << rtl::to_string(err) << "\n"; + } + return 0; + }; + + static auto _test3 = []() + { + auto err = ErasedReturnAwareTarget_GetMessage(bm::Node())(bm::g_longStr).err; + if (err != rtl::error::None) { + std::cerr << "[03] error: " << rtl::to_string(err) << "\n"; + } + return 0; + }; + + static auto _test4 = []() + { + auto err = ErasedReturnAndTarget_SendMessage(nodeObj)(bm::g_longStr).err; + if (err != rtl::error::None) { + std::cerr << "[04] error: " << rtl::to_string(err) << "\n"; + } + return 0; + }; + + static auto _test5 = []() + { + auto err = ErasedReturnAndTarget_GetMessage(nodeObj)(bm::g_longStr).err; + if (err != rtl::error::None) { + std::cerr << "[05] error: " << rtl::to_string(err) << "\n"; + } + return 0; + }; + + static auto _test6 = []() + { + auto [err, returnOpt] = ErasedTargetAwareReturn_SendMessage(nodeObj)(bm::g_longStr); + if (err != rtl::error::None) { + std::cerr << "[06] error: " << rtl::to_string(err) << "\n"; + } + return 0; + }; + + static auto _test7 = []() + { + auto [err, returnOpt] = ErasedTargetAwareReturn_GetMessage(nodeObj)(bm::g_longStr); + if (err != rtl::error::None) { + std::cerr << "[07] error: " << rtl::to_string(err) << "\n"; + } + return 0; + }; + + static auto _new_line = []() { + std::cerr << std::endl; + return 0; + }; +} + + +namespace bm_rtl +{ + void function__ErasedReturnType::set_string(benchmark::State& state) + { + static auto __ = _new_line(); + static auto _ = _test0(); + for (auto _ : state) + { + benchmark::DoNotOptimize(ErasedReturnFn_SendMessage(bm::g_longStr).err); + } + } + + void function__ErasedReturnType::get_string(benchmark::State& state) + { + static auto __ = _new_line(); + static auto _ = _test1(); + for (auto _ : state) + { + benchmark::DoNotOptimize(ErasedReturnFn_GetMessage(bm::g_longStr).err); + } + } +} + + +namespace bm_rtl +{ + void method____ErasedReturnType::set_string(benchmark::State& state) + { + static auto _ = _test2(); + static bm::Node node; + for (auto _ : state) + { + benchmark::DoNotOptimize(ErasedReturnAwareTarget_SendMessage(node)(bm::g_longStr)); + } + } + + void method____ErasedReturnType::get_string(benchmark::State& state) + { + static auto _ = _test3(); + static bm::Node node; + for (auto _ : state) + { + benchmark::DoNotOptimize(ErasedReturnAwareTarget_GetMessage(node)(bm::g_longStr)); + } + } + + void method____ErasedTargetType::set_string(benchmark::State& state) + { + static auto _ = _test6(); + static bm::Node node; + for (auto _ : state) + { + benchmark::DoNotOptimize(ErasedTargetAwareReturn_SendMessage(nodeObj)(bm::g_longStr)); + } + } + + void method____ErasedTargetType::get_string(benchmark::State& state) + { + static auto _ = _test7(); + static bm::Node node; + for (auto _ : state) + { + benchmark::DoNotOptimize(ErasedTargetAwareReturn_GetMessage(nodeObj)(bm::g_longStr)); + } + } + + void method____ErasedTargetAndReturnType::set_string(benchmark::State& state) + { + static auto _ = _test4(); + static bm::Node node; + for (auto _ : state) + { + benchmark::DoNotOptimize(ErasedReturnAndTarget_SendMessage(nodeObj)(bm::g_longStr)); + } + } + + void method____ErasedTargetAndReturnType::get_string(benchmark::State& state) + { + static auto _ = _test5(); + static bm::Node node; + for (auto _ : state) + { + benchmark::DoNotOptimize(ErasedReturnAndTarget_GetMessage(nodeObj)(bm::g_longStr)); + } + } +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.h b/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.h new file mode 100644 index 00000000..08dcaa3a --- /dev/null +++ b/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace bm_rtl +{ + struct function__ErasedReturnType + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; + + struct method____ErasedReturnType + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; + + struct method____ErasedTargetType + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; + + struct method____ErasedTargetAndReturnType + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/StandardCall.cpp b/RTLBenchmarkApp/src/StandardCall.cpp new file mode 100644 index 00000000..5fc48105 --- /dev/null +++ b/RTLBenchmarkApp/src/StandardCall.cpp @@ -0,0 +1,103 @@ + +#include +#include +#include +#include + +#include "BenchMark.h" +#include "StandardCall.h" + +namespace +{ + static auto _put_line = []() { + std::cout << "-----------------------------------------------" + "---------------------------------------------------" << std::endl; + return 0; + }; + + static auto _new_line = []() { + std::cout << std::endl; + return 0; + }; +} + + +namespace bm +{ + extern void sendMessage(argStr_t); + + extern retStr_t getMessage(argStr_t); + + extern std::optional g_work_done; + + extern std::function SendMessage; + + extern std::function NodeSendMessage; + + extern std::function GetMessage; + + extern std::function NodeGetMessage; +} + +namespace bm_call +{ + void direct__Function::set_string(benchmark::State& state) + { + for (auto _ : state) + { + bm::sendMessage(bm::g_longStr); + benchmark::DoNotOptimize(bm::g_work_done->c_str()); + } + } + + void direct__Function::get_string(benchmark::State& state) + { + static auto _ = _put_line(); + for (auto _ : state) + { + benchmark::DoNotOptimize(bm::getMessage(bm::g_longStr)); + } + } +} + + +namespace bm_std +{ + void function_calls__Function::set_string(benchmark::State& state) + { + static auto _ = _new_line(); + for (auto _ : state) + { + bm::SendMessage(bm::g_longStr); + benchmark::DoNotOptimize(bm::g_work_done->c_str()); + } + } + + void function_calls____Method::set_string(benchmark::State& state) + { + static bm::Node nodeObj; + for (auto _ : state) + { + bm::NodeSendMessage(nodeObj, bm::g_longStr); + benchmark::DoNotOptimize(bm::g_work_done->c_str()); + } + } + + void function_calls__Function::get_string(benchmark::State& state) + { + static auto _ = _new_line(); + for (auto _ : state) + { + benchmark::DoNotOptimize(bm::GetMessage(bm::g_longStr)); + } + } + + void function_calls____Method::get_string(benchmark::State& state) + { + static bm::Node nodeObj; + for (auto _ : state) + { + benchmark::DoNotOptimize(bm::NodeGetMessage(nodeObj, bm::g_longStr)); + } + } +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/StandardCall.h b/RTLBenchmarkApp/src/StandardCall.h new file mode 100644 index 00000000..b74bad74 --- /dev/null +++ b/RTLBenchmarkApp/src/StandardCall.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace bm_call +{ + struct direct__Function + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; +} + +namespace bm_std +{ + struct function_calls__Function + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; + + + struct function_calls____Method + { + static void set_string(benchmark::State& state); + + static void get_string(benchmark::State& state); + }; +} \ No newline at end of file diff --git a/RTLBenchmarkApp/src/StdFunction.cpp b/RTLBenchmarkApp/src/StdFunction.cpp new file mode 100644 index 00000000..b258b02d --- /dev/null +++ b/RTLBenchmarkApp/src/StdFunction.cpp @@ -0,0 +1,48 @@ + +#include +#include +#include "BenchMark.h" + +namespace bm +{ + extern std::size_t g_work_load; + std::string perform_work(const bm::argStr_t& pMsg) + { + auto workStr = std::string(); + for(int i = 0; i < bm::g_work_load; ++i) + { + workStr += pMsg; + } + return workStr; + } +} + + +namespace bm +{ + extern void sendMessage(argStr_t); + + extern retStr_t getMessage(argStr_t); + + std::function SendMessage = [](argStr_t& pMsg) + { + bm::sendMessage(pMsg); + }; + + std::function NodeSendMessage = [](bm::Node pNode, bm::argStr_t& pMsg) + { + pNode.sendMessage(pMsg); + }; + + std::function GetMessage = [](bm::argStr_t& pMsg) + { + auto retMsg = bm::getMessage(pMsg); + return retMsg; + }; + + std::function NodeGetMessage = [](bm::Node pNode, bm::argStr_t& pMsg) + { + auto retMsg = pNode.getMessage(pMsg); + return retMsg; + }; +} diff --git a/RTLBenchmarkApp/src/main.cpp b/RTLBenchmarkApp/src/main.cpp new file mode 100644 index 00000000..20c9a0f7 --- /dev/null +++ b/RTLBenchmarkApp/src/main.cpp @@ -0,0 +1,65 @@ + +#include +#include + +#include "StandardCall.h" +#include "ReflectedCallKnownReturn.h" +#include "ReflectedCallUnknownReturn.h" + +BENCHMARK(bm_call::direct__Function::set_string); + +BENCHMARK(bm_call::via_function_ptr__Function::set_string); +BENCHMARK(bm_call::via_function_ptr____Method::set_string); + +BENCHMARK(bm_std::function_calls__Function::set_string); +BENCHMARK(bm_std::function_calls____Method::set_string); + +BENCHMARK(bm_rtl::function_calls__Function::set_string); +BENCHMARK(bm_rtl::method_calls______Method::set_string); + +BENCHMARK(bm_rtl::function__ErasedReturnType::set_string); +BENCHMARK(bm_rtl::method____ErasedReturnType::set_string); +BENCHMARK(bm_rtl::method____ErasedTargetType::set_string); +BENCHMARK(bm_rtl::method____ErasedTargetAndReturnType::set_string); + +BENCHMARK(bm_call::direct__Function::get_string); + +BENCHMARK(bm_call::via_function_ptr__Function::get_string); +BENCHMARK(bm_call::via_function_ptr____Method::get_string); + +BENCHMARK(bm_std::function_calls__Function::get_string); +BENCHMARK(bm_std::function_calls____Method::get_string); + +BENCHMARK(bm_rtl::function_calls__Function::get_string); +BENCHMARK(bm_rtl::method_calls______Method::get_string); + +BENCHMARK(bm_rtl::function__ErasedReturnType::get_string); +BENCHMARK(bm_rtl::method____ErasedReturnType::get_string); +BENCHMARK(bm_rtl::method____ErasedTargetType::get_string); +BENCHMARK(bm_rtl::method____ErasedTargetAndReturnType::get_string); + +namespace bm +{ + extern std::size_t g_work_load; +} + +int main(int argc, char** argv) +{ + if (argc > 1) + { + bm::g_work_load = std::stoi(argv[1]); + for (int i = 1; i < argc - 1; ++i) { + argv[i] = argv[i + 1]; + } + --argc; + + std::cout << "\n======== RTL Benchmark Configuration ========\n" + << "Workload: concatenate string of length 500\n" + << "Scale : " << bm::g_work_load << " iterations\n" + << "=============================================\n\n"; + } + + ::benchmark::Initialize(&argc, argv); + if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; + ::benchmark::RunSpecifiedBenchmarks(); +} diff --git a/RTLTestRunApp/CMakeLists.txt b/RTLTestRunApp/CMakeLists.txt new file mode 100644 index 00000000..3b88d6c2 --- /dev/null +++ b/RTLTestRunApp/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.20) +project(RTLTestRunApp LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# =============================== +# Dependencies (GoogleTest) +# =============================== +include(FetchContent) + +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip +) + +# Prevent GTest from overriding CRT settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Avoid GTest adding its own tests into the solution +set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) +set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) +set(BUILD_GTEST ON CACHE BOOL "" FORCE) + +FetchContent_MakeAvailable(googletest) + +# =============================== +# Common Include Paths +# =============================== +set(RTL_INCLUDE_DIRS + inc + "${CMAKE_SOURCE_DIR}/CxxTestUtils/inc" + "${CMAKE_SOURCE_DIR}/CxxTestRegistration/inc" +) + +# =============================== +# Test Executable +# =============================== +set(CXX_EXE_NAME RTLTestRunApp) + +file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS src/*.cpp) +add_executable(${CXX_EXE_NAME} ${TEST_SOURCES}) + +target_include_directories(${CXX_EXE_NAME} PRIVATE ${RTL_INCLUDE_DIRS}) + +target_link_libraries(${CXX_EXE_NAME} + PRIVATE + CxxTestUtils + ReflectionTemplateLib + CxxTestRegistration + GTest::gtest_main +) + + +# =============================== +# GoogleTest Integration +# =============================== + +include(GoogleTest) +gtest_discover_tests(${CXX_EXE_NAME}) diff --git a/RTLTestRunApp/src/CMakeLists.txt b/RTLTestRunApp/src/CMakeLists.txt new file mode 100644 index 00000000..a867f887 --- /dev/null +++ b/RTLTestRunApp/src/CMakeLists.txt @@ -0,0 +1,71 @@ +# CMakeLists.txt for CxxReflectionTests +cmake_minimum_required(VERSION 3.20) + +project(RTLTestRunApp) + +# Create a variable containing the source files for your target +set(LOCAL_SOURCES_0 + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/ClassMethodsTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/StaticTypeCFunctionTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/ConstMethodOverloadTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/ConstructorTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/CopyConstructorTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/NameSpaceGlobalsTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/ReflectionOpErrorCodeTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/StaticMethodTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/PerfectForwardingTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/MoveConstructorTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/ReturnValueReflectionTest.cpp" + + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Constructor.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Function.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Method.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_ConstMethod.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_StaticMethod.cpp" + + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeAwareInvocationTests/TypeAware_Function.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeAwareInvocationTests/TypeAware_Method.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeAwareInvocationTests/TypeAware_ConstMethod.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FunctionalityTests/TypeAwareInvocationTests/TypeAware_StaticMethod.cpp" +) + +# Create a variable containing the source files for your target +set(LOCAL_ROBJECT + "${CMAKE_CURRENT_LIST_DIR}/RObjectTests/RObjectReflecting_bool.cpp" + "${CMAKE_CURRENT_LIST_DIR}/RObjectTests/RObjectReflecting_char.cpp" + "${CMAKE_CURRENT_LIST_DIR}/RObjectTests/RObjectReflecting_strings.cpp" + "${CMAKE_CURRENT_LIST_DIR}/RObjectTests/RObjectReflecting_int.cpp" + "${CMAKE_CURRENT_LIST_DIR}/RObjectTests/RObjectReflecting_arrays.cpp" + "${CMAKE_CURRENT_LIST_DIR}/RObjectTests/RObjectReflecting_stdUniquePtr.cpp" + "${CMAKE_CURRENT_LIST_DIR}/RObjectTests/RObjectReflecting_stdSharedPtr.cpp" + "${CMAKE_CURRENT_LIST_DIR}/RObjectTests/RObjectImplicitConversions.cpp" +) + +set(LOCAL_MY_REFLECTION + "${CMAKE_CURRENT_LIST_DIR}/MyReflectionTests/MyReflectingType.h" + "${CMAKE_CURRENT_LIST_DIR}/MyReflectionTests/MyReflectionTests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/MyReflectionTests/MyCxxTestRegistration.cpp" +) + + +set(LOCAL_CXXMIRROR + "${CMAKE_CURRENT_LIST_DIR}/CxxMirrorTests/CxxMirrorObjectTest.cpp" + "${CMAKE_CURRENT_LIST_DIR}/CxxMirrorTests/CxxMirrorThreadingTest.h" + "${CMAKE_CURRENT_LIST_DIR}/CxxMirrorTests/CxxMirrorThreadingTest.cpp" +) + + +# Add any additional source files if needed +target_sources(RTLTestRunApp + PRIVATE + "${CMAKE_CURRENT_LIST_DIR}/main.cpp" + "${LOCAL_SOURCES_0}" + "${LOCAL_ROBJECT}" + "${LOCAL_CXXMIRROR}" + "${LOCAL_MY_REFLECTION}" +) + +SOURCE_GROUP("Source Files\\FunctionalityTests" FILES ${LOCAL_SOURCES_0}) +SOURCE_GROUP("Source Files\\RObjectTests" FILES ${LOCAL_ROBJECT}) +SOURCE_GROUP("Source Files\\CxxMirrorTests" FILES ${LOCAL_CXXMIRROR}) +SOURCE_GROUP("Source Files\\MyReflectionTests" FILES ${LOCAL_MY_REFLECTION}) \ No newline at end of file diff --git a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp new file mode 100644 index 00000000..710507f6 --- /dev/null +++ b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp @@ -0,0 +1,391 @@ + +#include +#include + +#include +#include + +#include + +namespace +{ + const rtl::CxxMirror cxx_mirror() + { + return rtl::CxxMirror({ + + // Register char as a record type (fundamental but instantiable). + rtl::type().record("char").build(), + + // Register strlen as a global function (C library function). + rtl::type().function("strlen").build(strlen), + + // Register member function push_back(const int&) for std::vector. + // Demonstrates overload resolution via explicit signature selection. + rtl::type().member>().method("push_back").build(&std::vector::push_back), + + // Register const-qualified method empty() for std::vector. + // RTL enforces const-correctness by separating methodConst. + rtl::type().member>().methodConst("empty").build(&std::vector::empty), + + // Register std::vector itself as a record with name "vector_int". + rtl::type().record>("vector_int").build(), + + // Register strlen again, redundant and gets ignored. + rtl::type().function("strlen").build(std::strlen) + }); + } +} + + +namespace rtl_tests +{ + + TEST(CxxMirrorObjectTest, multiple_initializations_same_set__with_std_vector) + { + std::string mirrorStr0; + { + // 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); + mirrorStr0 = rtl::CxxMirrorToJson::toJson(mirror0); + } + std::string mirrorStr1; + { + // Freshly constructed mirror should serialize identically to previous one. + mirrorStr1 = rtl::CxxMirrorToJson::toJson(cxx_mirror()); + } + EXPECT_EQ(mirrorStr0, mirrorStr1); + + // Retrieve the reflected record for std::vector. + std::optional classVectorInt = cxx_mirror().getRecord("vector_int"); + ASSERT_TRUE(classVectorInt); + + // Create an instance of std::vector on the stack via RTL. + // Uses RObject with stack lifetime. + auto [err, robj] = classVectorInt->ctorT()(rtl::alloc::Stack); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + + { + // Lookup the const method empty() in std::vector. + std::optional oIsEmpty = classVectorInt->getMethod("empty"); + ASSERT_TRUE(oIsEmpty); + { + // materialize the caller. + rtl::method isEmpty = oIsEmpty->targetT().argsT().returnT(); + EXPECT_TRUE(isEmpty); + + // Exception-free API: returns error code + result object. + auto [err, ret] = isEmpty(std::cref(robj))(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + + // Safe typed access to return value via rtl::view. + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + EXPECT_TRUE(rview->get()); // Newly created vector should be empty. + } { + // materialize the caller with known return type and erased target. + rtl::method isEmpty = oIsEmpty->targetT().argsT().returnT(); + EXPECT_TRUE(isEmpty); + + auto [err, ret] = isEmpty(std::cref(robj))(); + EXPECT_TRUE(err == rtl::error::None); + EXPECT_TRUE(ret.has_value()); + EXPECT_EQ(ret.value(), true); + } + } + + // Prepare a native vector with values to push. + std::vector intArr0 = { 1565, 7271, 4357 }; + { + // Lookup push_back method and call it multiple times with different values. + std::optional oPushBack = classVectorInt->getMethod("push_back"); + ASSERT_TRUE(oPushBack); + + rtl::method pushBack = oPushBack->targetT().argsT().returnT(); + EXPECT_TRUE(pushBack); + { + auto [err, ret] = pushBack(robj)(intArr0[0]); + EXPECT_EQ(err, rtl::error::None); + EXPECT_EQ(ret, std::nullopt); + } { + auto [err, ret] = pushBack(robj)(intArr0[1]); + EXPECT_EQ(err, rtl::error::None); + EXPECT_EQ(ret, std::nullopt); + } { + auto [err, ret] = pushBack(robj)(intArr0[2]); + EXPECT_EQ(err, rtl::error::None); + EXPECT_EQ(ret, std::nullopt); + } + } + + // Verify that reflected object can be safely reinterpreted as std::vector. + EXPECT_TRUE(robj.canViewAs>()); + + // Access internal vector instance safely via rtl::view. + std::optional>> vecView = robj.view>(); + ASSERT_TRUE(vecView); + + // Get reference to actual underlying vector and compare with expected values. + auto& intArr1 = vecView->get(); + EXPECT_EQ(intArr0, intArr1); + } + + + // This test demonstrates redundant function registration handling + // and argument forwarding quirks for C-style strings. + TEST(CxxMirrorObjectTest, rednudant_registration__std_cstring_function) + { + auto cxxMirror = rtl::CxxMirror({ + + // Redundant registrations + rtl::type().function("strlen").build(std::strlen), + rtl::type().function("strlen").build(std::strlen) + +/* emits warning on console - + [WARNING] Multiple registrations of the same function-pointer detected. + function-pointer already registered as "strlen" + This registration is ignored. */ + }); + + std::optional fnCStrLen = cxxMirror.getFunction("strlen"); + ASSERT_TRUE(fnCStrLen); + + rtl::function cstrlen = fnCStrLen->argsT().returnT<>(); + EXPECT_TRUE(cstrlen); + EXPECT_EQ(cstrlen.get_init_error(), rtl::error::None); + { + // Case 1: normal pointer (deduces as 'const char*') + const char* cstr = "Reflection Template Library C++"; + + auto [err, ret] = cstrlen(cstr); + ASSERT_TRUE(err == rtl::error::None); + + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + + std::size_t rlen = rview->get(); + std::size_t clen = std::strlen(cstr); + EXPECT_EQ(rlen, clen); + } { + // Case 2: constexpr top-level const (deduces as 'const char* const&') + constexpr const char* cstr = "Reflection Template Library C++"; + + auto [err, ret] = cstrlen(cstr); + ASSERT_TRUE(err == rtl::error::None); + + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + + std::size_t rlen = rview->get(); + std::size_t clen = std::strlen(cstr); + EXPECT_EQ(rlen, clen); + } { + // Case 3: string literal (deduces as const char[N], here const char[32]) + auto [err, ret] = cstrlen("Reflection Template Library C++"); + ASSERT_TRUE(err == rtl::error::None); + + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + + std::size_t rlen = rview->get(); + std::size_t clen = std::strlen("Reflection Template Library C++"); + EXPECT_EQ(rlen, clen); + } + } + + + TEST(CxxMirrorObjectTest, redundant_registration__std_cstring_func_with_global_cstring) + { + auto cxxMirror = rtl::CxxMirror({ + + // Register strlen (C function) under the name "strlen". + // RTL tracks uniqueness of function-pointer registrations. + rtl::type().function("strlen").build(strlen), + + // Attempt to register the same function-pointer again. + // RTL emits a warning and ignores this redundant registration, + // ensuring stable, non-ambiguous metadata. + rtl::type().function("strlen").build(std::strlen) + + /* Console output: + [WARNING] Multiple registrations of the same function-pointer detected. + function-pointer already registered as "strlen" + This registration is ignored. + */ + }); + + // Retrieve the reflected function "strlen" from the mirror. + std::optional optCstrLen = cxxMirror.getFunction("strlen"); + ASSERT_TRUE(optCstrLen); + + auto strlen_fn = optCstrLen->argsT().returnT<>(); + ASSERT_TRUE(strlen_fn); + EXPECT_EQ(strlen_fn.get_init_error(), rtl::error::None); + + // RTL returns error code + result object instead of exceptions. + const char* cstr = "Modern C++ Reflection Framework"; + auto [err, ret] = strlen_fn(cstr); + + ASSERT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + // Safely extract the return value as size_t via typed view. + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + + std::size_t rlen = rview->get(); + std::size_t clen = std::strlen(cstr); + + // Verify RTL-reflected call matches native call. + EXPECT_EQ(rlen, clen); + } + + + TEST(CxxMirrorObjectTest, redundant_regis_with_namespace__std_cstring_func_with_global_cstring) + { + auto cxxMirror = rtl::CxxMirror({ + // Redundant registrations with different namespaces. + // No warning is emitted, because they produce different rtl::Function entries + // (one global, one inside namespace "std"). + // Both functions wrap the same function-pointer, so their FunctorIds match. + rtl::type().function("strlen").build(strlen), + rtl::type().ns("std").function("strlen").build(std::strlen) + }); + + // Lookup global function "strlen". + std::optional optCstrLen = cxxMirror.getFunction("strlen"); + ASSERT_TRUE(optCstrLen); + { + auto strlen_fn = optCstrLen->argsT().returnT<>(); + ASSERT_TRUE(strlen_fn); + EXPECT_EQ(strlen_fn.get_init_error(), rtl::error::None); + + const char* cstr = "Modern C++ Reflection Framework"; + // Call the reflected global strlen. + auto [err, ret] = strlen_fn(cstr); + ASSERT_TRUE(err == rtl::error::None); + + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + + std::size_t rlen = rview->get(); + std::size_t clen = strlen(cstr); + EXPECT_EQ(rlen, clen); + } + + // Lookup namespaced function "std::strlen". + std::optional stdStrLen = cxxMirror.getFunction("std", "strlen"); + ASSERT_TRUE(stdStrLen); + { + auto strlen_fn = stdStrLen->argsT().returnT<>(); + ASSERT_TRUE(strlen_fn); + EXPECT_EQ(strlen_fn.get_init_error(), rtl::error::None); + + const char* cstr = "Modern C++ Reflection Framework"; + // Call the reflected std::strlen. + auto [err, ret] = strlen_fn(cstr); + ASSERT_TRUE(err == rtl::error::None); + + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + + std::size_t rlen = rview->get(); + std::size_t clen = std::strlen(cstr); + EXPECT_EQ(rlen, clen); + } + + // Even though the functions are registered in different namespaces, + // the underlying FunctorIds (which identify function-pointers) must be equal. + const std::vector& cfunctorIds = optCstrLen->getFunctorsMeta(); + const std::vector& stdfunctorIds = stdStrLen->getFunctorsMeta(); + + EXPECT_EQ(cfunctorIds, stdfunctorIds); + } + + + + TEST(CxxMirrorObjectTest, redundant_regis_with_different_names__std_cstring_func_with_global_cstring) + { + auto cxxMirror = rtl::CxxMirror({ + // Redundant registrations with different symbolic names. + // No warning is emitted, since each rtl::Function has a distinct name. + // Both map to the same underlying function-pointer, so FunctorIds match. + rtl::type().function("cStrlen").build(strlen), + rtl::type().function("stdStrlen").build(std::strlen) + }); + + // Lookup function registered as "cStrlen". + std::optional optCstrLen = cxxMirror.getFunction("cStrlen"); + ASSERT_TRUE(optCstrLen); + { + auto strlen_fn = optCstrLen->argsT().returnT<>(); + ASSERT_TRUE(strlen_fn); + EXPECT_EQ(strlen_fn.get_init_error(), rtl::error::None); + + const char* cstr = "Modern C++ Reflection Framework"; + // Call reflected cStrlen. + auto [err, ret] = strlen_fn(cstr); + ASSERT_TRUE(err == rtl::error::None); + + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + + std::size_t rlen = rview->get(); + std::size_t clen = strlen(cstr); + EXPECT_EQ(rlen, clen); + } + + // Lookup function registered as "stdStrlen". + std::optional stdStrLen = cxxMirror.getFunction("stdStrlen"); + ASSERT_TRUE(stdStrLen); + { + auto strlen_fn = stdStrLen->argsT().returnT<>(); + ASSERT_TRUE(strlen_fn); + EXPECT_EQ(strlen_fn.get_init_error(), rtl::error::None); + + const char* cstr = "Modern C++ Reflection Framework"; + // Call reflected stdStrlen. + auto [err, ret] = strlen_fn(cstr); + ASSERT_TRUE(err == rtl::error::None); + + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + std::optional> rview = ret.view(); + ASSERT_TRUE(rview); + + std::size_t rlen = rview->get(); + std::size_t clen = std::strlen(cstr); + EXPECT_EQ(rlen, clen); + } + + // Despite different symbolic names, both reflect the same function-pointer. + // Hence, their FunctorIds must be identical. + const std::vector& cfunctorIds = optCstrLen->getFunctorsMeta(); + const std::vector& stdfunctorIds = stdStrLen->getFunctorsMeta(); + + EXPECT_EQ(cfunctorIds, stdfunctorIds); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.cpp b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.cpp new file mode 100644 index 00000000..ae425e01 --- /dev/null +++ b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.cpp @@ -0,0 +1,309 @@ + +#include +#include +#include +#include +#include + +#include "../../CxxTestProps/inc/Date.h" +#include "../../CxxTestProps/inc/Book.h" +#include "../../CxxTestProps/inc/Animal.h" +#include "../../CxxTestProps/inc/Person.h" +#include "../../CxxTestProps/inc/Library.h" +#include "../../CxxTestProps/inc/Complex.h" +#include "../../CxxTestProps/inc/StringOps.h" +#include "../MyReflectionTests/MyReflectingType.h" + +#include "TestUtilsBook.h" +#include "TestUtilsDate.h" +#include "TestUtilsPerson.h" +#include "TestUtilsAnimal.h" +#include "GlobalTestUtils.h" + +#include "CxxMirrorThreadingTest.h" + +using namespace test_utils; + +namespace rtl_tests +{ + void InitMirror::reflectingEvent() + { + auto _ = rtl::CxxMirror({ + + rtl::type().ns(event::ns).record(event::struct_).build(), + + rtl::type().member().method(event::str_reset).build(&nsdate::Event::reset), + }); + + std::cout << "\n [t2]\trtl_tests::InitMirror::reflectingEvent() ==> Done.\n"; + } + + + void InitMirror::reflectingLibrary() + { + auto _ = rtl::CxxMirror({ + + rtl::type().record(library::class_).build(), + + rtl::type().member().methodStatic(library::str_addBook).build(&Library::addBook), + + rtl::type().member().methodStatic(library::str_getBookByTitle).build(&Library::getBookByTitle) + }); + + std::cout << "\n [t5]\trtl_tests::InitMirror::reflectingLibrary() ==> Done.\n"; + } + + + void InitMirror::reflectingDate() + { + auto _ = rtl::CxxMirror({ + + rtl::type().ns(date::ns).record(date::struct_).build(), + + rtl::type().member().constructor().build(), + + rtl::type().member().constructor().build(), + + rtl::type().member().method(date::str_updateDate).build(&nsdate::Date::updateDate), + + rtl::type().member().methodConst(date::str_getAsString).build(&nsdate::Date::getAsString) + }); + + std::cout << "\n [t1]\trtl_tests::InitMirror::reflectingDate() ==> Done.\n"; + } + + + void InitMirror::reflectingCalender() + { + auto _ = rtl::CxxMirror({ + + rtl::type().ns(date::ns).record(calender::struct_).build(), + + rtl::type().member().methodStatic(calender::str_create).build(&nsdate::Calender::create), + + rtl::type().member().method(calender::str_getTheEvent).build(&nsdate::Calender::getTheEvent), + + rtl::type().member().method(calender::str_getTheDate).build(&nsdate::Calender::getTheDate), + + rtl::type().member().method(calender::str_getSavedEvent).build(&nsdate::Calender::getSavedEvent), + + rtl::type().member().method(calender::str_getSavedDate).build(&nsdate::Calender::getSavedDate) + }); + + std::cout << "\n [t7]\trtl_tests::InitMirror::reflectingCalender() ==> Done.\n"; + } + + + void InitMirror::reflectingPodsStl() + { + auto _ = rtl::CxxMirror({ + + rtl::type().function("strlen").build(std::strlen), + + rtl::type().record("char").build(), + + rtl::type().record>("vector_int").build(), + + rtl::type().ns("std").record("string").build(), + + rtl::type().ns("std").record("string_view").build(), + + rtl::type().member().methodConst("empty").build(&std::string::empty), + + rtl::type().member().methodConst("empty").build(&std::string_view::empty), + + rtl::type().member>().methodConst("empty").build(&std::vector::empty), + + rtl::type().member>().method("push_back").build(&std::vector::push_back) + }); + + std::cout << "\n [t6]\trtl_tests::InitMirror::reflectingPodsStl() ==> Done.\n"; + } + + + void InitMirror::reflectingCStyleFunctions() + { + auto _ = rtl::CxxMirror({ + + rtl::type().function(str_reverseString).build(reverseString), + + rtl::type().function(str_reverseString).build(reverseString), + + rtl::type().function(str_reverseString).build(reverseString), + + rtl::type().function(str_getComplexNumAsString).build(getComplexNumAsString), + + rtl::type().ns(str_complex).function(str_setReal).build(complex::setReal), + + rtl::type().ns(str_complex).function(str_setImaginary).build(complex::setImaginary), + + rtl::type().ns(str_complex).function(str_getMagnitude).build(complex::getMagnitude), + + rtl::type().ns("ext").function("sendString").build(my_type::ext::sendString), + + rtl::type().ns("ext").function("sendAsString").build(my_type::ext::sendAsString), + + rtl::type().ns("ext").function("sendAsString").build(my_type::ext::sendAsString), + + rtl::type().ns("ext").function("sendAsString").build(my_type::ext::sendAsString) + }); + + std::cout << "\n [t9]\trtl_tests::InitMirror::reflectingCStyleFunctions() ==> Done.\n"; + } + + + void InitMirror::reflectingBook() + { + auto _ = rtl::CxxMirror({ + + rtl::type().record(book::class_).build(), + + rtl::type().member().constructor().build(), + + rtl::type().member().method(book::str_setAuthor).build(&Book::setAuthor), + + rtl::type().member().method(book::str_addPreface).build(&Book::addPreface), + + rtl::type().member().method(book::str_setDescription).build(&Book::setDescription), + + rtl::type().member().method(book::str_getPublishedOn).build(&Book::getPublishedOn), + + rtl::type().member().method(book::str_addCopyrightTag).build(&Book::addCopyrightTag), + + rtl::type().member().method(book::str_updateBookInfo).build(&Book::updateBookInfo), + + rtl::type().member().method(book::str_updateBookInfo).build(&Book::updateBookInfo), + + rtl::type().member().method(book::str_updateBookInfo).build(&Book::updateBookInfo) + }); + + std::cout << "\n [t0]\trtl_tests::InitMirror::reflectingBook() ==> Done.\n"; + } + + + void InitMirror::reflectingMyTypePerson() + { + auto _ = rtl::CxxMirror({ + + rtl::type().record("Person").build(), + + rtl::type().member().constructor().build(), + + rtl::type().member().method("getName").build(&my_type::Person::getName), + + rtl::type().member().methodStatic("getDefaults").build(&my_type::Person::getDefaults), + + rtl::type().member().method("updateAddress").build(&my_type::Person::updateAddress), + + rtl::type().member().methodConst("updateAddress").build(&my_type::Person::updateAddress), + + rtl::type().member().method("setTitle").build(&my_type::Person::setTitle), + + rtl::type().member().method("setOccupation").build(&my_type::Person::setOccupation), + + rtl::type().member().method("setOccupation").build(&my_type::Person::setOccupation), + + rtl::type().member().method("setProfile").build(&my_type::Person::setProfile), + + rtl::type().member().method("setProfile").build(&my_type::Person::setProfile), + + rtl::type().member().methodConst("getProfile").build(&my_type::Person::getProfile) + }); + + std::cout << "\n [t8]\trtl_tests::InitMirror::reflectingMyTypePerson() ==> Done.\n"; + } + + + void InitMirror::reflectingPerson() + { + auto _ = rtl::CxxMirror({ + + rtl::type().record(person::class_).build(), + + rtl::type().member().constructor().build(), + + rtl::type().member().methodStatic(person::str_createPtr).build(&Person::createPtr), + + rtl::type().member().method(person::str_updateAddress).build(&Person::updateAddress), + + rtl::type().member().method(person::str_updateAddress).build(&Person::updateAddress), + + rtl::type().member().method(person::str_getFirstName).build(&Person::getFirstName), + + rtl::type().member().methodConst(person::str_updateLastName).build(&Person::updateLastName), + + rtl::type().member().methodConst(person::str_updateAddress).build(&Person::updateAddress), + + rtl::type().member().methodConst(person::str_updateAddress).build(&Person::updateAddress), + + rtl::type().member().methodStatic(person::str_getDefaults).build(&Person::getDefaults), + + rtl::type().member().methodStatic(person::str_createConst).build(&Person::createConst), + + rtl::type().member().methodStatic(person::str_getProfile).build(&Person::getProfile), + + rtl::type().member().methodStatic(person::str_getProfile).build(&Person::getProfile), + + rtl::type().member().methodStatic(person::str_getProfile).build(&Person::getProfile) + }); + + std::cout << "\n [t4]\trtl_tests::InitMirror::reflectingPerson() ==> Done.\n"; + } + + + void InitMirror::reflectingAnimal() + { + auto _ = rtl::CxxMirror({ + + rtl::type().record(animal::class_).build(), + + rtl::type().member().constructor().build(), + + rtl::type().member().method(animal::str_setFamilyName).build(&Animal::setFamilyName), + + rtl::type().member().methodConst(animal::str_getFamilyName).build(&Animal::getFamilyName), + + rtl::type().member().method(animal::str_setAnimalName).build(&Animal::setAnimalName), + + rtl::type().member().methodStatic(animal::str_updateZooKeeper).build(&Animal::updateZooKeeper), + + #if defined(__GNUC__) && !defined(__clang__) + /* GCC fails to automatically identify the correct overloaded functor to pick. (non-const-lvalue-ref & rvalue as argument) + we need to explicitly cast the functor like, static_cast(&Animal::setAnimalName). + */ rtl::type().member() + .method(animal::str_setAnimalName) + .build(static_cast(&Animal::setAnimalName)), //overloaded method, taking non-const lvalue reference as argument. + + rtl::type().member() + .method(animal::str_setAnimalName) + .build(static_cast(&Animal::setAnimalName)), //overloaded method, taking rvalue reference as argument. + + rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(static_cast(&Animal::updateZooKeeper)), //static method, taking non-const lvalue reference as argument. + + rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(static_cast(&Animal::updateZooKeeper)), //static method, taking rvalue reference as argument. + #else + rtl::type().member() + .method(animal::str_setAnimalName) + .build(&Animal::setAnimalName), + + rtl::type().member() + .method(animal::str_setAnimalName) + .build(&Animal::setAnimalName), + + rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(&Animal::updateZooKeeper), + + rtl::type().member() + .methodStatic(animal::str_updateZooKeeper) + .build(&Animal::updateZooKeeper) + #endif + }); + + std::cout << "\n [t3]\trtl_tests::InitMirror::reflectingAnimal() ==> Done.\n"; + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.h b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.h new file mode 100644 index 00000000..5facc836 --- /dev/null +++ b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorThreadingTest.h @@ -0,0 +1,20 @@ +#pragma once + +namespace rtl_tests +{ + struct InitMirror + { + static void reflectingDate(); + static void reflectingEvent(); + static void reflectingCalender(); + + static void reflectingBook(); + static void reflectingAnimal(); + static void reflectingPerson(); + static void reflectingLibrary(); + + static void reflectingPodsStl(); + static void reflectingMyTypePerson(); + static void reflectingCStyleFunctions(); + }; +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/ClassMethodsTests.cpp b/RTLTestRunApp/src/FunctionalityTests/ClassMethodsTests.cpp new file mode 100644 index 00000000..6b087bba --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/ClassMethodsTests.cpp @@ -0,0 +1,579 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsBook.h" +#include "TestUtilsDate.h" +#include "GlobalTestUtils.h" + +#include "../CxxTestProps/inc/StringWrap.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(RTLInterfaceCxxMirror, get_class_methods_with_wrong_names) + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + optional badMethod = classBook->getMethod("no_method"); + ASSERT_FALSE(badMethod.has_value()); + } + + + TEST(RTLInterfaceCxxMirror, verify_typeIds_of_registered_records) + { + const auto& rtl_recordIdMap = cxx::mirror().getRecordIdMap(); + + for (const auto& itr0 : cxx::mirror().getNamespaceRecordMap()) + { + const auto& namespaceRecordMap = itr0.second; + for (const auto& itr1 : namespaceRecordMap) + { + const std::string& recordName = itr1.first; + const traits::uid_t recordId = cxx::reflected_id(recordName); + const auto& itr = rtl_recordIdMap.find(recordId); + + ASSERT_TRUE(itr != rtl_recordIdMap.end()); + + const rtl::Record& reflectedClass = itr->second; + + auto [err, robj] = reflectedClass.ctorT<>()(rtl::alloc::Stack); + + if (recordName == event::struct_) { + //Event's default constructor is private or deleted. + EXPECT_TRUE(err == rtl::error::TypeNotDefaultConstructible); + ASSERT_TRUE(robj.isEmpty()); + } + else if (recordName == library::class_) { + //Library's copy-constructor is deleted or private. + EXPECT_TRUE(err == rtl::error::TypeNotCopyConstructible); + ASSERT_TRUE(robj.isEmpty()); + } + else if (recordName == "void") { + //no constructor of class std::string is registered in RTL, but the calss is registered. + EXPECT_TRUE(err == rtl::error::TypeNotDefaultConstructible); + ASSERT_TRUE(robj.isEmpty()); + } + else if (recordName == StrWrapB::struct_ || + recordName == StrWrapC::struct_ || + recordName == StrWrapD::struct_) { + EXPECT_TRUE(err == rtl::error::TypeNotDefaultConstructible); + } + else { + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + EXPECT_TRUE(robj.getTypeId() == recordId); + } + } + } + } + + + TEST(ReflectionMethodCall_heapInstance, wrong_args) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oSetAuthor = classBook->getMethod(book::str_setAuthor); + ASSERT_TRUE(oSetAuthor); + EXPECT_FALSE(oSetAuthor->hasSignature()); + + auto setAuthor = oSetAuthor->targetT<>().argsT().returnT<>(); + EXPECT_FALSE(setAuthor); + + auto [err1, ret] = setAuthor(book)(book::AUTHOR); + + EXPECT_TRUE(err1 == error::SignatureMismatch); + ASSERT_TRUE(ret.isEmpty()); + EXPECT_FALSE(book::test_method_setAuthor(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ReflectionMethodCall_stackInstance, wrong_args) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oSetAuthor = classBook->getMethod(book::str_setAuthor); + ASSERT_TRUE(oSetAuthor); + EXPECT_FALSE(oSetAuthor->hasSignature()); + + auto setAuthor = oSetAuthor->targetT().argsT().returnT(); + EXPECT_FALSE(setAuthor); + + auto [err1, ret] = setAuthor(book)(book::AUTHOR); + + EXPECT_TRUE(err1 == error::SignatureMismatch); + ASSERT_TRUE(ret.isEmpty()); + EXPECT_FALSE(book::test_method_setAuthor(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethod_heapInstance, args_void) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oGetPublishedOn = classBook->getMethod(book::str_getPublishedOn); + ASSERT_TRUE(oGetPublishedOn); + EXPECT_TRUE(oGetPublishedOn->hasSignature<>()); //empty template params checks for zero arguments. + + auto getPublishedOn = oGetPublishedOn->targetT().argsT().returnT(); + EXPECT_TRUE(getPublishedOn); + + auto [err1, ret] = getPublishedOn(book)(); + + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const std::string& retStr = ret.view()->get(); + EXPECT_TRUE(book::test_method_getPublishedOn_return(retStr)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethod_stackInstance, args_void) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oGetPublishedOn = classBook->getMethod(book::str_getPublishedOn); + ASSERT_TRUE(oGetPublishedOn); + EXPECT_TRUE(oGetPublishedOn->hasSignature<>()); //empty template params checks for zero arguments. + + auto getPublishedOn = oGetPublishedOn->targetT().argsT().returnT(); + EXPECT_TRUE(getPublishedOn); + + auto [err1, ret] = getPublishedOn(book)(); + + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const std::string& retStr = ret.view()->get(); + EXPECT_TRUE(book::test_method_getPublishedOn_return(retStr)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethod_heapInstance, args_string) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oSetAuthor = classBook->getMethod(book::str_setAuthor); + ASSERT_TRUE(oSetAuthor); + EXPECT_TRUE(oSetAuthor->hasSignature()); + + auto setAuthor = oSetAuthor->targetT().argsT().returnT(); + EXPECT_TRUE(setAuthor); + + auto [err1, ret] = setAuthor(book)(book::AUTHOR); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + EXPECT_TRUE(book::test_method_setAuthor(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethod_stackInstance, args_string) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oSetAuthor = classBook->getMethod(book::str_setAuthor); + ASSERT_TRUE(oSetAuthor); + EXPECT_TRUE(oSetAuthor->hasSignature()); + + auto setAuthor = oSetAuthor->targetT().argsT().returnT(); + EXPECT_TRUE(setAuthor); + + auto [err1, ret] = setAuthor(book)(book::AUTHOR); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + EXPECT_TRUE(book::test_method_setAuthor(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_heapInstance, args_void) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oUpdateBookInfo = classBook->getMethod(book::str_updateBookInfo); + ASSERT_TRUE(oUpdateBookInfo); + EXPECT_TRUE(oUpdateBookInfo->hasSignature<>()); //empty template params checks for zero arguments. + + auto updateBookInfo = oUpdateBookInfo->targetT().argsT().returnT(); + EXPECT_TRUE(updateBookInfo); + + auto [err1, ret] = updateBookInfo(book)(); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + EXPECT_TRUE(book::test_method_updateBookInfo(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_stackInstance, args_void) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oUpdateBookInfo = classBook->getMethod(book::str_updateBookInfo); + ASSERT_TRUE(oUpdateBookInfo); + EXPECT_TRUE(oUpdateBookInfo->hasSignature<>()); //empty template params checks for zero arguments. + + auto updateBookInfo = oUpdateBookInfo->targetT().argsT().returnT(); + EXPECT_TRUE(updateBookInfo); + + auto [err1, ret] = updateBookInfo(book)(); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + EXPECT_TRUE(book::test_method_updateBookInfo(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_heapInstance, args_string_double_charPtr) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oUpdateBookInfo = classBook->getMethod(book::str_updateBookInfo); + ASSERT_TRUE(oUpdateBookInfo); + EXPECT_TRUE((oUpdateBookInfo->hasSignature())); + + auto updateBookInfo = oUpdateBookInfo->targetT().argsT().returnT(); + EXPECT_TRUE(updateBookInfo); + + auto [err1, ret] = updateBookInfo(book)(book::AUTHOR, book::PRICE, book::TITLE); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + + const bool isSuccess = book::test_method_updateBookInfo(book); + EXPECT_TRUE(isSuccess); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_stackInstance, args_string_double_charPtr) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oUpdateBookInfo = classBook->getMethod(book::str_updateBookInfo); + ASSERT_TRUE(oUpdateBookInfo); + EXPECT_TRUE((oUpdateBookInfo->hasSignature())); + + auto updateBookInfo = oUpdateBookInfo->targetT().argsT().returnT(); + EXPECT_TRUE(updateBookInfo); + + auto [err1, ret] = updateBookInfo(book)(book::AUTHOR, book::PRICE, book::TITLE); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + + const bool isSuccess = book::test_method_updateBookInfo(book); + EXPECT_TRUE(isSuccess); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_heapInstance, args_charPtr_double_string) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oUpdateBookInfo = classBook->getMethod(book::str_updateBookInfo); + ASSERT_TRUE(oUpdateBookInfo); + EXPECT_TRUE((oUpdateBookInfo->hasSignature())); + + auto updateBookInfo = oUpdateBookInfo->targetT().argsT().returnT(); + EXPECT_TRUE(updateBookInfo); + + auto [err1, ret] = updateBookInfo(book)(book::TITLE, book::PRICE, book::AUTHOR); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + + const bool isSuccess = book::test_method_updateBookInfo(book); + EXPECT_TRUE(isSuccess); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_stackInstance, args_charPtr_double_string) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oUpdateBookInfo = classBook->getMethod(book::str_updateBookInfo); + ASSERT_TRUE(oUpdateBookInfo); + EXPECT_TRUE((oUpdateBookInfo->hasSignature())); + + auto updateBookInfo = oUpdateBookInfo->targetT().argsT().returnT(); + EXPECT_TRUE(updateBookInfo); + + auto [err1, ret] = updateBookInfo(book)(book::TITLE, book::PRICE, book::AUTHOR); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + + const bool isSuccess = book::test_method_updateBookInfo(book); + EXPECT_TRUE(isSuccess); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_stackInstance, method_args_const_string___call_with_non_const_string) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oAddCopyrightTag = classBook->getMethod(book::str_addCopyrightTag); + ASSERT_TRUE(oAddCopyrightTag); + EXPECT_TRUE(oAddCopyrightTag->hasSignature()); + + auto addCopyrightTag = oAddCopyrightTag->targetT().argsT().returnT(); + EXPECT_TRUE(addCopyrightTag); + + //actual signature is 'const string', but we are passing 'string' as argument. which resolves to right call. + //as long as any param_type in signature is not reference, const-qualifier do not matter. + auto [err1, ret] = addCopyrightTag(book)(book::COPYRIGHT_TAG); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + + const bool isSuccess = book::test_method_addCopyrightTag(book); + EXPECT_TRUE(isSuccess); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_heapInstance, method_args_const_string___call_with_non_const_string) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oAddCopyrightTag = classBook->getMethod(book::str_addCopyrightTag); + ASSERT_TRUE(oAddCopyrightTag); + EXPECT_TRUE((oAddCopyrightTag->hasSignature())); + + auto addCopyrightTag = oAddCopyrightTag->targetT().argsT().returnT(); + EXPECT_TRUE(addCopyrightTag); + + //actual signature is 'const string', but we are passing 'string' as argument. which resolves to right call. + //as long as any param_type in signature is not reference, const-qualifier do not matter. + auto [err1, ret] = addCopyrightTag(book)(book::COPYRIGHT_TAG); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + + const bool isSuccess = book::test_method_addCopyrightTag(book); + EXPECT_TRUE(isSuccess); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_stackInstance, method_taking_args_const_string_and_const_string_ref) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oAddPreface = classBook->getMethod(book::str_addPreface); + ASSERT_TRUE(oAddPreface); + EXPECT_FALSE((oAddPreface->hasSignature())); + EXPECT_FALSE((oAddPreface->hasSignature())); + EXPECT_FALSE((oAddPreface->hasSignature())); + //if reference is involved, then const-qualifier must be exactly same as in signature reference type. + EXPECT_TRUE((oAddPreface->hasSignature())); + + auto addPreface = oAddPreface->targetT().argsT().returnT(); + EXPECT_TRUE(addPreface); + + //if the signature has any one type as reference, then types must be explicitly specified using bind<...>() + //And reference type must be specified with exact qualifiers, other 'by value' types do no need to explicitly specify the cv-qualifiers. + auto [err1, ret] = addPreface.bind(book)(book::ACKNOWLEDGEMENTS, book::PREFACE); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + + const bool isSuccess = book::test_method_addPreface(book); + EXPECT_TRUE(isSuccess); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ClassBookMethodOverload_heapInstance, method_taking_args_const_string_and_const_string_ref) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT<>()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional oAddPreface = classBook->getMethod(book::str_addPreface); + ASSERT_TRUE(oAddPreface); + EXPECT_FALSE((oAddPreface->hasSignature())); + EXPECT_FALSE((oAddPreface->hasSignature())); + EXPECT_FALSE((oAddPreface->hasSignature())); + //if reference is involved, then const-qualifier must be exactly same as in signature reference type. + EXPECT_TRUE((oAddPreface->hasSignature())); + + auto addPreface = oAddPreface->targetT().argsT().returnT(); + EXPECT_TRUE(addPreface); + + //if the signature has any one type as reference, then types must be explicitly specified using bind<...>() + //And reference type must be specified with exact qualifiers, other 'by value' types do no need to explicitly specify the cv-qualifiers. + auto [err1, ret] = addPreface.bind(book)(book::ACKNOWLEDGEMENTS, book::PREFACE); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret.isEmpty()); + + const bool isSuccess = book::test_method_addPreface(book); + EXPECT_TRUE(isSuccess); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/ConstMethodOverloadTests.cpp b/RTLTestRunApp/src/FunctionalityTests/ConstMethodOverloadTests.cpp new file mode 100644 index 00000000..6d5da6fb --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/ConstMethodOverloadTests.cpp @@ -0,0 +1,287 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsAnimal.h" +#include "TestUtilsPerson.h" +#include "TestUtilsBook.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(ConstMethodOverload, explicitly_making_const_call__on_wrong_target) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book] = classBook->ctorT()(alloc::Stack); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional oUpdateLastName = classPerson->getMethod(person::str_updateLastName); + ASSERT_TRUE(oUpdateLastName); + EXPECT_TRUE(oUpdateLastName->hasSignature()); + + method updateLastName = oUpdateLastName->targetT().argsT().returnT(); + EXPECT_TRUE(updateLastName); + { + auto [err, ret] = updateLastName(book)(person::LAST_NAME); + // Only const method exits for this function, no non-const overload. + EXPECT_TRUE(err == error::NonConstOverloadMissing); + ASSERT_TRUE(ret.isEmpty()); + } { + auto [err, ret] = updateLastName(std::cref(book))(person::LAST_NAME); + + EXPECT_TRUE(err == error::TargetTypeMismatch); + ASSERT_TRUE(ret.isEmpty()); + } + } + } + + + TEST(ConstMethodOverload, explicitly_making_const_call__on_empty_target) + { + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional oUpdateLastName = classPerson->getMethod(person::str_updateLastName); + ASSERT_TRUE(oUpdateLastName); + EXPECT_TRUE(oUpdateLastName->hasSignature()); + + method updateLastName = oUpdateLastName->targetT().argsT().returnT(); + EXPECT_TRUE(updateLastName); + { + // only const-overload exists, this tries to call the non-const version since + // the 'robj' is non-const. + RObject robj; + auto [err, ret] = updateLastName(robj)(person::LAST_NAME); + EXPECT_TRUE(err == error::NonConstOverloadMissing); + ASSERT_TRUE(ret.isEmpty()); + } { + // Here the const-method is invoked, since the 'robj' is decleared const, + // it automatically binds to const-overload, however the 'robj' is empty + // hence the expecetd return error is error::EmptyRObject. + const RObject robj; + auto [err, ret] = updateLastName(robj)(person::LAST_NAME); + EXPECT_TRUE(err == error::EmptyRObject); + ASSERT_TRUE(ret.isEmpty()); + } + } + } + + + TEST(ConstMethodOverload, semantics_when_only_const_method_exists) + { + auto testWithAllocOn = [](alloc alloc)->void + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional oUpdateLastName = classPerson->getMethod(person::str_updateLastName); + ASSERT_TRUE(oUpdateLastName); + + auto [err0, person] = classPerson->ctorT()(alloc, person::FIRST_NAME); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(person.isEmpty()); + EXPECT_TRUE(oUpdateLastName->hasSignature()); + + method updateLastName = oUpdateLastName->targetT().argsT().returnT(); + EXPECT_TRUE(updateLastName); + { + auto [err, ret] = updateLastName(person)(person::LAST_NAME); + // only const method exists, no non-const overload found. + EXPECT_TRUE(err == error::NonConstOverloadMissing); + ASSERT_TRUE(ret.isEmpty()); + } { + // explicit call to const method. + auto [err, ret] = updateLastName(std::cref(person))(person::LAST_NAME); + + EXPECT_TRUE(err == error::None); + ASSERT_TRUE(ret.isEmpty()); + } + EXPECT_TRUE(person::test_method_updateLastName_const(person)); + }; + + testWithAllocOn(alloc::Heap); + EXPECT_TRUE(person::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + + testWithAllocOn(alloc::Stack); + EXPECT_TRUE(person::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ConstMethodOverload, semantics_when_const_and_nonconst_overload_exists) + { + auto testWithAllocOn = [](alloc alloc)->void + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + auto [err0, person] = classPerson->ctorT()(alloc, person::FIRST_NAME); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(person.isEmpty()); + + optional oUpdateAddress = classPerson->getMethod(person::str_updateAddress); + ASSERT_TRUE(oUpdateAddress); + EXPECT_TRUE(oUpdateAddress->hasSignature()); + + method updateAddress = oUpdateAddress->targetT().argsT().returnT(); + EXPECT_TRUE(updateAddress); + { + // sending 'person' as const (using std::cref) calls the const-method overload. + auto [err, ret] = updateAddress(cref(person))(person::ADDRESS); + EXPECT_TRUE(err == error::None); + ASSERT_TRUE(ret.isEmpty()); + } { + // sending 'person' as non-const calls the non-const-method overload. + auto [err, ret] = updateAddress(person)(person::ADDRESS); + EXPECT_TRUE(err == error::None); + ASSERT_TRUE(ret.isEmpty()); + } + }; + + testWithAllocOn(alloc::Heap); + EXPECT_TRUE(person::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + + testWithAllocOn(alloc::Stack); + EXPECT_TRUE(person::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ConstMethodOverload, explicit_method_resolution__only_non_const_method_exists__call_on_returned_const_target) + { + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional createConstPerson = classPerson->getMethod(person::str_createConst); + ASSERT_TRUE(createConstPerson); + + static_method createPerson = createConstPerson->argsT().returnT(); + EXPECT_TRUE(createPerson); + EXPECT_EQ(createPerson.get_init_error(), rtl::error::None); + + auto [err0, constPerson] = createPerson(); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(constPerson.isEmpty()); + + optional oGetFirstName = classPerson->getMethod(person::str_getFirstName); + ASSERT_TRUE(oGetFirstName); + EXPECT_TRUE(oGetFirstName->hasSignature<>()); + + method getFirstName = oGetFirstName->targetT().argsT().returnT(); + EXPECT_TRUE(getFirstName); + { + auto [err, ret] = getFirstName(cref(constPerson))(); + + // A non-const version exists, but the object itself is truly const. + // Therefore, only const-qualified methods can be called on it. + // However, no const-overload is available. + EXPECT_TRUE(err == error::ConstOverloadMissing); + ASSERT_TRUE(ret.isEmpty()); + } { + auto [err, ret] = getFirstName(constPerson)(); + EXPECT_TRUE(err == error::InvalidCallOnConstTarget); + ASSERT_TRUE(ret.isEmpty()); + } + } + EXPECT_TRUE(person::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ConstMethodOverload, explicit_method_resolution__only_non_const_method_exists__call_on_returned_const_pointer_target) + { + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional createConstPtrPerson = classPerson->getMethod(person::str_createPtr); + ASSERT_TRUE(createConstPtrPerson); + + static_method createPerson = createConstPtrPerson->argsT().returnT(); + EXPECT_TRUE(createPerson); + EXPECT_EQ(createPerson.get_init_error(), rtl::error::None); + + // Returns 'const Person*', unmanaged, need explicit call to 'delete'. + auto [err0, constPersonPtr] = createPerson(); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(constPersonPtr.isEmpty()); + + optional oGetFirstName = classPerson->getMethod(person::str_getFirstName); + ASSERT_TRUE(oGetFirstName); + EXPECT_TRUE(oGetFirstName->hasSignature<>()); + + method getFirstName = oGetFirstName->targetT().argsT().returnT(); + EXPECT_TRUE(getFirstName); + { + auto [err, ret] = getFirstName(cref(constPersonPtr))(); + // A non-const version exists, but the object itself is truly const. + // Therefore, only const-qualified methods can be called on it. + // However, no const-overload is available. + EXPECT_TRUE(err == error::ConstOverloadMissing); + ASSERT_TRUE(ret.isEmpty()); + } { + auto [err, ret] = getFirstName(constPersonPtr)(); + EXPECT_TRUE(err == error::InvalidCallOnConstTarget); + ASSERT_TRUE(ret.isEmpty()); + } + EXPECT_TRUE(person::delete_unmanaged_person_instance_created_via_createPtr(constPersonPtr)); + } + EXPECT_TRUE(person::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ConstMethodOverload, erased_target_known_return_void) + { + { + // Retrieve the metadata for the "Animal" class. + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + // Create an instance of the "Animal" class. + auto [err0, animal] = classAnimal->ctorT()(alloc::Heap); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(animal.isEmpty()); + + // Retrieve the "setAnimalName" method. + optional oSetAnimalName = classAnimal->getMethod(animal::str_setAnimalName); + ASSERT_TRUE(oSetAnimalName); + // Verify that the method has the correct signature for a const L-value reference. + EXPECT_TRUE((oSetAnimalName->hasSignature())); + + auto setAnimalName = oSetAnimalName->targetT().argsT().returnT(); + EXPECT_TRUE(setAnimalName); + + // Invoke the method with a const L-value reference. + auto [err1, ret1] = setAnimalName(std::cref(animal))(animal::NAME); + + EXPECT_EQ(err1, error::None); + EXPECT_EQ(ret1, std::nullopt); + + // Validate the behavior of the method. + EXPECT_TRUE(animal::test_method_const_setAnimalName_const_lvalue_ref_args(animal)); + } + + // Ensure that all instances are cleaned up. + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/ConstructorTests.cpp b/RTLTestRunApp/src/FunctionalityTests/ConstructorTests.cpp new file mode 100644 index 00000000..d7a1e24f --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/ConstructorTests.cpp @@ -0,0 +1,347 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsBook.h" +#include "TestUtilsDate.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(RTLInterfaceCxxMirror, get_record_types_with_wrong_names) + { + optional badFunc = cxx::mirror().getFunction(date::ns, "wrong_date_struct"); + EXPECT_FALSE(badFunc); + + optional badRec = cxx::mirror().getRecord(date::ns, "wrong" + std::string(date::struct_)); + EXPECT_FALSE(badRec); + } + + + TEST(HeapAllocConstructorDate, wrong_args) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + rtl::constructor ctorT = classDate->ctorT(); + auto [err, date] = ctorT(alloc::Heap, "wrong", 10); + + EXPECT_TRUE(err == error::SignatureMismatch); + ASSERT_TRUE(date.isEmpty()); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(StackAllocConstructorDate, wrong_args) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + rtl::constructor ctorT = classDate->ctorT(); + auto [err, date] = ctorT(alloc::Stack, "wrong", 10); + + EXPECT_TRUE(err == error::SignatureMismatch); + ASSERT_TRUE(date.isEmpty()); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(HeapAllocConstructorDate, args_void) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + auto [err, date] = classDate->ctorT()(alloc::Heap); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(date.isEmpty()); + EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor<>(date)); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(StackAllocConstructorDate, args_void) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + auto [err, date] = classDate->ctorT()(alloc::Stack); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(date.isEmpty()); + EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor<>(date)); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(HeapAllocConstructorDate, args_string) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + rtl::constructor ctorT = classDate->ctorT(); + auto [err, date] = ctorT(alloc::Heap, date::DATE_STR0); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(date.isEmpty()); + EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor(date)); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(StackAllocConstructorDate, args_string) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + rtl::constructor ctorT = classDate->ctorT(); + auto [err, date] = ctorT(alloc::Stack, date::DATE_STR0); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(date.isEmpty()); + EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor(date)); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(HeapAllocConstructorDate, args_unsigned_unsigned_unsigned) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + auto ctorT = classDate->ctorT(); + auto [err, date] = ctorT(alloc::Heap, date::DAY, date::MONTH, date::YEAR); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(date.isEmpty()); + + const bool isPassed = date::test_dynamic_alloc_instance_ctor(date); + EXPECT_TRUE(isPassed); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(StackAllocConstructorDate, args_unsigned_unsigned_unsigned) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + unsigned day = date::DAY; + unsigned month = date::MONTH; + unsigned year = date::YEAR; + + auto ctorT = classDate->ctorT(); + auto [err, date] = ctorT(alloc::Stack, day, month, year); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(date.isEmpty()); + + const bool isPassed = date::test_dynamic_alloc_instance_ctor(date); + EXPECT_TRUE(isPassed); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(DestructorDate, non_virtual_on_heap) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + auto [err, date] = classDate->ctorT()(alloc::Heap); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(date.isEmpty()); + EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor<>(date)); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(DestructorDate, non_virtual_on_stack) + { + { + optional classDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(classDate); + + auto [err, date] = classDate->ctorT()(alloc::Stack); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(date.isEmpty()); + EXPECT_TRUE(date::test_dynamic_alloc_instance_ctor<>(date)); + } + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(HeapAllocConstructorBook, wrong_args) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err, book] = classBook->ctorT()(alloc::Heap, 19.0, 87.5); + + EXPECT_TRUE(err == error::SignatureMismatch); + ASSERT_TRUE(book.isEmpty()); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(StackAllocConstructorBook, wrong_args) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err, book] = classBook->ctorT()(alloc::Stack, 19.0, 87.5); + + EXPECT_TRUE(err == error::SignatureMismatch); + ASSERT_TRUE(book.isEmpty()); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(HeapAllocConstructorBook, args_default) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err, book] = classBook->ctorT()(alloc::Heap); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(book.isEmpty()); + EXPECT_TRUE(book::test_dynamic_alloc_instance_ctor(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(StackAllocConstructorBook, args_default) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err, book] = classBook->ctorT()(alloc::Stack); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(book.isEmpty()); + EXPECT_TRUE(book::test_dynamic_alloc_instance_ctor(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(HeapAllocConstructorBook, args_double_string) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + rtl::constructor ctorT = classBook->ctorT(); + auto [err, book] = ctorT(alloc::Heap, book::PRICE, book::TITLE); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(book.isEmpty()); + + const bool isPassed = book::test_dynamic_alloc_instance_ctor(book); + EXPECT_TRUE(isPassed); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(StackAllocConstructorBook, args_double_string) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + rtl::constructor ctorT = classBook->ctorT(); + auto [err, book] = ctorT(alloc::Stack, book::PRICE, book::TITLE); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(book.isEmpty()); + + const bool isPassed = book::test_dynamic_alloc_instance_ctor(book); + EXPECT_TRUE(isPassed); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(DestructorBook, non_virtual_on_heap) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err, book] = classBook->ctorT()(alloc::Heap); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(book.isEmpty()); + EXPECT_TRUE(book::test_dynamic_alloc_instance_ctor(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(DestructorBook, non_virtual_on_stack) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err, book] = classBook->ctorT()(alloc::Stack); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(book.isEmpty()); + EXPECT_TRUE(book::test_dynamic_alloc_instance_ctor(book)); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/CopyConstructorTests.cpp b/RTLTestRunApp/src/FunctionalityTests/CopyConstructorTests.cpp new file mode 100644 index 00000000..8367af42 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/CopyConstructorTests.cpp @@ -0,0 +1,613 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsBook.h" +#include "TestUtilsDate.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(CopyConstructor, clone_default_instance_on_heap_source_on_heap) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book0] = classBook->ctorT()(alloc::Heap); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book0.isEmpty()); + + auto [err1, book1] = book0.clone(); + + EXPECT_TRUE(err1 == error::None); + EXPECT_FALSE(book1.isEmpty()); + + EXPECT_EQ(book0.getTypeId(), book1.getTypeId()); + + EXPECT_TRUE(book::get_book_instance_count() == 2); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 2); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, clone_default_instance_on_stack_source_on_stack) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book0] = classBook->ctorT()(alloc::Stack); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book0.isEmpty()); + + auto [err1, book1] = book0.clone(); + + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(book1.isEmpty()); + + EXPECT_TRUE(book::get_book_instance_count() == 2); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, clone_default_instance_on_heap_source_on_stack) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book0] = classBook->ctorT()(alloc::Stack); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book0.isEmpty()); + + auto [err1, book1] = book0.clone(); + + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(book1.isEmpty()); + + EXPECT_TRUE(book::get_book_instance_count() == 2); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, clone_default_instance_on_stack_source_on_heap) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, book0] = classBook->ctorT()(alloc::Heap); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book0.isEmpty()); + + auto [err1, book1] = book0.clone(); + + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(book1.isEmpty()); + + EXPECT_TRUE(book::get_book_instance_count() == 2); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, clone_mutated_instance_on_heap_source_on_heap) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + rtl::constructor ctorT = classBook->ctorT(); + + auto [err0, book] = ctorT(alloc::Heap, book::PRICE, book::TITLE); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + { + optional oSetAuthor = classBook->getMethod(book::str_setAuthor); + ASSERT_TRUE(oSetAuthor); + + auto setAuthor = oSetAuthor->targetT().argsT().returnT(); + + auto [err, ret] = setAuthor(book)(book::AUTHOR); + EXPECT_TRUE(err == error::None); + EXPECT_TRUE(ret.isEmpty()); + } { + optional oSetDescription = classBook->getMethod(book::str_setDescription); + ASSERT_TRUE(oSetDescription); + + auto setDescription = oSetDescription->targetT().argsT().returnT(); + + auto [err, ret] = setDescription(book)(book::DESCRIPTION); + EXPECT_TRUE(err == error::None); + EXPECT_TRUE(ret.isEmpty()); + } + auto [err1, bookCopy] = book.clone(); + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(bookCopy.isEmpty()); + + const bool isPassed = book::test_copy_ctor_with_mutated_object(bookCopy); + EXPECT_TRUE(isPassed); + + EXPECT_TRUE(book::get_book_instance_count() == 2); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 2); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, clone_mutated_instance_on_stack_source_on_stack) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + rtl::constructor ctorT = classBook->ctorT(); + + auto [err0, book] = ctorT(alloc::Stack, book::PRICE, book::TITLE); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + { + optional oSetAuthor = classBook->getMethod(book::str_setAuthor); + ASSERT_TRUE(oSetAuthor); + + auto setAuthor = oSetAuthor->targetT().argsT().returnT(); + + auto [err, ret] = setAuthor(book)(book::AUTHOR); + EXPECT_TRUE(err == error::None); + EXPECT_TRUE(ret.isEmpty()); + } { + optional oSetDescription = classBook->getMethod(book::str_setDescription); + ASSERT_TRUE(oSetDescription); + + auto setDescription = oSetDescription->targetT().argsT().returnT(); + + auto [err, ret] = setDescription(book)(book::DESCRIPTION); + EXPECT_TRUE(err == error::None); + EXPECT_TRUE(ret.isEmpty()); + } + auto [err1, bookCopy] = book.clone(); + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(bookCopy.isEmpty()); + + const bool isPassed = book::test_copy_ctor_with_mutated_object(bookCopy); + EXPECT_TRUE(isPassed); + + EXPECT_TRUE(book::get_book_instance_count() == 2); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, clone_mutated_instance_on_heap_source_on_stack) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + rtl::constructor ctorT = classBook->ctorT(); + + auto [err0, book] = ctorT(alloc::Stack, book::PRICE, book::TITLE); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + { + optional oSetAuthor = classBook->getMethod(book::str_setAuthor); + ASSERT_TRUE(oSetAuthor); + + auto setAuthor = oSetAuthor->targetT().argsT().returnT(); + + auto [err, ret] = setAuthor(book)(book::AUTHOR); + EXPECT_TRUE(err == error::None); + EXPECT_TRUE(ret.isEmpty()); + } { + optional oSetDescription = classBook->getMethod(book::str_setDescription); + ASSERT_TRUE(oSetDescription); + + auto setDescription = oSetDescription->targetT().argsT().returnT(); + + auto [err, ret] = setDescription(book)(book::DESCRIPTION); + EXPECT_TRUE(err == error::None); + EXPECT_TRUE(ret.isEmpty()); + } + auto [err1, bookCopy] = book.clone(); + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(bookCopy.isEmpty()); + + const bool isPassed = book::test_copy_ctor_with_mutated_object(bookCopy); + EXPECT_TRUE(isPassed); + + EXPECT_TRUE(book::get_book_instance_count() == 2); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, clone_mutated_instance_on_stack_source_on_heap) + { + { + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + rtl::constructor ctorT = classBook->ctorT(); + + auto [err0, book] = ctorT(alloc::Heap, book::PRICE, book::TITLE); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(book.isEmpty()); + { + optional oSetAuthor = classBook->getMethod(book::str_setAuthor); + ASSERT_TRUE(oSetAuthor); + + auto setAuthor = oSetAuthor->targetT().argsT().returnT(); + + auto [err, ret] = setAuthor(book)(book::AUTHOR); + EXPECT_TRUE(err == error::None); + EXPECT_TRUE(ret.isEmpty()); + } { + optional oSetDescription = classBook->getMethod(book::str_setDescription); + ASSERT_TRUE(oSetDescription); + + auto setDescription = oSetDescription->targetT().argsT().returnT(); + + auto [err, ret] = setDescription(book)(book::DESCRIPTION); + EXPECT_TRUE(err == error::None); + EXPECT_TRUE(ret.isEmpty()); + } + auto [err1, bookCopy] = book.clone(); + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(bookCopy.isEmpty()); + + const bool isPassed = book::test_copy_ctor_with_mutated_object(bookCopy); + EXPECT_TRUE(isPassed); + + EXPECT_TRUE(book::get_book_instance_count() == 2); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + EXPECT_TRUE(book::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, sharing_semantics__clone_on_stack_src_on_stack_mutate_after) + { + { + // Retrieve the reflected Record for the 'Calender' struct + optional typeCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(typeCalender); + + // Create a stack-allocated object via reflection + auto [err0, calender0] = typeCalender->ctorT()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(calender0.isEmpty()); + EXPECT_FALSE(calender0.isOnHeap()); + + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + + // The underlying object is expected to be copied via copy constructor. + auto [err1, calender1] = calender0.clone(); + + EXPECT_TRUE(err1 == error::None); + // Verify the object created is valid and on stack. + ASSERT_FALSE(calender1.isEmpty()); + EXPECT_FALSE(calender1.isOnHeap()); + EXPECT_TRUE(calender0.getTypeId() == calender1.getTypeId()); + + // Calender got cloned now. + EXPECT_TRUE(calender::get_instance_count() == 2); + // 'Calender' has shared_ptr and a std::unique_ptr, so one got shared and one newly created. + EXPECT_TRUE(event::get_instance_count() == 3); + // 'Event' has a unique_ptr and 3 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 3); + + optional oGetTheDate = typeCalender->getMethod(calender::str_getTheDate); + ASSERT_TRUE(oGetTheDate); + + rtl::method getTheDate = oGetTheDate->targetT().argsT().returnT(); + EXPECT_TRUE(getTheDate); + { + auto [err_0, date0] = getTheDate(calender0)(); + + EXPECT_TRUE(err_0 == error::None); + EXPECT_FALSE(date0.isOnHeap()); + ASSERT_FALSE(date0.isEmpty()); + + auto [err_1, date1] = getTheDate(calender1)(); + + EXPECT_TRUE(err_1 == error::None); + EXPECT_FALSE(date1.isOnHeap()); + ASSERT_FALSE(date1.isEmpty()); + + // both objects must be equal (shared via shared_ptr inside 'Calender') + EXPECT_TRUE(date::test_if_obejcts_are_equal(date0, date1)); + + optional structDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(structDate); + + optional oUpdateDate = structDate->getMethod(date::str_updateDate); + ASSERT_TRUE(oUpdateDate); + + method updateDate = oUpdateDate->targetT().argsT().returnT(); + EXPECT_TRUE(updateDate); + { + auto [err, ret] = updateDate(date0)(date::DATE_STR1); + ASSERT_TRUE(err == error::None && ret.isEmpty()); + // After mutation, they should be still equal. + EXPECT_TRUE(date::test_if_obejcts_are_equal(date0, date1)); + } + } + } + // After scope exit, stack instances are cleaned up automatically + EXPECT_TRUE(calender::get_instance_count() == 0); + EXPECT_TRUE(event::get_instance_count() == 0); + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, sharing_semantics__clone_on_heap_src_on_stack_mutate_after) + { + { + // Retrieve the reflected Record for the 'Calender' struct + optional typeCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(typeCalender); + + // Create a stack-allocated object via reflection + auto [err0, calender0] = typeCalender->ctorT()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(calender0.isEmpty()); + EXPECT_FALSE(calender0.isOnHeap()); + + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + + // The underlying object is expected to be copied via copy constructor. + auto [err1, calender1] = calender0.clone(); + + EXPECT_TRUE(err1 == error::None); + // Verify the object created is valid and on stack. + ASSERT_FALSE(calender1.isEmpty()); + EXPECT_TRUE(calender1.isOnHeap()); + EXPECT_TRUE(calender0.getTypeId() == calender1.getTypeId()); + + // Calender got cloned now. + EXPECT_TRUE(calender::get_instance_count() == 2); + // 'Calender' has shared_ptr and a std::unique_ptr, so one got shared and one newly created. + EXPECT_TRUE(event::get_instance_count() == 3); + // 'Event' has a unique_ptr and 3 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 3); + + optional oGetTheDate = typeCalender->getMethod(calender::str_getTheDate); + ASSERT_TRUE(oGetTheDate); + + rtl::method getTheDate = oGetTheDate->targetT().argsT().returnT(); + EXPECT_TRUE(getTheDate); + { + auto [err_0, date0] = getTheDate(calender0)(); + + EXPECT_TRUE(err_0 == error::None); + EXPECT_FALSE(date0.isOnHeap()); + ASSERT_FALSE(date0.isEmpty()); + + auto [err_1, date1] = getTheDate(calender1)(); + + EXPECT_TRUE(err_1 == error::None); + EXPECT_FALSE(date1.isOnHeap()); + ASSERT_FALSE(date1.isEmpty()); + + // both objects must be equal (shared via shared_ptr inside 'Calender') + EXPECT_TRUE(date::test_if_obejcts_are_equal(date0, date1)); + + optional structDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(structDate); + + optional oUpdateDate = structDate->getMethod(date::str_updateDate); + ASSERT_TRUE(oUpdateDate); + + method updateDate = oUpdateDate->targetT().argsT().returnT(); + EXPECT_TRUE(updateDate); + { + auto [err, ret] = updateDate(date0)(date::DATE_STR1); + ASSERT_TRUE(err == error::None && ret.isEmpty()); + // After mutation, they should be still equal. + EXPECT_TRUE(date::test_if_obejcts_are_equal(date0, date1)); + } + } + } + // After scope exit, stack instances are cleaned up automatically + EXPECT_TRUE(calender::get_instance_count() == 0); + EXPECT_TRUE(event::get_instance_count() == 0); + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, sharing_semantics__clone_on_stack_src_on_heap_mutate_after) + { + { + // Retrieve the reflected Record for the 'Calender' struct + optional typeCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(typeCalender); + + // Create a stack-allocated object via reflection + auto [err0, calender0] = typeCalender->ctorT()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(calender0.isEmpty()); + EXPECT_TRUE(calender0.isOnHeap()); + + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + + // The underlying object is expected to be copied via copy constructor. + auto [err1, calender1] = calender0.clone(); + + EXPECT_TRUE(err1 == error::None); + // Verify the object created is valid and on stack. + ASSERT_FALSE(calender1.isEmpty()); + EXPECT_FALSE(calender1.isOnHeap()); + EXPECT_TRUE(calender0.getTypeId() == calender1.getTypeId()); + + // Calender got cloned now. + EXPECT_TRUE(calender::get_instance_count() == 2); + // 'Calender' has shared_ptr and a std::unique_ptr, so one got shared and one newly created. + EXPECT_TRUE(event::get_instance_count() == 3); + // 'Event' has a unique_ptr and 3 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 3); + + optional oGetTheDate = typeCalender->getMethod(calender::str_getTheDate); + ASSERT_TRUE(oGetTheDate); + + rtl::method getTheDate = oGetTheDate->targetT().argsT().returnT(); + EXPECT_TRUE(getTheDate); + { + auto [err_0, date0] = getTheDate(calender0)(); + + EXPECT_TRUE(err_0 == error::None); + EXPECT_FALSE(date0.isOnHeap()); + ASSERT_FALSE(date0.isEmpty()); + + auto [err_1, date1] = getTheDate(calender1)(); + + EXPECT_TRUE(err_1 == error::None); + EXPECT_FALSE(date1.isOnHeap()); + ASSERT_FALSE(date1.isEmpty()); + + // both objects must be equal (shared via shared_ptr inside 'Calender') + EXPECT_TRUE(date::test_if_obejcts_are_equal(date0, date1)); + + optional structDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(structDate); + + optional oUpdateDate = structDate->getMethod(date::str_updateDate); + ASSERT_TRUE(oUpdateDate); + + method updateDate = oUpdateDate->targetT().argsT().returnT(); + EXPECT_TRUE(updateDate); + { + auto [err, ret] = updateDate(date0)(date::DATE_STR1); + ASSERT_TRUE(err == error::None && ret.isEmpty()); + // After mutation, they should be still equal. + EXPECT_TRUE(date::test_if_obejcts_are_equal(date0, date1)); + } + } + } + // After scope exit, stack instances are cleaned up automatically + EXPECT_TRUE(calender::get_instance_count() == 0); + EXPECT_TRUE(event::get_instance_count() == 0); + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(CopyConstructor, sharing_semantics__clone_on_heap_src_on_heap_mutate_after) + { + { + // Retrieve the reflected Record for the 'Calender' struct + optional typeCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(typeCalender); + + // Create a stack-allocated object via reflection + auto [err0, calender0] = typeCalender->ctorT()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(calender0.isEmpty()); + EXPECT_TRUE(calender0.isOnHeap()); + + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + + // The underlying object is expected to be copied via copy constructor. + auto [err1, calender1] = calender0.clone(); + + EXPECT_TRUE(err1 == error::None); + // Verify the object created is valid and on stack. + ASSERT_FALSE(calender1.isEmpty()); + EXPECT_TRUE(calender1.isOnHeap()); + EXPECT_TRUE(calender0.getTypeId() == calender1.getTypeId()); + + // Calender got cloned now. + EXPECT_TRUE(calender::get_instance_count() == 2); + // 'Calender' has shared_ptr and a std::unique_ptr, so one got shared and one newly created. + EXPECT_TRUE(event::get_instance_count() == 3); + // 'Event' has a unique_ptr and 3 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 3); + + optional oGetSavedDate = typeCalender->getMethod(calender::str_getSavedDate); + ASSERT_TRUE(oGetSavedDate); + + rtl::method getSavedDate = oGetSavedDate->targetT().argsT().returnT(); + EXPECT_TRUE(getSavedDate); + { + auto [err_0, date0] = getSavedDate(calender0)(); + + EXPECT_TRUE(err_0 == error::None); + EXPECT_FALSE(date0.isOnHeap()); + ASSERT_FALSE(date0.isEmpty()); + + auto [err_1, date1] = getSavedDate(calender1)(); + + EXPECT_TRUE(err_1 == error::None); + EXPECT_FALSE(date1.isOnHeap()); + ASSERT_FALSE(date1.isEmpty()); + + // both objects must be equal, created via default-constructor, different instances, not shared. + EXPECT_TRUE(date::test_if_obejcts_are_equal(date0, date1)); + + optional structDate = cxx::mirror().getRecord(date::ns, date::struct_); + ASSERT_TRUE(structDate); + + optional oUpdateDate = structDate->getMethod(date::str_updateDate); + ASSERT_TRUE(oUpdateDate); + + method updateDate = oUpdateDate->targetT().argsT().returnT(); + EXPECT_TRUE(updateDate); + { + auto [err, ret] = updateDate(date0)(date::DATE_STR1); + ASSERT_TRUE(err == error::None && ret.isEmpty()); + // After mutation, they should be not be equal, since both are unique instances. + EXPECT_FALSE(date::test_if_obejcts_are_equal(date0, date1)); + } + } + } + // After scope exit, stack instances are cleaned up automatically + EXPECT_TRUE(calender::get_instance_count() == 0); + EXPECT_TRUE(event::get_instance_count() == 0); + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } +} diff --git a/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp b/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp new file mode 100644 index 00000000..5e4ad0ca --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/MoveConstructorTests.cpp @@ -0,0 +1,278 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsDate.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(MoveSemantics, move_reflected_type_allocated_on_stack) + { + { + // Retrieve the reflected Record for the 'Calender' struct + optional classCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(classCalender); + + // Create a stack-allocated object via reflection + auto [err0, calender0] = classCalender->ctorT()(alloc::Stack); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(calender0.isEmpty()); + EXPECT_FALSE(calender0.isOnHeap()); + + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + + // Sets Calender's move operation counter to zero + calender::reset_move_ops_counter(); + + // 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); + + ASSERT_FALSE(calender1.isEmpty()); + EXPECT_FALSE(calender1.isOnHeap()); + + // '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); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + { + // Cloning a moved-from object ie an empty object; + auto [err, ret] = calender0.clone(); + EXPECT_TRUE(err == error::EmptyRObject); + ASSERT_TRUE(ret.isEmpty()); + } { + // Cloning a moved-from object ie an empty object; + auto [err, ret] = calender0.clone(); + EXPECT_TRUE(err == error::EmptyRObject); + ASSERT_TRUE(ret.isEmpty()); + } + } + // After scope exit, stack instances are cleaned up automatically + EXPECT_TRUE(calender::get_instance_count() == 0); + EXPECT_TRUE(event::get_instance_count() == 0); + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(MoveSemantics, move_reflected_type_allocated_on_heap) + { + { + // Retrieve the reflected Record for the 'Calender' struct + optional classCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(classCalender); + + // Create a stack-allocated object via reflection + auto [err0, calender0] = classCalender->ctorT()(alloc::Heap); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(calender0.isEmpty()); + EXPECT_TRUE(calender0.isOnHeap()); + + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + + // Sets Calender's move operation counter to zero + calender::reset_move_ops_counter(); + + // RObject created via alloc::HEAP, contains pointer to reflected type internally, So just the + // address wrapped in std::any inside Robject is moved. Calender's move constructor is not called. + RObject calender1 = std::move(calender0); + + // Calender's move constructor isn't called. + EXPECT_TRUE(calender::get_move_ops_count() == 0); + + ASSERT_FALSE(calender1.isEmpty()); + EXPECT_TRUE(calender1.isOnHeap()); + + // '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); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + } + // After scope exit, stack instances are cleaned up automatically + EXPECT_TRUE(calender::get_instance_count() == 0); + EXPECT_TRUE(event::get_instance_count() == 0); + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(MoveSemantics, move_returned_RObject_reflecting_true_const_ref) + { + { + // Retrieve the reflected Record for the 'Calender' struct + optional classCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(classCalender); + + optional oGetTheEvent = classCalender->getMethod(calender::str_getTheEvent); + ASSERT_TRUE(oGetTheEvent); + + // Create a stack-allocated object via reflection + auto [err, calender] = classCalender->ctorT()(alloc::Stack); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(calender.isEmpty()); + + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + { + method getTheEvent = oGetTheEvent->targetT().argsT().returnT(); + EXPECT_TRUE(getTheEvent); + + // getTheEvent() returns 'const Event&', hence Reflecetd as true-const. + auto [err0, event0] = getTheEvent(calender)(); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(event0.isEmpty()); + + optional classEvent = cxx::mirror().getRecord(event::ns, event::struct_); + ASSERT_TRUE(classEvent); + + optional oEventReset = classEvent->getMethod(event::str_reset); + ASSERT_TRUE(oEventReset); + + method eventReset = oEventReset->targetT().argsT().returnT(); + EXPECT_TRUE(eventReset); + { + auto [e0, r0] = eventReset(std::cref(event0))(); + EXPECT_TRUE(e0 == error::ConstOverloadMissing); + ASSERT_TRUE(r0.isEmpty()); + } { + auto [e0, r0] = eventReset(event0)(); + EXPECT_TRUE(e0 == error::InvalidCallOnConstTarget); + ASSERT_TRUE(r0.isEmpty()); + } + // TODO: provide option to 'const_cast' the underlying object being reflected. + //{ (should it be even allowed?) + // auto [e0, r0] = eventReset(constCast(event0))(); + // EXPECT_TRUE(e0 == error::IllegalConstCast); + // ASSERT_TRUE(r0.isEmpty()); + //} + + // RObject reflecting 'const Event&', storing pointer to reflected type internally, So just the + // address wrapped in std::any inside Robject is moved. Event's move constructor is not called. + RObject event1 = std::move(event0); + + ASSERT_FALSE(event1.isEmpty()); + + // '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. + auto [e0, r0] = eventReset(std::cref(event1))(); + EXPECT_TRUE(e0 == error::ConstOverloadMissing); + ASSERT_TRUE(r0.isEmpty()); + } { + // call to 'non-const' method on 'const' target fails here. + auto [e0, r0] = eventReset(event1)(); + EXPECT_TRUE(e0 == error::InvalidCallOnConstTarget); + ASSERT_TRUE(r0.isEmpty()); + } + } + // After move, these instance count must remain same. + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + } + // After scope exit, stack instances are cleaned up automatically + EXPECT_TRUE(calender::get_instance_count() == 0); + EXPECT_TRUE(event::get_instance_count() == 0); + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(MoveSemantics, move_returned_RObject_reflecting_stack_object) + { + { + // Retrieve the reflected Record for the 'Calender' struct + optional classCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(classCalender); + + optional optCreateCalender = classCalender->getMethod(calender::str_create); + ASSERT_TRUE(optCreateCalender); + + auto createCalenderFn = optCreateCalender->argsT<>().returnT<>(); + ASSERT_TRUE(createCalenderFn); + EXPECT_EQ(createCalenderFn.get_init_error(), rtl::error::None); + + // Calender::create is a static method that returns stack-allocated Calender object. + // Calling this via reflection, moves the return value from Calender::create to here. + auto [err0, calender0] = createCalenderFn(); + + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(calender0.isEmpty()); + EXPECT_FALSE(calender0.isOnHeap()); + + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + + // Sets Calender's move operation counter to zero + calender::reset_move_ops_counter(); + + // Moving a RObject created via alloc::Stack, invokes Calender's move constructor. + RObject calender1 = std::move(calender0); + + //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); + + ASSERT_FALSE(calender1.isEmpty()); + EXPECT_FALSE(calender1.isOnHeap()); + + // '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); + // 'Calender' has 2 'Event' instances, shared_ptr and a std::unique_ptr. + EXPECT_TRUE(event::get_instance_count() == 2); + // 'Event' has a unique_ptr and two 'Event' instances exists, So- + EXPECT_TRUE(date::get_instance_count() == 2); + } + // After scope exit, stack instances are cleaned up automatically + EXPECT_TRUE(calender::get_instance_count() == 0); + EXPECT_TRUE(event::get_instance_count() == 0); + EXPECT_TRUE(date::get_instance_count() == 0); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/NameSpaceGlobalsTests.cpp b/RTLTestRunApp/src/FunctionalityTests/NameSpaceGlobalsTests.cpp new file mode 100644 index 00000000..bc15c10c --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/NameSpaceGlobalsTests.cpp @@ -0,0 +1,324 @@ + +#include +#include + +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + + TEST(Reflecting_pod, construct_char_on_heap_and_stack) + { + optional charType = cxx::mirror().getRecord(cxx::reflected_id("char")); + ASSERT_TRUE(charType); + { + /* Attempting to construct a POD type('char') with a value directly via Record::create<>(). + Although the constructor for 'char' is registered, this call is resolved as if invoking + a copy constructor(signature: (const char&)), which is implicitly registered. + + Design Restriction : + - Direct invocation of copy constructors through Record::create<>() is intentionally disallowed. + - Copy construction is only permitted when cloning an existing reflected object + using RObject::clone<>(). + + Rationale : + - If the caller already knows the type 'T', there is no need to reflect its copy constructor + through create<>().A normal C++ copy(e.g., `T(other)`) is simpler and clearer. + - The only valid scenario for reflecting a copy constructor is when you are handling 'T' + as type-erased, for that, RTL provides rtl::reflect(..), which wraps an existing 'T' + into an RObject in a type-erased manner. (demonstrated in next test case.) + Therefore, this call yields 'SignatureMismatch' by design. + */ + auto [err, rchar] = charType->ctorT()(rtl::alloc::Stack, 'Q'); + EXPECT_TRUE(err == rtl::error::SignatureMismatch); + ASSERT_TRUE(rchar.isEmpty()); + } { + auto [err, rchar] = charType->ctorT()(rtl::alloc::Stack); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(rchar.isEmpty()); + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + { + auto [err, rchar] = charType->ctorT()(rtl::alloc::Heap); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(rchar.isEmpty()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(Reflecting_pod, construct_char_directly_and_clone) + { + //Now for cases, if you want to handle it type-erased and pass around. + RObject reflChar = rtl::reflect('Q'); + { + //Internally calls the copy constructor. + auto [err, rchar] = reflChar.clone(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(rchar.isEmpty()); + EXPECT_TRUE(rchar.canViewAs()); + + auto viewCh = rchar.view(); + ASSERT_TRUE(viewCh); + + char ch = viewCh->get(); + EXPECT_EQ(ch, 'Q'); + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + { + //Internally calls the copy constructor. + auto [err, rchar] = reflChar.clone(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(rchar.isEmpty()); + + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + EXPECT_TRUE(rchar.canViewAs()); + + // Internally, RTL manages all Heap allocated objects with std::unique_ptr. + EXPECT_TRUE(rchar.canViewAs>()); + + auto viewCh = rchar.view(); + ASSERT_TRUE(viewCh); + + char ch = viewCh->get(); + EXPECT_EQ(ch, 'Q'); + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(RTLInterfaceCxxMirror, get_global_functions_with_wrong_names) + { + { + optional badFunc = cxx::mirror().getFunction("wrong_namespace", "wrong_function"); + EXPECT_FALSE(badFunc); + } { + optional badFunc = cxx::mirror().getFunction(str_complex, "wrong_function"); + EXPECT_FALSE(badFunc); + } { + optional badFunc = cxx::mirror().getFunction("wrong_getComplexNumAsString"); + EXPECT_FALSE(badFunc); + } + } + + + TEST(FunctionInNameSpace, get_namespace_function_types) + { + optional setReal = cxx::mirror().getFunction(str_complex, str_setReal); + ASSERT_TRUE(setReal); + + optional setImaginary = cxx::mirror().getFunction(str_complex, str_setImaginary); + ASSERT_TRUE(setImaginary); + + EXPECT_TRUE(setReal->getNamespace() == str_complex); + EXPECT_TRUE(setReal->getFunctionName() == str_setReal); + EXPECT_TRUE(setImaginary->getNamespace() == str_complex); + EXPECT_TRUE(setImaginary->getFunctionName() == str_setImaginary); + } + + + TEST(FunctionInNameSpace, namespace_function_execute_return) + { + { + optional fnSetReal = cxx::mirror().getFunction(str_complex, str_setReal); + ASSERT_TRUE(fnSetReal); + EXPECT_TRUE(fnSetReal->hasSignature()); + + rtl::function setReal = fnSetReal->argsT().returnT<>(); + EXPECT_TRUE(setReal); + EXPECT_EQ(setReal.get_init_error(), rtl::error::None); + + auto [err, ret] = setReal(g_real); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_TRUE(ret.isEmpty()); + } { + optional fnSetImaginary = cxx::mirror().getFunction(str_complex, str_setImaginary); + ASSERT_TRUE(fnSetImaginary); + EXPECT_TRUE(fnSetImaginary->hasSignature()); + + rtl::function setImginary = fnSetImaginary->argsT().returnT<>(); + EXPECT_TRUE(setImginary); + EXPECT_EQ(setImginary.get_init_error(), rtl::error::None); + + auto [err, ret] = setImginary(g_imaginary); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_TRUE(ret.isEmpty()); + } { + optional fnGetMagnitude = cxx::mirror().getFunction(str_complex, str_getMagnitude); + ASSERT_TRUE(fnGetMagnitude); + EXPECT_TRUE(fnGetMagnitude->hasSignature<>()); //empty template params checks for zero arguments. + + rtl::function getMagnitude = fnGetMagnitude->argsT<>().returnT<>(); + EXPECT_TRUE(getMagnitude); + EXPECT_EQ(getMagnitude.get_init_error(), rtl::error::None); + + auto [err, ret] = getMagnitude(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + double retVal = ret.view()->get(); + double magnitude = abs(complex(g_real, g_imaginary)); + EXPECT_DOUBLE_EQ(magnitude, retVal); + } + } + + + TEST(FunctionInNameSpace, execute_with_wrong_signature) + { + optional fnSetReal = cxx::mirror().getFunction(str_complex, str_setReal); + ASSERT_TRUE(fnSetReal); + + EXPECT_TRUE(fnSetReal->hasSignature()); + EXPECT_FALSE(fnSetReal->hasSignature()); + + rtl::function setReal = fnSetReal->argsT().returnT<>(); + EXPECT_FALSE(setReal); + EXPECT_EQ(setReal.get_init_error(), rtl::error::SignatureMismatch); + + auto [err, robj] = setReal(g_real); + EXPECT_EQ(err, rtl::error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } + + + TEST(GlobalFunction, get_function_execute_return) + { + optional fnGetComplexAsStr = cxx::mirror().getFunction(str_getComplexNumAsString); + ASSERT_TRUE(fnGetComplexAsStr); + + rtl::function getComplexNumAsStr = fnGetComplexAsStr->argsT<>().returnT<>(); + EXPECT_TRUE(getComplexNumAsStr); + EXPECT_EQ(getComplexNumAsStr.get_init_error(), rtl::error::None); + + auto [err, ret] = getComplexNumAsStr(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + string retVal = ret.view()->get(); + string comlexNumStr = to_string(g_real) + "i" + to_string(g_imaginary); + EXPECT_TRUE(comlexNumStr == retVal); + } + + + TEST(GlobalFunction, overloaded_function_execute_return) + { + optional fnReverseString = cxx::mirror().getFunction(str_reverseString); + ASSERT_TRUE(fnReverseString); + + rtl::function reverseString = fnReverseString->argsT().returnT<>(); + ASSERT_TRUE(reverseString); + { + //STRA's type is 'const char*', function accepts 'string', + //so type-casting in place as 'string' + auto [err, ret] = reverseString(STRA); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + string retStr = ret.view()->get(); + auto expStr = std::string(STRA_REVERSE) + SUFFIX_std_string; + EXPECT_EQ(retStr, expStr); + } { + //STRB's type is 'const char*', function accepts 'string', + //so explicitly binding type in template (using bind<...>()) to enforce the type as 'string'. + auto [err, ret] = reverseString(STRB); + + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + string retStr = ret.view()->get(); + auto expStr = std::string(STRB_REVERSE) + SUFFIX_std_string; + EXPECT_EQ(retStr, expStr); + } { + rtl::function reverseString = fnReverseString->argsT<>().returnT<>(); + + auto [err, ret] = reverseString(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + string retStr = ret.view()->get(); + auto expStr = std::string(REV_STR_VOID_RET) + SUFFIX_void; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(Reflecting_STL_class, std_string__call_reflected_method) + { + optional stdStringClass = cxx::mirror().getRecord("std", "string"); + ASSERT_TRUE(stdStringClass); + + optional fnIsStringEmpty = stdStringClass->getMethod("empty"); + ASSERT_TRUE(fnIsStringEmpty); + + RObject reflected_str0 = rtl::reflect(std::string("")); //empty string. + { + auto isStringEmpty = fnIsStringEmpty->targetT().argsT().returnT(); + EXPECT_TRUE(isStringEmpty); + + auto [err, ret] = isStringEmpty(std::cref(reflected_str0))(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + EXPECT_TRUE(ret.view()->get()); + } + RObject reflected_str1 = rtl::reflect(std::string("not_empty")); + { + auto isStringEmpty = fnIsStringEmpty->targetT().argsT().returnT(); + EXPECT_TRUE(isStringEmpty); + + auto [err, ret] = isStringEmpty(std::cref(reflected_str1))(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + EXPECT_FALSE(ret.view()->get()); + } + } + + + TEST(Reflecting_STL_class, std_string_view__call_reflected_method) + { + optional stdStringClass = cxx::mirror().getRecord("std", "string_view"); + ASSERT_TRUE(stdStringClass); + + optional fnIsStringEmpty = stdStringClass->getMethod("empty"); + ASSERT_TRUE(fnIsStringEmpty); + + RObject reflected_str0 = rtl::reflect(""); //empty string. + { + auto isStringEmpty = fnIsStringEmpty->targetT().argsT().returnT(); + EXPECT_TRUE(isStringEmpty); + + auto [err, ret] = isStringEmpty(std::cref(reflected_str0))(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + EXPECT_TRUE(ret.view()->get()); + } + RObject reflected_str1 = rtl::reflect("not_empty"); + { + auto isStringEmpty = fnIsStringEmpty->targetT().argsT().returnT(); + EXPECT_TRUE(isStringEmpty); + + auto [err, ret] = isStringEmpty(std::cref(reflected_str1))(); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + EXPECT_FALSE(ret.view()->get()); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/PerfectForwardingTests.cpp b/RTLTestRunApp/src/FunctionalityTests/PerfectForwardingTests.cpp new file mode 100644 index 00000000..bb743143 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/PerfectForwardingTests.cpp @@ -0,0 +1,380 @@ +/** + * @file PerfectForwardingTests.cpp + * @brief This file contains unit tests to validate the behavior of perfect forwarding in the reflection system. + * + * Perfect forwarding ensures that arguments are forwarded to the correct method overload while preserving their + * value category (L-value, R-value, or const L-value). The tests use the reflection system to dynamically retrieve + * and invoke methods, ensuring that the correct overload is called based on the argument type and value category. + * + * Note: The explicitly provided template types (e.g., `std::string&`, `std::string&&`, `const std::string&`) are + * required by the design of the RTL to match the method signatures during invocation. + * + * Key Components: + * - `CxxMirror`: The main reflection interface that provides access to class metadata (`Record`) and methods (`Method`). + * - `Record`: Represents a reflected class/struct and provides access to its methods and constructors. + * - `Method`: Represents a reflected method and provides interfaces to invoke it dynamically. + * - `RObject`: A type-erased wrapper for return values and objects created via reflection, ensuring proper memory management. + */ + + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsAnimal.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + /** + * @brief Test that an R-value reference binds only to the corresponding overload. + * + * This test verifies that the reflection system correctly identifies and invokes the method + * overload that accepts an R-value reference (`std::string&&`). + */ + TEST(PerfectForwardingTest, overload_resolution_with_rvalue_ref_on_heap_object) + { + { + // Retrieve the metadata for the "Animal" class. + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + // Create an instance of the "Animal" class. + auto [err0, animal] = classAnimal->ctorT()(alloc::Heap); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(animal.isEmpty()); + + // Retrieve the "setAnimalName" method. + optional oSetAnimalName = classAnimal->getMethod(animal::str_setAnimalName); + ASSERT_TRUE(oSetAnimalName); + // Verify that the method has the correct signature for an R-value reference. + EXPECT_TRUE((oSetAnimalName->hasSignature())); + + auto setAnimalName = oSetAnimalName->targetT().argsT().returnT(); + EXPECT_TRUE(setAnimalName); + + // Invoke the method with an R-value reference. + auto [err1, ret1] = setAnimalName.bind(animal)(animal::NAME); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret1.isEmpty()); + + // Validate the behavior of the method. + EXPECT_TRUE(animal::test_method_setAnimalName_rvalue_args(animal)); + } + + // Ensure that all instances are cleaned up. + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + /** + * @brief Test that a non-const L-value reference binds only to the corresponding overload. + * + * This test verifies that the reflection system correctly identifies and invokes the method + * overload that accepts a non-const L-value reference (`std::string&`). */ + TEST(PerfectForwardingTest, overload_resolution_with_non_const_lvaue_ref_on_heap_object) + { + { + // Retrieve the metadata for the "Animal" class. + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + // Create an instance of the "Animal" class. + auto [err0, animal] = classAnimal->ctorT()(alloc::Heap); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(animal.isEmpty()); + + // Retrieve the "setAnimalName" method. + optional oSetAnimalName = classAnimal->getMethod(animal::str_setAnimalName); + ASSERT_TRUE(oSetAnimalName); + // Verify that the method has the correct signature for a non-const L-value reference. + EXPECT_TRUE((oSetAnimalName->hasSignature())); + + auto setAnimalName = oSetAnimalName->targetT().argsT().returnT(); + EXPECT_TRUE(setAnimalName); + + // Invoke the method with a non-const L-value reference. + auto [err1, ret1] = setAnimalName.bind(animal)(animal::NAME); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret1.isEmpty()); + + // Validate the behavior of the method. + EXPECT_TRUE(animal::test_method_setAnimalName_non_const_lvalue_ref_args(animal)); + } + + // Ensure that all instances are cleaned up. + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + /* + * @brief Test that a const L-value reference binds only to the corresponding overload. + * + * This test verifies that the reflection system correctly identifies and invokes the method + * overload that accepts a const L-value reference (`const std::string&`). */ + TEST(PerfectForwardingTest, overload_resolution_with_const_lvaue_ref_on_heap_object) + { + { + // Retrieve the metadata for the "Animal" class. + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + // Create an instance of the "Animal" class. + auto [err0, animal] = classAnimal->ctorT()(alloc::Heap); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(animal.isEmpty()); + + // Retrieve the "setAnimalName" method. + optional oSetAnimalName = classAnimal->getMethod(animal::str_setAnimalName); + ASSERT_TRUE(oSetAnimalName); + // Verify that the method has the correct signature for a const L-value reference. + EXPECT_TRUE((oSetAnimalName->hasSignature())); + + auto setAnimalName = oSetAnimalName->targetT().argsT().returnT(); + EXPECT_TRUE(setAnimalName); + + // Invoke the method with a const L-value reference. + auto [err1, ret1] = setAnimalName.bind(animal)(animal::NAME); + + EXPECT_TRUE(err1 == error::None); + EXPECT_TRUE(ret1.isEmpty()); + + // Validate the behavior of the method. + EXPECT_TRUE(animal::test_method_setAnimalName_const_lvalue_ref_args(animal)); + } + + // Ensure that all instances are cleaned up. + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + + /** + * @brief Test that an R-value reference binds only to the corresponding overload. + * + * This test verifies that the reflection system correctly identifies and invokes the method + * overload that accepts an R-value reference (`std::string&&`). + */ + TEST(PerfectForwardingTest, overload_resolution_with_rvalue_ref_on_stack_object) + { + { + // Retrieve the metadata for the "Animal" class. + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + // Create an instance of the "Animal" class. + auto [err0, animal] = classAnimal->ctorT()(alloc::Stack); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(animal.isEmpty()); + + // Retrieve the "setAnimalName" method. + optional oSetAnimalName = classAnimal->getMethod(animal::str_setAnimalName); + ASSERT_TRUE(oSetAnimalName); + // Verify that the method has the correct signature for an R-value reference. + EXPECT_TRUE((oSetAnimalName->hasSignature())); + + auto setAnimalName = oSetAnimalName->targetT().argsT().returnT(); + EXPECT_TRUE(setAnimalName); + + // Invoke the method with an R-value reference. + auto [err1, ret1] = setAnimalName.bind(animal)(animal::NAME); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret1.isEmpty()); + + // Validate the behavior of the method. + EXPECT_TRUE(animal::test_method_setAnimalName_rvalue_args(animal)); + } + + // Ensure that all instances are cleaned up. + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + /** + * @brief Test that a non-const L-value reference binds only to the corresponding overload. + * + * This test verifies that the reflection system correctly identifies and invokes the method + * overload that accepts a non-const L-value reference (`std::string&`). */ + TEST(PerfectForwardingTest, overload_resolution_with_non_const_lvaue_ref_on_stack_object) + { + { + // Retrieve the metadata for the "Animal" class. + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + // Create an instance of the "Animal" class. + auto [err0, animal] = classAnimal->ctorT()(alloc::Stack); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(animal.isEmpty()); + + // Retrieve the "setAnimalName" method. + optional oSetAnimalName = classAnimal->getMethod(animal::str_setAnimalName); + ASSERT_TRUE(oSetAnimalName); + // Verify that the method has the correct signature for a non-const L-value reference. + EXPECT_TRUE((oSetAnimalName->hasSignature())); + + auto setAnimalName = oSetAnimalName->targetT().argsT().returnT(); + EXPECT_TRUE(setAnimalName); + + // Invoke the method with a non-const L-value reference. + auto [err1, ret1] = setAnimalName.bind(animal)(animal::NAME); + + EXPECT_TRUE(err1 == error::None); + ASSERT_TRUE(ret1.isEmpty()); + + // Validate the behavior of the method. + EXPECT_TRUE(animal::test_method_setAnimalName_non_const_lvalue_ref_args(animal)); + } + + // Ensure that all instances are cleaned up. + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + /* + * @brief Test that a const L-value reference binds only to the corresponding overload. + * + * This test verifies that the reflection system correctly identifies and invokes the method + * overload that accepts a const L-value reference (`const std::string&`). */ + TEST(PerfectForwardingTest, overload_resolution_with_const_lvaue_ref_on_stack_object) + { + { + // Retrieve the metadata for the "Animal" class. + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + // Create an instance of the "Animal" class. + auto [err0, animal] = classAnimal->ctorT()(alloc::Stack); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(animal.isEmpty()); + + // Retrieve the "setAnimalName" method. + optional oSetAnimalName = classAnimal->getMethod(animal::str_setAnimalName); + ASSERT_TRUE(oSetAnimalName); + // Verify that the method has the correct signature for a const L-value reference. + EXPECT_TRUE((oSetAnimalName->hasSignature())); + + auto setAnimalName = oSetAnimalName->targetT().argsT().returnT(); + EXPECT_TRUE(setAnimalName); + + // Invoke the method with a const L-value reference. + auto [err1, ret1] = setAnimalName.bind(animal)(animal::NAME); + + EXPECT_TRUE(err1 == error::None); + EXPECT_TRUE(ret1.isEmpty()); + + // Validate the behavior of the method. + EXPECT_TRUE(animal::test_method_setAnimalName_const_lvalue_ref_args(animal)); + } + + // Ensure that all instances are cleaned up. + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(PerfectForwardingTest, static_fn_overload_resolution_with_rvalue_ref) + { + { + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + optional oUpdateZooKeeper = classAnimal->getMethod(animal::str_updateZooKeeper); + ASSERT_TRUE(oUpdateZooKeeper); + + const auto& isValid = oUpdateZooKeeper->hasSignature(); + EXPECT_TRUE(isValid); + + auto updateZooKeeper = oUpdateZooKeeper->argsT().returnT<>(); + { + auto [err, ret] = updateZooKeeper(animal::ZOO_KEEPER); + EXPECT_TRUE(err == error::ExplicitRefBindingRequired); + EXPECT_TRUE(ret.isEmpty()); + } { + auto [err, ret] = updateZooKeeper.bind()(animal::ZOO_KEEPER); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + EXPECT_TRUE(animal::test_method_updateZooKeeper(retStr)); + } + } + + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(PerfectForwardingTest, static_fn_overload_resolution_with_const_lvalue_ref) + { + { + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + optional oUpdateZooKeeper = classAnimal->getMethod(animal::str_updateZooKeeper); + ASSERT_TRUE(oUpdateZooKeeper); + + const auto& isValid = oUpdateZooKeeper->hasSignature(); + EXPECT_TRUE(isValid); + + rtl::static_method updateZooKeeper = oUpdateZooKeeper->argsT() + .returnT<>(); + + auto [err, ret] = updateZooKeeper.bind()(animal::ZOO_KEEPER); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + EXPECT_TRUE(animal::test_method_updateZooKeeper(retStr)); + } + + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(PerfectForwardingTest, static_fn_overload_resolution_with_non_const_lvalue_ref) + { + { + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + optional oUpdateZooKeeper = classAnimal->getMethod(animal::str_updateZooKeeper); + ASSERT_TRUE(oUpdateZooKeeper); + + const auto& isValid = oUpdateZooKeeper->hasSignature(); + EXPECT_TRUE(isValid); + + rtl::static_method updateZooKeeper = oUpdateZooKeeper->argsT() + .returnT<>(); + auto [err, ret] = updateZooKeeper.bind()(animal::ZOO_KEEPER); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + EXPECT_TRUE(animal::test_method_updateZooKeeper(retStr)); + } + + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/ReflectionOpErrorCodeTests.cpp b/RTLTestRunApp/src/FunctionalityTests/ReflectionOpErrorCodeTests.cpp new file mode 100644 index 00000000..395b7c1e --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/ReflectionOpErrorCodeTests.cpp @@ -0,0 +1,357 @@ + +/* +* +* Below error codes are covered in ConstMethodOverloadTests.cpp +* rtl::error::ConstOverloadMissing +* rtl::error::NonConstOverloadMissing +* rtl::error::InvalidCallOnConstTarget +* +* Covered in ReturnTypeErasedDispatch.cpp +* rtl::error::ExplicitRefBindingRequired +* +* and, +* rtl::error::FunctionNotRegistered, is not internally used by RTL. +* Function/Method objects are returned wrapped in std::optional<>, which will +* be empty if its not in registered in Reflection-system. +* +*/ + + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsBook.h" +#include "TestUtilsDate.h" +#include "TestUtilsPerson.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(ReflectionOpErrorCodeTests, rtl_error_strings) + { + EXPECT_EQ(rtl::to_string(rtl::error::None), rtl::errstr_None); + EXPECT_EQ(rtl::to_string(rtl::error::EmptyRObject), rtl::errstr_EmptyRObject); + EXPECT_EQ(rtl::to_string(rtl::error::InvalidCaller), rtl::errstr_InvalidCaller); + EXPECT_EQ(rtl::to_string(rtl::error::SignatureMismatch), rtl::errstr_SignatureMismatch); + EXPECT_EQ(rtl::to_string(rtl::error::TargetTypeMismatch), rtl::errstr_TargetTypeMismatch); + EXPECT_EQ(rtl::to_string(rtl::error::ReturnTypeMismatch), rtl::errstr_ReturnTypeMismatch); + EXPECT_EQ(rtl::to_string(rtl::error::RefBindingMismatch), rtl::errstr_RefBindingMismatch); + EXPECT_EQ(rtl::to_string(rtl::error::ExplicitRefBindingRequired), rtl::errstr_ExplicitRefBindingRequired); + EXPECT_EQ(rtl::to_string(rtl::error::InvalidStaticMethodCaller), rtl::errstr_InvalidStaticMethodCaller); + EXPECT_EQ(rtl::to_string(rtl::error::InvalidNonStaticMethodCaller), rtl::errstr_InvalidNonStaticMethodCaller); + EXPECT_EQ(rtl::to_string(rtl::error::FunctionNotRegistered), rtl::errstr_FunctionNotRegistered); + EXPECT_EQ(rtl::to_string(rtl::error::ConstOverloadMissing), rtl::errstr_ConstOverloadMissing); + EXPECT_EQ(rtl::to_string(rtl::error::NonConstOverloadMissing), rtl::errstr_NonConstOverloadMissing); + EXPECT_EQ(rtl::to_string(rtl::error::InvalidCallOnConstTarget), rtl::errstr_InvalidCallOnConstTarget); + EXPECT_EQ(rtl::to_string(rtl::error::TypeNotCopyConstructible), rtl::errstr_TypeNotCopyConstructible); + EXPECT_EQ(rtl::to_string(rtl::error::TypeNotDefaultConstructible), rtl::errstr_TypeNotDefaultConstructible); + EXPECT_EQ(rtl::to_string(rtl::error::StlWrapperHeapAllocForbidden), rtl::errstr_StlWrapperHeapAllocForbidden); + EXPECT_EQ(rtl::to_string(static_cast(-1)), rtl::errstr_Unknown); + } + + TEST(ReflectionOpErrorCodeTests, error_EmptyRObject) + { + { + RObject emptyObj; + ASSERT_TRUE(emptyObj.isEmpty()); + { + auto [err, person] = emptyObj.clone(); + EXPECT_TRUE(err == error::EmptyRObject); + ASSERT_TRUE(person.isEmpty()); + } { + auto [err, person] = emptyObj.clone(); + EXPECT_TRUE(err == error::EmptyRObject); + ASSERT_TRUE(person.isEmpty()); + } + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ReflectionOpErrorCodeTests, error_TypeNotDefaultConstructible) + { + optional classEvent = cxx::mirror().getRecord(event::ns, event::struct_); + ASSERT_TRUE(classEvent); + + auto [err0, robj0] = classEvent->ctorT()(alloc::Stack); + + EXPECT_TRUE(err0 == error::TypeNotDefaultConstructible); + ASSERT_TRUE(robj0.isEmpty()); + + auto [err1, robj1] = classEvent->ctorT()(alloc::Heap); + + EXPECT_TRUE(err1 == error::TypeNotDefaultConstructible); + ASSERT_TRUE(robj1.isEmpty()); + } + + + TEST(ReflectionOpErrorCodeTests, error_ReflectedObjectIsNotInWrapper) + { + char ch = 'R'; + RObject rCh = rtl::reflect(ch); + EXPECT_FALSE(rCh.isAllocatedByRtl()); + { + auto [err, rch] = rCh.clone(); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(rch.isEmpty()); + EXPECT_TRUE(rch.canViewAs()); + EXPECT_EQ(rch.view()->get(), 'R'); + } + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + { + auto [err, rch] = rCh.clone(); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(rch.isEmpty()); + EXPECT_TRUE(rch.canViewAs()); + EXPECT_EQ(rch.view()->get(), 'R'); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + { + auto [err, rch] = rCh.clone(); + EXPECT_TRUE(err == error::NotWrapperType); + ASSERT_TRUE(rch.isEmpty()); + /* this will not compile, fail with message - + static_assert failed: 'Heap allocation forbidden for STL-Wrappers (e.g. smart pointers/optionals/reference_wrappers).' */ + // auto [err0, rch0] = rChptr.clone(); + } + } + + + TEST(ReflectionOpErrorCodeTests, std_unique_ptr__error_TypeNotCopyConstructible) + { + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + std::unique_ptr chPtr = std::make_unique('R'); + + { + RObject rChptr = rtl::reflect(chPtr); + + ASSERT_FALSE(rChptr.isEmpty()); + EXPECT_FALSE(rChptr.isAllocatedByRtl()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + + //error reterr = cxx::mirror().setupCloning(rChptr); + //ASSERT_TRUE(reterr == error::None); + + EXPECT_TRUE(rChptr.canViewAs()); + { + auto viewCh = rChptr.view(); + ASSERT_TRUE(viewCh); + + char ch = viewCh->get(); + EXPECT_EQ(ch, 'R'); + } { + //Try to create copy of std::unique_ptr on stack. + auto [err, rch0] = rChptr.clone(); + EXPECT_TRUE(err == error::TypeNotCopyConstructible); + } { + // Try to create copy of std::unique_ptr explicitly on stack. + auto [err, rch0] = rChptr.clone(); + EXPECT_TRUE(err == error::TypeNotCopyConstructible); + } { + // Try to create copy of std::unique_ptr on heap. + auto [err, rch0] = rChptr.clone(); + EXPECT_TRUE(err == error::StlWrapperHeapAllocForbidden); + } { + // Now try to create copy of std::unique_ptr explicitly on heap. + auto [err, rch0] = rChptr.clone(); + EXPECT_TRUE(err == error::StlWrapperHeapAllocForbidden); + } { + // but we can definitly create the copy of underlying value. + auto [err, rch0] = rChptr.clone(); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(rch0.isEmpty()); + EXPECT_TRUE(rch0.canViewAs()); + + auto viewCh = rChptr.view(); + ASSERT_TRUE(viewCh); + + char ch = viewCh->get(); + EXPECT_EQ(ch, 'R'); + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + { + // but we can definitly create the copy of underlying value. + auto [err, rch0] = rChptr.clone(); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(rch0.isEmpty()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 2); + EXPECT_TRUE(rch0.canViewAs()); + + auto viewCh = rChptr.view(); + ASSERT_TRUE(viewCh); + + char ch = viewCh->get(); + EXPECT_EQ(ch, 'R'); + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ReflectionOpErrorCodeTests, copy_construct__error_TypeNotCopyConstructible) + { + { + optional classCalender = cxx::mirror().getRecord(calender::ns, calender::struct_); + ASSERT_TRUE(classCalender); + + //Events's constructor not registered, get its instance from 'Calander'. + optional getEvent = classCalender->getMethod(calender::str_getTheEvent); + ASSERT_TRUE(getEvent); + + // Create Calender, which will create a Event's instance. + auto [err0, calender] = classCalender->ctorT()(alloc::Stack); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(calender.isEmpty()); + + auto get_event = getEvent->targetT<>().argsT<>().returnT<>(); + + // Get the Event's instance. + auto [err1, event] = get_event(calender)(); + EXPECT_TRUE(err1 == error::None); + ASSERT_FALSE(event.isEmpty()); + + // Try to call copy-constructor of class Event. + auto [err3, eventCp1] = event.clone(); + + // Cannot create heap instance: Calender's copy constructor is deleted. + EXPECT_TRUE(err3 == error::TypeNotCopyConstructible); + ASSERT_TRUE(eventCp1.isEmpty()); + } + EXPECT_TRUE(calender::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ReflectionOpErrorCodeTests, alloc_on_stack__error_TypeNotCopyConstructible) + { + { + // Fetch the reflected Record for class 'Library'. + optional classLibrary = cxx::mirror().getRecord(library::class_); + ASSERT_TRUE(classLibrary); + { + // Attempt to create a reflected instance allocated on the heap. + auto [err, robj] = classLibrary->ctorT()(alloc::Heap); + /* Heap allocation succeeds: + * Even though Library's copy constructor is deleted, RObject internally stores + * the pointer directly inside std::any (type-erased), without requiring the type T + * to be copy-constructible. + */ EXPECT_TRUE(err == error::None); + ASSERT_FALSE(robj.isEmpty()); + } + // Ensure no leaked or lingering reflected instances. + EXPECT_TRUE(library::assert_zero_instance_count()); + { + // Attempt to create a reflected instance allocated on the stack. + auto [err, robj] = classLibrary->ctorT()(alloc::Stack); + /* Stack allocation fails: + * Creating a stack instance requires storing the actual object inside std::any. + * Since std::any requires the contained type T to be copy-constructible for emplacement, + * and Library's copy constructor is deleted, construction fails. + */ EXPECT_TRUE(err == error::TypeNotCopyConstructible); + ASSERT_TRUE(robj.isEmpty()); + } + } + } + + + TEST(ReflectionOpErrorCodeTests, static_method_call__error_SignatureMismatch) + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional optGetProfile = classPerson->getMethod(person::str_getProfile); + ASSERT_TRUE(optGetProfile); + EXPECT_TRUE(optGetProfile->hasSignature<>()); //empty template params checks for zero arguments. + + rtl::static_method getProfileFn = optGetProfile->argsT().returnT<>(); + EXPECT_FALSE(getProfileFn); + EXPECT_EQ(getProfileFn.get_init_error(), error::SignatureMismatch); + + auto [err, robj] = getProfileFn(std::string()); + EXPECT_EQ(err, error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } + + + TEST(ReflectionOpErrorCodeTests, method_call__error_EmptyRObject) + { + { + RObject emptyObj; + ASSERT_TRUE(emptyObj.isEmpty()); + + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err, ret] = classBook->getMethod(book::str_getPublishedOn) + ->targetT().argsT().returnT()(emptyObj)(); + + EXPECT_TRUE(err == error::EmptyRObject); + ASSERT_TRUE(ret.isEmpty()); + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ReflectionOpErrorCodeTests, method_call_using_heap_object__error_TargetMismatch) + { + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, person] = classPerson->ctorT()(alloc::Heap); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(person.isEmpty()); + + optional oGetPublishedOn = classBook->getMethod(book::str_getPublishedOn); + ASSERT_TRUE(oGetPublishedOn); + + rtl::method getPublishedOn = oGetPublishedOn->targetT().argsT().returnT(); + EXPECT_TRUE(getPublishedOn); + + auto [err1, ret] = getPublishedOn(person)(); + EXPECT_TRUE(err1 == error::TargetTypeMismatch); + ASSERT_TRUE(ret.isEmpty()); + } + EXPECT_TRUE(person::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(ReflectionOpErrorCodeTests, method_call_using_stack_object__error_TargetMismatch) + { + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional classBook = cxx::mirror().getRecord(book::class_); + ASSERT_TRUE(classBook); + + auto [err0, person] = classPerson->ctorT()(alloc::Stack); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(person.isEmpty()); + + optional oGetPublishedOn = classBook->getMethod(book::str_getPublishedOn); + ASSERT_TRUE(oGetPublishedOn); + + rtl::method getPublishedOn = oGetPublishedOn->targetT().argsT().returnT(); + EXPECT_TRUE(getPublishedOn); + + auto [err1, ret] = getPublishedOn(person)(); + EXPECT_TRUE(err1 == error::TargetTypeMismatch); + ASSERT_TRUE(ret.isEmpty()); + } + EXPECT_TRUE(person::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/ReturnValueReflectionTest.cpp b/RTLTestRunApp/src/FunctionalityTests/ReturnValueReflectionTest.cpp new file mode 100644 index 00000000..1f594f0c --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/ReturnValueReflectionTest.cpp @@ -0,0 +1,70 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsDate.h" + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(ReflecetdReturnValues, on_registered_return_type__test_cloning) + { + //I don't know if the 'Event' is class or struct..Reflection YaY!. :P + auto classEvent = cxx::mirror().getRecord(cxx::reflected_id(event::struct_)); + ASSERT_TRUE(classEvent); + + auto [err0, robj0] = classEvent->ctorT()(rtl::alloc::Stack); + + //Event's constructor is private, not accessible, Hence the error. + EXPECT_TRUE(err0 == rtl::error::TypeNotDefaultConstructible); + ASSERT_TRUE(robj0.isEmpty()); + { + auto classCalender = cxx::mirror().getRecord(cxx::reflected_id(calender::struct_)); + ASSERT_TRUE(classCalender); + + auto [err1, calender] = classCalender->ctorT()(rtl::alloc::Stack); + + EXPECT_TRUE(err1 == rtl::error::None); + ASSERT_FALSE(calender.isEmpty()); + + // 'Calender' instance created. + EXPECT_TRUE(calender::get_instance_count() == 1); + // 'Calender' has two 'Event' instances. + EXPECT_TRUE(event::get_instance_count() == 2); + + // Event's object can be obtained from Calender's object ('Calander' has-a 'Event'). + auto getEvent = classCalender->getMethod(calender::str_getTheEvent); + ASSERT_TRUE(getEvent); + + auto get_event = getEvent->targetT<>().argsT<>().returnT<>(); + + // get the Event's object from the 'Calender' object. + auto [err2, event] = get_event(calender)(); + + EXPECT_TRUE(err2 == rtl::error::None); + ASSERT_FALSE(event.isEmpty()); + EXPECT_TRUE(event.getTypeId() == cxx::reflected_id(event::struct_)); + { + auto [err, robj] = event.clone(); + //Event's copy-constructor private or deleted. + EXPECT_TRUE(err == rtl::error::TypeNotCopyConstructible); + ASSERT_TRUE(robj.isEmpty()); + // Two 'Event' instances, owned by 'Calender' + EXPECT_TRUE(event::get_instance_count() == 2); + } { + auto [err, robj] = event.clone(); + //Event's copy-constructor private or deleted. + EXPECT_TRUE(err == rtl::error::TypeNotCopyConstructible); + ASSERT_TRUE(robj.isEmpty()); + // Still, two 'Event' instances, owned by 'Calender' + EXPECT_TRUE(event::get_instance_count() == 2); + } + } + EXPECT_TRUE(calender::assert_zero_instance_count()); + //Once 'Calender' is destroyed, all 'Event's should too. + ASSERT_TRUE(event::assert_zero_instance_count()); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/StaticMethodTests.cpp b/RTLTestRunApp/src/FunctionalityTests/StaticMethodTests.cpp new file mode 100644 index 00000000..a9e80956 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/StaticMethodTests.cpp @@ -0,0 +1,204 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "TestUtilsPerson.h" + +using namespace std; +using namespace rtl; + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(StaticMethods, unique_method_call) + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional optGetDefaults = classPerson->getMethod(person::str_getDefaults); + ASSERT_TRUE(optGetDefaults); + EXPECT_TRUE(optGetDefaults->hasSignature<>()); //empty template params checks for zero arguments. + + auto getDefaultsFn = optGetDefaults->argsT<>().returnT<>(); + ASSERT_TRUE(getDefaultsFn); + EXPECT_EQ(getDefaultsFn.get_init_error(), rtl::error::None); + + auto [err, ret] = getDefaultsFn(); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + EXPECT_EQ(retStr, person::get_str_returned_on_call_getDefaults()); + } + + + TEST(StaticMethods, overload_method_void_call) + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional optGetProfile = classPerson->getMethod(person::str_getProfile); + ASSERT_TRUE(optGetProfile); + EXPECT_TRUE(optGetProfile->hasSignature<>()); //empty template params checks for zero arguments. + + auto getProfileFn = optGetProfile->argsT<>().returnT<>(); + ASSERT_TRUE(getProfileFn); + EXPECT_EQ(getProfileFn.get_init_error(), rtl::error::None); + + auto [err, ret] = getProfileFn(); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + EXPECT_EQ(retStr, person::get_str_returned_on_call_getProfile()); + } + + + TEST(StaticMethods, overload_method_args_bool_call) + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional optGetProfile = classPerson->getMethod(person::str_getProfile); + ASSERT_TRUE(optGetProfile); + EXPECT_TRUE(optGetProfile->hasSignature()); + + auto getProfileFn = optGetProfile->argsT().returnT<>(); + ASSERT_TRUE(getProfileFn); + EXPECT_EQ(getProfileFn.get_init_error(), rtl::error::None); + { + auto [err, ret] = getProfileFn(true); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + EXPECT_EQ(retStr, person::get_str_returned_on_call_getProfile(true)); + } { + //use the bind-call syntax. + auto [err, ret] = getProfileFn.bind()(false); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + EXPECT_EQ(retStr, person::get_str_returned_on_call_getProfile(false)); + } + } + + + TEST(StaticMethods, overload_method_args_string_size_t_call) + { + optional recOpt = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(recOpt.has_value()); + + const Record& classPerson = recOpt.value(); + optional methOpt = classPerson.getMethod(person::str_getProfile); + ASSERT_TRUE(methOpt.has_value()); + + const Method& optGetProfile = methOpt.value(); + EXPECT_TRUE((optGetProfile.hasSignature())); + + auto getProfileFn = optGetProfile.argsT().returnT<>(); + ASSERT_TRUE(getProfileFn); + EXPECT_EQ(getProfileFn.get_init_error(), rtl::error::None); + + auto [err, ret] = getProfileFn(person::OCCUPATION, person::AGE); + + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + const string& checkStr = person::get_str_returned_on_call_getProfile(); + + EXPECT_EQ(retStr, checkStr); + } + + + TEST(StaticMethods, static_method_call_on_target_instance) + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional getDefaultsOpt = classPerson->getMethod(person::str_getDefaults); + ASSERT_TRUE(getDefaultsOpt); + EXPECT_TRUE(getDefaultsOpt->hasSignature<>()); //empty template params checks for zero arguments. + { + rtl::method getDefaultsFn = getDefaultsOpt.value().targetT().argsT().returnT(); + + EXPECT_FALSE(getDefaultsFn); + EXPECT_EQ(getDefaultsFn.get_init_error(), error::SignatureMismatch); + + auto [err0, person] = classPerson->ctorT<>()(alloc::Heap); + + EXPECT_EQ(err0, error::None); + ASSERT_FALSE(person.isEmpty()); + + auto [err, ret] = getDefaultsFn(person)(); + + EXPECT_EQ(err, error::SignatureMismatch); + EXPECT_TRUE(ret.isEmpty()); + } { + rtl::static_method getDefaultsFn = getDefaultsOpt.value().argsT().returnT(); + + auto [err, ret] = getDefaultsFn(); + + EXPECT_EQ(err, error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + auto& retStr = ret.view()->get(); + EXPECT_EQ(retStr, person::get_str_returned_on_call_getDefaults()); + } + } + + + TEST(StaticMethods, static_method_call_on_target_instance_with_args) + { + optional classPerson = cxx::mirror().getRecord(person::class_); + ASSERT_TRUE(classPerson); + + optional getProfileOpt = classPerson->getMethod(person::str_getProfile); + ASSERT_TRUE(getProfileOpt); + EXPECT_TRUE((getProfileOpt->hasSignature())); + + { + rtl::method optGetProfile = getProfileOpt.value() + .targetT() + .argsT() + .returnT(); + EXPECT_FALSE(optGetProfile); + EXPECT_EQ(optGetProfile.get_init_error(), error::SignatureMismatch); + + auto [err0, person] = classPerson->ctorT()(alloc::Heap); + + EXPECT_EQ(err0, error::None); + ASSERT_FALSE(person.isEmpty()); + + auto [err, ret] = optGetProfile(person)(person::OCCUPATION, person::AGE); + + EXPECT_EQ(err, error::SignatureMismatch); + ASSERT_TRUE(ret.isEmpty()); + } { + rtl::static_method optGetProfile = getProfileOpt.value() + .argsT() + .returnT(); + auto [err, ret] = optGetProfile(person::OCCUPATION, person::AGE); + + EXPECT_EQ(err, error::None); + ASSERT_FALSE(ret.isEmpty()); + EXPECT_TRUE(ret.canViewAs()); + + const string& retStr = ret.view()->get(); + const string& checkStr = person::get_str_returned_on_call_getProfile(); + EXPECT_EQ(retStr, checkStr); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_ConstMethod.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_ConstMethod.cpp new file mode 100644 index 00000000..7ff6d463 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_ConstMethod.cpp @@ -0,0 +1,437 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" +#include "../CxxTestProps/inc/StringConst.h" + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(TypeAware_ConstMethod, std_string_view_method_call_with_known_signature) + { + std::optional stdStringViewClass = cxx::mirror().getRecord("std", "string_view"); + ASSERT_TRUE(stdStringViewClass); + + std::optional isStringEmpty = stdStringViewClass->getMethod("empty"); + ASSERT_TRUE(isStringEmpty); + { + rtl::method is_empty = isStringEmpty->targetT() + .argsT<>() + .returnT(); + EXPECT_FALSE(is_empty); + } { + rtl::const_method is_empty = isStringEmpty->targetT() + .argsT<>() + .returnT(); + ASSERT_TRUE(is_empty); + + EXPECT_TRUE(is_empty(std::string(""))()); + + EXPECT_FALSE(is_empty(std::string("not_empty"))()); + + EXPECT_TRUE(is_empty(std::string_view(""))()); + + EXPECT_FALSE(is_empty(std::string_view("view_not_empty"))()); + + EXPECT_TRUE(is_empty("")()); + + EXPECT_FALSE(is_empty("view_not_empty")()); + } + } + + + TEST(TypeAware_ConstMethod, init_errors_validation) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::SignatureMismatch); + }{ + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::ReturnTypeMismatch); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_TRUE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::None); + } + } + + + TEST(TypeAware_ConstMethod, overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(StrConst())(STRA); + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_const_char_ptr + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(StrConst())(STRB); + auto exp_str = std::string(StrConst::struct_) + STRB_REVERSE + SUFFIX_std_string + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT<>() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(StrConst())(); + auto exp_str = std::string(StrConst::struct_) + REV_STR_VOID_RET + SUFFIX_void + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_ConstMethod, lvalue_ref_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + //argument lvalue-ref. + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + //non-const target + StrConst target; + std::string lv_str = STRA; + std::string ret_str = reverse_string(target)(lv_str); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_lvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + //argument const-lvalue-ref. + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + //non-const target + StrConst target; + const std::string lv_str = STRA; + std::string ret_str = reverse_string(target)(lv_str); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_clvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + //argument lvalue-ref. + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + //const target. + const StrConst target; + std::string lv_str = STRA; + std::string ret_str = reverse_string(target)(lv_str); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_lvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + //argument const-lvalue-ref. + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + //const target. + const StrConst target; + const std::string lv_str = STRA; + std::string ret_str = reverse_string(target)(lv_str); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_clvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_ConstMethod, rvalue_ref_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + { + //non-const target. + StrConst target; + std::string ret_str = reverse_string(target)(STRA); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_rvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + //const-target + const StrConst target; + std::string ret_str = reverse_string(target)(STRA); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_rvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } + } + + + TEST(TypeAware_ConstMethod, ptr_and_const_ptr_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + StrConst target; + std::string str = STRA; + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(&str); + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_ptr + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(&str); + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_cptr + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_ConstMethod, std_string_method_call_with_known_signature) + { + std::optional stdStringClass = cxx::mirror().getRecord("std", "string"); + ASSERT_TRUE(stdStringClass); + + std::optional isStringEmpty = stdStringClass->getMethod("empty"); + ASSERT_TRUE(isStringEmpty); + { + rtl::method is_empty = isStringEmpty->targetT() + .argsT<>() + .returnT(); + EXPECT_FALSE(is_empty); + } { + rtl::const_method is_empty = isStringEmpty->targetT() + .argsT<>() + .returnT(); + ASSERT_TRUE(is_empty); + + EXPECT_TRUE(is_empty(std::string(""))()); + + EXPECT_FALSE(is_empty(std::string("not_empty"))()); + + EXPECT_TRUE(is_empty("")()); + + EXPECT_FALSE(is_empty("view_not_empty")()); + } + } + + + TEST(TypeAware_ConstMethod, distinct_functions_with_ref_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + StrConst target; + std::string str = STRA; + { + std::optional reverseString = optStringUtil->getMethod(str_revStrConstRefArg); + ASSERT_TRUE(reverseString); + + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + StrConst target; + std::string ret_str = reverse_string(target)(str); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + std::optional reverseString = optStringUtil->getMethod(str_revStrNonConstRefArg); + ASSERT_TRUE(reverseString); + + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + auto lvstr = std::string_view(str); + std::string ret_str = reverse_string(target)(lvstr); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + std::optional reverseString = optStringUtil->getMethod(str_revStrRValueRefArg); + ASSERT_TRUE(reverseString); + + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(str)); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view_rvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_ConstMethod, overloads_with_ref_and_value_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + StrConst target; + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValRef); + ASSERT_TRUE(reverseString); + { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(STRA)); + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string_view str = STRA; + std::string ret_str = reverse_string(target)(str); + + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_ConstMethod, overloads_with_const_ref_and_value_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + StrConst target; + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValCRef); + ASSERT_TRUE(reverseString); + { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(STRA)); + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(STRA)); + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_ConstMethod, overloads_with_ref_and_const_ref_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); + ASSERT_TRUE(optStringUtil); + + StrConst target; + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValRefAndCRef); + ASSERT_TRUE(reverseString); + { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string_view str = STRA; + std::string ret_str = reverse_string(target)(str); + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(STRA)); + auto exp_str = std::string(StrConst::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref + SUFFIX_const; + EXPECT_EQ(ret_str, exp_str); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_Function.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_Function.cpp new file mode 100644 index 00000000..1f478a43 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_Function.cpp @@ -0,0 +1,309 @@ + +#include +#include +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" + + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(TypeAware_Function, init_errors_validation) + { + std::optional setReal = cxx::mirror().getFunction(str_complex, str_setReal); + ASSERT_TRUE(setReal); + { + EXPECT_TRUE(setReal->getNamespace() == str_complex); + EXPECT_TRUE(setReal->getFunctionName() == str_setReal); + { + rtl::function functor = setReal->argsT().returnT(); + EXPECT_TRUE(functor); + EXPECT_EQ(functor.get_init_error(), rtl::error::None); + } { + rtl::function functor = setReal->argsT().returnT(); + EXPECT_FALSE(functor); + EXPECT_EQ(functor.get_init_error(), rtl::error::SignatureMismatch); + } + } + + std::optional setImaginary = cxx::mirror().getFunction(str_complex, str_setImaginary); + ASSERT_TRUE(setImaginary); + { + EXPECT_TRUE(setImaginary->getNamespace() == str_complex); + EXPECT_TRUE(setImaginary->getFunctionName() == str_setImaginary); + { + rtl::function functor = setImaginary->argsT().returnT(); + EXPECT_TRUE(functor); + EXPECT_EQ(functor.get_init_error(), rtl::error::None); + } { + rtl::function functor = setImaginary->argsT().returnT(); + EXPECT_FALSE(functor); + EXPECT_EQ(functor.get_init_error(), rtl::error::ReturnTypeMismatch); + } + } + } + + + TEST(TypeAware_Function, namespace_fn_call_with_known_signature) + { + std::optional getMagnitude = cxx::mirror().getFunction(str_complex, str_getMagnitude); + ASSERT_TRUE(getMagnitude); + + rtl::function get_magnitude = getMagnitude->argsT<>().returnT(); + ASSERT_TRUE(get_magnitude); + + std::optional setReal = cxx::mirror().getFunction(str_complex, str_setReal); + ASSERT_TRUE(setReal); + + rtl::function set_real = setReal->argsT().returnT(); + ASSERT_TRUE(set_real); + + std::optional setImaginary = cxx::mirror().getFunction(str_complex, str_setImaginary); + ASSERT_TRUE(setImaginary); + + rtl::function set_imaginary = setImaginary->argsT().returnT(); + ASSERT_TRUE(set_imaginary); + + set_real(g_real); + set_imaginary(g_imaginary); + + double retVal = get_magnitude(); + + double magnitude = abs(std::complex(g_real, g_imaginary)); + + EXPECT_DOUBLE_EQ(magnitude, retVal); + } + + + TEST(TypeAware_Function, global_fn_call_with_known_signature) + { + std::optional getComplexNumStr = cxx::mirror().getFunction(str_getComplexNumAsString); + ASSERT_TRUE(getComplexNumStr); + { + rtl::function get_complex_num_str = getComplexNumStr->argsT<>().returnT(); + EXPECT_FALSE(get_complex_num_str); + } { + rtl::function get_complex_num_str = getComplexNumStr->argsT<>().returnT(); + EXPECT_FALSE(get_complex_num_str); + } { + rtl::function get_complex_num_str = getComplexNumStr->argsT<>().returnT(); + ASSERT_TRUE(get_complex_num_str); + + std::string ret_str = get_complex_num_str(); + + std::string complex_num_str = std::to_string(g_real) + "i" + std::to_string(g_imaginary); + + EXPECT_EQ(complex_num_str, ret_str); + } + } + + + TEST(TypeAware_Function, overload_resolution_with_known_signatures) + { + std::optional reverseString = cxx::mirror().getFunction(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::function reverse_string = reverseString->argsT().returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(STRA); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_const_char_ptr; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(STRB); + auto exp_str = std::string(STRB_REVERSE) + SUFFIX_std_string; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::function reverse_string = reverseString->argsT<>().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(); + auto exp_str = std::string(REV_STR_VOID_RET) + SUFFIX_void; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Function, lvalue_ref_overload_resolution_with_known_signatures) + { + std::optional reverseString = cxx::mirror().getFunction(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string lv_str = STRA; + std::string ret_str = reverse_string(lv_str); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_lvref; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + const std::string lv_str = STRA; + std::string ret_str = reverse_string(lv_str); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_clvref; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Function, rvalue_ref_overload_resolution_with_known_signatures) + { + std::optional reverseString = cxx::mirror().getFunction(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(STRA); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_rvref; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + EXPECT_FALSE(reverse_string); + } + } + + + TEST(TypeAware_Function, ptr_and_const_ptr_overload_resolution_with_known_signatures) + { + std::string str = STRA; + std::optional reverseString = cxx::mirror().getFunction(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(&str); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_ptr; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(&str); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_cptr; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Function, distinct_functions_with_ref_args_call_with_known_signature) + { + std::string str = STRA; + { + std::optional reverseString = cxx::mirror().getFunction(str_revStrConstRefArg); + ASSERT_TRUE(reverseString); + + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(str); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view_clvref; + EXPECT_EQ(ret_str, exp_str); + } { + std::optional reverseString = cxx::mirror().getFunction(str_revStrNonConstRefArg); + ASSERT_TRUE(reverseString); + + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + auto lvstr = std::string_view(str); + std::string ret_str = reverse_string(lvstr); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view_lvref; + EXPECT_EQ(ret_str, exp_str); + } { + std::optional reverseString = cxx::mirror().getFunction(str_revStrRValueRefArg); + ASSERT_TRUE(reverseString); + + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(str)); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view_rvref; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Function, overloads_with_ref_and_value_args_call_with_known_signature) + { + std::optional reverseString = cxx::mirror().getFunction(str_revStrOverloadValRef); + ASSERT_TRUE(reverseString); + { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(STRA)); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string_view str = STRA; + std::string ret_str = reverse_string(str); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view_lvref; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Function, overloads_with_const_ref_and_value_args_call_with_known_signature) + { + std::optional reverseString = cxx::mirror().getFunction(str_revStrOverloadValCRef); + ASSERT_TRUE(reverseString); + { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(STRA)); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(STRA)); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view_clvref; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Function, overloads_with_ref_and_const_ref_args_call_with_known_signature) + { + std::optional reverseString = cxx::mirror().getFunction(str_revStrOverloadValRefAndCRef); + ASSERT_TRUE(reverseString); + { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string_view str = STRA; + std::string ret_str = reverse_string(str); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view_lvref; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::function reverse_string = reverseString->argsT().returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(STRA)); + auto exp_str = std::string(STRA_REVERSE) + SUFFIX_std_string_view_clvref; + EXPECT_EQ(ret_str, exp_str); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_Method.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_Method.cpp new file mode 100644 index 00000000..8013e060 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_Method.cpp @@ -0,0 +1,365 @@ + +#include +#include + +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" +#include "../CxxTestProps/inc/StringMute.h" + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(TypeAware_Method, init_errors_validation) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::SignatureMismatch); + }{ + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::ReturnTypeMismatch); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_TRUE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::None); + } + } + + + TEST(TypeAware_Method, overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::const_method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(StrMute())(STRA); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_const_char_ptr; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(StrMute())(STRB); + auto exp_str = std::string(StrMute::struct_) + STRB_REVERSE + SUFFIX_std_string; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT<>() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(StrMute())(); + auto exp_str = std::string(StrMute::struct_) + REV_STR_VOID_RET + SUFFIX_void; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Method, lvalue_ref_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + //non-const target. + StrMute target; + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + //argument lvalue-ref + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + std::string lv_str = STRA; + std::string ret_str = reverse_string(target)(lv_str); + + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_lvref; + EXPECT_EQ(ret_str, exp_str); + } { + //argument const-lvalue-ref + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + const std::string lv_str = STRA; + std::string ret_str = reverse_string(target)(lv_str); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_clvref; + EXPECT_EQ(ret_str, exp_str); + } { + //argument lvalue-ref + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + //const-target. + const StrMute& c_target = target; + std::string lv_str = STRA; + + // compile error - + // std::string ret_str = reverse_string(const_target)(lv_str); + std::string ret_str = reverse_string(const_cast(c_target))(lv_str); + + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_lvref; + EXPECT_EQ(ret_str, exp_str); + } { + //argument const-lvalue-ref + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + //const-target. + const StrMute& c_target = target; + std::string lv_str = STRA; + + // compile error - + // std::string ret_str = reverse_string(c_target)(lv_str); + std::string ret_str = reverse_string(const_cast(c_target))(lv_str); + + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_clvref; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Method, rvalue_ref_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + StrMute target; + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(STRA); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_rvref; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } + } + + + TEST(TypeAware_Method, ptr_and_const_ptr_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + StrMute target; + std::string str = STRA; + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(&str); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_ptr; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(&str); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_cptr; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Method, distinct_functions_with_ref_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + StrMute target; + std::string str = STRA; + { + std::optional reverseString = optStringUtil->getMethod(str_revStrConstRefArg); + ASSERT_TRUE(reverseString); + + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(str); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref; + EXPECT_EQ(ret_str, exp_str); + } { + std::optional reverseString = optStringUtil->getMethod(str_revStrNonConstRefArg); + ASSERT_TRUE(reverseString); + + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + auto lvstr = std::string_view(str); + std::string ret_str = reverse_string(target)(lvstr); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref; + EXPECT_EQ(ret_str, exp_str); + } { + std::optional reverseString = optStringUtil->getMethod(str_revStrRValueRefArg); + ASSERT_TRUE(reverseString); + + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(str)); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_rvref; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Method, overloads_with_ref_and_value_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + StrMute target; + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValRef); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(STRA)); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string_view str = STRA; + std::string ret_str = reverse_string(target)(str); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Method, overloads_with_const_ref_and_value_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + StrMute target; + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValCRef); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(STRA)); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(STRA)); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_Method, overloads_with_ref_and_const_ref_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + StrMute target; + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValRefAndCRef); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string_view str = STRA; + std::string ret_str = reverse_string(target)(str); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::method reverse_string = reverseString->targetT() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(target)(std::string_view(STRA)); + auto exp_str = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref; + EXPECT_EQ(ret_str, exp_str); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_StaticMethod.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_StaticMethod.cpp new file mode 100644 index 00000000..b8009f6d --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeAwareInvocationTests/TypeAware_StaticMethod.cpp @@ -0,0 +1,399 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" +#include "../CxxTestProps/inc/StringMute.h" +#include "../CxxTestProps/inc/StringConst.h" +#include "../CxxTestProps/inc/StringStatic.h" + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(TypeAware_StaticMethod, init_errors_validation) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::static_method reverse_string = reverseString->argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::SignatureMismatch); + } { + rtl::static_method reverse_string = reverseString->argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::ReturnTypeMismatch); + } { + rtl::static_method reverse_string = reverseString->argsT() + .returnT(); + EXPECT_TRUE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::None); + } + } + + + TEST(TypeAware_StaticMethod, using_wrong_class_n_callable_apis_for_static_method) + { + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); // has only static-methods. + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString.value() + .targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::SignatureMismatch); + } { + rtl::function reverse_string = static_cast(reverseString.value()) + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::InvalidStaticMethodCaller); + } + } { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); // doesn't have any static-methods. + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::InvalidNonStaticMethodCaller); + } { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); // doesn't have any static-methods. + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::InvalidNonStaticMethodCaller); + } + } + } + + + TEST(TypeAware_StaticMethod, overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil.value().getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString.value() + .targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::method reverse_string = reverseString.value() + .targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::method reverse_string = reverseString.value() + .targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::const_method reverse_string = reverseString.value() + .targetT() + .argsT() + .returnT(); + EXPECT_FALSE(reverse_string); + } { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(STRA); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_const_char_ptr + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(STRB); + auto exp_str = std::string(StrStatic::struct_) + STRB_REVERSE + SUFFIX_std_string + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::static_method reverse_string = reverseString.value() + .argsT<>() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(); + auto exp_str = std::string(StrStatic::struct_) + REV_STR_VOID_RET + SUFFIX_void + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_StaticMethod, lvalue_ref_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + //non-const target. + StrMute target; + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + //argument lvalue-ref + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + std::string lv_str = STRA; + std::string ret_str = reverse_string(lv_str); + + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_lvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + //argument const-lvalue-ref + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + const std::string lv_str = STRA; + std::string ret_str = reverse_string(lv_str); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_clvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + //argument lvalue-ref + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + std::string lv_str = STRA; + std::string ret_str = reverse_string(lv_str); + + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_lvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + //argument const-lvalue-ref + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + //const-target. + const StrMute& c_target = target; + std::string lv_str = STRA; + + std::string ret_str = reverse_string(lv_str); + + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_clvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_StaticMethod, rvalue_ref_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(STRA); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_rvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_StaticMethod, ptr_and_const_ptr_overload_resolution_with_known_signatures) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::string str = STRA; + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(&str); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_ptr + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(&str); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_cptr + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_StaticMethod, distinct_functions_with_ref_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::string str = STRA; + { + std::optional reverseString = optStringUtil->getMethod(str_revStrConstRefArg); + ASSERT_TRUE(reverseString); + + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(str); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + std::optional reverseString = optStringUtil->getMethod(str_revStrNonConstRefArg); + ASSERT_TRUE(reverseString); + + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + auto lvstr = std::string_view(str); + std::string ret_str = reverse_string(lvstr); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + std::optional reverseString = optStringUtil->getMethod(str_revStrRValueRefArg); + ASSERT_TRUE(reverseString); + + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(str)); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view_rvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_StaticMethod, overloads_with_ref_and_value_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValRef); + ASSERT_TRUE(reverseString); + { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(STRA)); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string_view str = STRA; + std::string ret_str = reverse_string(str); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_StaticMethod, overloads_with_const_ref_and_value_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValCRef); + ASSERT_TRUE(reverseString); + { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(STRA)); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(STRA)); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } + } + + + TEST(TypeAware_StaticMethod, overloads_with_ref_and_const_ref_args_call_with_known_signature) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_revStrOverloadValRefAndCRef); + ASSERT_TRUE(reverseString); + { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string_view str = STRA; + std::string ret_str = reverse_string(str); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT(); + ASSERT_TRUE(reverse_string); + + std::string ret_str = reverse_string(std::string_view(STRA)); + auto exp_str = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref + SUFFIX_static; + EXPECT_EQ(ret_str, exp_str); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnAndTargetErased_ConstMethod.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnAndTargetErased_ConstMethod.cpp new file mode 100644 index 00000000..a68000d9 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnAndTargetErased_ConstMethod.cpp @@ -0,0 +1,58 @@ + +#include +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" +#include "../CxxTestProps/inc/StringConstOverload.h" + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(ReturnAndTargetErased_ConstMethod, auto_resolution_to_const_method) + { + std::optional recStrConstOverload = cxx::mirror().getRecord(StrConstOverload::struct_); + ASSERT_TRUE(recStrConstOverload); + + auto testWithAlloc = [&](rtl::alloc pAlloc) + { + auto [err, robj] = recStrConstOverload->ctorT()(pAlloc); + EXPECT_EQ(err, rtl::error::None); + EXPECT_TRUE(!robj.isEmpty()); + + std::optional oReverseString = recStrConstOverload->getMethod(str_reverseString); + ASSERT_TRUE(oReverseString); + + // Both const & non-const overloads are present for this method. + rtl::method reverseString = oReverseString->targetT().argsT().returnT(); + EXPECT_TRUE(reverseString); + { + auto [err, ret] = reverseString(robj)(); + EXPECT_EQ(err, rtl::error::None); + EXPECT_TRUE(!ret.isEmpty()); + ASSERT_TRUE(ret.canViewAs()); + + const std::string& retStr = ret.view()->get(); + const std::string& expectedStr = std::string(StrConstOverload::struct_) + REV_STR_VOID_RET + + SUFFIX_void; + EXPECT_EQ(retStr, expectedStr); + } { + auto [err, ret] = reverseString(std::cref(robj))(); + EXPECT_EQ(err, rtl::error::None); + EXPECT_TRUE(!ret.isEmpty()); + ASSERT_TRUE(ret.canViewAs()); + + const std::string& retStr = ret.view()->get(); + const std::string& expectedStr = std::string(StrConstOverload::struct_) + REV_STR_VOID_RET + + SUFFIX_void + SUFFIX_const; + EXPECT_EQ(retStr, expectedStr); + } + }; + + testWithAlloc(rtl::alloc::Heap); + testWithAlloc(rtl::alloc::Stack); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_ConstMethod.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_ConstMethod.cpp new file mode 100644 index 00000000..e69de29b diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Constructor.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Constructor.cpp new file mode 100644 index 00000000..b8897362 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Constructor.cpp @@ -0,0 +1,279 @@ + +#include +#include + +#include "GlobalTestUtils.h" +#include "TestMirrorProvider.h" +#include "../CxxTestProps/inc/StringWrap.h" + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(ReturnErased_Constructor, std_string_constructor_call) + { + { + rtl::constructor ctorT; + EXPECT_FALSE(ctorT); + + auto [err, robj] = ctorT(rtl::alloc::Stack, 0); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } + std::optional classStdString = cxx::mirror().getRecord("std", "string"); + ASSERT_TRUE(classStdString); + { + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto ctorT = classStdString->ctorT<>(); + EXPECT_TRUE(ctorT); + + auto [err, robj] = ctorT(alloc_on); + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& spartaStr = viewStr->get(); + EXPECT_EQ(spartaStr.length(), 0); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } + const char* SPARTA = "This is Spaartaaa!!"; + { + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto ctorT = classStdString->ctorT(); + EXPECT_TRUE(ctorT); + + auto [err, robj] = ctorT(alloc_on, SPARTA); + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& spartaStr = viewStr->get(); + EXPECT_EQ(spartaStr, std::string(SPARTA)); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } + } + + + TEST(ReturnErased_Constructor, by_value_overloaded_ctor_call) + { + std::optional classStrWrap = cxx::mirror().getRecord(StrWrapA::struct_); + ASSERT_TRUE(classStrWrap); + { + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto ctorT = classStrWrap->ctorT<>(); + EXPECT_TRUE(ctorT); + + auto [err, robj] = ctorT(alloc_on); + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& stdStr = viewStr->get(); + EXPECT_EQ(stdStr.sstr(), + (std::string(StrWrapA::struct_) + SUFFIX_ctor)); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } + const char* SPARTA = "This is Spaartaaa!!"; + { + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto ctorT = classStrWrap->ctorT(); + EXPECT_TRUE(ctorT); + + auto [err, robj] = ctorT(alloc_on, SPARTA); + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& stdStr = viewStr->get(); + EXPECT_EQ(stdStr.sstr(), + (std::string(StrWrapA::struct_) + std::string(SPARTA) + + SUFFIX_std_string_view + SUFFIX_ctor)); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } { + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto ctorT = classStrWrap->ctorT(); + EXPECT_TRUE(ctorT); + + auto [err, robj] = ctorT(alloc_on, SPARTA); + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& stdStr = viewStr->get(); + EXPECT_EQ(stdStr.sstr(), + (std::string(StrWrapA::struct_) + std::string(SPARTA) + + SUFFIX_const_char_ptr + SUFFIX_ctor)); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } + } + + + TEST(ReturnErased_Constructor, by_ref_overloaded_ctor_call) + { + const char* SPARTA = "This is Spaartaaa!!"; + std::optional classStrWrap = cxx::mirror().getRecord(StrWrapA::struct_); + ASSERT_TRUE(classStrWrap); + + auto ctorT = classStrWrap->ctorT(); + EXPECT_TRUE(ctorT); + { + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto [err, robj] = ctorT.bind()(alloc_on, SPARTA); + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& stdStr = viewStr->get(); + EXPECT_EQ(stdStr.sstr(), + (std::string(StrWrapA::struct_) + std::string(SPARTA) + + SUFFIX_std_string_lvref + SUFFIX_ctor)); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } { + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto [err, robj] = ctorT.bind()(alloc_on, SPARTA); + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& stdStr = viewStr->get(); + EXPECT_EQ(stdStr.sstr(), + (std::string(StrWrapA::struct_) + std::string(SPARTA) + + SUFFIX_std_string_rvref + SUFFIX_ctor)); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } { + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto [err, robj] = ctorT.bind()(alloc_on, SPARTA); + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& stdStr = viewStr->get(); + EXPECT_EQ(stdStr.sstr(), + (std::string(StrWrapA::struct_) + std::string(SPARTA) + + SUFFIX_std_string_clvref + SUFFIX_ctor)); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } + } + + + TEST(ReturnErased_Constructor, auto_overload_resolution) + { + const char* SPARTA = "This is Spaartaaa!!"; + { + std::optional classStrWrap = cxx::mirror().getRecord(StrWrapA::struct_); + ASSERT_TRUE(classStrWrap); + + auto ctorT = classStrWrap->ctorT(); + EXPECT_TRUE(ctorT); + + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto [err, robj] = ctorT(alloc_on, SPARTA); + // More than one reference-based overloads exists. + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + EXPECT_TRUE(robj.isEmpty()); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } { + std::optional classStrWrap = cxx::mirror().getRecord(StrWrapB::struct_); + ASSERT_TRUE(classStrWrap); + + auto ctorT = classStrWrap->ctorT(); + EXPECT_TRUE(ctorT); + + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto [err, robj] = ctorT(alloc_on, SPARTA); + // More than one reference-based overloads exists. + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + EXPECT_TRUE(robj.isEmpty()); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } { + std::optional classStrWrap = cxx::mirror().getRecord(StrWrapC::struct_); + ASSERT_TRUE(classStrWrap); + + auto ctorT = classStrWrap->ctorT(); + EXPECT_TRUE(ctorT); + + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto [err, robj] = ctorT(alloc_on, SPARTA); + // only non-const-reference-based ctor exists. + // mutating call should be explicit. + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + EXPECT_TRUE(robj.isEmpty()); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } { + std::optional classStrWrap = cxx::mirror().getRecord(StrWrapD::struct_); + ASSERT_TRUE(classStrWrap); + + auto ctorT = classStrWrap->ctorT(); + EXPECT_TRUE(ctorT); + + auto testCreateOn = [&](rtl::alloc alloc_on) + { + auto [err, robj] = ctorT(alloc_on, SPARTA); + // only const-reference-based ctor exists. + // non-mutating call chosen by default. + EXPECT_EQ(err, rtl::error::None); + EXPECT_FALSE(robj.isEmpty()); + + const auto viewStr = robj.view(); + ASSERT_TRUE(viewStr); + + const auto& stdStr = viewStr->get(); + EXPECT_EQ(stdStr.sstr(), + (std::string(StrWrapD::struct_) + std::string(SPARTA) + + SUFFIX_std_string_clvref + SUFFIX_ctor)); + }; + testCreateOn(rtl::alloc::Heap); + testCreateOn(rtl::alloc::Stack); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Function.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Function.cpp new file mode 100644 index 00000000..2cfd9420 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Function.cpp @@ -0,0 +1,555 @@ + +#include +#include +#include +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" + +using namespace test_utils; +using namespace test_mirror; + +// TODO: test cases for functions with return type 'void'. + +namespace rtl_tests +{ + TEST(ReturnErased_Function, invalid_erased_return_rtl_function) + { + { + rtl::function erased_ret_fn; + EXPECT_FALSE(erased_ret_fn); + + auto [err, robj] = erased_ret_fn(); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } + + rtl::function erased_ret_fn; + EXPECT_FALSE(erased_ret_fn); + { + auto [err, robj] = erased_ret_fn(0); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } { + auto [err, robj] = erased_ret_fn.bind()(0); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } { + auto [err, robj] = erased_ret_fn.bind()(0); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } + } + + + TEST(ReturnErased_Function, implicit_resolutions_to_call_by_value_overloads) + { + auto reverseStrOpt = cxx::mirror().getFunction(str_reverseString); + ASSERT_TRUE(reverseStrOpt); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + { + rtl::function reverseString = reverseStrOpt->argsT().returnT<>(); + EXPECT_FALSE(reverseString); + EXPECT_EQ(reverseString.get_init_error(), rtl::error::SignatureMismatch); + { + auto [err, robj] = reverseString(const_cast(STRA)); + EXPECT_EQ(err, rtl::error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } { + auto [err, robj] = reverseString.bind()(const_cast(STRA)); + + EXPECT_EQ(err, rtl::error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::function reverseString = reverseStrOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_const_char_ptr; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind()(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_const_char_ptr; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::function reverseString = reverseStrOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind()(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::function reverseString = reverseStrOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + std::string str = STRA; + auto [err, robj] = reverseString(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_ptr; + EXPECT_EQ(retStr, expStr); + } { + std::string str = STRA; + auto [err, robj] = reverseString.bind()(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_ptr; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::function reverseString = reverseStrOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + const std::string str = STRA; + auto [err, robj] = reverseString(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_cptr; + EXPECT_EQ(retStr, expStr); + } { + const std::string str = STRA; + auto [err, robj] = reverseString.bind()(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_cptr; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature<>()); + { + rtl::function reverseString = reverseStrOpt->argsT<>().returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(REV_STR_VOID_RET) + SUFFIX_void; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind()(); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(REV_STR_VOID_RET) + SUFFIX_void; + EXPECT_EQ(retStr, expStr); + } + } + } + + + TEST(ReturnErased_Function, implicit_resolution_to_ambiguous_lvalue_and_cref_overload) + { + auto revStrOverloadValCRefOpt = cxx::mirror().getFunction(str_revStrOverloadValCRef); + ASSERT_TRUE(revStrOverloadValCRefOpt); + + EXPECT_FALSE(revStrOverloadValCRefOpt->hasSignature()); + EXPECT_FALSE(revStrOverloadValCRefOpt->hasSignature()); + + // Both by-value (T) and const-ref (const T&) overloads exist. + EXPECT_TRUE(revStrOverloadValCRefOpt->hasSignature()); + EXPECT_TRUE(revStrOverloadValCRefOpt->hasSignature()); + std::string_view str = STRA; + + rtl::function reverseString = revStrOverloadValCRefOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + // RTL chooses the safe by-value overload implicitly. The const-ref + // path requires explicit binding only to disambiguate intent. + // Note: If only const T& existed (no by-value overload), RTL would + // call it implicitly, since binding to const-ref cannot mutate the caller. + auto [err, robj] = reverseString(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view; + EXPECT_EQ(retStr, expStr); + } { + // explicit call by value resolution. + auto [err, robj] = reverseString.bind()(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(ReturnErased_Function, explicit_resolution_to_ambiguous_lvalue_and_cref_overload) + { + auto revStrOverloadValCRefOpt = cxx::mirror().getFunction(str_revStrOverloadValCRef); + ASSERT_TRUE(revStrOverloadValCRefOpt); + + EXPECT_FALSE(revStrOverloadValCRefOpt->hasSignature()); + EXPECT_FALSE(revStrOverloadValCRefOpt->hasSignature()); + + // Both by-value (T) and const-ref (const T&) overloads exist. + EXPECT_TRUE(revStrOverloadValCRefOpt->hasSignature()); + EXPECT_TRUE(revStrOverloadValCRefOpt->hasSignature()); + std::string_view str = STRA; + + rtl::function reverseString = revStrOverloadValCRefOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + // Explicitly selecting the const-ref overload using .bind(). + // If no by-value overload were present, implicit resolution to const-ref + // would have worked automatically, because const-ref cannot mutate. + auto [err, robj] = reverseString.bind()(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view_clvref; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind()(str); + + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + ASSERT_TRUE(robj.isEmpty()); + } + } + + + TEST(ReturnErased_Function, implicit_resolution_to_ambiguous_lvalue_and_ref_overload) + { + auto revStrOverloadValRefOpt = cxx::mirror().getFunction(str_revStrOverloadValRef); + ASSERT_TRUE(revStrOverloadValRefOpt); + + EXPECT_FALSE(revStrOverloadValRefOpt->hasSignature()); + EXPECT_FALSE(revStrOverloadValRefOpt->hasSignature()); + + // Here both by-value (T) and non-const ref (T&) overloads exist. + EXPECT_TRUE(revStrOverloadValRefOpt->hasSignature()); + EXPECT_TRUE(revStrOverloadValRefOpt->hasSignature()); + std::string_view str = STRA; + + rtl::function reverseString = revStrOverloadValRefOpt->argsT().returnT<>(); + { + // Here also, RTL prioritizes the safe-by-value overload automatically + // since it guarantees no mutation. The non-const ref overload remains + // accessible only through explicit binding to preserve mutability intent. + auto [err, robj] = reverseString(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view; + EXPECT_EQ(retStr, expStr); + } { + // explicit call by value resolution. + auto [err, robj] = reverseString.bind()(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(ReturnErased_Function, explicit_resolution_to_ambiguous_lvalue_and_ref_overload) + { + auto revStrOverloadValRefOpt = cxx::mirror().getFunction(str_revStrOverloadValRef); + ASSERT_TRUE(revStrOverloadValRefOpt); + + EXPECT_FALSE(revStrOverloadValRefOpt->hasSignature()); + EXPECT_FALSE(revStrOverloadValRefOpt->hasSignature()); + + // Here both by-value (T) and non-const ref (T&) overloads exist. + EXPECT_TRUE(revStrOverloadValRefOpt->hasSignature()); + EXPECT_TRUE(revStrOverloadValRefOpt->hasSignature()); + std::string_view str = STRA; + + rtl::function reverseString = revStrOverloadValRefOpt->argsT().returnT<>(); + { + // Explicitly selecting the non-const ref overload. + // Even though the by-value overload is preferred implicitly for safety, + // the user can override that choice by binding explicitly as T&, + // signaling the intent to allow mutation through reflection. + auto [err, robj] = reverseString.bind()(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view_lvref; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind()(str); + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + ASSERT_TRUE(robj.isEmpty()); + } + } + + + TEST(ReturnErased_Function, calling_non_overloaded_non_const_ref_argument) + { + auto revStrNonConstRefArgOpt = cxx::mirror().getFunction(str_revStrNonConstRefArg); + ASSERT_TRUE(revStrNonConstRefArgOpt); + + EXPECT_FALSE(revStrNonConstRefArgOpt->hasSignature()); + EXPECT_FALSE(revStrNonConstRefArgOpt->hasSignature()); + EXPECT_FALSE(revStrNonConstRefArgOpt->hasSignature()); + + // Here no overloads exists, only non-const ref (T&) argument. + EXPECT_TRUE(revStrNonConstRefArgOpt->hasSignature()); + std::string_view str = STRA; + + rtl::function reverseString = revStrNonConstRefArgOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + + // Calls that may mutate user data (T&) require explicit intent. + // Hence, the dispatcher returns 'ExplicitRefBindingRequired' error. + // Since no call by value overload exists. + { + auto [err, robj] = reverseString(str); + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + } { + // expected non-const ref binding. + auto [err, robj] = reverseString.bind()(str); + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + } { + // By calling .bind(), the user explicitly signals willingness to let + // the function modify the argument. This re-enables the T& call path and + // executes successfully, producing the expected result. + auto [err, robj] = reverseString.bind()(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view_lvref; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(ReturnErased_Function, calling_non_overloaded_const_ref_argument) + { + auto revStrConstRefArgOpt = cxx::mirror().getFunction(str_revStrConstRefArg); + ASSERT_TRUE(revStrConstRefArgOpt); + + EXPECT_FALSE(revStrConstRefArgOpt->hasSignature()); + EXPECT_FALSE(revStrConstRefArgOpt->hasSignature()); + EXPECT_FALSE(revStrConstRefArgOpt->hasSignature()); + + // Here no overloads exists, only non-const ref (T&) argument. + EXPECT_TRUE(revStrConstRefArgOpt->hasSignature()); + std::string_view str = STRA; + + rtl::function reverseString = revStrConstRefArgOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + // This call resolves to the const-ref overload (no other overloads exist), + // so the argument is implicitly bound as a const reference. + auto [err, robj] = reverseString(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view_clvref; + EXPECT_EQ(retStr, expStr); + } { + // explicit binding must also behave the same way. + auto [err, robj] = reverseString.bind()(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view_clvref; + EXPECT_EQ(retStr, expStr); + } { + // explicit binding to non-const ref returns error. + auto [err, robj] = reverseString.bind()(str); + + // expected 'const T&' + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + ASSERT_TRUE(robj.isEmpty()); + } + } + + + TEST(ReturnErased_Function, calling_non_overloaded_rvalue_ref_argument) + { + auto revStrRValueRefArgOpt = cxx::mirror().getFunction(str_revStrRValueRefArg); + ASSERT_TRUE(revStrRValueRefArgOpt); + + EXPECT_FALSE(revStrRValueRefArgOpt->hasSignature()); + EXPECT_FALSE(revStrRValueRefArgOpt->hasSignature()); + EXPECT_FALSE(revStrRValueRefArgOpt->hasSignature()); + + // Here no overloads exists, only non-const ref (T&) argument. + EXPECT_TRUE(revStrRValueRefArgOpt->hasSignature()); + + rtl::function reverseString = revStrRValueRefArgOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(std::string_view(STRA)); + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + } { + auto [err, robj] = reverseString.bind()(std::string_view(STRA)); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view_rvref; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(ReturnErased_Function, implicit_resolution_to_ambiguous_ref_and_cref_overload) + { + auto revStrOverloadValRefNCrefOpt = cxx::mirror().getFunction(str_revStrOverloadValRefAndCRef); + ASSERT_TRUE(revStrOverloadValRefNCrefOpt); + + EXPECT_FALSE(revStrOverloadValRefNCrefOpt->hasSignature()); + EXPECT_FALSE(revStrOverloadValRefNCrefOpt->hasSignature()); + + // Here distinct overloads exists, with non-const ref (T&) and const-ref (const T&). + EXPECT_TRUE(revStrOverloadValRefNCrefOpt->hasSignature()); + EXPECT_TRUE(revStrOverloadValRefNCrefOpt->hasSignature()); + std::string_view str = STRA; + + rtl::function reverseString = revStrOverloadValRefNCrefOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + // Both T& and const T& overloads are viable for an lvalue argument. + // RTL avoids implicit ambiguity by requiring explicit ref binding + // when mutation is possible (non-const ref path). + auto [err, robj] = reverseString(str); + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + } { + auto [err, robj] = reverseString.bind()(str); + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + } { + auto [err, robj] = reverseString.bind()(str); + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + } + } + + + TEST(ReturnErased_Function, explicit_resolution_to_ambiguous_ref_and_cref_overload) + { + auto revStrOverloadValRefNCrefOpt = cxx::mirror().getFunction(str_revStrOverloadValRefAndCRef); + ASSERT_TRUE(revStrOverloadValRefNCrefOpt); + + EXPECT_FALSE(revStrOverloadValRefNCrefOpt->hasSignature()); + EXPECT_FALSE(revStrOverloadValRefNCrefOpt->hasSignature()); + + // Here distinct overloads exists, with non-const ref (T&) and const-ref (const T&). + EXPECT_TRUE(revStrOverloadValRefNCrefOpt->hasSignature()); + EXPECT_TRUE(revStrOverloadValRefNCrefOpt->hasSignature()); + std::string_view str = STRA; + + rtl::function reverseString = revStrOverloadValRefNCrefOpt->argsT().returnT<>(); + EXPECT_TRUE(reverseString); + { + // Explicitly selecting the non-const ref overload. + // Caller signals intent to allow mutation by binding as T&. + auto [err, robj] = reverseString.bind()(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view_lvref; + EXPECT_EQ(retStr, expStr); + } { + // Explicitly selecting the const ref overload. + // Note: If only 'const T&' existed, RTL would have resolved it implicitly. + // But since both 'T&' and 'const T&' overloads are available, + // RTL treats the situation as ambiguous and requires explicit selection + // to avoid guessing the user's intent regarding mutability. + auto [err, robj] = reverseString.bind()(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(STRA_REVERSE) + SUFFIX_std_string_view_clvref; + EXPECT_EQ(retStr, expStr); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Method.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Method.cpp new file mode 100644 index 00000000..c2fb873e --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_Method.cpp @@ -0,0 +1,624 @@ + +#include +#include +#include +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" +#include "../CxxTestProps/inc/StringMute.h" + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(ReturnErased_Method, invalid_erased_return_rtl_function) + { + { + rtl::method erased_ret_mt; + EXPECT_FALSE(erased_ret_mt); + + auto [err, robj] = erased_ret_mt(0)(); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } + + rtl::method erased_ret_mt; + EXPECT_FALSE(erased_ret_mt); + { + auto [err, robj] = erased_ret_mt('a')(0); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } { + auto [err, robj] = erased_ret_mt.bind('a')(0); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } { + auto [err, robj] = erased_ret_mt.bind('a')(0); + EXPECT_EQ(err, rtl::error::InvalidCaller); + EXPECT_TRUE(robj.isEmpty()); + } + } + + + TEST(ReturnErased_Method, implicit_resolutions_to_call_by_value_overloads) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseStrOpt); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + { + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_FALSE(reverseString); + { + auto [err, robj] = reverseString(StrMute())(const_cast(STRA)); + + EXPECT_EQ(err, rtl::error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } { + auto [err, robj] = reverseString.bind(StrMute())(const_cast(STRA)); + + EXPECT_EQ(err, rtl::error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(StrMute())(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_const_char_ptr; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind(StrMute())(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_const_char_ptr; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(StrMute())(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind(StrMute())(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + std::string str = STRA; + auto [err, robj] = reverseString(StrMute())(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_ptr; + EXPECT_EQ(retStr, expStr); + } { + std::string str = STRA; + auto [err, robj] = reverseString.bind(StrMute())(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_ptr; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + const std::string str = STRA; + auto [err, robj] = reverseString(StrMute())(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_cptr; + EXPECT_EQ(retStr, expStr); + } { + const std::string str = STRA; + auto [err, robj] = reverseString.bind(StrMute())(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_cptr; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature<>()); + { + rtl::method reverseString = reverseStrOpt->targetT() + .argsT<>() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(StrMute())(); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + REV_STR_VOID_RET + SUFFIX_void; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind(StrMute())(); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + REV_STR_VOID_RET + SUFFIX_void; + EXPECT_EQ(retStr, expStr); + } + } + } + + + TEST(ReturnErased_Method, implicit_resolution_to_ambiguous_lvalue_and_cref_overload) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrOverloadValCRef); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Both by-value (T) and const-ref (const T&) overloads exist. + EXPECT_TRUE(reverseStrOpt->hasSignature()); + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + std::string_view str = STRA; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + // RTL chooses the safe by-value overload implicitly. The const-ref + // path requires explicit binding only to disambiguate intent. + // Note: If only const T& existed (no by-value overload), RTL would + // call it implicitly, since binding to const-ref cannot mutate the caller. + auto [err, robj] = reverseString(target)(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view; + EXPECT_EQ(retStr, expStr); + } { + // explicit call by value resolution. + auto [err, robj] = reverseString.bind(target)(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(ReturnErased_Method, explicit_resolution_to_ambiguous_lvalue_and_cref_overload) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrOverloadValCRef); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Both by-value (T) and const-ref (const T&) overloads exist. + EXPECT_TRUE(reverseStrOpt->hasSignature()); + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + std::string_view str = STRA; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + // Explicitly selecting the const-ref overload using .bind(). + // If no by-value overload were present, implicit resolution to const-ref + // would have worked automatically, because const-ref cannot mutate. + auto [err, robj] = reverseString.bind(target)(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind(target)(str); + + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + ASSERT_TRUE(robj.isEmpty()); + } + } + + + TEST(ReturnErased_Method, implicit_resolution_to_ambiguous_lvalue_and_ref_overload) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrOverloadValRef); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Here both by-value (T) and non-const ref (T&) overloads exist. + EXPECT_TRUE(reverseStrOpt->hasSignature()); + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + std::string_view str = STRA; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + // Here also, RTL prioritizes the safe-by-value overload automatically + // since it guarantees no mutation. The non-const ref overload remains + // accessible only through explicit binding to preserve mutability intent. + auto [err, robj] = reverseString(target)(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view; + EXPECT_EQ(retStr, expStr); + } { + // explicit call by value resolution. + auto [err, robj] = reverseString.bind(target)(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(ReturnErased_Method, explicit_resolution_to_ambiguous_lvalue_and_ref_overload) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrOverloadValRef); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Here both by-value (T) and non-const ref (T&) overloads exist. + EXPECT_TRUE(reverseStrOpt->hasSignature()); + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + std::string_view str = STRA; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + // Explicitly selecting the non-const ref overload. + // Even though the by-value overload is preferred implicitly for safety, + // the user can override that choice by binding explicitly as T&, + // signaling the intent to allow mutation through reflection. + auto [err, robj] = reverseString.bind(target)(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind(target)(str); + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + ASSERT_TRUE(robj.isEmpty()); + } + } + + + TEST(ReturnErased_Method, calling_non_overloaded_non_const_ref_argument) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrNonConstRefArg); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Here no overloads exists, only non-const ref (T&) argument. + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + std::string_view str = STRA; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + // Calls that may mutate user data (T&) require explicit intent. + // Hence, the dispatcher returns 'ExplicitRefBindingRequired' error. + // Since no call by value overload exists. + { + auto [err, robj] = reverseString(target)(str); + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + } { + // expected non-const ref binding. + auto [err, robj] = reverseString.bind(target)(str); + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + } { + // By calling .bind(), the user explicitly signals willingness to let + // the function modify the argument. This re-enables the T& call path and + // executes successfully, producing the expected result. + auto [err, robj] = reverseString.bind(target)(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(ReturnErased_Method, calling_non_overloaded_const_ref_argument) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrConstRefArg); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Here no overloads exists, only non-const ref (T&) argument. + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + std::string_view str = STRA; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + // This call resolves to the const-ref overload (no other overloads exist), + // so the argument is implicitly bound as a const reference. + auto [err, robj] = reverseString(target)(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref; + EXPECT_EQ(retStr, expStr); + } { + // explicit binding must also behave the same way. + auto [err, robj] = reverseString.bind(target)(str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref; + EXPECT_EQ(retStr, expStr); + } { + // explicit binding to non-const ref returns error. + auto [err, robj] = reverseString.bind(target)(str); + + // expected 'const T&' + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + ASSERT_TRUE(robj.isEmpty()); + } + } + + + TEST(ReturnErased_Method, calling_non_overloaded_rvalue_ref_argument) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrRValueRefArg); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Here no overloads exists, only non-const ref (T&) argument. + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(target)(std::string_view(STRA)); + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + } { + auto [err, robj] = reverseString.bind(target)(std::string_view(STRA)); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_rvref; + EXPECT_EQ(retStr, expStr); + } + } + + + TEST(ReturnErased_Method, implicit_resolution_to_ambiguous_ref_and_cref_overload) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrOverloadValRefAndCRef); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Here distinct overloads exists, with non-const ref (T&) and const-ref (const T&). + EXPECT_TRUE(reverseStrOpt->hasSignature()); + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + std::string_view str = STRA; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + // Both T& and const T& overloads are viable for an lvalue argument. + // RTL avoids implicit ambiguity by requiring explicit ref binding + // when mutation is possible (non-const ref path). + auto [err, robj] = reverseString(target)(str); + EXPECT_EQ(err, rtl::error::ExplicitRefBindingRequired); + } { + auto [err, robj] = reverseString.bind(target)(str); + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + } { + auto [err, robj] = reverseString.bind(target)(str); + EXPECT_EQ(err, rtl::error::RefBindingMismatch); + } + } + + + TEST(ReturnErased_Method, explicit_resolution_to_ambiguous_ref_and_cref_overload) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_revStrOverloadValRefAndCRef); + ASSERT_TRUE(reverseStrOpt); + + EXPECT_FALSE(reverseStrOpt->hasSignature()); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + + // Here distinct overloads exists, with non-const ref (T&) and const-ref (const T&). + EXPECT_TRUE(reverseStrOpt->hasSignature()); + EXPECT_TRUE(reverseStrOpt->hasSignature()); + + StrMute target; + std::string_view str = STRA; + rtl::method reverseString = reverseStrOpt->targetT() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + // Explicitly selecting the non-const ref overload. + // Caller signals intent to allow mutation by binding as T&. + auto [err, robj] = reverseString.bind(target)(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_lvref; + EXPECT_EQ(retStr, expStr); + } { + // Explicitly selecting the const ref overload. + // Note: If only 'const T&' existed, RTL would have resolved it implicitly. + // But since both 'T&' and 'const T&' overloads are available, + // RTL treats the situation as ambiguous and requires explicit selection + // to avoid guessing the user's intent regarding mutability. + auto [err, robj] = reverseString.bind(target)(str); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrMute::struct_) + STRA_REVERSE + SUFFIX_std_string_view_clvref; + EXPECT_EQ(retStr, expStr); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_StaticMethod.cpp b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_StaticMethod.cpp new file mode 100644 index 00000000..c75d8796 --- /dev/null +++ b/RTLTestRunApp/src/FunctionalityTests/TypeErasedInvocationTests/ReturnErased_StaticMethod.cpp @@ -0,0 +1,254 @@ + +#include +#include +#include + +#include "TestMirrorProvider.h" +#include "GlobalTestUtils.h" +#include "../CxxTestProps/inc/StringMute.h" +#include "../CxxTestProps/inc/StringConst.h" +#include "../CxxTestProps/inc/StringStatic.h" + +using namespace test_utils; +using namespace test_mirror; + +namespace rtl_tests +{ + TEST(ReturnErased_StaticMethod, using_wrong_class_n_callable_apis_for_static_method) + { + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); // has only static-methods. + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::method reverse_string = reverseString.value() + .targetT() + .argsT() + .returnT<>(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::SignatureMismatch); + + auto [err, robj] = reverse_string(StrStatic())(std::string()); + EXPECT_EQ(err, rtl::error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } { + rtl::function reverse_string = static_cast(reverseString.value()) + .argsT() + .returnT<>(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::InvalidStaticMethodCaller); + + auto [err, robj] = reverse_string(std::string()); + EXPECT_EQ(err, rtl::error::InvalidStaticMethodCaller); + EXPECT_TRUE(robj.isEmpty()); + } + } { + std::optional optStringUtil = cxx::mirror().getRecord(StrConst::struct_); // doesn't have any static-methods. + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT<>(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::InvalidNonStaticMethodCaller); + + auto [err, robj] = reverse_string(std::string()); + EXPECT_EQ(err, rtl::error::InvalidNonStaticMethodCaller); + EXPECT_TRUE(robj.isEmpty()); + } { + std::optional optStringUtil = cxx::mirror().getRecord(StrMute::struct_); // doesn't have any static-methods. + ASSERT_TRUE(optStringUtil); + + std::optional reverseString = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseString); + { + rtl::static_method reverse_string = reverseString.value() + .argsT() + .returnT<>(); + EXPECT_FALSE(reverse_string); + EXPECT_EQ(reverse_string.get_init_error(), rtl::error::InvalidNonStaticMethodCaller); + + auto [err, robj] = reverse_string(std::string()); + EXPECT_EQ(err, rtl::error::InvalidNonStaticMethodCaller); + EXPECT_TRUE(robj.isEmpty()); + } + } + } + + + TEST(ReturnErased_StaticMethod, implicit_resolutions_to_call_by_value_overloads) + { + std::optional optStringUtil = cxx::mirror().getRecord(StrStatic::struct_); + ASSERT_TRUE(optStringUtil); + + std::optional reverseStrOpt = optStringUtil->getMethod(str_reverseString); + ASSERT_TRUE(reverseStrOpt); + EXPECT_FALSE(reverseStrOpt->hasSignature()); + { + rtl::method reverseString = reverseStrOpt.value() + .targetT() + .argsT() + .returnT<>(); + EXPECT_FALSE(reverseString); + { + auto [err, robj] = reverseString(StrStatic())(const_cast(STRA)); + + EXPECT_EQ(err, rtl::error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } { + auto [err, robj] = reverseString.bind(StrStatic())(const_cast(STRA)); + + EXPECT_EQ(err, rtl::error::SignatureMismatch); + EXPECT_TRUE(robj.isEmpty()); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::method reverseString = reverseStrOpt.value() + .targetT() + .argsT() + .returnT<>(); + EXPECT_FALSE(reverseString); + { + auto [err, robj] = reverseString(StrStatic())(STRA); + EXPECT_EQ(err, rtl::error::SignatureMismatch); + } + } { + rtl::static_method reverseString = reverseStrOpt.value() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(STRA); + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_const_char_ptr + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::static_method reverseString = reverseStrOpt.value() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind()(STRA); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::static_method reverseString = reverseStrOpt.value() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + std::string str = STRA; + auto [err, robj] = reverseString(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_ptr + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } { + std::string str = STRA; + auto [err, robj] = reverseString.bind()(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_ptr + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature()); + { + rtl::static_method reverseString = reverseStrOpt.value() + .argsT() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + const std::string str = STRA; + auto [err, robj] = reverseString(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_cptr + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } { + const std::string str = STRA; + auto [err, robj] = reverseString.bind()(&str); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + STRA_REVERSE + SUFFIX_std_string_cptr + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } + } + EXPECT_TRUE(reverseStrOpt->hasSignature<>()); + { + rtl::static_method reverseString = reverseStrOpt.value() + .argsT<>() + .returnT<>(); + EXPECT_TRUE(reverseString); + { + auto [err, robj] = reverseString(); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + REV_STR_VOID_RET + SUFFIX_void + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } { + auto [err, robj] = reverseString.bind()(); + + EXPECT_EQ(err, rtl::error::None); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + const std::string& retStr = robj.view()->get(); + std::string expStr = std::string(StrStatic::struct_) + REV_STR_VOID_RET + SUFFIX_void + SUFFIX_static; + EXPECT_EQ(retStr, expStr); + } + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/MyReflectionTests/MyCxxMirrorProvider.cpp b/RTLTestRunApp/src/MyReflectionTests/MyCxxMirrorProvider.cpp new file mode 100644 index 00000000..b9b917f9 --- /dev/null +++ b/RTLTestRunApp/src/MyReflectionTests/MyCxxMirrorProvider.cpp @@ -0,0 +1,191 @@ + +#include + +#include "MyReflectingType.h" + +namespace my_type +{ + const rtl::CxxMirror& MyReflection() + { + static auto cxx_mirror = rtl::CxxMirror( { + + /* Register a free(C - style) function within a namespace. + If registered with a namespace, it must also be specified when querying: + cxx_mirror().getFunction("ext", "sendString") + Note: when registering free functions, the '&' operator is not required + when passing the function pointer to build(). + */ rtl::type().ns("ext").function("sendString").build(ext::sendString), + + + /* Another free (C-style) function inside a namespace. + This example demonstrates overloaded function registration. + Available overloads are: + void sendAsString(Person) + void sendAsString(Person&&) + void sendAsString(const char*) + + Since multiple overloads exist, the compiler cannot automatically deduce + the correct function pointer. Therefore, the parameter type must be explicitly + specified with `.function<>()`. + + This guides `.build()` to correctly resolve the intended overload. + Omitting the template type will result in a compile-time error. + */ rtl::type().ns("ext").function("sendAsString").build(ext::sendAsString), + + + /* Next overload registration: + void sendAsString(Person) + As with other overloads, the signature must be explicitly specified + so that `.build()` can select the correct function pointer. + */ rtl::type().ns("ext").function("sendAsString").build(ext::sendAsString), + + + /* And finally, the overload with an rvalue parameter: + void sendAsString(Person&&) + Again, the signature must be explicitly specified + to ensure `.build()` resolves to the correct function pointer. + */ rtl::type().ns("ext").function("sendAsString").build(ext::sendAsString), + + + /* Register a class/struct type without a namespace. + Since no namespace is provided, it will be queried directly by name, e.g.: + cxx_mirror().getRecord("Person"); + + (class/struct- generally termed as 'Record' as per LLVM's naming convention) + + This registration implicitly adds the default constructor, copy constructor, + and destructor. Explicitly registering these members is not allowed and + will result in a compile-time error. + + The order of registration does not matter- the type can be registered before + or after its members. However, the type itself must be registered; otherwise, + any attempted member registrations will be ignored and a warning will be + displayed on the console. + */ rtl::type().record("Person").build(), + + // rtl::type().member().constructor().build(), // Default constructor, will not compile. + // rtl::type().member().constructor().build(), // Copy constructor, will not compile. + // rtl::type().member().constructor().build(), // Move constructor, will not compile. + + + /* Legal registration of an overloaded constructor. + In this case, there are two possible overloads: `std::string&` and `const std::string&`. + + Note that we do not specify `&` in the template parameter. When calling this constructor + reflectively with a `std::string`, the argument is forwarded as a universal reference (&&). + By C++ rules, this binds naturally to `const std::string&`, without requiring any special + handling in RTL. + + If the class provides only a `std::string&` constructor (and no `const std::string&`), + then this registration will fail to compile. Similarly, if three overloads exist- + `std::string`, `std::string&`, and `const std::string&`- the compiler itself will report + an ambiguity error. + + You may explicitly register with `std::string&` or `const std::string&`, but RTL will + normalize types by stripping `const` and reference qualifiers during registration. + */ rtl::type().member().constructor().build(), + + + /* Registers a regular non-const member-function. + This function can only be called on a non-const `Person` object. + Attempting to call it on a true-const `Person` object will result in `error::ConstCallViolation`. + See test case: `non_const_method_semantics__on_true_const_target`. + `non_const_method_semantics__on_logical_const_target` + */ rtl::type().member().method("getName").build(&Person::getName), + + + /* Registering a static member-function. + Must be registered via `.methodStatic()`, otherwise it is a compile-time error. + `.methodStatic()` restricts `build()` to only accept static member-function pointers. + + Runtime semantics: + Static methods are independent of object state, so they can always be invoked + regardless of whether the reflected context is const or non-const. + */ rtl::type().member().methodStatic("getDefaults").build(&Person::getDefaults), + + + /* Registering a non-const member-function. + Must be registered via `.method()`, otherwise it is a compile-time error. + The non-const overload of `updateAddress` is automatically selected here, because + `.method()` restricts `build()` to only accept non-const member-function pointers. + + If multiple overloads are available, the correct one is resolved at runtime. + See test case: `const_based_overload_resolution_semantics__on_true_const_target` & + `const_based_overload_resolution_semantics__on_logical_const_target` + */ rtl::type().member().method("updateAddress").build(&Person::updateAddress), + + + /* Registering a const member-function. + Must be registered via `.methodConst()`, otherwise it is a compile-time error. + The const overload of `updateAddress` is automatically selected here, because + `.methodConst()` restricts `build()` to only accept const member-function pointers. + + If multiple overloads are available, the correct one is resolved at runtime. + See test case: `const_based_overload_resolution_semantics__on_true_const_target` & + `const_based_overload_resolution_semantics__on_logical_const_target` + */ rtl::type().member().methodConst("updateAddress").build(&Person::updateAddress), + + + + /* Registers the member function `setTitle`, which only accepts an rvalue reference (`std::string&&`). + To invoke this method reflectively, the argument type `std::string&&` must be explicitly specified. + See test case: `perfect_forwarding_seamantics__rvalue_ref`. + */ rtl::type().member().method("setTitle").build(&Person::setTitle), + + + /* Registers the overloaded member function `setOccupation` that accepts an rvalue-reference (`std::string&&`). + Since this method has multiple overloads, RTL cannot automatically deduce the correct one (unlike `setTitle`, + which had no overloads). Therefore, we must explicitly specify the rvalue-ref type in the `method` template parameter. + For overload resolution, see test case: `perfect_forwarding_semantics__overload_resolution`. + */ rtl::type().member().method("setOccupation").build(&Person::setOccupation), + + + /* Registers the other overloaded version of `setOccupation` that accepts a const-lvalue-reference (`const std::string&`). + Similar to the rvalue-ref case, this overload cannot be picked automatically, so we explicitly specify the + `const std::string&` type in the `method` template parameter. + For overload resolution, see test case: `perfect_forwarding_semantics__overload_resolution`. + */ rtl::type().member().method("setOccupation").build(&Person::setOccupation), + + + /* The method `setProfile` has two overloads. + To register one, you must explicitly specify the parameter type in the template argument. + For example: `method(...)`. Without this, compilation will fail. + Note: overload resolution happens at runtime (see test cases `overload_resolution_semantics__*`). + */ rtl::type().member().method("setProfile").build(&Person::setProfile), + + + /************************************************************************************* + TODO: by value and by-ref overload should not be allowed (enforce compiler behaviour) + RTL should catch and ignore this kind of registration. + **************************************************************************************/ + /* Example to illustrate overload behavior: + + Person person("Tim"); + person.setProfile(std::string("Tim's prof")); + - This compiles fine, as it binds to `setProfile(std::string)` + (the version taking the argument by value). + + std::string profStr = "Tim's profile"; + person.setProfile(profStr); + - This does not compile, because `profStr` is an lvalue. + It could bind to either `setProfile(std::string)` or + `setProfile(std::string&)`, creating ambiguity. + + However, RTL can successfully register both overloads by explicitly specifying + the reference type in `method()`s template parameter, e.g. `method(...)`. + Overload resolution still occurs at runtime. See test case `overload_resolution__setProfile`, + which shows that even when explicitly registering the `std::string&` overload, a reflective call + with an rvalue will still resolve to the `std::string` (by value) version, because that is the + only syntactically valid match. + */ rtl::type().member().method("setProfile").build(&Person::setProfile), + + + /* The method `getProfile` has only 'const' version, No non-const overload. + Must be registered via `.methodConst()`, otherwise it is a compile-time error. + Note: overload resolution happens at runtime (see test case `overload_resolution__setProfile`). + */ rtl::type().member().methodConst("getProfile").build(&Person::getProfile), + }); + + return cxx_mirror; + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/MyReflectionTests/MyReflectingType.h b/RTLTestRunApp/src/MyReflectionTests/MyReflectingType.h new file mode 100644 index 00000000..b6c8554b --- /dev/null +++ b/RTLTestRunApp/src/MyReflectionTests/MyReflectingType.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +namespace my_type +{ + struct Person + { + const std::string name; + + Person(std::string& pName) : name(pName) {} + + Person(const std::string& pName) : name(pName) {} + + std::string getName() { return ("called_non_const__" + name); } + + std::string setTitle(std::string&&) { return "called_by_ref_rvalue"; } + + std::string updateAddress() { return "called_non_const_overload"; } + + std::string updateAddress() const { return "called_const_overload"; } + + std::string setProfile(std::string pProfStr) { return "called_by_val"; } + + std::string setProfile(std::string& pProfStr) { return "called_by_ref"; } + + std::string getProfile() const { return "only_const_method_version_exists"; } + + std::string setOccupation(std::string&& pProfStr) { return "called_by_rvalue_ref"; } + + std::string setOccupation(const std::string& pProfStr) { return "called_by_ref_lvalue"; } + + static std::string getDefaults() { return "Person_defaults_returned"; } + }; + + + namespace ext { + + static std::string sendString(std::string pString) { return ("sent_string_" + pString); } + + static std::string sendAsString(Person pPerson) { return "sent_string_lvalue_" + pPerson.name; } + + static std::string sendAsString(Person&& pPerson) { return "sent_string_rvalue_" + pPerson.name; } + + static std::string sendAsString(const char* pCString) { return "sent_string_literal_" + std::string(pCString); } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/MyReflectionTests/MyReflectionTests.cpp b/RTLTestRunApp/src/MyReflectionTests/MyReflectionTests.cpp new file mode 100644 index 00000000..108d6c76 --- /dev/null +++ b/RTLTestRunApp/src/MyReflectionTests/MyReflectionTests.cpp @@ -0,0 +1,603 @@ + +#include +#include + +#include "MyReflectingType.h" + +using namespace my_type; + +namespace my_type { extern const rtl::CxxMirror& MyReflection(); } + +namespace +{ + TEST(MyReflectionTests, invoking_semantics__C_style_function_with_no_overload) + { + { + // Attempt to retrieve the C-style function without specifying a namespace. + std::optional optSendString = MyReflection().getFunction("sendString"); + // Not found, since it was registered under the 'ext' namespace. + EXPECT_FALSE(optSendString); + } { + // Retrieve the function with its correct namespace. + std::optional optSendString = MyReflection().getFunction("ext", "sendString"); + // Found successfully. + ASSERT_TRUE(optSendString); + + auto sendStringFn = optSendString->argsT().returnT<>(); + ASSERT_TRUE(sendStringFn); + EXPECT_EQ(sendStringFn.get_init_error(), rtl::error::None); + + auto theStr = std::string("Initiating reflection tests."); + auto expectReturnStr = ("sent_string_" + theStr); + + // Nothing to bind here, since this is a non-member (C-style) function. + // However, if the function takes reference parameters that require perfect forwarding, + // the binding can be specified explicitly using `bind()`, `bind()`, or `bind()`. + // In essence, `bind()` enables correct forwarding semantics for function calls. + auto [err, ret] = sendStringFn(theStr); + + // Reflected call executes successfully. + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // We know the return type is std::string. + EXPECT_TRUE(ret.canViewAs()); + + // Extract the std::string view from `ret`. + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + // Confirms that the expected function was invoked. + EXPECT_EQ(retStr, expectReturnStr); + } + } + + + TEST(MyReflectionTests, overload_resolution_semantics__arg_const_char_ptr) + { + // Retrieve the function with its correct namespace. + std::optional optSendAsString = MyReflection().getFunction("ext", "sendAsString"); + // Found successfully. + ASSERT_TRUE(optSendAsString); + + auto theStr = std::string("const_char_ptr."); + auto expectReturnStr = ("sent_string_literal_" + theStr); + + auto sendAsStringFn = optSendAsString->argsT().returnT<>(); + ASSERT_TRUE(sendAsStringFn); + EXPECT_EQ(sendAsStringFn.get_init_error(), rtl::error::None); + + // Nothing to bind here, since this is a non-member (C-style) function and it does not + // require arguments to be perfectly forwarded. + // The argument passed is `const char*`, and the corresponding overload has been registered. + // The reflective call succeeds. If a mismatched argument is passed, + // `error::SignatureMismatch` will be returned. + auto [err, ret] = sendAsStringFn(theStr.c_str()); + + // Reflected call executes successfully. + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // We know the return type is std::string. + EXPECT_TRUE(ret.canViewAs()); + + // Extract the std::string view from `ret`. + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + // Confirms that the expected function was invoked. + EXPECT_EQ(retStr, expectReturnStr); + } + + + TEST(MyReflectionTests, overload_resolution_semantics__arg_lvalue) + { + // Retrieve the function from its namespace. + std::optional optSendAsString = MyReflection().getFunction("ext", "sendAsString"); + ASSERT_TRUE(optSendAsString); // Function found successfully. + + auto nameStr = std::string("person_Eric"); + auto person = Person(nameStr); + auto expectReturnStr = ("sent_string_lvalue_" + nameStr); + + auto sendAsStringFn = optSendAsString->argsT().returnT<>(); + ASSERT_TRUE(sendAsStringFn); + EXPECT_EQ(sendAsStringFn.get_init_error(), rtl::error::None); + + // Nothing to bind here: the call is with a regular lvalue. + // This resolves to the overload `sendAsString(Person)`. + // The overload was registered, so the reflective call will succeed. + // If the argument type mismatches, `error::SignatureMismatch` will be returned. + auto [err, ret] = sendAsStringFn(person); + + // Validate reflective call succeeded. + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // Verify return type and extract result. + EXPECT_TRUE(ret.canViewAs()); + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + // Confirms the correct overload was invoked. + EXPECT_EQ(retStr, expectReturnStr); + } + + + TEST(MyReflectionTests, overload_resolution_with_perfect_forwarding_semantics__arg_rvalue) + { + // Retrieve the function from its namespace. + std::optional optSendAsString = MyReflection().getFunction("ext", "sendAsString"); + ASSERT_TRUE(optSendAsString); // Function found successfully. + + auto nameStr = std::string("person_Logan"); + + auto sendAsStringFn = optSendAsString->argsT().returnT<>(); + ASSERT_TRUE(sendAsStringFn); + EXPECT_EQ(sendAsStringFn.get_init_error(), rtl::error::None); + { + // Although the argument is an rvalue (Person&&), + // overload resolution prefers the by-value overload (Person) + // over the rvalue-reference overload when both are viable. + // As a result, the call resolves to the by-value function. + auto [err, ret] = sendAsStringFn(Person(nameStr)); + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // Verify return type and extract result. + EXPECT_TRUE(ret.canViewAs()); + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + auto expectReturnStr = ("sent_string_lvalue_" + nameStr); + // Confirms the correct overload was invoked. + EXPECT_EQ(retStr, expectReturnStr); + } { + // Now invoke the rvalue-ref overload: `sendAsString(Person&&)`. + // To ensure this overload is selected, we must explicitly bind + // with `Person&&`. This is achieved through perfect forwarding, + // since overload resolution cannot deduce rvalue-ref automatically. + // + // The overload was registered, so the reflective call will succeed. + // If the argument type mismatches, `error::SignatureMismatch` will be returned. + auto [err, ret] = sendAsStringFn.bind()(Person(nameStr)); + + // Validate reflective call succeeded. + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // Verify return type and extract result. + EXPECT_TRUE(ret.canViewAs()); + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + auto expectReturnStr = ("sent_string_rvalue_" + nameStr); + // Confirms the correct overload was invoked. + EXPECT_EQ(retStr, expectReturnStr); + } + } + + + TEST(MyReflectionTests, invoking_static_member_function_semantics) + { + // Retrieve the reflected class metadata. + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + // Retrieve the static method from the class. + std::optional optGetDefaults = classPerson->getMethod("getDefaults"); + ASSERT_TRUE(optGetDefaults); + { + auto getDefaultsFn = optGetDefaults->argsT<>().returnT<>(); + ASSERT_TRUE(getDefaultsFn); + EXPECT_EQ(getDefaultsFn.get_init_error(), rtl::error::None); + + // Call the static member function directly. + // Semantics are the same as a free function: + // nothing to bind unless perfect-forwarding arguments are involved. + // Since it's static, no instance of the class is required. + auto [err, ret] = getDefaultsFn(); + + // Validate reflective call succeeded. + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // Verify return type and extract result. + EXPECT_TRUE(ret.canViewAs()); + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + auto expectReturnStr = std::string("Person_defaults_returned"); + // Confirms the expected static function was invoked. + EXPECT_EQ(retStr, expectReturnStr); + } + } + + + TEST(MyReflectionTests, overload_resolution_semantics__constructor) + { + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + const char* name = "Charlie"; + // Invokes the overloaded constructor that takes 'const std::string&'. + // It will not match the overload with 'std::string&', because arguments + // are forwarded as universal references (&&), which bind only to + // 'const std::string&'. This resolution is handled by the compiler, + // not by RTL. + auto [err, robj] = classPerson->ctorT()(rtl::alloc::Stack, name); + + EXPECT_TRUE(err == rtl::error::None); + ASSERT_TRUE(!robj.isEmpty()); + ASSERT_TRUE(robj.canViewAs()); + + auto view = robj.view(); + EXPECT_TRUE(view); + + const Person& person = view->get(); + EXPECT_EQ(name, person.name); + } + + + TEST(MyReflectionTests, overload_resolution_semantics__method) + { + // Tests runtime overload resolution between `std::string` (by value) + // and `std::string&` overloads of Person::setProfile. + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + // Create a Person instance the regular way. + Person orgTim("Tim"); + + // Reflect into RObject. Internally this creates a copy of 'orgTim' on the stack. + rtl::RObject robjTim = rtl::reflect(orgTim); + + std::optional oSetProfile = classPerson->getMethod("setProfile"); + ASSERT_TRUE(oSetProfile); + + rtl::method setProfile = oSetProfile->targetT() + .argsT() + .returnT(); + EXPECT_TRUE(setProfile); + // NOTE for documentation: + // Calling with a constant-size array (like `"profStr"`) will not compile, + // because array-to-pointer decay is not supported here. + // Instead, use a `const char*` or `std::string`. + // auto [err, ret] = setProfile(robjTim)("profStr"); + + { + auto [err, ret] = setProfile(robjTim)("Tim's prof"); + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // We know the return type is std::string. + EXPECT_TRUE(ret.canViewAs()); + + // Extract the std::string view from `ret`. + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + // Confirms that the overload taking `std::string` by value was invoked. + EXPECT_EQ(retStr, "called_by_val"); + } { + std::string profStr = "Tim's profile."; + + // TODO: by value and by-ref overload should not be allowed. + auto [err, ret] = setProfile.bind(robjTim)("Tim's profile."); + + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // Again, return type is std::string. + EXPECT_TRUE(ret.canViewAs()); + + // Extract the std::string view from `ret`. + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + // Even though compiler doesn't allows this but RTL can call both the methods successfully, + // TODO: by value and by-ref overload should not be allowed. + EXPECT_EQ(retStr, "called_by_ref"); + } + } + + + TEST(MyReflectionTests, perfect_forwarding_seamantics__rvalue_ref) + { + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + // Create a Person instance the regular way. + Person orgTim("Tim"); + + // Reflect into RObject. Internally this creates a copy of 'orgTim' on the stack. + rtl::RObject robjTim = rtl::reflect(orgTim); + + std::optional oSetTitle = classPerson->getMethod("setTitle"); + ASSERT_TRUE(oSetTitle); + + rtl::method setTitle = oSetTitle->targetT() + .argsT() + .returnT(); + EXPECT_TRUE(setTitle); + { + // Attempt to call 'setTitle' with an rvalue string. + // This fails because reflection will first attempt to resolve the call + // against a by-value parameter (`std::string`) instead of the actual + // registered signature (`std::string&&`). + auto [err, ret] = setTitle(robjTim)(std::string("Mr.")); + EXPECT_TRUE(err == rtl::error::ExplicitRefBindingRequired); + EXPECT_TRUE(ret.isEmpty()); + } { + // To invoke the method successfully, we must perfectly forward `std::string` as an rvalue-ref. + // This requires explicitly specifying `std::string&&` in the template parameter pack of `bind`. + // Note: passing a string literal works fine here, since it is implicitly convertible to `std::string`; + // wrapping with `std::string("Mr.")` is unnecessary. + auto [err, ret] = setTitle.bind(robjTim)("Mr."); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + + // We know the return type is std::string. + EXPECT_TRUE(ret.canViewAs()); + + // Extract the std::string view from `ret`. + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + // Confirms that the `setTitle(std::string&&)` overload was correctly invoked. + EXPECT_EQ(retStr, "called_by_ref_rvalue"); + } + } + + + TEST(MyReflectionTests, perfect_forwarding_semantics__overload_resolution) + { + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + // Create a Person instance the regular way. + Person orgTim("Tim"); + + // Reflect into RObject. Internally this creates a copy of 'orgTim' on the stack. + rtl::RObject robjTim = rtl::reflect(orgTim); + + std::optional oSetOccupation = classPerson->getMethod("setOccupation"); + ASSERT_TRUE(oSetOccupation); + + rtl::method setOccupation = oSetOccupation->targetT() + .argsT() + .returnT(); + EXPECT_TRUE(setOccupation); + { + // Attempt to call 'setOccupation' with an rvalue string. + // Expectation: should match the rvalue-ref overload (`std::string&&`). + // Actual: fails because reflection first attempts to match a by-value + // parameter (`std::string`) instead of the registered signature. + auto [err, ret] = setOccupation(robjTim)(std::string("Teacher")); + EXPECT_TRUE(err == rtl::error::ExplicitRefBindingRequired); + EXPECT_TRUE(ret.isEmpty()); + } { + // Attempt to call 'setOccupation' with a const-lvalue string. + // Expectation: should match the const-lvalue-ref overload (`const std::string&`). + // Actual: fails for the same reason reflection attempts by-value resolution first. + const std::string occupationStr = "Teacher"; + auto [err, ret] = setOccupation(robjTim)(occupationStr); + EXPECT_TRUE(err == rtl::error::ExplicitRefBindingRequired); + EXPECT_TRUE(ret.isEmpty()); + } { + // Correctly invoke the rvalue-ref overload by explicitly binding + // `std::string&&` in the template parameter pack and perfectly forwarding. + auto [err, ret] = setOccupation.bind(robjTim)("Teacher"); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + + // The return type is known to be std::string. + EXPECT_TRUE(ret.canViewAs()); + + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + // Confirms that the `setOccupation(std::string&&)` overload was correctly invoked. + EXPECT_EQ(retStr, "called_by_rvalue_ref"); + } { + // Correctly invoke the const-lvalue-ref overload by explicitly binding + // `const std::string&` in the template parameter pack and perfectly forwarding. + auto [err, ret] = setOccupation.bind(robjTim)("Teacher"); + EXPECT_TRUE(err == rtl::error::None); + ASSERT_FALSE(ret.isEmpty()); + + // The return type is known to be std::string. + EXPECT_TRUE(ret.canViewAs()); + + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + // Confirms that the `setOccupation(const std::string&)` overload was correctly invoked. + EXPECT_EQ(retStr, "called_by_ref_lvalue"); + } + } + + + TEST(MyReflectionTests, const_method_semantics__on_true_const_target) + { + // Case 1: Reflecting a true-const Person. + const Person constSam = Person("Const-Sam"); + // Reflect 'const Person' into RObject. + // RTL never performs an implicit const_cast on const objects. + // Since 'constSam' is genuinely const, RTL preserves that constness. + // This applies equally to any object returned by reflective calls. + rtl::RObject robj = rtl::reflect(constSam); + + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + std::optional oGetProfile = classPerson->getMethod("getProfile"); + ASSERT_TRUE(oGetProfile); + + rtl::method getProfile = oGetProfile->targetT().argsT().returnT(); + EXPECT_TRUE(getProfile); + { + // For 'getProfile' only a const overload is registered. + // Since 'robj' reflects a const object, only const methods can be called on it. + // making 'robj' as const (using std::cref) ensures to call the const-method on it. + auto [err, ret] = getProfile(std::cref(robj))(); + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + // Validate return type and value. + EXPECT_TRUE(ret.canViewAs()); + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + std::string expectReturnStr = "only_const_method_version_exists"; + EXPECT_EQ(retStr, expectReturnStr); + } { + // Attempt to bind a truly-const object to a non-const method. + // Since the object is genuinely const, the call fails because no + // non-const overload is registered for the same. + auto [err, ret] = getProfile(robj)(); + // Expected: NonConstOverloadMissing. + EXPECT_TRUE(err == rtl::error::NonConstOverloadMissing); + EXPECT_TRUE(ret.isEmpty()); + } + } + + + TEST(MyReflectionTests, non_const_method_semantics__on_true_const_target) + { + // Case 1: Reflecting a true-const Person. + const Person constSam = Person("Const-Sam"); + // Reflect 'const Person' into RObject. + // RTL never performs an implicit const_cast on const objects. + // Since 'constSam' is genuinely const, RTL preserves that constness. + // This applies equally to any object returned by reflective calls. + rtl::RObject robj = rtl::reflect(constSam); + + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + // only a non-const overload exists(and registered) for 'getName'. + std::optional oGetName = classPerson->getMethod("getName"); + ASSERT_TRUE(oGetName); + + rtl::method getName = oGetName->targetT().argsT().returnT(); + EXPECT_TRUE(getName); + { + // using std::cref() here, we are enforcing to call the const-method + // overload of 'getName' (which doesn't exists). + auto [err, ret] = getName(std::cref(robj))(); + // 'robj' reflects a true-const Person, but 'getName' is non-const. + // RTL searches for a const overload, which is not present. + // Expected: ConstOverloadMissing. + EXPECT_TRUE(err == rtl::error::ConstOverloadMissing); + EXPECT_TRUE(ret.isEmpty()); + } { + // Explicitly attempt to bind the true-const object to a non-const method. + // Since the object is truly const, const_cast is unsafe. + auto [err, ret] = getName(robj)(); + // Expected: InvalidCallOnConstTarget. + EXPECT_TRUE(err == rtl::error::InvalidCallOnConstTarget); + EXPECT_TRUE(ret.isEmpty()); + } + } + + + TEST(MyReflectionTests, const_based_overload_resolution_semantics__on_const_target) + { + // Case 1: Reflecting a true-const Person. + const Person constSam = Person("Const-Sam"); + // Reflect 'const Person' into RObject. + // RTL never performs an implicit const_cast on const objects. + // Since 'constSam' is genuinely const, RTL preserves that constness. + // This applies equally to any object returned by reflective calls. + rtl::RObject robj = rtl::reflect(constSam); + + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + std::optional oUpdateAddress = classPerson->getMethod("updateAddress"); + ASSERT_TRUE(oUpdateAddress); + + rtl::method updateAddress = oUpdateAddress->targetT().argsT().returnT(); + EXPECT_TRUE(updateAddress); + { + std::string expectReturnStr = "called_const_overload"; + // Both const and non-const overloads are registered. + // Since 'robj' reflecting a true-const, RTL invokes the const overload without fail. + auto [err, ret] = updateAddress(std::cref(robj))(); + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + EXPECT_TRUE(ret.canViewAs()); + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + EXPECT_EQ(retStr, expectReturnStr); + } { + // Explicitly attempt to call the non-const overload. + // Unsafe here, since the object is truly const. + auto [err, ret] = updateAddress(robj)(); + // Expected: IllegalConstCast. + EXPECT_TRUE(err == rtl::error::InvalidCallOnConstTarget); + EXPECT_TRUE(ret.isEmpty()); + } + } + + + TEST(MyReflectionTests, const_based_overload_resolution_semantics__on_non_const_target) + { + // Case 2: Reflecting a mutable Person. + rtl::RObject robj = rtl::reflect(Person("Mutable-Sam")); + + std::optional classPerson = MyReflection().getRecord("Person"); + ASSERT_TRUE(classPerson); + + std::optional oUpdateAddress = classPerson->getMethod("updateAddress"); + ASSERT_TRUE(oUpdateAddress); + + rtl::method updateAddress = oUpdateAddress->targetT().argsT().returnT(); + EXPECT_TRUE(updateAddress); + { + std::string expectReturnStr = "called_const_overload"; + // Both const and non-const overloads are registered. + // Since 'robj' is mutable, but we can explicitly call the const overload + // by making sending the 'robj' as const (using std::cref()). + auto [err, ret] = updateAddress(std::cref(robj))(); + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + EXPECT_TRUE(ret.canViewAs()); + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + EXPECT_EQ(retStr, expectReturnStr); + } { + std::string expectReturnStr = "called_non_const_overload"; + // Explicit request for the non-const overload by sending the 'robj' as non-const. + auto [err, ret] = updateAddress(robj)(); + EXPECT_TRUE(err == rtl::error::None); + EXPECT_FALSE(ret.isEmpty()); + + EXPECT_TRUE(ret.canViewAs()); + std::optional> strView = ret.view(); + ASSERT_TRUE(strView); + + const std::string& retStr = strView->get(); + EXPECT_EQ(retStr, expectReturnStr); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/RObjectTests/RObjectImplicitConversions.cpp b/RTLTestRunApp/src/RObjectTests/RObjectImplicitConversions.cpp new file mode 100644 index 00000000..ac7bf0f2 --- /dev/null +++ b/RTLTestRunApp/src/RObjectTests/RObjectImplicitConversions.cpp @@ -0,0 +1,56 @@ + +#include + +#include + +namespace rtl_tests +{ + TEST(RObject_conversions, implicit_safe_and_unsafe) + { + using rtl::traits::is_safe_conversion_v; + + // === Self conversions (trivial) === + static_assert(is_safe_conversion_v); + static_assert(is_safe_conversion_v); + static_assert(is_safe_conversion_v); + + //static_assert(is_safe_conversion_v); // pointer -> void* + + // === Safe conversions (should all be true) === + static_assert(is_safe_conversion_v); // widening bool -> int + static_assert(is_safe_conversion_v); // widening bool -> double + + static_assert(is_safe_conversion_v); // widening int -> long + static_assert(is_safe_conversion_v); // widening int -> long long + static_assert(is_safe_conversion_v); // exact int -> double + static_assert(is_safe_conversion_v); // true on typical platforms + static_assert(is_safe_conversion_v); // true + static_assert(is_safe_conversion_v); + static_assert(is_safe_conversion_v); + + static_assert(is_safe_conversion_v); // widening char -> int + static_assert(is_safe_conversion_v); // widening short -> int + static_assert(is_safe_conversion_v); // widening float -> double + static_assert(is_safe_conversion_v); + static_assert(is_safe_conversion_v); + + // === Unsafe conversions (should all be false) === + static_assert(!is_safe_conversion_v); // narrowing + static_assert(!is_safe_conversion_v); + static_assert(!is_safe_conversion_v); // narrowing float precision + static_assert(!is_safe_conversion_v); // narrowing + truncation + static_assert(!is_safe_conversion_v); // narrowing + truncation + static_assert(!is_safe_conversion_v); // narrowing + static_assert(!is_safe_conversion_v); // narrowing + static_assert(!is_safe_conversion_v); // sign change + static_assert(!is_safe_conversion_v); // sign change + static_assert(!is_safe_conversion_v); // pointer -> pointer different type + static_assert(!is_safe_conversion_v); // dropping const + static_assert(!is_safe_conversion_v); // adding const (still not safe in our conservative def) + static_assert(!is_safe_conversion_v); // // Technically "safe" but yields large number (-1) + static_assert(!is_safe_conversion_v); // false + static_assert(!is_safe_conversion_v); // false + + EXPECT_TRUE(true); + } +} diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_arrays.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_arrays.cpp new file mode 100644 index 00000000..27cbe53d --- /dev/null +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_arrays.cpp @@ -0,0 +1,73 @@ +/** + * @file RObjectReflectionTests.cpp + * @brief Unit tests for rtl::RObject reflection system, validating support for std::vector and trivial C-style arrays. + * + * This suite tests the behavior of `rtl::reflect` and `.view()`: + * - Ensures reflection works for lvalue, rvalue, and pointer forms. + * - Verifies zero-copy behavior for pointer-based inputs. + * - Confirms support for reflection of C-style arrays into std::array. + * + * Components tested: + * - `rtl::reflect` -> creates RObject from value or pointer + * - `RObject::view` -> provides typed, non-owning access to the internal value + * - `canViewAs` -> checks if a view of type T is supported + */ + +#include +#include + +using namespace rtl; + +namespace rtl_tests { + + // Test: Reflect lvalue std::vector + TEST(RObject_view_vector, init_with_stdVector_int_lvalue) + { + std::vector input = { 1, 2, 3, 4, 5 }; + RObject robj = rtl::reflect(input); // reflect by copy + + ASSERT_TRUE(robj.canViewAs>()); + + auto vec_view = robj.view>(); + ASSERT_TRUE(vec_view.has_value()); + + const std::vector& inputView = vec_view->get(); + ASSERT_EQ(inputView, input); + } + + + // Test: Reflect rvalue std::vector + TEST(RObject_view_vector, init_with_stdVector_int_rvalue) + { + RObject robj = rtl::reflect(std::vector({ 1, 2, 3, 4, 5 })); + + ASSERT_TRUE(robj.canViewAs>()); + + auto vec_view = robj.view>(); + ASSERT_TRUE(vec_view.has_value()); + + const std::vector& inputView = vec_view->get(); + ASSERT_EQ(inputView, std::vector({ 1, 2, 3, 4, 5 })); + } + + // Macro: Generate tests for trivial C-style arrays -> std::array + #define TEST_TRIVIAL_ARRAY_REFLECTION(TYPE, SIZE, ...) \ + TEST(RObject_array_reflection, reflect_##TYPE##_array_##SIZE) \ + { \ + TYPE data[SIZE] = { __VA_ARGS__ }; \ + RObject robj = rtl::reflect(data); \ + ASSERT_TRUE(robj.canViewAs>()); \ + auto view = robj.view>(); \ + ASSERT_TRUE(view.has_value()); \ + const std::vector& arr = view->get(); \ + for (size_t i = 0; i < arr.size(); ++i) \ + EXPECT_EQ(arr[i], data[i]); \ + } + + // Tests for all trivial types with various array sizes + TEST_TRIVIAL_ARRAY_REFLECTION(int, 3, 1, 2, 3) + TEST_TRIVIAL_ARRAY_REFLECTION(float, 4, 1.0f, 2.0f, 3.0f, 4.0f) + TEST_TRIVIAL_ARRAY_REFLECTION(double, 2, 3.14, 2.71) + TEST_TRIVIAL_ARRAY_REFLECTION(bool, 3, true, false, true) + +} // namespace rtl_tests diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_bool.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_bool.cpp new file mode 100644 index 00000000..8727a221 --- /dev/null +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_bool.cpp @@ -0,0 +1,167 @@ + +#include +#include + +using namespace rtl; + + +namespace rtl_tests +{ + TEST(RObject_bool_value, reflect_bool_view_as_bool) + { + // Reflect a bool value into RObject + RObject robj = rtl::reflect(true); + + // Check if RObject can be viewed as bool (true type or convertible) + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as bool + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the underlying value + const bool& cref = view->get(); + + // Confirm the value is equal to the original + ASSERT_EQ(cref, true); + } + + + TEST(RObject_bool_value, reflect_bool_view_as_int) + { + // Reflect a bool value (false) into RObject + RObject robj = rtl::reflect(false); + + // Check if RObject can be viewed as int (via conversion) + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as int + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted int value + const int& cref = view->get(); + + // Confirm the value matches expected result of bool(false) -> int(0) + ASSERT_EQ(cref, 0); + } + + + // Test reflecting a bool and viewing it as char + TEST(RObject_bool_value, reflect_bool_view_as_char) + { + // Reflect the value `true` into RObject + RObject robj = rtl::reflect(true); + + // Check if the RObject can reflect as `char` + ASSERT_TRUE(robj.canViewAs()); + + // Get the reflected value as `char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted char value + const char& cref = view->get(); + + // Verify the reflected `char` value is correct + ASSERT_EQ(cref, static_cast(true)); + } + + + // Test reflecting a bool and viewing it as signed char + TEST(RObject_bool_value, reflect_bool_view_as_signed_char) + { + // Reflect the value `false` into RObject + RObject robj = rtl::reflect(false); + + // Check if the value can be reflected as `signed char` + ASSERT_TRUE(robj.canViewAs()); + + // Get the reflected value as `signed char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted signed char value + const signed char& cref = view->get(); + + // Verify the converted value matches the original bool value + ASSERT_EQ(cref, static_cast(false)); + } + + + // Test reflecting a bool and viewing it as unsigned char + TEST(RObject_bool_value, reflect_bool_view_as_unsigned_char) + { + // Reflect the value `true` into RObject + RObject robj = rtl::reflect(true); + + // Check if RObject can reflect as `unsigned char` + ASSERT_TRUE(robj.canViewAs()); + + // Get the reflected value as `unsigned char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned char value + const unsigned char& cref = view->get(); + + // Confirm the converted value matches the original bool value + ASSERT_EQ(cref, static_cast(true)); + } + + + // Test reflecting a bool and viewing it as short + TEST(RObject_bool_value, reflect_bool_view_as_short) + { + // Reflect the value `false` into RObject + RObject robj = rtl::reflect(false); + + // Check if the value can be reflected as `short` + ASSERT_TRUE(robj.canViewAs()); + + // Get the reflected value as `short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted short value + const short& cref = view->get(); + + // Confirm the converted value matches original bool value + ASSERT_EQ(cref, static_cast(false)); + } + + + // Test reflecting a bool and viewing it as unsigned short + TEST(RObject_bool_value, reflect_bool_view_as_unsigned_short) + { + // Reflect the value `true` into RObject + RObject robj = rtl::reflect(true); + + // Check if the value can be reflected as `unsigned short` + ASSERT_TRUE(robj.canViewAs()); + + // Get the reflected value as `unsigned short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned short value + const unsigned short& cref = view->get(); + + // Confirm the converted value matches original bool value + ASSERT_EQ(cref, static_cast(true)); + } +} diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_char.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_char.cpp new file mode 100644 index 00000000..32dfa518 --- /dev/null +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_char.cpp @@ -0,0 +1,123 @@ + +#include +#include + +using namespace rtl; + + +namespace rtl_tests +{ + // Test reflecting a char and viewing it as signed char + TEST(RObject_char_value, reflect_char_view_as_signed_char) + { + // Reflect the value 'A' (ASCII 65) into RObject + RObject robj = rtl::reflect('A'); + + // Check if RObject can reflect as `signed char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `signed char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted signed char value + const signed char& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast('A')); + } + + + // Test reflecting a char and viewing it as unsigned char + TEST(RObject_char_value, reflect_char_view_as_unsigned_char) + { + // Reflect the value 'A' (ASCII 65) into RObject + RObject robj = rtl::reflect('A'); + + // Check if RObject can reflect as `unsigned char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `unsigned char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned char value + const unsigned char& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast('A')); + } + + + // Test reflecting a char and viewing it as short + TEST(RObject_char_value, reflect_char_view_as_short) + { + // Reflect the value 'A' (ASCII 65) into RObject + RObject robj = rtl::reflect('A'); + + // Check if RObject can reflect as `short` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted short value + const short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast('A')); + } + + + // Test reflecting a char and viewing it as unsigned short + TEST(RObject_char_value, reflect_char_view_as_unsigned_short) + { + // Reflect the value 'A' (ASCII 65) into RObject + RObject robj = rtl::reflect('A'); + + // Check if RObject can reflect as `unsigned short` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `unsigned short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned short value + const unsigned short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast('A')); + } + + + // Test reflecting a char and viewing it as int + TEST(RObject_char_value, reflect_char_view_as_int) + { + // Reflect the value 'A' (ASCII 65) into RObject + RObject robj = rtl::reflect('A'); + + // Check if RObject can reflect as `int` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `int` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted int value + const int& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast('A')); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_int.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_int.cpp new file mode 100644 index 00000000..a193484f --- /dev/null +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_int.cpp @@ -0,0 +1,804 @@ + +#include +#include + +using namespace rtl; + +namespace rtl_tests +{ + // Test reflecting an int and viewing it as bool + TEST(RObject_int_rvalue, reflect_int_view_as_bool) + { + // Reflect an int value (e.g., 5) into RObject + RObject robj = rtl::reflect(5); + + // Check if RObject can reflect as `bool` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `bool` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted bool value + const bool& cref = view->get(); + + // Verify the conversion result (non-zero -> true) + ASSERT_EQ(cref, true); + } + + + // Test reflecting an int and viewing it as char + TEST(RObject_int_rvalue, reflect_int_view_as_char) + { + // Reflect an int value (e.g., 65) into RObject + RObject robj = rtl::reflect(65); + + // Check if RObject can reflect as `char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted char value + const char& cref = view->get(); + + // Verify the conversion result (65 -> 'A') + ASSERT_EQ(cref, static_cast(65)); + } + + + // Test reflecting an int and viewing it as signed char + TEST(RObject_int_rvalue, reflect_int_view_as_signed_char) + { + // Reflect an int value (e.g., 97) into RObject + RObject robj = rtl::reflect(97); + + // Check if RObject can reflect as `signed char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `signed char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted signed char value + const signed char& cref = view->get(); + + // Verify the conversion result (97 -> 'a') + ASSERT_EQ(cref, static_cast(97)); + } + + + // Test reflecting an int and viewing it as unsigned char + TEST(RObject_int_rvalue, reflect_int_view_as_unsigned_char) + { + // Reflect an int value (e.g., 255) into RObject + RObject robj = rtl::reflect(255); + + // Check if RObject can reflect as `unsigned char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `unsigned char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned char value + const unsigned char& cref = view->get(); + + // Verify the conversion result (255 -> '\xff') + ASSERT_EQ(cref, static_cast(255)); + } + + + // Test reflecting an int and viewing it as short + TEST(RObject_int_rvalue, reflect_int_view_as_short) + { + // Reflect an int value (e.g., 32767) into RObject + RObject robj = rtl::reflect(32767); + + // Check if RObject can reflect as `short` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted short value + const short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast(32767)); + } + + + // Test reflecting an int and viewing it as unsigned short + TEST(RObject_int_rvalue, reflect_int_view_as_unsigned_short) + { + // Reflect an int value (e.g., 65535) into RObject + RObject robj = rtl::reflect(65535); + + // Check if RObject can reflect as `unsigned short` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `unsigned short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned short value + const unsigned short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast(65535)); + } +} + + +namespace rtl_tests +{ + // Test reflecting an int and viewing it as bool + TEST(RObject_int_lvalue, reflect_int_ptr_view_as_int_ptr) + { + int value = 5; // Example int value + + // Reflect an int value pointer into RObject + RObject robj = rtl::reflect(&value); + + // Check if RObject can reflect as `const int *` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `const int *` + auto view = robj.view(); + + // Ensure the view is valid + ASSERT_TRUE(view.has_value()); + + // Access the pointer returned by the view + const int& cref = view->get(); + + // Verify the addresses are same, no copy made. + ASSERT_EQ(&cref, &value); + } + + + // Test reflecting an int and viewing it as bool + TEST(RObject_int_lvalue, reflect_int_ptr_view_as_int_value) + { + int value = 5; // Example int value + + // Reflect an int value pointer into RObject + RObject robj = rtl::reflect(&value); + + // Check if RObject can reflect as `int` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `int` + auto view = robj.view(); + + // Ensure the view is valid + ASSERT_TRUE(view.has_value()); + + // Access the pointer returned by the view + int cref = view->get(); + + // Verify the addresses are same, no copy made. + ASSERT_EQ(cref, value); + } + + + // Test reflecting an int and viewing it as bool + TEST(RObject_int_lvalue, reflect_int_view_as_bool) + { + int value = 5; // Example int value + + // Reflect an int value (e.g., 5) into RObject + RObject robj = rtl::reflect(value); + + // Check if RObject can reflect as `bool` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `bool` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted bool value + const bool& cref = view->get(); + + // Verify the conversion result (non-zero -> true) + ASSERT_EQ(cref, true); + } + + + // Test reflecting an int and viewing it as char + TEST(RObject_int_lvalue, reflect_int_view_as_char) + { + int value = 65; // Example int value + + // Reflect an int value (e.g., 65) into RObject + RObject robj = rtl::reflect(value); + + // Check if RObject can reflect as `char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted char value + const char& cref = view->get(); + + // Verify the conversion result (65 -> 'A') + ASSERT_EQ(cref, static_cast(value)); + } + + + // Test reflecting an int and viewing it as signed char + TEST(RObject_int_lvalue, reflect_int_view_as_signed_char) + { + int value = 97; // Example int value + + // Reflect an int value (e.g., 97) into RObject + RObject robj = rtl::reflect(value); + + // Check if RObject can reflect as `signed char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `signed char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted signed char value + const signed char& cref = view->get(); + + // Verify the conversion result (97 -> 'a') + ASSERT_EQ(cref, static_cast(value)); + } + + + // Test reflecting an int and viewing it as unsigned char + TEST(RObject_int_lvalue, reflect_int_view_as_unsigned_char) + { + int value = 255; // Example int value + + // Reflect an int value (e.g., 255) into RObject + RObject robj = rtl::reflect(value); + + // Check if RObject can reflect as `unsigned char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `unsigned char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned char value + const unsigned char& cref = view->get(); + + // Verify the conversion result (255 -> '\xff') + ASSERT_EQ(cref, static_cast(value)); + } + + + // Test reflecting an int and viewing it as short + TEST(RObject_int_lvalue, reflect_int_view_as_short) + { + int value = 32767; // Example int value + + // Reflect an int value (e.g., 32767) into RObject + RObject robj = rtl::reflect(value); + + // Check if RObject can reflect as `short` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted short value + const short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast(value)); + } + + + // Test reflecting an int and viewing it as unsigned short + TEST(RObject_int_lvalue, reflect_int_view_as_unsigned_short) + { + int value = 65535; // Example int value + + // Reflect an int value (e.g., 65535) into RObject + RObject robj = rtl::reflect(value); + + // Check if RObject can reflect as `unsigned short` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `unsigned short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned short value + const unsigned short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast(value)); + } +} + + + + +namespace rtl_tests +{ + // Test reflecting an int* and viewing it as bool + TEST(RObject_int_pointer_lvalue, reflect_int_view_as_bool_true) + { + int *ptr = new int(5); + + // Reflect an int value (e.g., 5) into RObject + RObject robj = rtl::reflect(ptr); + + // Check if RObject can reflect as `bool` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `bool` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted bool value + const bool& cref = view->get(); + + // Verify the conversion result (non-zero -> true) + ASSERT_EQ(cref, true); + + delete ptr; // Clean up the dynamically allocated memory + } + + + // Test reflecting an int* and viewing it as bool + TEST(RObject_int_pointer_lvalue, reflect_int_view_as_bool_false) + { + int* ptr = new int(0); + + // Reflect an int value (e.g., 5) into RObject + RObject robj = rtl::reflect(ptr); + + // Check if RObject can reflect as `bool` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `bool` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted bool value + const bool& cref = view->get(); + + // Verify the conversion result (non-zero -> true) + ASSERT_EQ(cref, false); + } + + + // Test reflecting an int* and viewing it as char + TEST(RObject_int_pointer_lvalue, reflect_int_view_as_char) + { + int* ptr = new int(65); + + // Reflect an int value (e.g., 65) into RObject + RObject robj = rtl::reflect(ptr); + + // Check if RObject can reflect as `char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted char value + const char& cref = view->get(); + + // Verify the conversion result (65 -> 'A') + ASSERT_EQ(cref, static_cast(65)); + + delete ptr; // Clean up the dynamically allocated memory + } + + + // Test reflecting an int* and viewing it as signed char + TEST(RObject_int_pointer_lvalue, reflect_int_view_as_signed_char) + { + int* ptr = new int(97); + + // Reflect an int value (e.g., 97) into RObject + RObject robj = rtl::reflect(ptr); + + // Check if RObject can reflect as `signed char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `signed char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted signed char value + const signed char& cref = view->get(); + + // Verify the conversion result (97 -> 'a') + ASSERT_EQ(cref, static_cast(97)); + + delete ptr; // Clean up the dynamically allocated memory + } + + + // Test reflecting an int and viewing it as unsigned char + TEST(RObject_int_pointer_lvalue, reflect_int_view_as_unsigned_char) + { + int* ptr = new int(255); + + // Reflect an int value (e.g., 255) into RObject + RObject robj = rtl::reflect(ptr); + + // Check if RObject can reflect as `unsigned char` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `unsigned char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned char value + const unsigned char& cref = view->get(); + + // Verify the conversion result (255 -> '\xff') + ASSERT_EQ(cref, static_cast(255)); + + delete ptr; // Clean up the dynamically allocated memory + } + + + // Test reflecting an int and viewing it as short + TEST(RObject_int_pointer_lvalue, reflect_int_view_as_short) + { + int* ptr = new int(32767); + + // Reflect an int value (e.g., 32767) into RObject + RObject robj = rtl::reflect(ptr); + + // Check if RObject can reflect as `short` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted short value + const short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast(32767)); + + delete ptr; // Clean up the dynamically allocated memory + } + + + // Test reflecting an int and viewing it as unsigned short + TEST(RObject_int_pointer_lvalue, reflect_int_view_as_unsigned_short) + { + int* ptr = new int(65535); + + // Reflect an int value (e.g., 65535) into RObject + RObject robj = rtl::reflect(ptr); + + // Check if RObject can reflect as `unsigned short` + ASSERT_TRUE(robj.canViewAs()); + + // Get a view of the value as `unsigned short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned short value + const unsigned short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast(65535)); + + delete ptr; // Clean up the dynamically allocated memory + } +} + + +namespace rtl_tests +{ + // Test reflecting an int* and viewing it as bool + TEST(RObject_int_pointer_rvalue, reflect_int_view_as_bool_true) + { + /* Reflect an int value(e.g., 5) into RObject + * Intentionally relinquishing ownership of dynamically allocated memory + * to test RObject creation with an rvalue pointer. + */ RObject robj = rtl::reflect(new int(5)); + + // Check if RObject can reflect as `bool` + ASSERT_TRUE(robj.canViewAs()); + { + // Get a view of the value as `bool` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted bool value + const bool& cref = view->get(); + + // Verify the conversion result (non-zero -> true) + ASSERT_EQ(cref, true); + } { + ASSERT_TRUE(robj.canViewAs()); + + auto view = robj.view(); + + ASSERT_TRUE(view.has_value()); + + // rtl::view<> holds ref to the entity in RObject; + // delete the dynamically allocated memory (new int) + const int& cref = view->get(); + delete& cref; + } + } + + + // Test reflecting an int* and viewing it as bool + TEST(RObject_int_pointer_rvalue, reflect_int_view_as_bool_false) + { + /* Reflect an int value (e.g., 0) into RObject + * Intentionally relinquishing ownership of dynamically allocated memory + * to test RObject creation with an rvalue pointer. + */ RObject robj = rtl::reflect(new int(0)); + + // Check if RObject can reflect as `bool` + ASSERT_TRUE(robj.canViewAs()); + { + // Get a view of the value as `bool` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted bool value + const bool& cref = view->get(); + + // Verify the conversion result (non-zero -> true) + ASSERT_EQ(cref, false); + } { + ASSERT_TRUE(robj.canViewAs()); + + auto view = robj.view(); + + ASSERT_TRUE(view.has_value()); + + // rtl::view<> holds ref to the entity in RObject; + // delete the dynamically allocated memory (new int) + const int& cref = view->get(); + delete& cref; + } + + //Caution: The dynamically allocated memory (new int) is not deleted here. + } + + + // Test reflecting an int* and viewing it as char + TEST(RObject_int_pointer_rvalue, reflect_int_view_as_char) + { + /* Reflect an int value(e.g., 65) into RObject + * Intentionally relinquishing ownership of dynamically allocated memory + * to test RObject creation with an rvalue pointer. + */ RObject robj = rtl::reflect(new int(65)); + + // Check if RObject can reflect as `char` + ASSERT_TRUE(robj.canViewAs()); + { + // Get a view of the value as `char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted char value + const char& cref = view->get(); + + // Verify the conversion result (65 -> 'A') + ASSERT_EQ(cref, static_cast(65)); + } { + ASSERT_TRUE(robj.canViewAs()); + + auto view = robj.view(); + + ASSERT_TRUE(view.has_value()); + + // rtl::view<> holds ref to the entity in RObject; + // delete the dynamically allocated memory (new int) + const int& cref = view->get(); + delete& cref; + } + } + + + // Test reflecting an int* and viewing it as signed char + TEST(RObject_int_pointer_rvalue, reflect_int_view_as_signed_char) + { + /* Reflect an int value(e.g., 97) into RObject + * Intentionally relinquishing ownership of dynamically allocated memory + * to test RObject creation with an rvalue pointer. + */ RObject robj = rtl::reflect(new int(97)); + + // Check if RObject can reflect as `signed char` + ASSERT_TRUE(robj.canViewAs()); + { + // Get a view of the value as `signed char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted signed char value + const signed char& cref = view->get(); + + // Verify the conversion result (97 -> 'a') + ASSERT_EQ(cref, static_cast(97)); + } { + ASSERT_TRUE(robj.canViewAs()); + + auto view = robj.view(); + + ASSERT_TRUE(view.has_value()); + + // rtl::view<> holds ref to the entity in RObject; + // delete the dynamically allocated memory (new int) + const int& cref = view->get(); + delete& cref; + } + } + + + // Test reflecting an int and viewing it as unsigned char + TEST(RObject_int_pointer_rvalue, reflect_int_view_as_unsigned_char) + { + /* Reflect an int value(e.g., 255) into RObject + * Intentionally relinquishing ownership of dynamically allocated memory + * to test RObject creation with an rvalue pointer. + */ RObject robj = rtl::reflect(new int(255)); + + // Check if RObject can reflect as `unsigned char` + ASSERT_TRUE(robj.canViewAs()); + { + // Get a view of the value as `unsigned char` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned char value + const unsigned char& cref = view->get(); + + // Verify the conversion result (255 -> '\xff') + ASSERT_EQ(cref, static_cast(255)); + } { + ASSERT_TRUE(robj.canViewAs()); + + auto view = robj.view(); + + ASSERT_TRUE(view.has_value()); + + // rtl::view<> holds ref to the entity in RObject; + // delete the dynamically allocated memory (new int) + const int& cref = view->get(); + delete& cref; + } + } + + + // Test reflecting an int and viewing it as short + TEST(RObject_int_pointer_rvalue, reflect_int_view_as_short) + { + /* Reflect an int value(e.g., 32767) into RObject + * Intentionally relinquishing ownership of dynamically allocated memory + * to test RObject creation with an rvalue pointer. + */ RObject robj = rtl::reflect(new int(32767)); + + // Check if RObject can reflect as `short` + ASSERT_TRUE(robj.canViewAs()); + { + // Get a view of the value as `short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted short value + const short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast(32767)); + } { + ASSERT_TRUE(robj.canViewAs()); + + auto view = robj.view(); + + ASSERT_TRUE(view.has_value()); + + // rtl::view<> holds ref to the entity in RObject; + // delete the dynamically allocated memory (new int) + const int& cref = view->get(); + delete& cref; + } + } + + + // Test reflecting an int and viewing it as unsigned short + TEST(RObject_int_pointer_rvalue, reflect_int_view_as_unsigned_short) + { + /* Reflect an int value(e.g., 65535) into RObject + * Intentionally relinquishing ownership of dynamically allocated memory + * to test RObject creation with an rvalue pointer. + */ RObject robj = rtl::reflect(new int(65535)); + + // Check if RObject can reflect as `unsigned short` + ASSERT_TRUE(robj.canViewAs()); + { + // Get a view of the value as `unsigned short` + auto view = robj.view(); + + // Ensure the view is valid (conversion succeeded) + ASSERT_TRUE(view.has_value()); + + // Access the converted unsigned short value + const unsigned short& cref = view->get(); + + // Verify the conversion result + ASSERT_EQ(cref, static_cast(65535)); + } { + ASSERT_TRUE(robj.canViewAs()); + + auto view = robj.view(); + + ASSERT_TRUE(view.has_value()); + + // rtl::view<> holds ref to the entity in RObject; + // delete the dynamically allocated memory (new int) + const int& cref = view->get(); + delete& cref; + } + } +} diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp new file mode 100644 index 00000000..fb913a99 --- /dev/null +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdSharedPtr.cpp @@ -0,0 +1,642 @@ + +#include +#include + + +#include +#include + +#include "Node.h" + +using namespace test_utils; +using namespace rtl; + + +namespace rtl::unit_test +{ + TEST(RObject_reflecting_shared_ptr, sharing_semantics__pod) + { + constexpr const int NUM = -20438; + RObject robj = reflect(std::make_shared(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + // Verify reflection at wrapper level. + // Ensure RObject recognizes it can be viewed as a shared_ptr. + EXPECT_TRUE(robj.canViewAs>()); + { + // Obtain a view of the shared_ptr. + auto view = robj.view>(); + ASSERT_TRUE(view.has_value()); + + { + // Accessing via 'const ref' does not increase reference count. + const std::shared_ptr& sptrVal = view->get(); + EXPECT_EQ(*sptrVal, NUM); + EXPECT_TRUE(sptrVal.use_count() == 1); + } { + // Copying the shared_ptr makes a shallow copy (ref-counted). + std::shared_ptr sptrVal = view->get(); + EXPECT_EQ(*sptrVal, NUM); + EXPECT_TRUE(sptrVal.use_count() == 2); + } + // Original view is still valid, back to count 1 after local copy goes out of scope. + const std::shared_ptr& sptr = view->get(); + EXPECT_TRUE(sptr.use_count() == 1); + } + + // Final state check. + // At the end, ownership should return to robj alone. + auto view = robj.view>(); + EXPECT_TRUE(view); + + const std::shared_ptr& sptr = view->get(); + EXPECT_TRUE(sptr.use_count() == 1); + } + + + TEST(RObject_reflecting_shared_ptr, sharing_semantics__Node) + { + ASSERT_TRUE(Node::instanceCount() == 0); + ASSERT_TRUE(Node::assertResourcesReleased()); + { + constexpr const int NUM = -45109; + RObject robj = reflect(std::make_shared(NUM)); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(Node::instanceCount() == 1); + + // Verify reflection at wrapper level. + // Ensure RObject recognizes it can be viewed as a shared_ptr. + EXPECT_TRUE(robj.canViewAs>()); + { + // Obtain a view of the shared_ptr. + auto view = robj.view>(); + ASSERT_TRUE(view.has_value()); + + { + // Accessing via 'const ref' does not increase reference count. + const std::shared_ptr& nptr = view->get(); + EXPECT_EQ(nptr->data(), NUM); + EXPECT_TRUE(nptr.use_count() == 1); + ASSERT_TRUE(Node::instanceCount() == 1); + } { + // Copying the shared_ptr makes a shallow copy (ref-counted). + std::shared_ptr nptr = view->get(); + EXPECT_EQ(nptr->data(), NUM); + EXPECT_TRUE(nptr.use_count() == 2); + ASSERT_TRUE(Node::instanceCount() == 1); + } + // Original view is still valid, back to count 1 after local copy goes out of scope. + EXPECT_TRUE(view->get().use_count() == 1); + } + // Final state check. + // At the end, ownership should return to robj alone. + auto view = robj.view>(); + EXPECT_TRUE(view); + + const std::shared_ptr& node = view->get(); + EXPECT_TRUE(node.use_count() == 1); + } + ASSERT_TRUE(Node::instanceCount() == 0); + ASSERT_TRUE(Node::assertResourcesReleased()); + } + + + TEST(RObject_reflecting_shared_ptr, cloning_semantics__pod_stack) + { + constexpr const int NUM = -20438; + RObject robj = reflect(std::make_shared(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + // --- Step 1: Clone by default (entity::Auto semantics) --- + { + // Default cloning shallow-copies the wrapper. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::None); + + // View clone as 'shared_ptr'. + EXPECT_TRUE(robj0.canViewAs>()); + + auto ptrView = robj0.view>(); + ASSERT_TRUE(ptrView); + + const std::shared_ptr& sptr = ptrView->get(); + EXPECT_EQ(*sptr, NUM); + + // View as the underlying int. + EXPECT_TRUE(robj0.canViewAs()); + + auto view = robj0.view(); + EXPECT_TRUE(view); + EXPECT_EQ(view->get(), NUM); + } + + // --- Step 2: Clone by 'Value' (entity::Value semantics) --- + { + // Copies the underlying value, *not* the wrapper. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(robj0.isEmpty()); + + // Cannot view as shared_ptr, because we cloned the contained value. + EXPECT_FALSE(robj0.canViewAs>()); + + // Instead, can view as the underlying int. + EXPECT_TRUE(robj0.canViewAs()); + + auto view = robj0.view(); + EXPECT_TRUE(view); + EXPECT_EQ(view->get(), NUM); + } + + // --- Step 3: Clone with explicit wrapper semantics --- + { + // Explicitly request a clone at the wrapper level (entity::Wrapper). + // This performs a shallow copy of the shared_ptr, incrementing ref count. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::None); + + // Now the clone can also be viewed as shared_ptr. + EXPECT_TRUE(robj0.canViewAs>()); + + auto ptrView = robj0.view>(); + ASSERT_TRUE(ptrView); + + const std::shared_ptr& nptr = ptrView->get(); + EXPECT_EQ(*nptr, NUM); + + auto view = robj0.view>(); + ASSERT_TRUE(view.has_value()); + + { + // Access as const ref: no copy, ref count remains shared between robj & robj0. + const std::shared_ptr& sptrVal = view->get(); + EXPECT_EQ(*sptrVal, NUM); + EXPECT_TRUE(sptrVal.use_count() == 2); // shared by robj + robj0 + } { + // Explicit copy makes another shallow copy of the shared_ptr. + std::shared_ptr sptrVal = view->get(); + EXPECT_EQ(*sptrVal, NUM); + EXPECT_TRUE(sptrVal.use_count() == 3); // shared by robj + robj0 + sptrVal + } + // After local copy is gone, back to 2 owners (robj + robj0). + EXPECT_TRUE(view->get().use_count() == 2); + } + + // --- Step 4: Final state check --- + // At the end, ownership should return to robj alone. + auto view = robj.view>(); + EXPECT_TRUE(view); + + const std::shared_ptr& sptr = view->get(); + ASSERT_TRUE(sptr.use_count() == 1); + } + + + TEST(RObject_reflecting_shared_ptr, cloning_semantics__pod_heap) + { + constexpr const int NUM = -291823; + RObject robj = reflect(std::make_shared(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + // --- Step 1: Clone by default (entity::Auto semantics) --- + { + // Default cloning shallow-copies the wrapper. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::StlWrapperHeapAllocForbidden); + ASSERT_TRUE(robj0.isEmpty()); + } + + // --- Step 2: Clone by 'Value' (entity::Value semantics) --- + { + // Copies the underlying value, *not* the wrapper. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::None); + ASSERT_FALSE(robj0.isEmpty()); + + // Cannot view as shared_ptr, because we cloned the contained value. + EXPECT_FALSE(robj0.canViewAs>()); + + // Instead, can view as the underlying int. + EXPECT_TRUE(robj0.canViewAs()); + + auto view = robj0.view(); + EXPECT_TRUE(view); + EXPECT_EQ(view->get(), NUM); + } + + // --- Step 3: Clone with explicit wrapper semantics --- + { + // Explicitly request a clone at the wrapper level (entity::Wrapper). + // This performs a shallow copy of the shared_ptr, incrementing ref count. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::StlWrapperHeapAllocForbidden); + ASSERT_TRUE(robj0.isEmpty()); + } + + // --- Step 4: Final state check --- + // At the end, ownership should return to robj alone. + auto view = robj.view>(); + EXPECT_TRUE(view); + + const std::shared_ptr& sptr = view->get(); + ASSERT_TRUE(sptr.use_count() == 1); + } + + + TEST(RObject_reflecting_shared_ptr, cloning_semantics__Node_on_stack) + { + ASSERT_TRUE(Node::instanceCount() == 0); + ASSERT_TRUE(Node::assertResourcesReleased()); + { + constexpr const int NUM = -45109; + RObject robj = reflect(std::make_shared(NUM)); + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(Node::instanceCount() == 1); + + // --- Step 2: Clone by default (entity::Auto semantics) --- + { + // Default cloning shallow-copies the wrapper. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::None); + ASSERT_TRUE(Node::instanceCount() == 1); + + // View clone as 'shared_ptr'. + EXPECT_TRUE(robj0.canViewAs>()); + + auto ptrView = robj0.view>(); + ASSERT_TRUE(ptrView); + + const auto& nptr = ptrView->get(); + EXPECT_EQ(nptr->data(), NUM); + + // View as the underlying Node. + EXPECT_TRUE(robj0.canViewAs()); + auto node = robj0.view(); + EXPECT_EQ(node->get().data(), NUM); + } + + // --- Step 3: Clone by 'Value' (entity::Value semantics) --- + { + // Copies the underlying value, *not* the wrapper. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::TypeNotCopyConstructible); + ASSERT_TRUE(Node::instanceCount() == 1); + ASSERT_TRUE(robj0.isEmpty()); + } + + // --- Step 4: Clone with explicit wrapper semantics --- + { + // Explicitly request a clone at the wrapper level (entity::Wrapper). + // This performs a shallow copy of the shared_ptr, incrementing ref count. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::None); + ASSERT_TRUE(Node::instanceCount() == 1); + + // Now the clone can also be viewed as shared_ptr. + EXPECT_TRUE(robj0.canViewAs>()); + + auto view = robj0.view>(); + ASSERT_TRUE(view.has_value()); + { + // Access as const ref: no copy, ref count remains shared between robj & robj0. + const std::shared_ptr& nptr = view->get(); + EXPECT_EQ(nptr->data(), NUM); + EXPECT_TRUE(nptr.use_count() == 2); // shared by robj + robj0 + } { + // Explicit copy makes another shallow copy of the shared_ptr. + std::shared_ptr nptr = view->get(); + EXPECT_EQ(nptr->data(), NUM); + EXPECT_TRUE(nptr.use_count() == 3); // shared by robj + robj0 + sptrVal + } + // After local copy is gone, back to 2 owners (robj + robj0). + EXPECT_TRUE(view->get().use_count() == 2); + } + + // --- Step 4: Final state check --- + // At the end, ownership should return to robj alone. + auto view = robj.view>(); + EXPECT_TRUE(view); + + const std::shared_ptr& node = view->get(); + ASSERT_TRUE(node.use_count() == 1); + } + ASSERT_TRUE(Node::instanceCount() == 0); + ASSERT_TRUE(Node::assertResourcesReleased()); + } + + + TEST(RObject_reflecting_shared_ptr, cloning_semantics__Node_on_heap) + { + ASSERT_TRUE(Node::instanceCount() == 0); + ASSERT_TRUE(Node::assertResourcesReleased()); + { + constexpr const int NUM = 241054; + RObject robj = reflect(std::make_shared(NUM)); + + ASSERT_FALSE(robj.isEmpty()); + ASSERT_TRUE(Node::instanceCount() == 1); + + // --- Step 2: Clone by default (entity::Auto semantics) --- + { + // Default cloning shallow-copies the wrapper. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::StlWrapperHeapAllocForbidden); + ASSERT_TRUE(robj0.isEmpty()); + ASSERT_TRUE(Node::instanceCount() == 1); + } + + // --- Step 3: Clone by 'Value' (entity::Value semantics) --- + { + // Copies the underlying value, *not* the wrapper. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::TypeNotCopyConstructible); + ASSERT_TRUE(Node::instanceCount() == 1); + ASSERT_TRUE(robj0.isEmpty()); + } + + // --- Step 4: Clone with explicit wrapper semantics --- + { + // Explicitly request a clone at the wrapper level (entity::Wrapper). + // This performs a shallow copy of the shared_ptr, incrementing ref count. + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == error::StlWrapperHeapAllocForbidden); + ASSERT_TRUE(robj0.isEmpty()); + ASSERT_TRUE(Node::instanceCount() == 1); + } + + // --- Step 4: Final state check --- + // At the end, ownership should return to robj alone. + auto view = robj.view>(); + EXPECT_TRUE(view); + + const std::shared_ptr& node = view->get(); + ASSERT_TRUE(node.use_count() == 1); + } + ASSERT_TRUE(Node::instanceCount() == 0); + ASSERT_TRUE(Node::assertResourcesReleased()); + } + + + TEST(RObject_reflecting_shared_ptr, reflect_init_with_lvalue) + { + { + const int NUM = -1629; + std::shared_ptr nodePtr = std::make_shared(NUM); + { + RObject robj = reflect(nodePtr); + ASSERT_FALSE(robj.isEmpty()); + EXPECT_TRUE(nodePtr.use_count() == 2); + + // Check if RObject can reflect as `Node` + EXPECT_TRUE(robj.canViewAs()); + { + auto view = robj.view(); + ASSERT_TRUE(view); + + const Node& node = view->get(); + EXPECT_EQ(node.data(), NUM); + // Ensure no copy is made for viewing. + EXPECT_TRUE(Node::instanceCount() == 1); + // Being shared by 'nodePtr' & 'robj'. + EXPECT_TRUE(nodePtr.use_count() == 2); + } + // Check if RObject can reflect as `shared_ptr` + EXPECT_TRUE(robj.canViewAs>()); + { + // Get a view of the view as `shared_ptr` + auto view = robj.view>(); + ASSERT_TRUE(view.has_value()); + { + std::shared_ptr node = view->get(); + EXPECT_EQ(node->data(), NUM); + //being shared by 'nodePtr', 'robj' and 'node'. + EXPECT_TRUE(nodePtr.use_count() == 3); + } { + const std::shared_ptr& node = view->get(); + EXPECT_EQ(node->data(), NUM); + //being shared by 'nodePtr', 'robj' and 'node'. + EXPECT_TRUE(nodePtr.use_count() == 2); + } + } + //still shared by 'nodePtr' & 'robj'. + EXPECT_TRUE(nodePtr.use_count() == 2); + } + //now owned by 'uptr' alone. + EXPECT_TRUE(nodePtr.use_count() == 1); + } + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + } + + + TEST(RObject_reflecting_shared_ptr, reflect_init_with_rvalue) + { + { + constexpr const int NUM = 6839; + RObject robj = reflect(std::make_shared(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + EXPECT_TRUE(Node::instanceCount() == 1); + // Check if RObject can reflect as `shared_ptr` + EXPECT_TRUE(robj.canViewAs>()); + //view just holds ref/ptr. + auto view = robj.view>(); + ASSERT_TRUE(view.has_value()); + + const std::shared_ptr& sptrNode = view->get(); //no copy + EXPECT_EQ(sptrNode->data(), NUM); + { + std::shared_ptr sptrNode0 = view->get(); + //owned by 'robj' & sptrNode0. + EXPECT_TRUE(sptrNode.use_count() == 2); + } + //owned by 'robj' alone, no 'lvalue' exists in this scope. + EXPECT_TRUE(sptrNode.use_count() == 1); + EXPECT_TRUE(robj.canViewAs()); + { + auto view = robj.view(); + ASSERT_TRUE(view); + + const Node& node = view->get(); + EXPECT_EQ(node.data(), NUM); + //owned by 'robj' alone. + EXPECT_TRUE(sptrNode.use_count() == 1); + } + } + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + } + + + TEST(RObject_reflecting_shared_ptr, move_semantics_pod) + { + constexpr const int NUM = 25738; + RObject robj = reflect(std::make_shared(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + // Check if RObject can reflect as `shared_ptr` + EXPECT_TRUE(robj.canViewAs>()); + { + // Get a view of the value as `shared_ptr` + auto view = robj.view>(); + // Ensure the view is valid + ASSERT_TRUE(view.has_value()); + { + std::shared_ptr sptrVal = view->get(); + + EXPECT_EQ(*sptrVal, NUM); + //being shared by robj & sptrVal. + EXPECT_TRUE(sptrVal.use_count() == 2); + } + //here owned by 'robj' alone. + EXPECT_TRUE(view->get().use_count() == 1); + } { + //create copy of RObject itself. + RObject robj0 = std::move(robj); + //robj should be empty now. + ASSERT_TRUE(robj.isEmpty()); + + auto view = robj0.view>(); + ASSERT_TRUE(view.has_value()); + { + const std::shared_ptr& sptrVal = view->get(); + + EXPECT_EQ(*sptrVal, NUM); + //single owner now, just robj0. + EXPECT_TRUE(sptrVal.use_count() == 1); + } { + //copy of shared_ptr got created. + std::shared_ptr sptrVal = view->get(); + + EXPECT_EQ(*sptrVal, NUM); + //being shared by two entities- robj0 & sptrVal. + EXPECT_TRUE(sptrVal.use_count() == 2); + } + //now owned by 'robj0' alone. + EXPECT_TRUE(view->get().use_count() == 1); + } + } + + + TEST(RObject_reflecting_shared_ptr, move_semantics_Node) + { + { + constexpr const int NUM = -15442; + RObject robj = reflect(std::make_shared(NUM)); + ASSERT_FALSE(robj.isEmpty()); + EXPECT_TRUE(robj.canViewAs>()); + { + // Get a view of the value as `shared_ptr` + auto view = robj.view>(); + // Ensure the view is valid + ASSERT_TRUE(view.has_value()); + { + std::shared_ptr sptrNode = view->get(); + EXPECT_EQ(sptrNode->data(), NUM); + // Being shared by robj & sptrVal. + EXPECT_TRUE(sptrNode.use_count() == 2); + } + // Here owned by 'robj' alone. + EXPECT_TRUE(view->get().use_count() == 1); + } { + //create copy of RObject itself. + RObject robj0 = std::move(robj); + //robj should be empty now. + ASSERT_TRUE(robj.isEmpty()); + + auto view = robj0.view>(); + ASSERT_TRUE(view.has_value()); + { + const std::shared_ptr& sptrNode = view->get(); + + EXPECT_EQ(sptrNode->data(), NUM); + //single owner now, just robj0. + EXPECT_TRUE(sptrNode.use_count() == 1); + } { + //copy of shared_ptr got created. + std::shared_ptr sptrNode = view->get(); + + EXPECT_EQ(sptrNode->data(), NUM); + //being shared by two entities- robj0 & sptrVal. + EXPECT_TRUE(sptrNode.use_count() == 2); + } + //now owned by 'robj0' alone. + EXPECT_TRUE(view->get().use_count() == 1); + } + } + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + } + + + TEST(RObject_reflecting_shared_ptr, reflect_and_create_copies) + { + { + constexpr const int NUM = 10742; + RObject robj = reflect(std::make_shared(NUM)); + + ASSERT_FALSE(robj.isEmpty()); + EXPECT_TRUE(robj.canViewAs>()); + + auto view = robj.view>(); + ASSERT_TRUE(view.has_value()); + + // Access underlying value via the reflected shared_ptr + const std::shared_ptr& sptrNode = view->get(); + EXPECT_EQ(sptrNode->data(), NUM); + + // --------------------------------------------------------------------- + // 1. Heap-clone of STL wrappers is forbidden. + // This prevents accidental deep copies of smart pointers that + // could violate ownership semantics (e.g. double-deletion). + // --------------------------------------------------------------------- + auto [err, badObj] = robj.clone(); + EXPECT_TRUE(err == error::StlWrapperHeapAllocForbidden); + ASSERT_TRUE(badObj.isEmpty()); + + // --------------------------------------------------------------------- + // 2. clone using 'entity::Value': tries to copy the contained entity. + // Since Node is explicitly non-copyable, this yields an error. + // --------------------------------------------------------------------- + { + auto [err0, robj0] = robj.clone(); + EXPECT_TRUE(err0 == error::TypeNotCopyConstructible); + } + + // --------------------------------------------------------------------- + // 3. Explicit clone of the wrapper (entity::Wrapper): + // This performs a shallow copy of std::shared_ptr, incrementing the + // reference count while leaving the Node untouched. + // This demonstrates how RTL allows smart pointer semantics to be + // preserved even when the pointee type itself is non-copyable. + // --------------------------------------------------------------------- + { + auto [err0, robj0] = robj.clone(); + EXPECT_TRUE(err0 == error::None); + + auto view = robj0.view>(); + ASSERT_TRUE(view.has_value()); + + const std::shared_ptr& sptrNode0 = view->get(); + EXPECT_EQ(sptrNode0->data(), NUM); + { + // Making another copy of shared_ptr, still shallow (reference-counted) + std::shared_ptr sptrNode1 = view->get(); + EXPECT_EQ(sptrNode0->data(), NUM); + // Now shared by three entities: robj, robj0, and sptrNode1 + EXPECT_TRUE(sptrNode.use_count() == 3); + } + // Back to two owners: robj and robj0 + EXPECT_TRUE(sptrNode.use_count() == 2); + } + + // Finally, back to sole ownership by robj + EXPECT_TRUE(sptrNode.use_count() == 1); + EXPECT_TRUE(Node::instanceCount() == 1); + } + + // After leaving scope: no leaks, all resources released + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdUniquePtr.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdUniquePtr.cpp new file mode 100644 index 00000000..ca949a9f --- /dev/null +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_stdUniquePtr.cpp @@ -0,0 +1,441 @@ + +#include +#include +#include + +#include "Node.h" + +using namespace test_utils; +using namespace rtl; + +// TODO: Refine these, remove moot cases after this-> UPDATE: MOVING DISALLOWED NOW. + +namespace rtl::unit_test +{ + TEST(RObject_reflecting_unique_ptr, clone_on__heap_stack) + { + const int NUM = 43728; + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + { + RObject robj0 = reflect(std::make_unique(NUM)); + ASSERT_FALSE(robj0.isEmpty()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + { + auto [err, robj] = robj0.clone(); + EXPECT_TRUE(err == error::TypeNotCopyConstructible); + ASSERT_TRUE(robj.isEmpty()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } { + auto [err, robj] = robj0.clone(); + EXPECT_TRUE(err == error::StlWrapperHeapAllocForbidden); + ASSERT_TRUE(robj.isEmpty()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + } + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(RObject_reflecting_unique_ptr, lvalue_no_double_delete) + { + { + constexpr int NUM = 1635; + int* numPtr = new int(NUM); + std::unique_ptr srcPtr(numPtr); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + + // Reflect a move-only type directly into RObject + RObject robj = reflect(std::move(srcPtr)); + ASSERT_FALSE(robj.isEmpty()); + + EXPECT_TRUE(robj.canViewAs>()); + // unique_ptr, ownership managed by RTL. + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + + auto view = robj.view>(); + ASSERT_TRUE(view); + + // get() - UPDATE: MOVING DISALLOWED NOW. + const std::unique_ptr& uptr = view->get(); + ASSERT_TRUE(uptr); + + // RTL gave up the ownership after move-op. + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + + // Access the moved-out value + EXPECT_EQ(*uptr, NUM); + + // this is compile error now. + //int* ptr = uptr.release(); + } + // there must not be any crash. + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(RObject_reflecting_unique_ptr, rvalue_no_double_delete) + { + { + int NUM = 5323; + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + + // Reflect a move-only type directly into RObject + RObject robj = reflect(std::unique_ptr(new Node(NUM))); + ASSERT_FALSE(robj.isEmpty()); + + EXPECT_TRUE(robj.canViewAs>()); + // unique_ptr, ownership managed by RTL. + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + + auto view = robj.view>(); + ASSERT_TRUE(view); + + // get() - UPDATE: MOVING DISALLOWED NOW. + const std::unique_ptr& uptr = view->get(); + ASSERT_TRUE(uptr); + // RTL still owns it. + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + // Access the value + EXPECT_EQ(uptr->data(), NUM); + } + // there must not be any crash. + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(RObject_reflecting_unique_ptr, pod_init_with_lvalue) + { + constexpr const int NUM = 8839; + std::unique_ptr uptr = std::make_unique(NUM); + // No heap leaks- ownership accounting is perfect + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + + // Reflect a move-only type directly into RObject + RObject robj = reflect(std::move(uptr)); + ASSERT_FALSE(robj.isEmpty()); + + // RObject can transparently expose the pointee type + EXPECT_TRUE(robj.canViewAs()); + + auto intView = robj.view(); + ASSERT_TRUE(intView); + + const int& valueNum = intView->get(); + EXPECT_EQ(valueNum, NUM); + + // RObject can also reflect as the original move-only type + EXPECT_TRUE(robj.canViewAs>()); + + // Multiple independent views to the same stored object- all valid before a move + auto view0 = robj.view>(); + ASSERT_TRUE(view0); + + auto view1 = robj.view>(); + ASSERT_TRUE(view1); + + auto view2 = robj.view>(); + ASSERT_TRUE(view2); + + // unique_ptr, ownership managed by RTL. + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + + // get() - UPDATE: MOVING DISALLOWED NOW. + const std::unique_ptr& uptr0 = view0->get(); + ASSERT_TRUE(uptr0); + + // Access the moved-out value + EXPECT_EQ(*uptr0, NUM); + + // Verify the original pointer address matches + EXPECT_EQ(uptr0.get(), &valueNum); + + // RTL still owns it + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + + + TEST(RObject_reflecting_unique_ptr, init_with_lvalue) + { + { + constexpr const int NUM = 16238; + std::unique_ptr uptr = std::make_unique(NUM); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + // Reflect a move-only type directly into RObject + RObject robj = reflect(std::move(uptr)); + ASSERT_FALSE(robj.isEmpty()); + + // RObject can transparently expose the pointee type + EXPECT_TRUE(robj.canViewAs()); + + auto nodeView = robj.view(); + ASSERT_TRUE(nodeView); + + const Node& node = nodeView->get(); + EXPECT_EQ(node.data(), NUM); + + // RObject can also reflect as the original move-only type + EXPECT_TRUE(robj.canViewAs>()); + { + // Multiple independent views to the same stored object- all valid before a move + auto view0 = robj.view>(); + ASSERT_TRUE(view0); + + auto view1 = robj.view>(); + ASSERT_TRUE(view1); + + auto view2 = robj.view>(); + ASSERT_TRUE(view2); + + // unique_ptr, ownership managed by RTL. + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + + // UPDATE: MOVING DISALLOWED NOW. + // A move from any view transfers ownership of the underlying object + // RObject remains alive and type-consistent, but now holds an empty unique_ptr + const std::unique_ptr& uptr0 = view0->get(); + ASSERT_TRUE(uptr0); + + // Access the moved-out value + EXPECT_EQ(uptr0->data(), NUM); + + // Verify the original pointer address matches + EXPECT_EQ(uptr0.get(), &node); + + // RObject still exists with correct metadata, but the stored unique_ptr is now empty + ASSERT_FALSE(robj.isEmpty()); + + // RTL still owns it + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + // Node still exists. + EXPECT_TRUE(Node::instanceCount() == 1); + } + EXPECT_TRUE(Node::instanceCount() == 1); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + } + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + + TEST(RObject_reflecting_unique_ptr, destructor_call__reflectecting_lvalue) + { + { + const int NUM = 24028; + std::unique_ptr nodePtr = std::make_unique(NUM); + RObject robj = reflect(nodePtr); + ASSERT_FALSE(robj.isEmpty()); + + // Check if RObject can reflect as `Node` + EXPECT_TRUE(robj.canViewAs()); + { + auto view = robj.view(); + ASSERT_TRUE(view); + + const Node& node = view->get(); + EXPECT_EQ(node.data(), NUM); + // Ensure no copy is made for viewing. + EXPECT_TRUE(Node::instanceCount() == 1); + } + // Check if RObject can reflect as `shared_ptr` + EXPECT_FALSE(robj.canViewAs>()); + { + // Get a view of the view as `shared_ptr` + auto view = robj.view>(); + EXPECT_FALSE(view); + } + // Check if RObject can reflect as `unique_ptr` + EXPECT_TRUE(robj.canViewAs>()); + { + // Get a view of the view as `shared_ptr` + auto view = robj.view>(); + EXPECT_TRUE(view); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + EXPECT_TRUE(Node::instanceCount() == 1); + } + } + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + } + + + TEST(RObject_reflecting_unique_ptr, destructor_call__reflectecting_rvalue) + { + { + const int NUM = 28228; + RObject robj = reflect(std::make_unique(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + // Check if RObject can reflect as `Node` + EXPECT_TRUE(robj.canViewAs()); + { + auto view = robj.view(); + ASSERT_TRUE(view); + + const Node& node = view->get(); + EXPECT_EQ(node.data(), NUM); + // Ensure no copy is made for viewing. + EXPECT_TRUE(Node::instanceCount() == 1); + } + // Check if RObject can reflect as `shared_ptr` + EXPECT_FALSE(robj.canViewAs>()); + { + // Get a view of the view as `shared_ptr` + auto view = robj.view>(); + ASSERT_FALSE(view); + } + // Check if RObject can reflect as `unique_ptr` + EXPECT_TRUE(robj.canViewAs>()); + { + // Get a view of the view as `shared_ptr` + auto view = robj.view>(); + EXPECT_TRUE(view); + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 1); + EXPECT_TRUE(Node::instanceCount() == 1); + } + } + EXPECT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + } + + + TEST(RObject_reflecting_unique_ptr, init_with_rvalue) + { + { + constexpr const int NUM = 32443; + RObject robj = reflect(std::make_unique(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + EXPECT_TRUE(Node::instanceCount() == 1); + EXPECT_TRUE(robj.canViewAs()); + { + auto view = robj.view(); + ASSERT_TRUE(view); + + const Node& node = view->get(); + EXPECT_EQ(node.data(), NUM); + } + // Check if RObject can be viewed as `unique_ptr` + EXPECT_TRUE(robj.canViewAs>()); + { + auto view = robj.view>(); + ASSERT_TRUE(view); + ASSERT_FALSE(robj.isEmpty()); + + // UPDATE: MOVING DISALLOWED NOW. + const std::unique_ptr& uptrNode = view->get(); + EXPECT_EQ(uptrNode->data(), NUM); + } + } + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(RObject_reflecting_unique_ptr, init_with_const_lvalue) + { + { + const int NUM = 35729; + std::unique_ptr nodePtr = std::make_unique(NUM); + { + RObject robj = reflect(nodePtr); + ASSERT_FALSE(robj.isEmpty()); + + // Check if RObject can reflect as `Node` + EXPECT_TRUE(robj.canViewAs()); + { + auto view = robj.view(); + ASSERT_TRUE(view); + + const Node& node = view->get(); + EXPECT_EQ(node.data(), NUM); + // Ensure no copy is made for viewing. + EXPECT_TRUE(Node::instanceCount() == 1); + } + // Check if RObject can reflect as `unique_ptr` + EXPECT_FALSE(robj.canViewAs>()); + { + // Get a view of the view as `unique_ptr` + auto view = robj.view>(); + ASSERT_FALSE(view); + } + // Check if RObject can reflect as `unique_ptr` + EXPECT_TRUE(robj.canViewAs>()); + { + // Get a view of the view as `unique_ptr` + auto view = robj.view>(); + EXPECT_TRUE(view); + } + } + } + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + + TEST(RObject_reflecting_unique_ptr, init_with_const_rvalue) + { + { + const int NUM = 39929; + RObject robj = reflect(std::make_unique(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + // Check if RObject can reflect as `Node` + EXPECT_TRUE(robj.canViewAs()); + { + auto view = robj.view(); + ASSERT_TRUE(view); + + const Node& node = view->get(); + EXPECT_EQ(node.data(), NUM); + // Ensure no copy is made for viewing. + EXPECT_TRUE(Node::instanceCount() == 1); + } + // Check if RObject can reflect as `unique_ptr` + EXPECT_FALSE(robj.canViewAs>()); + { + // Get a view of the view as `unique_ptr` + auto view = robj.view>(); + ASSERT_FALSE(view); + } + // Check if RObject can reflect as `unique_ptr` + EXPECT_TRUE(robj.canViewAs>()); + { + // Get a view of the view as `unique_ptr` + auto view = robj.view>(); + EXPECT_TRUE(view); + } + } + EXPECT_TRUE(Node::instanceCount() == 0); + EXPECT_TRUE(Node::assertResourcesReleased()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } + + TEST(RObject_reflecting_unique_ptr, create_clones) + { + const int NUM = 45429; + RObject robj = reflect(std::make_unique(NUM)); + ASSERT_FALSE(robj.isEmpty()); + + // Check if RObject can reflect as `Node` + EXPECT_TRUE(robj.canViewAs()); + { + auto view = robj.view(); + ASSERT_TRUE(view); + + const Node& node = view->get(); + EXPECT_EQ(node.data(), NUM); + // Ensure no copy is made for viewing. + EXPECT_TRUE(Node::instanceCount() == 1); + } { + auto [err, robj0] = robj.clone(); + EXPECT_TRUE(err == rtl::error::TypeNotCopyConstructible); + ASSERT_TRUE(robj0.isEmpty()); + } + } +} \ No newline at end of file diff --git a/RTLTestRunApp/src/RObjectTests/RObjectReflecting_strings.cpp b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_strings.cpp new file mode 100644 index 00000000..24387071 --- /dev/null +++ b/RTLTestRunApp/src/RObjectTests/RObjectReflecting_strings.cpp @@ -0,0 +1,490 @@ + +#include +#include + +using namespace rtl; + +namespace +{ + static const std::string STR_STD_STRING = "string_type: std::string"; + static constexpr const char* STR_CONST_CHAR_POINTER = "string_type: const_char_*."; + + static char STR_CHAR_ARRAY[] = "string_type: const_char_array."; + static constexpr const char STR_CONST_CHAR_ARRAY[] = "string_type: const_char_array."; + + static const std::string_view STR_STD_STRING_VIEW = "string_type: std::string_view"; + + //initialize RTL, necessary for RObject conversions to work. + static auto _= rtl::CxxMirror({/*..empty..*/}); +} + + +namespace rtl_tests +{ + + TEST(RObject_view_negative_test, disallowed_mutable_views_should_not_compile) + { + RObject robj = rtl::reflect(std::string("Immutable")); + + /* The following lines SHOULD NOT COMPILE if uncommented: + These are intentionally commented to enforce design-time correctness. + */ + + /* ASSERT_FALSE(robj.canViewAs()); //Mutable pointer not allowed + ASSERT_FALSE(robj.canViewAs()); //Mutable C-string + ASSERT_FALSE(robj.canViewAs()); //Reference not supported + ASSERT_FALSE(robj.canViewAs()); //Rvalue ref not allowed + + auto bad1 = robj.view(); //Mutable pointer not allowed + auto bad2 = robj.view(); //Mutable C-string + auto bad3 = robj.view(); //Reference not supported + auto bad4 = robj.view(); //Rvalue ref not allowed + */ + } + + + TEST(RObject_view_negative_test, incompatible_view_returns_nullopt) + { + RObject robj = rtl::reflect(std::string("test")); + + ASSERT_FALSE(robj.canViewAs()); + + // Request a view of an incompatible type + auto view = robj.view(); + ASSERT_FALSE(view.has_value()); // Must return nullopt + } + + + TEST(RObject_view_negative_test, incompatible_reflected_type_returns_nullopt) + { + int value = 42; + RObject robj = rtl::reflect(&value); + + // Although value is stored, it's not a string + ASSERT_FALSE(robj.canViewAs()); + auto view0 = robj.view(); + ASSERT_FALSE(view0.has_value()); + + ASSERT_FALSE(robj.canViewAs()); + auto view1 = robj.view(); + ASSERT_FALSE(view1.has_value()); + } +} + + +namespace unit_test +{ + TEST(RObject_init_with_stdString_pointer, view_as_std_string) + { + // Create an RObject that reflects a std::string pointer. + RObject robj = rtl::reflect(&STR_STD_STRING); + + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + const std::string& str_cref = view->get(); + + // Validate the addresses are same, no copy made. + ASSERT_EQ(&str_cref, &STR_STD_STRING); + } + + + TEST(RObject_init_with_stdString_pointer, view_as_const_char_ptr) + { + // Create an RObject that reflects a std::string pointer. + RObject robj = rtl::reflect(&STR_STD_STRING); + + // Check if the value can be accessed as 'const char*'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'const char*' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Ensure the returned pointer is the original std::string's buffer (no copy). + const char& str_cref = view->get(); + ASSERT_EQ(&str_cref, STR_STD_STRING.c_str()); + } + + + TEST(RObject_init_with_stdString_pointer, view_as_std_string_view) + { + // Create an RObject that reflects a std::string pointer. + RObject robj = rtl::reflect(&STR_STD_STRING); + + // Check if the value can be accessed as 'std::string_view'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string_view' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Validate the string_view content matches the original input. + const std::string_view& str_cref = view->get(); + ASSERT_EQ(str_cref, STR_STD_STRING); + } + + + TEST(RObject_view_as_std_string_and_string_view, init_with_empty_literal) + { + // Create an RObject that reflects a empty string literal rvalue + RObject robj = rtl::reflect(""); + + // Check if the value can be accessed as 'std::string_view'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string_view' and verify it is present. + auto view0 = robj.view(); + ASSERT_TRUE(view0.has_value()); + + // Validate the 'string_view' content matches the original input. + const std::string_view& str_view = view0->get(); + ASSERT_EQ(str_view, ""); + + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view1 = robj.view(); + ASSERT_TRUE(view1.has_value()); + + // Validate the string content matches the original input. + const std::string& str_cref = view1->get(); + ASSERT_EQ(str_cref, ""); + } + + + TEST(RObject_view_as_std_string_and_string_view, init_with_charArray) + { + // Create an RObject that reflects a string value (init with 'char[]'). + RObject robj = rtl::reflect(STR_CHAR_ARRAY); + + // Check if the value can be accessed as 'std::string_view'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string_view' and verify it is present. + auto view0 = robj.view(); + ASSERT_TRUE(view0.has_value()); + + // Validate the string content matches the original input. + const std::string_view& str_view = view0->get(); + ASSERT_EQ(str_view, STR_CHAR_ARRAY); + + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view1 = robj.view(); + ASSERT_TRUE(view1.has_value()); + + // Validate the string content matches the original input. + const std::string& str_cref = view1->get(); + ASSERT_EQ(str_cref, STR_CHAR_ARRAY); + + // Check if the value can be accessed as 'const char*'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'const char*' and verify it is present. + auto view2 = robj.view(); + ASSERT_TRUE(view2.has_value()); + + //since the char[] is wrapped in string_view, base address is stored, data not copied. + const char& str_addr = view2->get(); + ASSERT_EQ(&str_addr, STR_CHAR_ARRAY); + } + + + TEST(RObject_init_with_charArray, view_as_const_char_ptr) + { + // Create an RObject that reflects a string value (init with 'char[]'). + RObject robj = rtl::reflect(STR_CHAR_ARRAY); + + // Check if the value can be accessed as 'const char*'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'const char*' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + const char& str_cref = view->get(); + // Ensure the returned pointer is the original array (no copy). + ASSERT_EQ(&str_cref, STR_CHAR_ARRAY); + // Validate the string content. + ASSERT_EQ(std::string_view(&str_cref), std::string_view(STR_CHAR_ARRAY)); + } + + + TEST(RObject_view_as_std_string_and_string_view, init_with_constCharArray) + { + // Create an RObject that reflects a string value (init with 'const char[]'). + RObject robj = rtl::reflect(STR_CONST_CHAR_ARRAY); + + // Check if the value can be accessed as 'std::string_view'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string_view' and verify it is present. + auto view0 = robj.view(); + ASSERT_TRUE(view0.has_value()); + + // Validate the string content matches the original input. + const std::string_view& str_view = view0->get(); + ASSERT_EQ(str_view, STR_CONST_CHAR_ARRAY); + + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view1 = robj.view(); + ASSERT_TRUE(view1.has_value()); + + //since the char[] is wrapped in string_view, but will return std::string copy. + const std::string& str_cref = view1->get(); + ASSERT_EQ(str_cref, STR_CONST_CHAR_ARRAY); + + // Check if the value can be accessed as 'const char*'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'const char*' and verify it is present. + auto view2 = robj.view(); + ASSERT_TRUE(view2.has_value()); + + //since the char[] is wrapped in string_view, base address is stored, data not copied. + const char& str_addr = view2->get(); + ASSERT_EQ(&str_addr, STR_CONST_CHAR_ARRAY); + } + + + TEST(RObject_view_as_const_char_ptr, init_with_constCharArray) + { + // Create an RObject that reflects a string value (init with 'const char[]'). + RObject robj = rtl::reflect(STR_CONST_CHAR_ARRAY); + + // Check if the value can be accessed as 'const char*'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'const char*' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + const char& str_cref = view->get(); + + //the addresses are same + ASSERT_EQ(&str_cref, STR_CONST_CHAR_ARRAY); + + // Validate the C-string content matches the original input. + ASSERT_EQ(std::string_view(&str_cref), STR_CONST_CHAR_ARRAY); + } + + + TEST(RObject_view_as_std_string_and_string_view, init_with_constCharPtr) + { + // Create an RObject that reflects a string value (init with 'const char*'). + RObject robj = rtl::reflect(STR_CONST_CHAR_POINTER); + + // Check if the value can be accessed as 'std::string'. + ASSERT_FALSE(robj.canViewAs()); + + // Check if the value can be accessed as 'std::string'. + ASSERT_FALSE(robj.canViewAs()); + + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Validate the string content matches the original input. + const char& str_addr = view->get(); + ASSERT_EQ(&str_addr, STR_CONST_CHAR_POINTER); + } + + + TEST(RObject_init_with_stdString, view_as_std_string) + { + // Create an RObject that reflects a string value (init with 'std::string'). + RObject robj = rtl::reflect(STR_STD_STRING); + + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view0 = robj.view(); + ASSERT_TRUE(view0.has_value()); + + // Validate the string content matches the original input. + const std::string& str_cref = view0->get(); + ASSERT_EQ(str_cref, STR_STD_STRING); + + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'const char*' and verify it is present. + auto view1 = robj.view(); + ASSERT_TRUE(view1.has_value()); + + // Validate the base address are different, since RObject is reflecting a copy. + const char& str_addr = view1->get(); + ASSERT_NE(&str_addr, STR_STD_STRING.c_str()); + } + + + TEST(RObject_init_with_stdString, clone_and_view) + { + // Create an RObject that reflects a string value (init with 'std::string'). + RObject robj = rtl::reflect(STR_STD_STRING); + + EXPECT_TRUE(robj.canViewAs()); + EXPECT_TRUE(robj.canViewAs()); + + auto testWithAlloc = [&]() + { + auto [err, robjcp] = robj.clone(); + + EXPECT_EQ(err, rtl::error::None); + EXPECT_EQ(robj.getTypeId(), robjcp.getTypeId()); + { + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robjcp.template canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view = robjcp.template view(); + ASSERT_TRUE(view.has_value()); + + // Validate the string content matches the original input. + const std::string& str_cref = view->get(); + ASSERT_EQ(str_cref, STR_STD_STRING); + } { + ASSERT_TRUE(robjcp.template canViewAs()); + + // Try to obtain a view as 'const char*' and verify it is present. + auto view = robjcp.template view(); + ASSERT_TRUE(view.has_value()); + + // Validate the base address are different, since RObject is reflecting a copy. + const char& str_addr = view->get(); + ASSERT_NE(&str_addr, STR_STD_STRING.c_str()); + } + }; + + // Should even std::string to 'char' conversion be allowed implicitly? + // Need to re-think it. The implicit conversions are not used in core dispatch yet. + testWithAlloc.operator()(); + testWithAlloc.operator()(); + } + + + TEST(RObject_init_with_stdString_rvalue, view_as_std_string) + { + // Create an RObject that reflects a string value (init with 'std::string' rvalue). + RObject robj = rtl::reflect(std::string(STR_STD_STRING)); + + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Validate the string content matches the original input. + const std::string& str_cref = view->get(); + ASSERT_EQ(str_cref, STR_STD_STRING); + } + + + TEST(RObject_init_with_stdString, view_as_std_string_view) + { + // Create an RObject that reflects a string value (init with 'std::string'). + RObject robj = rtl::reflect(STR_STD_STRING); + + // Check if the value can be accessed as 'std::string_view'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string_view' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Validate the string_view content matches the original input. + const std::string_view& str_cref = view->get(); + ASSERT_EQ(str_cref, STR_STD_STRING); + } + + + TEST(RObject_init_with_stdStringView, view_as_std_string) + { + // Create an RObject that reflects a string value (init with 'std::string_view'). + // Stores a copy of the 'std::string_view' as a 'std::string'. + RObject robj = rtl::reflect(STR_STD_STRING_VIEW); + + // Check if the value can be accessed as 'std::string'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Validate the string content matches the original input. + const std::string& str_cref = view->get(); + ASSERT_EQ(str_cref, STR_STD_STRING_VIEW); + } + + + TEST(RObject_init_with_stdStringView, view_as_std_string_view) + { + // Create an RObject that reflects a string value (init with 'std::string_view'). + // Stores a copy of the 'std::string_view' as a 'std::string'. + RObject robj = rtl::reflect(STR_STD_STRING_VIEW); + + // Check if the value can be accessed as 'std::string_view'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string_view' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Validate the string_view content matches the original input. + const std::string_view& str_cref = view->get(); + ASSERT_EQ(str_cref, STR_STD_STRING_VIEW); + } + + + TEST(RObject_init_with_stdStringView_rvalue, view_as_std_string_view) + { + // Create an RObject that reflects a string value (init with 'std::string_view'). + // Stores a copy of the 'std::string_view' as a 'std::string'. + RObject robj = rtl::reflect(std::string_view(STR_CONST_CHAR_POINTER)); + + // Check if the value can be accessed as 'std::string_view'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'std::string_view' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Validate the string_view content matches the original input. + const std::string_view& str_cref = view->get(); + ASSERT_EQ(str_cref, STR_CONST_CHAR_POINTER); + } + + + TEST(RObject_init_with_stdStringView, view_as_const_char_ptr) + { + // Create an RObject that reflects a string value (init with 'std::string_view'). + // Stores a copy of the 'std::string_view' as a 'std::string'. + RObject robj = rtl::reflect(STR_STD_STRING_VIEW); + + // Check if the value can be accessed as 'const char*'. + ASSERT_TRUE(robj.canViewAs()); + + // Try to obtain a view as 'const char*' and verify it is present. + auto view = robj.view(); + ASSERT_TRUE(view.has_value()); + + // Validate the C-string content matches the original input. + const char& str_cref = view->get(); + ASSERT_EQ(std::string_view(&str_cref), STR_STD_STRING_VIEW); + } +} diff --git a/RTLTestRunApp/src/main.cpp b/RTLTestRunApp/src/main.cpp new file mode 100644 index 00000000..9d1f253d --- /dev/null +++ b/RTLTestRunApp/src/main.cpp @@ -0,0 +1,38 @@ + +#include +#include +#include "CxxMirrorTests/CxxMirrorThreadingTest.h" + + +class GlobalTestEnvironment : public ::testing::Environment +{ +public: + void SetUp() override + { + std::cout << "\n----------------------------------------------------------------------"; + std::cout << "\n CxxMirror ==> Initialization & Multithreading-Test "; + std::cout << "\n----------------------------------------------------------------------"; + { + std::jthread t0(rtl_tests::InitMirror::reflectingBook); + std::jthread t1(rtl_tests::InitMirror::reflectingDate); + std::jthread t2(rtl_tests::InitMirror::reflectingEvent); + std::jthread t3(rtl_tests::InitMirror::reflectingAnimal); + std::jthread t4(rtl_tests::InitMirror::reflectingPerson); + std::jthread t5(rtl_tests::InitMirror::reflectingLibrary); + std::jthread t6(rtl_tests::InitMirror::reflectingPodsStl); + std::jthread t7(rtl_tests::InitMirror::reflectingCalender); + std::jthread t8(rtl_tests::InitMirror::reflectingMyTypePerson); + std::jthread t9(rtl_tests::InitMirror::reflectingCStyleFunctions); + } + std::cout << "\n----------------------------------------------------------------------\n\n"; + } +}; + + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new GlobalTestEnvironment); + + return RUN_ALL_TESTS(); +} diff --git a/ReflectionTemplateLib/CMakeLists.txt b/ReflectionTemplateLib/CMakeLists.txt index dcc251ee..1f5f3c20 100644 --- a/ReflectionTemplateLib/CMakeLists.txt +++ b/ReflectionTemplateLib/CMakeLists.txt @@ -1,23 +1,22 @@ -# CMakeLists.txt for ReflectionTemplateLib - -# Set the minimum required CMake version cmake_minimum_required(VERSION 3.20) -# Set the project name -project(ReflectionTemplateLib) +project(ReflectionTemplateLib LANGUAGES CXX) + +add_library(${PROJECT_NAME} STATIC) -set(CMAKE_CXX_STANDARD 20) +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20) -SET(CXX_LIB_NAME ReflectionTemplateLib) +set(LOCAL_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_access.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_builder.h" +) -ADD_LIBRARY(${PROJECT_NAME} STATIC "") +target_sources(${PROJECT_NAME} PRIVATE ${LOCAL_HEADERS}) -INCLUDE_DIRECTORIES(common) -INCLUDE_DIRECTORIES(detail/inc) -INCLUDE_DIRECTORIES(access/inc) -INCLUDE_DIRECTORIES(builder/inc) +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/rtl +) -# Add the source directory -INCLUDE(detail/src/CMakeLists.txt) -INCLUDE(access/src/CMakeLists.txt) -INCLUDE(builder/CMakeLists.txt) \ No newline at end of file +add_subdirectory(rtl) diff --git a/ReflectionTemplateLib/access/inc/CxxMirror.h b/ReflectionTemplateLib/access/inc/CxxMirror.h deleted file mode 100644 index 81b49cde..00000000 --- a/ReflectionTemplateLib/access/inc/CxxMirror.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "CxxReflection.h" - -namespace rtl { - - namespace access - { - //forward decls - class Record; - class Function; - - /* @class: CxxMirror - * provides interface to access registered functions/methods by name. - * its the single point of access to whole reflection system. - * all the type registration is done while constructing its object. - * its objects can be createed locally and will be destroyed as regular object, at scope's end. - * deleted copy constructor and assignment operator, can only be passed around as reference or wrapped in a smart pointer. - * the inherited data members are freed upon destruction, except the 'functor-containers', they have static lifetime. - * 'functor-containers' are not member of this or base class, base only contains 'Function' objects which is a hash-key for looking up a particular functor. - * creating multiple objects of CxxMirror and registring the same functor will not increase the 'functor-container' size. - * once a functor is registered, no entry will be added to the 'functor-container' for the same functor. - * registering the same functor will create duplicate hash-key 'Function' object, which will be ignored if in the same 'CxxMirror' object. - if two different 'CxxMirror' objects are created and registering the same functor, the functor-container will have only one entry for the functor - but two identical 'Function' objects will be created, held by respective 'CxxMirror' object. - */ class CxxMirror : public detail::CxxReflection - { - public: - - //constructor, taking function objects, other constructors are disabled. - CxxMirror(const std::vector& pFunctions); - - //get the class/struct's member-functions hash-keys wrapped in a 'Record' object. - std::optional getRecord(const std::string& pRecordName) const; - - //get the non-member functions hash-keys. - std::optional getFunction(const std::string& pFunctionName) const; - - //get the class/struct's member-functions hash-keys wrapped in a 'Record' object, registered with a namespace name. - std::optional getRecord(const std::string& pNameSpaceName, const std::string& pRecordName) const; - - //get the non-member functions hash-keys, registered with a namespace name. - std::optional getFunction(const std::string& pNameSpaceName, const std::string& pFunctionName) const; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/CxxMirrorToJson.h b/ReflectionTemplateLib/access/inc/CxxMirrorToJson.h deleted file mode 100644 index 40ab5fbf..00000000 --- a/ReflectionTemplateLib/access/inc/CxxMirrorToJson.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace rtl { - - namespace access { - class CxxMirror; - } - - struct CxxMirrorToJson - { - static void dump(access::CxxMirror& pCxxMirror, const std::string& pFilePathStr); - }; -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/Function.h b/ReflectionTemplateLib/access/inc/Function.h deleted file mode 100644 index 6309c737..00000000 --- a/ReflectionTemplateLib/access/inc/Function.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "RStatus.h" -#include "FunctorId.h" -#include "Constants.h" - -namespace rtl { - - namespace detail { - //forward decls - class CxxReflection; - class ReflectionBuilder; - } - - namespace access - { - /* @class: Function, (callable object) - * every functor (function/method pointer), constructor, destructor registered will produce a 'Function' object - * it contains the meta-data of the functor along with 'FunctorId' to lookup for the same in functor-table. - * once the Function object is obtained, it can be called with the correct set of arguments, which will finally - perform call on the functor represented by this object. - */ class Function - { - //TypeQ::Const/Mute represents the const/non-const member-function, Type::None for non-member functions. - const TypeQ m_qualifier; - - //type id of class/struct (if it represents a member-function, else always '0') - const std::size_t m_recordTypeId; - - //name of the class/struct it belongs to, empty for non-member function. - const std::string m_record; - - //name of the function as supplied by the user. - const std::string m_function; - - //name of the namespace as supplied by the user. - const std::string m_namespace; - - //FunctorId acts as a hash-key to look up the functor in table. multiple 'FunctoreId' for overloaded functors. - mutable std::vector m_functorIds; - - Function(const std::string& pNamespace, const std::string& pClassName, - const std::string& pFuncName, const detail::FunctorId& pFunctorId, - const std::size_t pRecordTypeId, const TypeQ pQualifier); - - void addOverload(const Function& pOtherFunc) const; - - GETTER_REF(std::vector, FunctorIds, m_functorIds) - - protected: - - Function(const Function& pOther, const detail::FunctorId& pFunctorId, - const std::string& pFunctorName); - - const std::size_t hasSignatureId(const std::size_t& pSignatureId) const; - - public: - - //simple inlined getters. - GETTER(TypeQ, Qualifier, m_qualifier) - GETTER(std::string, RecordName, m_record) - GETTER(std::string, Namespace, m_namespace) - GETTER(std::string, FunctionName, m_function) - GETTER(std::size_t, RecordTypeId, m_recordTypeId) - GETTER(std::vector, Functors, m_functorIds) - - template - const bool hasSignature() const; - - template - RStatus operator()(_args...params) const noexcept; - - template - RStatus call(_args...params) const noexcept; - - friend detail::CxxReflection; - friend detail::ReflectionBuilder; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/Function.hpp b/ReflectionTemplateLib/access/inc/Function.hpp deleted file mode 100644 index 9bf7f023..00000000 --- a/ReflectionTemplateLib/access/inc/Function.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include "RStatus.h" -#include "Function.h" -#include "Instance.h" -#include "FunctorContainer.h" - -namespace rtl { - - namespace access - { - /* @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 const bool Function::hasSignature() const - { - //hasSignatureId() returns the index of the 'lambda' in functor-container, which cannot be '-1'. - return (hasSignatureId(detail::FunctorContainer<_arg0, _args...>::getContainerId()) != -1); - } - - - /* @method: hasSignature() - @param: set of arguments, explicitly specified as template parameter. - @return: bool, if the functor associated with this object doesn't takes any argument. - */ template<> - inline const bool Function::hasSignature() const - { - //hasSignatureId() returns the index of 'lambda' in functor-container, which cannot be '-1'. - return (hasSignatureId(detail::FunctorContainer<>::getContainerId()) != -1); - } - - - /* @method: operator()() - @param: variadic arguments. - @return: RStatus, containing the call status & return value of from the reflected call. - * if the arguments did not match with any overload, returns RStatus with Error::SignatureMismatch - * providing optional syntax, Function::call() does the exact same thing. - */ template - inline RStatus Function::operator()(_args ...params) const noexcept - { - const std::size_t& index = hasSignatureId(detail::FunctorContainer<_args...>::getContainerId()); - if (index != -1) //true, if the arguments sent matches the functor signature associated with this 'Function' object - { - return detail::FunctorContainer<_args...>::forwardCall(index, params...); - } - //else return with Error::SignatureMismatch. - return RStatus(Error::SignatureMismatch); - } - - - /* @method: call() - @param: variadic arguments. - @return: RStatus, containing the call status & return value of from the reflected call. - * if the arguments did not match with any overload, returns RStatus with Error::SignatureMismatch. - * providing optional syntax, Function::operator()() does the exact same thing. - */ template - inline RStatus Function::call(_args ...params) const noexcept - { - const std::size_t& index = hasSignatureId(detail::FunctorContainer<_args...>::getContainerId()); - if (index != -1) //true, if the arguments sent matches the functor signature associated with this 'Function' object - { - return detail::FunctorContainer<_args...>::forwardCall(index, params...); - } - //else return with Error::SignatureMismatch. - return RStatus(Error::SignatureMismatch); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/Instance.h b/ReflectionTemplateLib/access/inc/Instance.h deleted file mode 100644 index 387b4a6a..00000000 --- a/ReflectionTemplateLib/access/inc/Instance.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "TypeId.h" -#include "Constants.h" - -namespace rtl { - - namespace access - { - //forward decls - class Record; - class RStatus; - class Function; - - /* @class: Instance - * type erased wrapper for objects created on heap via reflection. - * 'Instance' objects are only returned from Record::clone() & Recoed::instance() - * empty 'Instance' is returned if constructor is not found or if called with wrong args. - * 'Instance' objects are never created on heap, only the underlying object is created on heap. - * the lifetime of the underlying object is managed by std::shared_ptr. - */ class Instance - { - //indicates if object const/non-const. - mutable TypeQ m_qualifier; - - //type id of the containd object. - const std::size_t m_typeId; - - //allocated object, stored without type info. - const std::any m_anyObject; - - /* shared_ptr, wil be shared between the copies of the 'Instance'. - does not holds the objcet constructed via reflection. - it only contains a custom deleter to be called on the underlying object. - */ const std::shared_ptr m_destructor; - - //private constructors, only class 'Record' can access. - explicit Instance(); - explicit Instance(const std::any& pRetObj, const RStatus& pStatus, const Function& pDctor); - - public: - - //creating copies is allowed. - Instance(const Instance&); - - //simple inlined getters. - GETTER(std::any, , m_anyObject); - GETTER(std::size_t, TypeId, m_typeId); - GETTER(TypeQ, Qualifier, m_qualifier); - - //checks if it contains object constructed via reflection. - const bool isEmpty() const; - - //check the contained object is const or not. - const bool isConst() const; - - //treat the object constructed via reflection as const or non-const. - void makeConst(const bool& pCastAway = false); - - //get the current number of objects constructed via reflection. - static std::size_t getInstanceCount(); - - friend Record; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/Method.h b/ReflectionTemplateLib/access/inc/Method.h deleted file mode 100644 index f3610c6e..00000000 --- a/ReflectionTemplateLib/access/inc/Method.h +++ /dev/null @@ -1,173 +0,0 @@ -#pragma once - -#include - -#include "Function.h" -#include "Instance.h" - -namespace rtl { - - namespace access - { - //forward decls - class Method; - class Record; - - /* @class: MethodInvoker - @param: , can be any 'FunctorType' other than FunctorType::Static. - * invokes the assigned method on the assigned object. - * invokes only non-static member function via reflection. - * its objects are only cretaed and returned by 'Method::on()' method. - * purpose of this class is only to provide method call syntax like, 'method.on(target).call(params...)' - */ template - class MethodInvoker - { - //the method to be called. - const Method& m_method; - - //the object on which, the method needs to be called. - const Instance& m_target; - - MethodInvoker(const Method& pMethod, const Instance& pTarget); - - public: - - template - RStatus call(_args...) const noexcept; - - friend Method; - }; - - - /* @class: MethodInvoker - @param: FunctorType::Static (explicitly specialized) - * invokes the assigned method on the assigned object. - * invokes only static member function via reflection. - * its objects are only cretaed and returned by 'Method::on()' method. - * purpose of this class is only to provide method call syntax like, 'method.on().call(params...)' - * 'on()' will take no target as parameter, since the method being called is 'static'. - */ template<> - class MethodInvoker - { - const Method& m_method; - - MethodInvoker(const Method& pMethod); - - public: - - template - RStatus call(_args...) const noexcept; - - friend Method; - }; - - - /* @class: Method - * extends 'Function' class and adds interfaces to call member function. - * invokes only static & non-static member functions via reflection. - * deletes the base's 'operator()()'. - * redefines 'operator()()', to accept only target object and returns lambda. - * the returned lambda is then called with the arguments corresponding to the functor associated with it. - */ class Method : public Function - { - //private ctor, called by 'Record' class. - explicit Method(const Function& pFunction); - - //private ctor, called by 'Record' class. - explicit Method(const Function& pFunction, const detail::FunctorId& pFunctorId, const std::string& pFunctorName); - - //invokes the constructor associated with this 'Method' - template - RStatus invokeCtor(_args...params) const; - - //invokes the member-function associated with this 'Method' - template - RStatus invoke(const Instance& pTarget, _args...params) const; - - //invokes only const member-function associated with this 'Method' - template - RStatus invokeConst(const Instance& pTarget, _args...params) const; - - //invokes only static member-function associated with this 'Method' - template - RStatus invokeStatic(_args...params) const; - - //called from class 'Record', creates a 'Method' object for destructor. - static Method getDestructorMethod(const Function& pFunction, const detail::FunctorId& pFunctorId); - - public: - - //indicates if a particular set of arguments accepted by the functor associated with it. - template - const bool hasSignature() const; - - //set 'no' object to call static method. (takes no parameter) - const MethodInvoker on() const; - - //set 'target' object on which the functor associated with this will be called. - const MethodInvoker on(const Instance& pTarget) const; - - - /* @method: operator()() - @return: lambda - * accepts no arguments for 'target', since associated functor is static-member-functions. - * returns a lambda, which forwards the call to finally call the associated static-member-function functor. - * provides syntax like,'method()(params...)', first'()' is empty & second'()' takes the actual params. - */ constexpr auto operator()() const - { - return [this](auto...params) { - return Function::operator()(params...); - }; - } - - - /* @method: operator()(const Instance&) - @param: const Instance& (target object) - @return: lambda - * accepts 'pTarget', which contains the actual object on which the member-function functor associated with 'this' is invoked. - * returns a lambda, which forwards the call to finally call the associated non-static-member-function functor. - * provides syntax like, 'method(pTarget)(params...)', keeping the target & params seperate. - */ constexpr auto operator()(const Instance& pTarget) const - { - return [&](auto...params)->RStatus - { - if (pTarget.isEmpty()) { - //if the target is empty. - return RStatus(Error::EmptyInstance); - } - - if (pTarget.getTypeId() != getRecordTypeId()) { - //if the target type-id & type-id of the 'class/struct' owner of the associated functor do not match. - return RStatus(Error::InstanceTypeMismatch); - } - - switch (pTarget.getQualifier()) - { - //if the target is non-const, const & non-const member function can be invoked on it. - case TypeQ::Mute: return invoke(pTarget, params...); - - //if the target is const, only const member function can be invoked on it. - case TypeQ::Const: return invokeConst(pTarget, params...); - } - - //only an empty 'Instance' will have TypeQ::None. - return RStatus(Error::EmptyInstance); - }; - } - - //deletes base class 'operator()()' - template - RStatus operator()(_args...) const noexcept = delete; - - //deletes base class 'call()' - template - RStatus call(_args...) const noexcept = delete; - - //friends :) - template - friend class MethodInvoker; - friend detail::CxxReflection; - friend Record; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/Method.hpp b/ReflectionTemplateLib/access/inc/Method.hpp deleted file mode 100644 index 40ea066e..00000000 --- a/ReflectionTemplateLib/access/inc/Method.hpp +++ /dev/null @@ -1,184 +0,0 @@ -#pragma once -#include "Method.h" - -namespace rtl -{ - namespace access - { - //MethodInvoker, holds const-ref of the 'Method' and 'Instance' on which it will be invoked. - template - inline MethodInvoker<_type>::MethodInvoker(const Method& pMethod, const Instance& pTarget) - : m_method(pMethod) - , m_target(pTarget) { - } - - - /* @method: call() - @params: params... (corresponding to functor associated with 'm_method') - @return: RStatus, indicating success of the reflected call. - * invokes non-static-member-function functor associated with 'm_method' on object 'm_target'. - */ template - template - inline RStatus MethodInvoker<_type>::call(_args ...params) const noexcept - { - if (m_target.isEmpty()) { - //if the target is empty. - return RStatus(Error::EmptyInstance); - } - - if (m_target.getTypeId() != m_method.getRecordTypeId()) { - //if the m_target's type-id & type-id of the 'class/struct' owner of the associated functor(m_method's) do not match. - return RStatus(Error::InstanceTypeMismatch); - } - - switch (m_target.getQualifier()) - { - //if the target is non-const, const & non-const both type member-function can be invoked on it. - case TypeQ::Mute: return m_method.invoke(m_target, params...); - - //if the m_target is const, only const member function can be invoked on it. - case TypeQ::Const: return m_method.invokeConst(m_target, params...); - } - - //only an empty 'Instance' will have TypeQ::None. - return RStatus(Error::EmptyInstance); - } - - //MethodInvoker, holds only 'Method' associated with a static-member-function. - inline MethodInvoker::MethodInvoker(const Method& pMethod) - :m_method(pMethod) { - } - - - template - inline RStatus MethodInvoker::call(_args ...params) const noexcept - { - //invokes the static-member-function functor associated with 'm_method'. no need of 'm_target' as other 'MethodInvoker'. - return m_method.invokeStatic(params...); - } - } - - - namespace access - { - /* @method: on() - @return: MethodInvoker - * accepts no arguments for 'target', since associated functor is static-member-functions. - */ inline const MethodInvoker Method::on() const - { - return MethodInvoker(*this); - } - - - /* @method: on() - @return: MethodInvoker - * accepts 'pTarget', which contains the actual object on which the member-function functor associated with 'this' is invoked. - */ inline const MethodInvoker Method::on(const Instance& pTarget) const - { - return MethodInvoker(*this, pTarget); - } - - - /* @method: invokeCtor() - @params: variable arguments. - @return: RStatus - * calls the constructor with given arguments. - */ template - inline RStatus Method::invokeCtor(_args ...params) const - { - return Function::operator()(params...); - } - - - /* @method: invokeStatic() - @params: variable arguments. - @return: RStatus - * with given arguments, calls the static-member-function functor associated with this 'Method'. - */ template - inline RStatus Method::invokeStatic(_args ...params) const - { - return Function::operator()(params...); - } - - - /* @method: hasSignature() - @return: bool - * checks if the member-function functor associated with this 'Method', takes zero arguments or not. - */ template<> - inline const bool Method::hasSignature() const - { - switch (getQualifier()) - { - case TypeQ::None: return Function::hasSignature(); - case TypeQ::Mute: return (hasSignatureId(detail::MethodContainer::getContainerId()) != -1); - case TypeQ::Const: return (hasSignatureId(detail::MethodContainer::getContainerId()) != -1); - } - return false; - } - - - /* @method: hasSignature<...>() - @params: template params, <_arg0, ..._args> (expects at least one args- _args0) - @return: bool - * checks if the member-function functor associated with this 'Method', takes template specified arguments set or not. - */ template - inline const bool Method::hasSignature() const - { - switch (getQualifier()) - { - case TypeQ::None: return Function::hasSignature<_arg0, _args...>(); - case TypeQ::Mute: return (hasSignatureId(detail::MethodContainer::getContainerId()) != -1); - case TypeQ::Const: return (hasSignatureId(detail::MethodContainer::getContainerId()) != -1); - } - return false; - } - - - /* @method: invokeConst() - @params: 'pTarget' (on which the method to be invoked), 'params...' (method arguments) - @return: 'RStatus', indicating the success of reflected method call. - * invokes only a const-member-function functor. - */ template - inline RStatus Method::invokeConst(const Instance& pTarget, _args ...params) const - { - //if the given argument's associated MethodContainer contains such member-functor, then make the call. - const std::size_t& index = hasSignatureId(detail::MethodContainer::getContainerId()); - if (index != -1) - { - //make the call. - return detail::MethodContainer::forwardCall(pTarget.get(), index, params...); - } - else { - //if the associated MethodContainer contains no such member-functor, check if such functor is present in container holding non-const functors. - const std::size_t& index = hasSignatureId(detail::MethodContainer::getContainerId()); - if (index != -1) { - //if yes, then return error indicating such 'functor' is present but can be called on only non-const 'Instance'. - return RStatus(Error::InstanceConstMismatch); - } - } - //return this error if the given argument's associated MethodContainer not found (const/non-const both). - return RStatus(Error::SignatureMismatch); - } - - - /* @method: invokeConst() - @params: 'pTarget' (on which the method to be invoked), 'params...' (method arguments) - @return: 'RStatus', indicating the success of reflected method call. - * can invoke a 'const' or non-const-member-function functor. - */ template - inline RStatus Method::invoke(const Instance& pTarget, _args ...params) const - { - //if the given argument's associated MethodContainer contains such member-functor, then make the call. - const std::size_t& index = hasSignatureId(detail::MethodContainer::getContainerId()); - if (index != -1) - { - //make the call. - return detail::MethodContainer::forwardCall(pTarget.get(), index, params...); - } - else { - //if no such member-functor is found in non-const MethodContainer, check if such functor is present in const MethodContainer and call. - return invokeConst(pTarget, params...); - } - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/RStatus.h b/ReflectionTemplateLib/access/inc/RStatus.h deleted file mode 100644 index d61d8be9..00000000 --- a/ReflectionTemplateLib/access/inc/RStatus.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include -#include "Constants.h" -#include "TypeId.h" - -namespace rtl -{ - namespace access - { - /* @class: RStatus - * Every reflection call made, returns a RStatus object. - * it contains the error status of the call, defined by enum rtl::Error (in Constants.h) - * indicates all possible failure-errors that could happen on calling reflected funtion/method/constructor. - * it also contains the return value/object from the reflected function/method call wrapped under std::any. - */ class RStatus - { - //indicates the reflection call status error - const Error m_callStatus; - - //indicates whether the returned value from reflected call is const/non-const. - const TypeQ m_typeQualifier; - - //contains the return value of the from reflected call. Type erased. - const std::any m_returnObj; - - //type-id of the return value. - const std::size_t m_typeId; - - public: - - //used when the reflected call doesn't have any return value, or in case of call failure. - RStatus(const Error pCallStatus); - - //used when the reflected call returns a value, called only in case of no call failure. - RStatus(const std::any& pRetObj, const std::size_t pTypeId, const TypeQ pQualifier); - - GETTER(std::any, Return, m_returnObj) - GETTER(std::size_t, TypeId, m_typeId) - GETTER(TypeQ, Qualifier, m_typeQualifier) - - //RStatus object converted to bool based on call succes or not. - operator bool() const { - //Error::None, reflected call successful. - return (m_callStatus == Error::None); - } - - //RStatus object can be directly checked agains any error-code. - const bool operator==(const Error pError) const { - return (m_callStatus == pError); - } - - //check if the returned object is of certain type. expected type must be passed as template param. - //if the expected type is 'const', must be used as templeate parameter. - template - constexpr const bool isOfType() const { - return (detail::TypeId<_type>::get() == m_typeId); - } - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/Record.h b/ReflectionTemplateLib/access/inc/Record.h deleted file mode 100644 index 2ae78ae4..00000000 --- a/ReflectionTemplateLib/access/inc/Record.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Method.h" - -namespace rtl { - - //forward decls - namespace detail { - class CxxReflection; - } - - namespace access - { - //forward decls - class Method; - class RStatus; - class Instance; - - /* @class: Record - * represents a reflected class/struct. - * contains registered member-functions as 'Method' objects. - * provides interface to access methods by name. - * provides interface to construct instances of the class/struct using the registered constructors. - */ class Record - { - const std::string m_recordName; - - mutable std::unordered_map< std::string, access::Method > m_methods; - - Record(const std::string& pRecordName); - - std::unordered_map< std::string, access::Method >& getFunctionsMap() const; - - public: - - Record() = delete; - - std::optional getMethod(const std::string& pMethod) const; - - //creates dynamic instance, calling copy ctor, using new. - const std::pair clone(Instance& pOther) const; - - //creates dynamic instance, using new. - template - const std::pair instance(_ctorArgs ...params) const; - - const std::unordered_map< std::string, access::Method >& getMethodMap() const; - - //only class which can create objects of this class & manipulates 'm_methods'. - friend class detail::CxxReflection; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/inc/Record.hpp b/ReflectionTemplateLib/access/inc/Record.hpp deleted file mode 100644 index 42a47fec..00000000 --- a/ReflectionTemplateLib/access/inc/Record.hpp +++ /dev/null @@ -1,52 +0,0 @@ - -#include "Record.h" -#include "RStatus.h" -#include "Method.h" -#include "Constants.h" -#include "Instance.h" - -namespace rtl { - - namespace access - { - /* @method: instance - @param: ...params (any number/type of arguments) - @return: std::pair - * calls the constructor of the calss/struct represented by this 'Record' object. - * returns the dynamically allocated object of the calss/struct along with the status. - * only default or any other overloaded constructor is called, except copy (for that check, Record::clone()). - * if the signature(...params) did not match any registered ctor, Error::SignatureMismatch is returned as RStatus. - * if no constructor found, Error::ConstructorNotFound is returned as RStatus. - * in case of reflected call failure, empty 'Instance' will be returned. - * on success Error::None will be returned along with the newly constructed object wrapped under 'Instance' (type erased). - */ template - inline const std::pair Record::instance(_ctorArgs ...params) const - { - const auto& itr = m_methods.find(CtorName::ctor(m_recordName)); - - //if registered constructor is found for the class/struct represented by this 'Record' object. - if (itr != m_methods.end()) { - - //invoke the constructor, forwarding the arguments. - const RStatus& status = itr->second.invokeCtor(params...); - - //if status is 'true', object construction is successful. - if (status) { - - //get the destructor 'Function', which is gauranteed to be present, if at least one constructor is registered. - const Function dctor = *getMethod(CtorName::dctor(m_recordName)); - - //construct the 'Instance' object, assigning the destructor as custom deleter, its lifetime is managed via std::shared_ptr. - return std::make_pair(status, Instance(status.getReturn(), status, dctor)); - } - //if reflected call fails, return with empty 'Instance'. - return std::make_pair(status, Instance()); - } - else { - - //if no constructor found, return with empty 'Instance'. - return std::make_pair(RStatus(Error::ConstructorNotFound), Instance()); - } - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/src/CMakeLists.txt b/ReflectionTemplateLib/access/src/CMakeLists.txt deleted file mode 100644 index 3421a930..00000000 --- a/ReflectionTemplateLib/access/src/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# Create a variable containing the source files for your target -set(LOCAL_SOURCES - "${CMAKE_CURRENT_LIST_DIR}/CxxMirror.cpp" - "${CMAKE_CURRENT_LIST_DIR}/CxxMirrorToJson.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Function.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Instance.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Method.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Record.cpp" - "${CMAKE_CURRENT_LIST_DIR}/RStatus.cpp" -) - -SET(COMMON_HEADERS - "${PROJECT_SOURCE_DIR}/common/Constants.h" - "${PROJECT_SOURCE_DIR}/common/RTLibInterface.h" -) - -SET(LOCAL_HEADERS - "${PROJECT_SOURCE_DIR}/access/inc/CxxMirror.h" - "${PROJECT_SOURCE_DIR}/access/inc/CxxMirrorToJson.h" - "${PROJECT_SOURCE_DIR}/access/inc/Function.h" - "${PROJECT_SOURCE_DIR}/access/inc/Function.hpp" - "${PROJECT_SOURCE_DIR}/access/inc/Instance.h" - "${PROJECT_SOURCE_DIR}/access/inc/Method.h" - "${PROJECT_SOURCE_DIR}/access/inc/Method.hpp" - "${PROJECT_SOURCE_DIR}/access/inc/Record.h" - "${PROJECT_SOURCE_DIR}/access/inc/Record.hpp" - "${PROJECT_SOURCE_DIR}/access/inc/RStatus.h" -) - -# Add any additional source files if needed -target_sources(ReflectionTemplateLib - PRIVATE - "${LOCAL_HEADERS}" - "${COMMON_HEADERS}" - "${LOCAL_SOURCES}" -) - - -SOURCE_GROUP("Source Files\\Access" FILES ${LOCAL_SOURCES}) -SOURCE_GROUP("Header Files\\Access" FILES ${LOCAL_HEADERS}) \ No newline at end of file diff --git a/ReflectionTemplateLib/access/src/CxxMirror.cpp b/ReflectionTemplateLib/access/src/CxxMirror.cpp deleted file mode 100644 index 26d9db53..00000000 --- a/ReflectionTemplateLib/access/src/CxxMirror.cpp +++ /dev/null @@ -1,89 +0,0 @@ - -#include "Record.h" -#include "Function.h" -#include "Method.h" -#include "CxxMirror.h" -#include "Constants.h" - -namespace rtl { - - namespace access - { - /* @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({ Reflect().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) { - } - - - /* @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 - { - return getRecord(NAMESPACE_GLOBAL, pRecord); - } - - - /* @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 - { - return getFunction(NAMESPACE_GLOBAL, pFunction); - } - - - /* @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 - { - const auto& nsRecordMap = getNamespaceRecordMap(); - const auto& itr = nsRecordMap.find(pNameSpace); - if (itr != nsRecordMap.end()) - { - const auto& recordMap = itr->second; - const auto& itr0 = recordMap.find(pRecord); - if (itr0 != recordMap.end()) { - return std::make_optional(itr0->second); - } - } - 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 - { - const auto& nsFunctionMap = getNamespaceFunctionsMap(); - const auto& itr = nsFunctionMap.find(pNameSpace); - if (itr != nsFunctionMap.end()) - { - const auto& functionMap = itr->second; - const auto& itr0 = functionMap.find(pFunction); - if (itr0 != functionMap.end()) { - return std::make_optional(itr0->second); - } - } - return std::nullopt; - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/src/CxxMirrorToJson.cpp b/ReflectionTemplateLib/access/src/CxxMirrorToJson.cpp deleted file mode 100644 index cbe2cf73..00000000 --- a/ReflectionTemplateLib/access/src/CxxMirrorToJson.cpp +++ /dev/null @@ -1,107 +0,0 @@ - -#include -#include - -#include "Method.h" -#include "Record.h" -#include "Function.h" -#include "CxxMirror.h" -#include "CxxMirrorToJson.h" - -using namespace rtl::access; -using namespace rtl::detail; - -namespace -{ - const std::string toJson(const FunctorId& pFunctorId) - { - std::stringstream sout; - sout << "{\"hash_code\": \"" << std::to_string(pFunctorId.getHashCode()) << "\","; - sout << "\"signature\": \"" << pFunctorId.getSignatureStr() << "\"}"; - return sout.str(); - } - - const std::string toJson(const Function& pFunction) - { - std::stringstream sout; - const auto& functors = pFunction.getFunctors(); - const std::string& record = pFunction.getRecordName(); - const std::string& nmspace = pFunction.getNamespace(); - - sout << "{" << (record.empty() ? "\"function\"" : "\"method\"") << ": \"" << pFunction.getFunctionName() << "\","; - if (nmspace != rtl::NAMESPACE_GLOBAL) { - sout << "\"namespace\": \"" << nmspace << "\","; - } - if (!record.empty()) { - sout << "\"record\": \"" << record << "\","; - } - - int index = 0; - sout << "\"functorId\": ["; - for (const auto& funtorId : functors) { - sout << toJson(funtorId); - if (++index < functors.size()) { - sout << ", "; - } - } - sout << "]}"; - return sout.str(); - } - - - const std::string toJson(CxxMirror& pCxxMirror) - { - std::stringstream sout; - sout << "["; - bool atLeastOne = false; - const auto& nsfuncMap = pCxxMirror.getNamespaceFunctionsMap(); - for (const auto& itr : nsfuncMap) - { - for (const auto& itr0 : itr.second) - { - const std::string& functionStr = toJson(itr0.second); - sout << functionStr << ","; - atLeastOne = true; - } - } - - const auto& recfuncMap = pCxxMirror.getNamespaceRecordMap(); - for (const auto& itr : recfuncMap) - { - for (const auto& itr0 : itr.second) - { - for (const auto& itr1 : itr0.second.getMethodMap()) - { - const std::string& methodStr = toJson(itr1.second); - sout << methodStr << ","; - atLeastOne = true; - } - } - } - - std::string str = sout.str(); - if (str.back() == ',') str.pop_back(); - str.push_back(']'); - return str; - } -} - - -namespace rtl -{ - void CxxMirrorToJson::dump(CxxMirror& pCxxMirror, const std::string& pFilePathStr) - { - std::string fileStr = pFilePathStr; - std::replace(fileStr.begin(), fileStr.end(), '\\', '/'); - std::fstream fout(fileStr, std::ios::out); - if (!fout.is_open()) { - return; - } - fout << toJson(pCxxMirror); - fout.flush(); - fout.close(); - if (fout.fail() || fout.bad()) { - return; - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/src/Function.cpp b/ReflectionTemplateLib/access/src/Function.cpp deleted file mode 100644 index 0402d4ef..00000000 --- a/ReflectionTemplateLib/access/src/Function.cpp +++ /dev/null @@ -1,84 +0,0 @@ - -#include "Function.h" - -namespace rtl { - - namespace access - { - /* @constructor: Function() - @params: pNamespace - given namespace while registering the type. - * pRecord - given class/struct name, empty if this 'Function' represents a non-member functor - * pFunction - given name of the function as string. - * pFunctorId - 'FunctorId', generated for every functor being registered. - * pRecordTypeId - type id of class/struct if the functor is member-function, '0' for non-member-functions. - * pQualifier - whether the member-function is const or non-const. TypeQ::None for non-member-functions. - * 'Function' object is created for every functor (member/non-member) being registered. - */ Function::Function(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction, const detail::FunctorId& pFunctorId, - const std::size_t pRecordTypeId, const TypeQ pQualifier) - : m_qualifier(pQualifier) - , m_recordTypeId(pRecordTypeId) - , m_record(pRecord) - , m_function(pFunction) - , m_namespace(pNamespace) - , m_functorIds({ pFunctorId }) { - } - - - /* @constructor: Function() - @params: pOther - 'Function' object associated with a constructor. - * pFunctorId - 'FunctorId', object associated with a destructor. - * pFunctorName - name of the destructor. - * this constructor is only called to create 'Function' object associated with destructor. - * the destructor 'FunctorId' is added to the 'Function' object associated with a constructor while registration. - * the very first registration of constructor adds the destructor lambda in the functor-container and sends its - 'FunctorId' with the 'Function' object associated with a constructor. - */ Function::Function(const Function& pOther, const detail::FunctorId& pFunctorId, - const std::string& pFunctorName) - : m_qualifier(pOther.m_qualifier) - , m_recordTypeId(pOther.m_recordTypeId) - , m_record(pOther.m_record) - , m_function(pFunctorName) - , m_namespace(pOther.m_namespace) - , m_functorIds({ pFunctorId }) { - } - - - /* @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. - */ 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) { - if (functorId.getSignatureId() == pSignatureId) { - return functorId.getIndex(); - } - } - return -1; - } - - - /* @method: addOverload() - @param: 'Function' object - * every 'Function' object produced while registration will have a single 'FunctorId' object, except constructors. - * for overloads, registered with the same name, the 'FunctorId' from the 'pOtherFunc' object will be added to this. - * if the same functor is registered again with the same name, it will be ignored. - */ void Function::addOverload(const Function& pOtherFunc) const - { - const std::size_t& otherFuncSignId = pOtherFunc.m_functorIds[0].getSignatureId(); - //simple linear-search, efficient for small set of elements. - for (const auto& functorId : m_functorIds) { - if (functorId.getSignatureId() == otherFuncSignId) { - return; //ignore and return since its already registered. - } - } - - //add the 'functorId' of the overloaded functor. - m_functorIds.push_back(pOtherFunc.m_functorIds[0]); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/src/Instance.cpp b/ReflectionTemplateLib/access/src/Instance.cpp deleted file mode 100644 index 649c9e9d..00000000 --- a/ReflectionTemplateLib/access/src/Instance.cpp +++ /dev/null @@ -1,100 +0,0 @@ - -#include - -#include "TypeId.hpp" -#include "RStatus.h" -#include "Instance.h" -#include "Function.hpp" - -namespace { - - //global, used to assign to shared pointer with custom deleter. - static std::size_t g_instanceCount = 0; -} - -namespace rtl { - - namespace access - { - /* @method: isEmpty() - @return: bool - * checks if std::any object has value or not. - * objects constructed via reflection is held by std::any (instead of void*) - * if reflected constructor call fails, 'Insatnce' object returned with empty 'm_anyObject'. - */ const bool Instance::isEmpty() const { - return (!m_anyObject.has_value()); - } - - - /* @method: isConst() - @return: bool - * tells how the object held by 'm_anyObject' should be treated. - * every object constructed via reflected constructor call is a non-const object pointer. - * it can be made to treated as const by calling Instance::makeConst(). - */ const bool Instance::isConst() const { - return (m_qualifier == TypeQ::Const); - } - - - /* @method: getInstanceCount() - @return: std::size_t (g_instanceCount). - * returns the number of objects constructed via reflected constructor call. - * g_instanceCount is incremented only on successful reflected constructor call. - * g_instanceCount is decremented only when reflected destructor call. - */ std::size_t Instance::getInstanceCount() { - return g_instanceCount; - } - - - /* @method: makeConst() - @param: bool, (true by default) - * objects constructed via reflected constructor call, held by 'm_anyObject' as a non-const object pointer. - * 'm_qualifier' indicates how the object should be treated- as const or non-const. - * if 'm_qualifier' is TypeQ::Const, only const member function will be called on the object held by 'm_anyObject' - * if 'm_qualifier' is TypeQ::Mute,, only non-const member function will be called on the objject held by 'm_anyObject' - */ void Instance::makeConst(const bool& pCastAway) { - m_qualifier = (pCastAway ? TypeQ::Mute : TypeQ::Const); - } - - /* @constructor: Instance() - * creates 'Instance' with empty 'm_anyObject'. - * 'm_typeId' will be zero which indicates no-type. - * this constructor is called only when reflected constructor call fails. - */ Instance::Instance() - : m_qualifier(TypeQ::None) - , m_typeId(detail::TypeId<>::None) { - } - - //copy-constructor, public access. - Instance::Instance(const Instance& pOther) - : m_qualifier(pOther.m_qualifier) - , m_typeId(pOther.m_typeId) - , m_anyObject(pOther.m_anyObject) - , m_destructor(pOther.m_destructor) { - } - - - /* @constructor: Instance() - @params: 'const std::any&', contains pointer to the allocated object via reflection constructor call. - * 'const RStatus&', status returned via reflection constructor call. - * 'const Function&', callable 'Function', calls the reflecetd destructor. - * creates 'Instance' containing pointer to the allocated object via reflection constructor call. - * this constructor is called only on successful object creation on heap via reflected constructor call. - * 'm_destructor' (shared_ptr) is given a custom deleter, which calls destructor on the allocated(via reflection) object. - * 'm_destructor' holds a dummy void* pointer (address of 'g_instanceCount'), for which is a primitive type. - * this is done to avoid dynamic allocation of 'Instance' object to manage it with 'shared_ptr'. - * shared_ptr('m_destructor') holds the dummy void* but calls the actual destructor which destroys the object constructed(via reflection). - */ Instance::Instance(const std::any& pRetObj, const RStatus& pStatus, const Function& pDctor) - : m_qualifier(TypeQ::Mute) - , m_typeId(pStatus.getTypeId()) - , m_anyObject(pRetObj) - , m_destructor(&g_instanceCount, [=](void* ptr) - { - pDctor(pRetObj); - (*static_cast(ptr))--; - }) - { - g_instanceCount++; - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/src/Method.cpp b/ReflectionTemplateLib/access/src/Method.cpp deleted file mode 100644 index 89e2f06a..00000000 --- a/ReflectionTemplateLib/access/src/Method.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -#include "Method.h" - -namespace rtl { - - namespace access - { - Method::Method(const Function& pFunction) - : Function(pFunction) { - } - - - Method::Method(const Function& pFunction, const detail::FunctorId& pFunctorId, const std::string& pFunctorName) - : Function(pFunction, pFunctorId, pFunctorName) { - } - - - Method Method::getDestructorMethod(const Function& pFunction, const detail::FunctorId& pFunctorId) - { - const std::string dctorStr = CtorName::dctor(pFunction.getRecordName()); - return Method(pFunction, pFunctorId, dctorStr); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/src/RStatus.cpp b/ReflectionTemplateLib/access/src/RStatus.cpp deleted file mode 100644 index 06fd8988..00000000 --- a/ReflectionTemplateLib/access/src/RStatus.cpp +++ /dev/null @@ -1,23 +0,0 @@ - -#include "RStatus.h" - -namespace rtl { - - namespace access { - - RStatus::RStatus(const Error pCallStatus) - : m_callStatus(pCallStatus) - , m_typeQualifier(TypeQ::None) - //no type is represented by value '0'. - , m_typeId(detail::TypeId<>::None) { - } - - - RStatus::RStatus(const std::any& pRetObj, const std::size_t pTypeId, const TypeQ pQualifier) - : m_callStatus(Error::None) - , m_typeQualifier(pQualifier) - , m_returnObj(pRetObj) - , m_typeId(pTypeId) { - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/access/src/Record.cpp b/ReflectionTemplateLib/access/src/Record.cpp deleted file mode 100644 index 4df8986d..00000000 --- a/ReflectionTemplateLib/access/src/Record.cpp +++ /dev/null @@ -1,129 +0,0 @@ - -#include "Record.h" -#include "Method.h" -#include "RStatus.h" -#include "Instance.h" -#include "Constants.h" -#include "Function.hpp" - -namespace rtl { - - namespace access - { - Record::Record(const std::string& pRecordName) - : m_recordName(pRecordName) - { - } - - - /* @method: getFunctionsMap - @param: none - @return: std::unordered_map< std::string, access::Method >& - * get set of all registered methods contained by the class/struct represented by this 'Record'. - * provides 'mutable' map, which only detail::CxxReflection class can access. - */ std::unordered_map< std::string, access::Method >& Record::getFunctionsMap() const - { - return m_methods; - } - - - /* @method: getMethodMap - @param: none - @return: const std::unordered_map< std::string, access::Method >& - * get set of all registered methods contained by the class/struct represented by this 'Record'. - * provides 'const' map, publicly accessible. - */ const std::unordered_map& Record::getMethodMap() const - { - return m_methods; - } - - - /* @method: getMethod - @param: const std::string& (name of the method) - @return: std::optional - * if the method isn't found by the given name, std::nullopt is returned. - */ std::optional Record::getMethod(const std::string& pMethod) const - { - const auto& itr = m_methods.find(pMethod); - if (itr != m_methods.end()) { - return std::optional(itr->second); - } - return std::nullopt; - } - - - /* @method: clone - @param: Instance& (containing class/struct's object represented by this 'Record') - @return: std::pair (RStatus: call success or not, Instance: containing copy constructed object) - * calls copy constructor of class/struct represented by this 'Record' - * creates copy of the object wrapped inside 'Instance' object. - * returns 'RStatus' object indicating the success of the reflection call with other infos. - */ const std::pair Record::clone(Instance& pOther) const - { - //validate the source object, should not be empty. - if (pOther.isEmpty()) { - //return empty instance with error status. - return std::make_pair(RStatus(Error::EmptyInstance), Instance()); - } - - const std::string& dctor = CtorName::dctor(m_recordName); - const std::string& copyStr = CtorName::copy(m_recordName); - const std::string& constCopyStr = CtorName::constCopy(m_recordName); - - std::optional destructor = getMethod(dctor); - std::optional constCopyCtor = getMethod(constCopyStr); - - //if the object is const, only copy constructor with 'const&' can be called on it. - if (pOther.isConst()) - { - if (constCopyCtor) - { - /* type of the object wrapped under source 'Instance' should match with type of the class/struct - associated by constructor ('Function')object. - */ if (constCopyCtor->getRecordTypeId() != pOther.getTypeId()) { - //if source instance & ctor type didn't match, return empty instance with error status. - return std::make_pair(RStatus(Error::InstanceTypeMismatch), Instance()); - } - //object and type validated. call the const-copy-constructor. - RStatus status = (*constCopyCtor)(pOther.get()); - return std::make_pair(status, Instance(status.getReturn(), status, *destructor)); - } - else { - //if the object is 'const' and no constructor found accepting 'const&' - return std::make_pair(RStatus(Error::ConstCopyConstructorNotFound), Instance()); - } - } - else { - //if the source 'Instance' is non-const, find copy-constructor taking non-const ref. - std::optional copyCtor = getMethod(copyStr); - if (copyCtor) - { - /* type of the object wrapped under source 'Instance' should match with type of the class/struct - associated by constructor ('Function')object. - */ if (copyCtor->getRecordTypeId() != pOther.getTypeId()) { - //if source instance & ctor type didn't match, return empty instance with error status. - return std::make_pair(RStatus(Error::InstanceTypeMismatch), Instance()); - } - //object and type validated. call the non-const-copy-constructor. - RStatus status = (*copyCtor)(pOther.get()); - return std::make_pair(status, Instance(status.getReturn(), status, *destructor)); - } - //if copy-constructor taking non-const ref not found, and with const-ref found, use that copy constructor. - else if (constCopyCtor) - { - /* type of the object wrapped under source 'Instance' should match with type of the class/struct - associated by constructor ('Function')object. - */ if (constCopyCtor->getRecordTypeId() != pOther.getTypeId()) { - //if source instance & ctor type didn't match, return empty instance with error status. - return std::make_pair(RStatus(Error::InstanceTypeMismatch), Instance()); - } - //object and type validated. call the const-copy-constructor. - RStatus status = (*constCopyCtor)(pOther.get()); - return std::make_pair(status, Instance(status.getReturn(), status, *destructor)); - } - } - //if no registered copy constructor found, return empty instance with error status. - return std::make_pair(RStatus(Error::CopyConstructorNotFound), Instance()); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/CMakeLists.txt b/ReflectionTemplateLib/builder/CMakeLists.txt deleted file mode 100644 index 7956d660..00000000 --- a/ReflectionTemplateLib/builder/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Create a variable containing the source files for your target - -SET(COMMON_HEADERS - "${PROJECT_SOURCE_DIR}/common/Constants.h" -) - -SET(LOCAL_HEADERS - "${CMAKE_CURRENT_LIST_DIR}/inc/ConstructorBuilder.h" - "${CMAKE_CURRENT_LIST_DIR}/inc/ConstructorBuilder.hpp" - "${CMAKE_CURRENT_LIST_DIR}/inc/Builder.h" - "${CMAKE_CURRENT_LIST_DIR}/inc/Builder.hpp" - "${CMAKE_CURRENT_LIST_DIR}/inc/RecordBuilder.h" - "${CMAKE_CURRENT_LIST_DIR}/inc/RecordBuilder.hpp" - "${CMAKE_CURRENT_LIST_DIR}/inc/Reflect.h" - "${CMAKE_CURRENT_LIST_DIR}/inc/Reflect.hpp" -) - -# Add any additional source files if needed -target_sources(ReflectionTemplateLib - PRIVATE - "${LOCAL_HEADERS}" - "${COMMON_HEADERS}" -) - -SOURCE_GROUP("Header Files\\Builder" FILES ${LOCAL_HEADERS}) \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/inc/Builder.h b/ReflectionTemplateLib/builder/inc/Builder.h deleted file mode 100644 index 88818597..00000000 --- a/ReflectionTemplateLib/builder/inc/Builder.h +++ /dev/null @@ -1,182 +0,0 @@ -#pragma once - -#include "Function.h" -#include "ReflectionBuilder.hpp" - -namespace rtl { - - namespace builder - { - /* @struct: Builder - @param: specialized with TypeQ, - * TypeQ::Mute - provides interface to register member funtion. - * TypeQ::Const - provides interface to register const-member funtions. - * TypeQ::None - provides interface to register non-member and static member funtions. - @param: - * _signature: arguments types of functions pointers or constructors (auto deduced/explicitly specified). - * provides interface to register all sort of functions, methods & constructors. - * every specialization has a 'build()' function, which accepts a function pointer. - * function pointer can be non-member or member(static/const/non-const) functions. - */ template - struct Builder; - } - - - namespace builder - { - /* @struct: Builder - * specialized specifically to register overloaded non-member & static member functions with no arguments. - * Objects of this class will be created & returned by these functions, - * - Reflect::function(..) - * - RecordBuilder<_recordType>::methodStatic(..) - * with template parameter is only 'void', explicitly specified. - */ template<> - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build(_returnType(*pFunctor)()) const; - }; - - - /* @struct: Builder - * specialized specifically to register overloaded non-member & static member functions with any arguments. - * Objects of this class will be created & returned by these functions, - * - Reflect::function<...>(..) - * - RecordBuilder<_recordType>::methodStatic<...>(..) - * with template parameters can be anything, explicitly specified. - */ template - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build(_returnType(*pFunctor)(_signature...)) const; - }; - - - /* @struct: Builder - * specialized specifically to register non-member functions with any signature and with no overloads. - * Objects of this class will be created & returned by these functions, - * - Reflect::function(..) - * - RecordBuilder<_recordType>::methodStatic(..) - * with no template parameters specified. - */ template<> - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build(_returnType(*pFunctor)(_signature...)) const; - }; - } - - - namespace builder - { - /* @struct: Builder - * specialized specifically to register overloaded const-member-functions with no arguments. - * Objects of this class will be created & returned by function, - * - RecordBuilder<_recordType>::methodConst(..) - * with template parameters is only 'void' explicitly specified. - */ template<> - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build(_returnType(_recordType::* pFunctor)() const) const; - }; - - - /* @struct: Builder - * specialized specifically to register overloaded const-member-functions with any arguments. - * Objects of this class will be created & returned by function, - * - RecordBuilder<_recordType>::methodConst<...>(..) - * with template parameters can be anything, explicitly specified. - */ template - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build(_returnType(_recordType::* pFunctor)(_signature...) const) const; - }; - - - /* @struct: Builder - * specialized specifically to register non-overloaded const-member-functions with any arguments. - * Objects of this class will be created & returned by function, - * - RecordBuilder<_recordType>::methodConst() - * with no template parameters specified. - */ template<> - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build(_returnType(_recordType::* pFunctor)(_signature...) const) const; - }; - } - - - namespace builder - { - /* @struct: Builder - * specialized specifically to register overloaded non-const-member-functions with no arguments. - * Objects of this class will be created & returned by function, - * - RecordBuilder<_recordType>::method(..) - * with template parameters is only 'void' explicitly specified. - */ template<> - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build(_returnType(_recordType::* pFunctor)()) const; - }; - - - /* @struct: Builder - * specialized specifically to register overloaded non-const-member-functions with no arguments. - * Objects of this class will be created & returned by function, - * - RecordBuilder<_recordType>::method(..) - * with template parameters is only 'void' explicitly specified. - */ template - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build(_returnType(_recordType::* pFunctor)(_signature...)) const; - }; - - - /* @struct: Builder - * specialized specifically to register non-overloaded non-const-member-functions and constructors with any arguments. - * Objects of this class will be created & returned by function, - * - RecordBuilder<_recordType>::method() - with no template parameters specified. - * - RecordBuilder<_recordType>::constructor<...>() - template parameters can be anything or none, explicitly specified. - */ template<> - struct Builder : protected detail::ReflectionBuilder - { - Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - template - constexpr const access::Function build() const; - - template - constexpr const access::Function build(_returnType(_recordType::* pFunctor)(_signature...)) const; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/inc/Builder.hpp b/ReflectionTemplateLib/builder/inc/Builder.hpp deleted file mode 100644 index 46bba871..00000000 --- a/ReflectionTemplateLib/builder/inc/Builder.hpp +++ /dev/null @@ -1,231 +0,0 @@ -#pragma once - -#include "Builder.h" - -namespace rtl { - - namespace builder - { - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - /* @method: build() - @param: _returnType(*)(_signature...) - @return: 'access::Function' object. - * accepts all non-member and static-member function pointer. - * called on the objects returned by 'Reflect::function()' & 'RecordBuilder<_recordType>::methodStatic(..)'. - * template params are auto deduced from the function pointer passed. - */ template - inline constexpr const access::Function Builder::build(_returnType(*pFunctor)(_signature...)) const - { - return buildFunctor(pFunctor); - } - } - - - namespace builder - { - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - /* @method: build() - @param: _returnType(*)() - @return: 'access::Function' object. - * accepts a non-member or static-member function pointer with no arguments. - * called on objects returned by 'Reflect::function(..)' & 'RecordBuilder<_recordType>::methodStatic(..)' - * template param 'void' is explicitly specified. - */ template - inline constexpr const access::Function Builder::build(_returnType(*pFunctor)()) const - { - return buildFunctor(pFunctor); - } - } - - - namespace builder - { - template - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - - /* @method: build() - @param: _returnType(*)(_signature...) - @return: 'access::Function' object. - * it accepts a non-member or static-member function pointer. - * called on objects returned by 'Reflect::function<...>(..)' & 'RecordBuilder<_recordType>::methodStatic<...>(..)'. - * template params are explicitly specified. - */ template - template - inline constexpr const access::Function Builder::build(_returnType(*pFunctor)(_signature...)) const - { - return buildFunctor(pFunctor); - } - } - - - namespace builder - { - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - /* @method: build() - @param: _returnType(_recordType::*)(_signature...) const. - @return: 'access::Function' object. - * accepts function pointer of a const-member-function with any signature. - * called on object returned by 'RecordBuilder<_recordType>::methodConst()' - * template params will be auto deduced from the function pointer passed. - */ template - inline constexpr const access::Function Builder::build(_returnType(_recordType::* pFunctor)(_signature...) const) const - { - return buildMethodFunctor(pFunctor); - } - } - - - namespace builder - { - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - /* @method: build() - @param: _returnType(_recordType::*)() const. - @return: 'access::Function' object. - * accepts a const-member-function pointer with no arguments. - * called on object returned by 'RecordBuilder<_recordType>::methodConst()' - * template param 'void' is explicitly specified. - */ template - inline constexpr const access::Function Builder::build(_returnType(_recordType::* pFunctor)() const) const - { - return buildMethodFunctor(pFunctor); - } - } - - - namespace builder - { - template - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - /* @method: build() - @param: _returnType(_recordType::*)(_signature...) const. - @return: 'access::Function' object. - * accepts a const-member-function pointer with any arguments. - * called on object returned by 'RecordBuilder<_recordType>::methodConst<...>()' - * template param are explicitly specified. - */ template - template - inline constexpr const access::Function Builder::build(_returnType(_recordType::* pFunctor)(_signature...) const) const - { - return buildMethodFunctor(pFunctor); - } - } - - - namespace builder - { - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - - /* @method: build() - @param: none - @return: 'access::Function' object. - * accepts no arguments, builds copy constructor which takes const object source. - * called on object returned by 'RecordBuilder<_recordType>::constructor<...>()' - * template params <...>, explicitly specified. - * calling with zero template params will build the default constructor ie, 'RecordBuilder<_recordType>::constructor()' - */ template - inline constexpr const access::Function Builder::build() const - { - //this code-block is retained by compiler, if copy constructor with non-const ref('_recordType&') is being registered. - if constexpr (std::is_same_v<_recordType&, typename detail::TypeId<_signature...>::HEAD>) - { - return buildCopyConstructor<_recordType, _signature...>(); - } - //this code-block is retained by compiler, if copy constructor with const-ref('const _recordType&') is being registered. - else if constexpr (std::is_same_v::HEAD>) - { - return buildConstCopyConstructor<_recordType, _signature...>(); - } - //if any other constructor except, copy constructor is being registered, this code-block will be retained. - else - { - return buildConstructor<_recordType, _signature...>(); - } - } - - - /* @method: build() - @param: _returnType(_recordType::*)(_signature...) - @return: 'access::Function' object. - * accepts a non-const-member-function pointer with any arguments. - * called on object returned by 'RecordBuilder<_recordType>::method()' - * template params are auto deduced from the pointer passed. - */ template - inline constexpr const access::Function Builder::build(_returnType(_recordType::* pFunctor)(_signature...)) const - { - return buildMethodFunctor(pFunctor); - } - } - - - namespace builder - { - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - - /* @method: build() - @param: _returnType(_recordType::*)() - @return: 'access::Function' object. - * accepts a non-const-member-function pointer with no arguments. - * called on object returned by 'RecordBuilder<_recordType>::method()' - * template param 'void' is explicitly specified. - */ template - inline constexpr const access::Function Builder::build(_returnType(_recordType::* pFunctor)()) const - { - return buildMethodFunctor(pFunctor); - } - } - - - namespace builder - { - template - inline Builder::Builder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : ReflectionBuilder(pNamespace, pRecord, pFunction) { - } - - /* @method: build() - @param: _returnType(_recordType::*)(_signature...) - @return: 'access::Function' object. - * accepts a non-const-member-function pointer with any arguments. - * called on object returned by 'RecordBuilder<_recordType>::method<...>()' - * template params are explicitly specified. - */ template - template - inline constexpr const access::Function Builder::build(_returnType(_recordType::* pFunctor)(_signature...)) const - { - return buildMethodFunctor(pFunctor); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/inc/ConstructorBuilder.h b/ReflectionTemplateLib/builder/inc/ConstructorBuilder.h deleted file mode 100644 index c29db0ee..00000000 --- a/ReflectionTemplateLib/builder/inc/ConstructorBuilder.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "Constants.h" - -namespace rtl { - - namespace builder - { - /* @class: ConstructorBuilder - @param: _recordType - struct/class type. - * _signature...- constructor args type (none/_record&/const _record& or any combination of parameters) - * provides interface to register constructors/destructor of a class/struct. - * when the very first constructor(any- copy/default/parametrized) is registered, destructor gets registered implicitly. - * all the objects are created via reflection are on heap, using 'new'. - * the constructed objects are returned wrapped in 'Instance' object, with type erased. - * lifetime of created objects are managed using 'shared_ptr'. - */ template - class ConstructorBuilder - { - //given name of the class/struct. - const std::string& m_record; - - //given name of the namespace. - const std::string& m_namespace; - - /* type of constructor to be registered. - FunctorType::Ctor - default/parametrized constructor. - FunctorType::CopyCtor - copy constructor args, '_recordType&' - FunctorType::CopyCtorConst - copy constructor args, 'const _recordType&' - */ const FunctorType m_ctorType; - - ConstructorBuilder() = delete; - - public: - - ConstructorBuilder(const std::string& pNamespace, const std::string& pRecord, - const FunctorType& pCtorType); - - inline constexpr const access::Function build() const; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/inc/ConstructorBuilder.hpp b/ReflectionTemplateLib/builder/inc/ConstructorBuilder.hpp deleted file mode 100644 index e6608590..00000000 --- a/ReflectionTemplateLib/builder/inc/ConstructorBuilder.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "Function.h" -#include "Builder.hpp" -#include "ConstructorBuilder.h" - -namespace rtl { - - namespace builder - { - template - inline ConstructorBuilder<_recordType, _ctorSignature...>::ConstructorBuilder(const std::string& pNamespace, const std::string& pRecord, - const FunctorType& pCtorType) - : m_record(pRecord) - , m_namespace(pNamespace) - , m_ctorType(pCtorType) - { - } - - - /* @method: build() - @param: none - @return: 'Function' object. - * constructs temparory object of class Builder with given class/struct, namespace name & constructor type. - * forwards the call to Builder::build(). - */ template - inline constexpr const access::Function ConstructorBuilder<_recordType, _ctorSignature...>::build() const - { - const auto& ctorName = (m_ctorType == FunctorType::CopyCtor ? CtorName::copy(m_record) : - (m_ctorType == FunctorType::CopyCtorConst ? CtorName::constCopy(m_record) : CtorName::ctor(m_record))); - - return Builder(m_namespace, m_record, ctorName).build<_recordType, _ctorSignature...>(); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/inc/RecordBuilder.h b/ReflectionTemplateLib/builder/inc/RecordBuilder.h deleted file mode 100644 index 21970f2c..00000000 --- a/ReflectionTemplateLib/builder/inc/RecordBuilder.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "Function.h" - -namespace rtl { - - namespace builder - { - template - class ConstructorBuilder; - - /* @class: RecordBuilder - @param: <_recordType>, a struct/class type. - * provides interface to register member-function & constructors/destructor of a class/struct. - */ template - class RecordBuilder - { - const std::string& m_record; - const std::string& m_namespace; - - public: - - RecordBuilder(const std::string& pNamespace, const std::string& pRecord); - - template - constexpr const ConstructorBuilder<_recordType, _signature...> constructor() const; - - constexpr const Builder method(const std::string& pFunction) const; - - constexpr const Builder methodStatic(const std::string& pFunction) const; - - constexpr const Builder methodConst(const std::string& pFunction) const; - - template - constexpr const Builder method(const std::string& pFunction) const; - - template - constexpr const Builder methodStatic(const std::string& pFunction) const; - - template - constexpr const Builder methodConst(const std::string& pFunction) const; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/inc/RecordBuilder.hpp b/ReflectionTemplateLib/builder/inc/RecordBuilder.hpp deleted file mode 100644 index 5de80103..00000000 --- a/ReflectionTemplateLib/builder/inc/RecordBuilder.hpp +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include "RecordBuilder.h" -#include "ConstructorBuilder.hpp" - -namespace rtl { - - namespace builder - { - template - inline RecordBuilder<_recordType>::RecordBuilder(const std::string& pNamespace, const std::string& pRecord) - : m_record(pRecord) - , m_namespace(pNamespace) { - } - - - /* @method: methodStatic() - @param: std::string, name of function as string. - @return: Builder - * registers only static member functions. - * used for registering unique static member function, if overload exists, use templated version 'methodStatic<...>()'. - * the 'build(..)' called on return object will accepts static member function pointer only. - * compiler error on 'build(..)' if non-static member or non-member function pointer is passed. - */ template - inline constexpr const Builder RecordBuilder<_recordType>::methodStatic(const std::string& pFunction) const - { - return Builder(m_namespace, m_record, pFunction); - } - - - /* @method: methodStatic<...>() - @param: std::string, name of function as string. - @return: Builder - * registers only static member functions. - * used for registering overloads, if unique member function, use non-templated version 'methodStatic()'. - * template parameters must be explicitly specified, should be exactly same as the member-function being registered. - * the 'build(..)' called on return object will accepts static member function pointer only. - * compiler error on 'build(..)' if const member or non-member function pointer is passed. - */ template - template - inline constexpr const Builder RecordBuilder<_recordType>::methodStatic(const std::string& pFunction) const - { - return Builder(m_namespace, m_record, pFunction); - } - - - /* @method: method() - @param: std::string, name of function as string. - @return: Builder - * registers non-const, non-static member functions. - * the 'build(..)' called on return object will accepts non-const, non-static member-function-pointer only. - * compiler error on 'build(..)' if const, static member or non-member function pointer is passed. - */ template - inline constexpr const Builder RecordBuilder<_recordType>::method(const std::string& pFunction) const - { - return Builder(m_namespace, m_record, pFunction); - } - - - /* @method: methodConst() - @param: std::string, name of function as string. - @return: Builder - * registers const member functions. - * used for registering unique member function, if overload exists, use templated version 'methodConst<...>()'. - * template parameters must be explicitly specified, should be exactly same as the member-function being registered. - * the 'build(..)' called on return object will accepts non-const member-function-pointer only. - * compiler error 'build(..)' if non-const, static member or non-member function pointer is passed. - */ template - inline constexpr const Builder RecordBuilder<_recordType>::methodConst(const std::string& pFunction) const - { - return Builder(m_namespace, m_record, pFunction); - } - - - /* @method: method() - @param: std::string, name of function as string. - @return: Builder - * registers non-const member functions. - * used for registering overloads, for unique member function, use non-templated version 'method()'. - * template parameters must be explicitly specified, should be exactly same as the member-function being registered. - * the 'build(..)' called on return object will accepts non-const member-function-pointer only. - * compiler error on 'build(..)' if const, static member or non-member function pointer is passed. - */ template - template - inline constexpr const Builder RecordBuilder<_recordType>::method(const std::string& pFunction) const - { - return Builder(m_namespace, m_record, pFunction); - } - - - /* @method: methodConst<...>() - @param: std::string, name of function as string. - @return: Builder - * registers const member functions. - * used for registering overloads, for unique member function, use non-templated version 'methodConst()'. - * template parameters must be explicitly specified, should be exactly same as the member-function being registered. - * the 'build(..)' called on return object will accepts const member-function-pointer only. - * compiler error on 'build(..)' if non-const, static member or non-member function pointer is passed. - */ template - template - inline constexpr const Builder RecordBuilder<_recordType>::methodConst(const std::string& pFunction) const - { - return Builder(m_namespace, m_record, pFunction); - } - - - /* @method: constructor<...>() - @param: none - @return: ConstructorBuilder<_recordType, _signature...> - * the copy constructors params are detected at compile time only. - * template params <...> - any combination of parameters. - */ template - template - inline constexpr const ConstructorBuilder<_recordType, _signature...> RecordBuilder<_recordType>::constructor() const - { - //this code-block is retained by compiler, if copy constructor with non-const ref('_recordType&') is being registered. - if constexpr (std::is_same_v<_recordType&, typename detail::TypeId<_signature...>::HEAD>) - { - return ConstructorBuilder<_recordType, _signature...>(m_namespace, m_record, FunctorType::CopyCtor); - } - //this code-block is retained by compiler, if copy constructor with const-ref('const _recordType&') is being registered. - else if constexpr (std::is_same_v::HEAD>) - { - return ConstructorBuilder<_recordType, _signature...>(m_namespace, m_record, FunctorType::CopyCtorConst); - } - //if any other constructor except, copy constructor is being registered, this code-block will be retained. - else - { - return ConstructorBuilder<_recordType, _signature...>(m_namespace, m_record, FunctorType::Ctor); - } - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/inc/Reflect.h b/ReflectionTemplateLib/builder/inc/Reflect.h deleted file mode 100644 index 341ca0c4..00000000 --- a/ReflectionTemplateLib/builder/inc/Reflect.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include "Constants.h" -#include "Builder.h" - -namespace rtl { - - namespace builder - { - template - class RecordBuilder; - - /* @class: Reflect - * provides interface to register all kinds of functions (member/non-member). - */ class Reflect - { - //name of the class, struct being registered. - std::string m_record; - - //name of the namespace being registered. - std::string m_namespace; - - public: - - Reflect(); - Reflect(const Reflect&) = delete; - Reflect& operator=(const Reflect&) = delete; - - Reflect& nameSpace(const std::string& pNamespace); - - template - constexpr const Builder function(const std::string& pFunction); - - template - constexpr const RecordBuilder<_recordType> record(const std::string& pClass); - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/builder/inc/Reflect.hpp b/ReflectionTemplateLib/builder/inc/Reflect.hpp deleted file mode 100644 index d1147033..00000000 --- a/ReflectionTemplateLib/builder/inc/Reflect.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "Reflect.h" -#include "Builder.hpp" -#include "RecordBuilder.hpp" - -namespace rtl { - - namespace builder - { - inline Reflect::Reflect() - : m_record("") - //If no namespace is given, types are kept under default name: NAMESPACE_GLOBAL. - , m_namespace(NAMESPACE_GLOBAL) { - } - - - /* @function: nameSpace() - @param: std::string, name of the 'namespace' as string. - @return: '*this', Reflect. - * used to group registered function, class/struct under a namespace name. - * its an internal grouping of registered types under a 'namespace' name. - * providing a namespace is optional. registration can be done without a namespace name, even if a type exists in one. - * if types are registered with 'namespace' name, then it must be passed when retriving the objects from 'CxxMirror', - check functions, CxxMirror::getFunction("name_space", "func_name") & CxxMirror::getRecord("name_space","class_name"), - if no namespace is given, then CxxMirror::getFunction("func_name") & CxxMirror::getRecord("class_name") - */ inline Reflect& Reflect::nameSpace(const std::string& pNamespace) - { - m_namespace = pNamespace; - return *this; - } - - - /* @function: function() - @param: std::string (name of the function). - @return: Builder - * registers only non-member functions. - * the 'build(..)' called on return object accepts non-member function pointer only. - * compiler error on 'build(..)' if member function pointer is passed. - */ template<> - inline const Builder Reflect::function(const std::string& pFunction) - { - return Builder(m_namespace, m_record, pFunction); - } - - - /* @function: record() - @param: std::string (name of class/struct) - @return: RecordBuilder<_recordType> - * provides object of 'RecordBuilder', which provides interface to registers member functions of class/struct of '_recordType'. - * the 'build(..)' called on return object accepts non-member function pointer only. - * compiler error on 'build(..)' if function pointer passed is not a member of class/struct- '_recordType'. - */ template - inline constexpr const RecordBuilder<_recordType> Reflect::record(const std::string& pClass) - { - return RecordBuilder<_recordType>(m_namespace, pClass); - } - - - /* @method: function<...>() - @param: std::string (name of function) - @return: Builder - * registers only non-member functions. - * used for registering overloads, if unique member function, use non-templated version 'function()'. - * template parameters must be explicitly specified, should be exactly same as the function being registered. - * the 'build(..)' called on return object accepts non-member function pointer only. - * compiler error on 'build(..)' if any member function pointer is passed. - */ template - inline constexpr const Builder Reflect::function(const std::string& pFunction) - { - return Builder(m_namespace, m_record, pFunction); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/common/Constants.h b/ReflectionTemplateLib/common/Constants.h deleted file mode 100644 index 3ae4fc51..00000000 --- a/ReflectionTemplateLib/common/Constants.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include - -namespace rtl { - - //Qualifier type. - enum class TypeQ - { - None, - Mute, //Mutable - Const, //Constant - }; - - //Qualifier type. - enum class FunctorType - { - None, - Ctor, - CopyCtor, - CopyCtorConst, - DCtor, - Static, - Method, - Function - }; - - - enum class Error - { - None, - EmptyInstance, - SignatureMismatch, - InstanceTypeMismatch, - InstanceConstMismatch, - ConstructorNotFound, - CopyConstructorNotFound, - ConstCopyConstructorNotFound - }; - - constexpr const char* NAMESPACE_GLOBAL = "namespace_global"; - - struct CtorName - { - static const std::string ctor(const std::string& pRecordName) { - return (pRecordName + "::" + pRecordName + "()"); - } - - static const std::string dctor(const std::string& pRecordName) { - return (pRecordName + "::~" + pRecordName + "()"); - } - - static const std::string copy(const std::string& pRecordName) { - return (pRecordName + "::" + pRecordName + "(" + pRecordName + "&)"); - } - - static const std::string constCopy(const std::string& pRecordName) { - return (pRecordName + "::" + pRecordName + "(const " + pRecordName + "&)"); - } - }; - - -#define GETTER(_varType, _name, _var) \ - inline constexpr const _varType& get##_name() const { \ - return _var; \ - } - - -#define GETTER_REF(_varType, _name, _var) \ - inline _varType& get##_name() const { \ - return _var; \ - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/common/RTLibInterface.h b/ReflectionTemplateLib/common/RTLibInterface.h deleted file mode 100644 index 9a03c56a..00000000 --- a/ReflectionTemplateLib/common/RTLibInterface.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -/* -* Provides interface to register all types. -* Reflect().nameSpace("namespaceName").function<>("funcName").build(funcPtr) -* Reflect().nameSpace("namespaceName").record("className").constructor<>("methodName").build() -* Reflect().nameSpace("namespaceName").record("className").method<>("methodName").build(&MethodPtr) -* -* template params are for overloading the different signatures (of method/function/constructors). -* if the function/method is unique, no need to specify the signature as templete params. if they -* are overloaded and any one of them takes zero params, then that function must be registered by specifying as -* template parameter. Constructor overloads do not need to specify as tempelate params even if other overload exists. -* decleared in namespace rtl::builder. */ -#include "Reflect.hpp" - - -/* -* Interface to access user defined class/struct(s) and its members(veariables, functions, constructor & destructor). -* it encapsulates all the member's information and provides objects (Function/Method) to access them. -* the Record objects are obtained from reflection object ie, CxxMirror, querying by string. -* decleared in namespace rtl::access.*/ -#include "Record.hpp" - - -/* -* Provides interface to call global functions (may or not be in a namespace), static member functions of class/struct(s). -* it overloads "operator()". can be called as functionObj(..args..), where functionObj is object of "class Function" -* the global Function objects can be directly obtained from reflection object ie, CxxMirror, querying by string. -* decleared in namespace rtl::access.*/ -#include "Function.hpp" - - -/* -* Provides interface to call methods on objects created via reflection of classes/structs. -* it also overloads "operator()", but this takes the object (type 'Instance') instead of the method arguments and returns -* the obeject of class 'MethodInvoker, which provides 'invoke' function to finally call the method with arguments. -* -* Difference between Method & Function class: -* - They both overload the operator(), but when calling via "Function" object, it takes parameters to be passed. -* - When calling via "Method", it takes target object on which the reflected method needs to be called and then provides -* interface 'invoke()' on the return value, which takes the actual parameters. So, -* Function call: function(..args..); -* Method call: method(targetObj).invoke(..args..); -* -* decleared in namespace rtl::access. */ -#include "Method.hpp" - - -/* -* RStatus, Provides interface to check if the call succeeded and to access the return values obtained -* from calling methods/functions/constructors if any. It contains object of Instance, which may or may not have the return value. -* Instance hold resource, it is owned by RStatus, once 'reteaseReturn()' is called on RStatus, it will relieve itseld from the ownership. -* -* 'Instance' is a wrapper class for std::any, which adds interface to perform exception-safe non-rtti type check. and -* calls the destructor when goes out of scope, only for the objects created by calling instance() method on Record objects, -* ie, the destructor will only be called for the objects that are created via reflection on the heap. It will not be called for -* the objects recieved as return vales from reflected method/function call. -* - supports only move semantics. -* Interfaces: -* - get(), provides the std::any object, which can be checked using has_value() if it contains any object. -* - isOfType<_type>(), checks of the underlying object is of '_type'. -* - finally, std::any_cast<_type>() can be used to obtain the actual object with '_type' -* For example, a function returns value as 'std::string', but calling it via reflection will return the 'Instance' -* object (suppose, retObj). it must be validated before finally applying the std::any_cast<>() to avoid exception, like, -* 1. if(retObj.get().has_value() == true) -* 2. if(retObj.isOfType() == true) -* 3. std::string str = std::any_cast(retObj.get()) -* -* decleared in namespace rtl::access. */ -#include "RStatus.h" - - -/* Class containing everything required to provide reflection interface and functionality. -* Users are required to instantiate this class and pass all registration as constructor parameter. */ -#include "CxxMirror.h" \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/CallReflector.h b/ReflectionTemplateLib/detail/inc/CallReflector.h deleted file mode 100644 index 8d5b355a..00000000 --- a/ReflectionTemplateLib/detail/inc/CallReflector.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include "Constants.h" - -namespace rtl { - - namespace access { - //forward decl. - class RStatus; - } - - namespace detail - { - /* @struct: CallReflector - @param: _derivedType (type which inherits this class) - * retrieves the lambda at given index and calls it with the arguments supplied. - * deriving classes are, MethodContainer & FunctorContainer. - */ template - struct CallReflector - { - /* @method: forwardCall - @param: pFunctorIndex (index of the lambda), _args...(arguments to be passed to that lambda) - * gets the lambda vector from '_derivedType' and calls the lambda at given index with '_args'. - * this 'forwardCall' is for calling lambda containing non-member-function and static-member-function functors. - */ template - static access::RStatus forwardCall(std::size_t pFunctorIndex, _params..._args) - { - //'getFunctors()' must be implemented by _derivedType (FunctorContainer). - return _derivedType::getFunctors().at(pFunctorIndex)(_args...); - } - - - /* @method: forwardCall - @param: pFunctorIndex (index of the lambda), _args...(arguments to be passed to that lambda) - * gets the lambda vector from '_derivedType' and calls the lambda at given index with '_args'. - * this 'forwardCall' is for calling lambda containing member-function functors. - */ template - static access::RStatus forwardCall(const std::any& pTarget, std::size_t pFunctorIndex, _params..._args) - { - //'getMethodFunctors()' is implemented by _derivedType (MethodContainer) - return _derivedType::getMethodFunctors().at(pFunctorIndex)(pTarget, _args...); - } - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/CxxReflection.h b/ReflectionTemplateLib/detail/inc/CxxReflection.h deleted file mode 100644 index 3ef39c6e..00000000 --- a/ReflectionTemplateLib/detail/inc/CxxReflection.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Constants.h" - -namespace rtl { - - namespace access - { - //Forward decls. - class Record; - class Method; - class Function; - } - - namespace detail - { - /* @class: CxxReflection - * base class for main 'CxxMirror' interface. - * accepts 'Function' objects for construction, frowared from 'CxxMirror' constructor - * organizes the 'Function' objects by namespace, class/structs. - */ class CxxReflection - { - using RecordMap = std::unordered_map ; - using MethodMap = std::unordered_map ; - using FunctionMap = std::unordered_map ; - - //contains 'Record' (class/struct) objects, mapped with given namespace name. - std::unordered_map m_nsRecordsMap; - - //contains 'Function' (non-member-function) objects, mapped with given namespace name. - std::unordered_map m_nsFunctionsMap; - - void organizeFunctorsMetaData(const access::Function& pFunction); - - void addRecord(RecordMap& pRecordMap, const access::Function& pFunction); - void addMethod(MethodMap& pMethodMap, const access::Function& pFunction); - void addFunction(FunctionMap& pFunctionMap, const access::Function& pFunction); - - protected: - - CxxReflection() = delete; - CxxReflection(CxxReflection&) = delete; - CxxReflection& operator=(CxxReflection&) = delete; - - CxxReflection(const std::vector& pFunctions); - - public: - - //returns the complete map of registered methods grouped by namespace, contained in 'Record' (class/struct) objects. - constexpr const std::unordered_map& getNamespaceRecordMap() const { - return m_nsRecordsMap; - } - - //returns the complete map of registered functions ('Function' objects) under a namespace. - constexpr const std::unordered_map& getNamespaceFunctionsMap() const { - return m_nsFunctionsMap; - } - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/FunctorContainer.h b/ReflectionTemplateLib/detail/inc/FunctorContainer.h deleted file mode 100644 index 302665a8..00000000 --- a/ReflectionTemplateLib/detail/inc/FunctorContainer.h +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "Constants.h" -#include "CallReflector.h" -#include "SetupFunction.hpp" -#include "SetupConstructor.hpp" - -namespace rtl { - - namespace detail - { - //forward decl - class ReflectionBuilder; - //unique id generator. - extern std::atomic g_containerIdCounter; - - /* @class: FunctorContainer - @param: '_signature...' (combination of any types) - * container class for holding lambda's wrapping functor, constructor/destructor calls of same signatures. - * maintains a std::vector with static lifetime. - */ template - class FunctorContainer : public SetupFunction>, - public SetupConstructor>, - public CallReflector> - { - using FunctionLambda = std::function < access::RStatus(_signature...) >; - public: - - //every FunctorContainer<...> will have a unique-id. - static const std::size_t& getContainerId() { - return m_containerId; - } - - //get the vector holding lambdas as 'const-ref' - const static std::vector& getFunctors() { - return m_functors; - } - - //get functor container type(_signature...) as string with given 'returnType'. - template - static const std::string getSignatureStr(const bool pIsMember = false) { - const std::string& retStr = TypeId<_returnType>::toString(); - return (retStr + (pIsMember ? "::" : " ") + "(" + TypeId<_signature...>::toString() + ")"); - } - - private: - - //holds unique-id - static const std::size_t m_containerId; - - //vector holding lambdas - static std::vector m_functors; - - /* @method: pushBack - @params: pFunctor (lambda containing functor or constructor/destructor call) - pGetIndex (lambda providing index if the functor is already registered) - pUpdate (lambda updating the already registered functors/ctor/d'tor set) - @return: index of newly added or already existing lambda in vector 'm_functors'. - */ static const std::size_t pushBack(const FunctionLambda& pFunctor, - std::function pGetIndex, - std::function pUpdate) - { - //critical section, thread safe. - static std::mutex mtx; - std::lock_guard lock(mtx); - - std::size_t index = pGetIndex(); - if (index == -1) { - index = m_functors.size(); - pUpdate(index); - m_functors.push_back(pFunctor); - } - return index; - } - - //friends :) - friend ReflectionBuilder; - friend SetupFunction>; - friend SetupConstructor>; - }; - - template - const std::size_t FunctorContainer<_signature...>::m_containerId = g_containerIdCounter.fetch_add(1); - - template - std::vector::FunctionLambda> FunctorContainer<_signature...>::m_functors; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/FunctorId.h b/ReflectionTemplateLib/detail/inc/FunctorId.h deleted file mode 100644 index b1893fde..00000000 --- a/ReflectionTemplateLib/detail/inc/FunctorId.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include "TypeId.h" -#include "Constants.h" - -namespace rtl -{ - namespace detail - { - /* @class: FunctorId - * 'FunctorId' object is generated for every functor (member/non-member function pointer) registered. - * acts as a hash-key to lookup a particular functor in the functor-table. - * first, using 'm_containerId', the functor-table container is found. - * once table is found, the functor is accessed at index 'm_index', (never fails, noexcept) - * 'FunctorId' generated for a each functor is unique, even for overloaded functions. - * multiple registartion of same functor will generate same duplicate 'FunctorId'. - */ class FunctorId - { - //index of the functor in the functor-table. - const std::size_t m_index; - - //return type-id of the functor registered. - const std::size_t m_returnId; - - //if functor is a member-function, type id of class/struct it belongs to. - const std::size_t m_recordId; - - //containerId of the functor-table. - const std::size_t m_containerId; - - //signature of functor as string. platform dependent, may not be very much readable format. - const std::string m_signature; - - public: - - FunctorId() - : m_index(-1) - , m_returnId(TypeId<>::None) - , m_recordId(TypeId<>::None) - , m_containerId(TypeId<>::None) - , m_signature("") { - } - - FunctorId(const std::size_t& pIndex, - const std::size_t& pReturnId, const std::size_t& pRecordId, - const std::size_t& pContainerId, const std::string& pSignature) - : m_index(pIndex) - , m_returnId(pReturnId) - , m_recordId(pRecordId) - , m_containerId(pContainerId) - , m_signature(pSignature) { - } - - GETTER(std::size_t, Index, m_index) - GETTER(std::size_t, SignatureId, m_containerId) - GETTER(std::string, SignatureStr, m_signature) - - //get a unique hascode representing a functor. - std::size_t getHashCode() const; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/MethodContainer.h b/ReflectionTemplateLib/detail/inc/MethodContainer.h deleted file mode 100644 index fc7d5c35..00000000 --- a/ReflectionTemplateLib/detail/inc/MethodContainer.h +++ /dev/null @@ -1,169 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "Constants.h" - -#include "CallReflector.h" -#include "SetupMethod.hpp" - -namespace rtl { - - namespace detail - { - //forward decl - class ReflectionBuilder; - //unique id generator. - extern std::atomic g_containerIdCounter; - - template - class MethodContainer; - - /* @class: MethodContainer - @param: '_signature...' (combination of any types) - * container class for holding lambda's wrapping non-const-member-function functor calls of same signatures. - * maintains a std::vector with static lifetime. - */ template - class MethodContainer : public SetupMethod>, - public CallReflector> - { - using MethodLambda = std::function < access::RStatus(std::any, _signature...) >; - - public: - - //every MethodContainer will have a unique-id. - static const std::size_t& getContainerId() { - return m_containerId; - } - - //get the vector holding lambdas as 'const-ref' - static const std::vector& getMethodFunctors() { - return m_methodPtrs; - } - - //get container type as string - template - static const std::string getSignatureStr() { - return (TypeId<_returnType>::toString() + " " + TypeId<_recordType>::toString() + "::(" + TypeId<_signature...>::toString() + ")"); - } - - private: - - //holds unique-id - static const std::size_t m_containerId; - - //vector holding lambdas - static std::vector m_methodPtrs; - - /* @method: pushBack - @params: pFunctor (lambda containing non-const-member-function functor call) - pGetIndex (lambda providing index if the functor is already registered) - pUpdate (lambda updating the already registered functors set) - @return: index of newly added or already existing lambda in vector 'm_methodPtrs'. - */ static const std::size_t pushBack(const MethodLambda& pFunctor, - std::function pGetIndex, - std::function pUpdateIndex) - { - //critical section, thread safe. - static std::mutex mtx; - std::lock_guard lock(mtx); - - std::size_t index = pGetIndex(); - if (index == -1) { - index = m_methodPtrs.size(); - pUpdateIndex(index); - m_methodPtrs.push_back(pFunctor); - } - return index; - } - - //friends :) - friend ReflectionBuilder; - friend SetupMethod>; - }; - - template - const std::size_t MethodContainer::m_containerId = g_containerIdCounter.fetch_add(1); - - template - std::vector::MethodLambda> - MethodContainer::m_methodPtrs; - } - - - namespace detail - { - /* @class: MethodContainer - @param: '_signature...' (combination of any types) - * container class for holding lambda's wrapping const-member-function functor calls of same signatures. - * maintains a std::vector with static lifetime. - */ template - class MethodContainer : public SetupMethod>, - public CallReflector> - { - using MethodLambda = std::function < access::RStatus(std::any, _signature...) >; - - public: - - //every MethodContainer will have a unique-id. - static const std::size_t& getContainerId() { - return m_containerId; - } - - //get the vector holding lambdas as 'const-ref' - static const std::vector& getMethodFunctors() { - return m_methodPtrs; - } - - //get container type as string - template - static const std::string getSignatureStr() { - return (TypeId<_returnType>::toString() + " " + TypeId<_recordType>::toString() + "::(" + TypeId<_signature...>::toString() + ") const"); - } - - private: - - //holds unique-id - static const std::size_t m_containerId; - - //vector holding lambdas - static std::vector m_methodPtrs; - - /* @method: pushBack - @params: pFunctor (lambda containing const-member-function functor call) - pGetIndex (lambda providing index if the functor is already registered) - pUpdate (lambda updating the already registered functors set) - @return: index of newly added or already existing lambda in vector 'm_methodPtrs'. - */ static const std::size_t pushBack(const MethodLambda& pFunctor, - std::function pGetIndex, - std::function pUpdateIndex) - { - //critical section, thread safe. - static std::mutex mtx; - std::lock_guard lock(mtx); - - std::size_t index = pGetIndex(); - if (index == -1) { - index = m_methodPtrs.size(); - pUpdateIndex(index); - m_methodPtrs.push_back(pFunctor); - } - return index; - } - - //friends :) - friend ReflectionBuilder; - friend SetupMethod>; - }; - - template - const std::size_t MethodContainer::m_containerId = g_containerIdCounter.fetch_add(1); - - template - std::vector::MethodLambda> - MethodContainer::m_methodPtrs; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/ReflectionBuilder.h b/ReflectionTemplateLib/detail/inc/ReflectionBuilder.h deleted file mode 100644 index 8977b71a..00000000 --- a/ReflectionTemplateLib/detail/inc/ReflectionBuilder.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "Function.h" - -namespace rtl { - - namespace detail - { - /* @class: ReflectionBuilder - * adds the given non-member, static-member 'functor' to the 'FunctionContainer'. - * adds the given const/non-const member, non-static-member 'functor' to the 'MethodContainer'. - * adds the constructor and destructor to 'FunctionContainer'. - */ class ReflectionBuilder - { - protected: - - const std::string& m_record; - const std::string& m_function; - const std::string& m_namespace; - - explicit ReflectionBuilder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction); - - //adds constructor (any overload) to the 'FunctorContainer'. - template - const access::Function buildConstructor() const; - - //adds copy constructor to the 'FunctorContainer'. - template - const access::Function buildCopyConstructor() const; - - //adds const-copy constructor to the 'FunctorContainer'. - template - const access::Function buildConstCopyConstructor() const; - - //adds 'pFunctor' to the 'FunctorContainer'. - template - const access::Function buildFunctor(_returnType(*pFunctor)(_signature...)) const; - - //adds 'pFunctor' to the 'MethodContainer'. - template - const access::Function buildMethodFunctor(_returnType(_recordType::* pFunctor)(_signature...)) const; - - //adds 'pFunctor' to the 'MethodContainer'. - template - const access::Function buildMethodFunctor(_returnType(_recordType::* pFunctor)(_signature...) const) const; - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/ReflectionBuilder.hpp b/ReflectionTemplateLib/detail/inc/ReflectionBuilder.hpp deleted file mode 100644 index cf3c968e..00000000 --- a/ReflectionTemplateLib/detail/inc/ReflectionBuilder.hpp +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include "ReflectionBuilder.h" -#include "FunctorContainer.h" -#include "MethodContainer.h" - -namespace rtl { - - namespace detail - { - inline ReflectionBuilder::ReflectionBuilder(const std::string& pNamespace, const std::string& pRecord, - const std::string& pFunction) - : m_record(pRecord) - , m_function(pFunction) - , m_namespace(pNamespace) { - } - - /* @method: buildFunctor() - @return: 'Function', object associated with the given functor. - @param: 'pFunctor', function pointer with, - * '_returnType' & '_signature...'(auto deduced). - * adds the function pointer in 'FunctorContainer' - * accepts only a non-member or static-member function pointer. - * builds the 'Function' object containing hash-key & meta-data for the given functor. - */ template - inline const access::Function ReflectionBuilder::buildFunctor(_returnType(*pFunctor)(_signature...)) const - { - const std::string& typeStr = detail::TypeId<_signature...>::toString(); - const detail::FunctorId functorId = detail::FunctorContainer<_signature...>::addFunctor(pFunctor); - return access::Function(m_namespace, m_record, m_function, functorId, TypeId<>::None, TypeQ::None); - } - - - /* @method: buildFunctor() - @return: 'Function', object associated with the given functor. - @param: 'pFunctor', function pointer with, '_recordType' (class/struct), - * '_returnType' & '_signature...'(auto deduced). - * adds the function pointer in 'MethodContainer' - * accepts only a non-static, non-const member function pointer. - * builds the 'Function' object containing hash-key & meta-data for the given functor. - */ template - inline const access::Function ReflectionBuilder::buildMethodFunctor(_returnType(_recordType::* pFunctor)(_signature...)) const - { - const std::string& typeStr = detail::TypeId<_signature...>::toString(); - const detail::FunctorId functorId = detail::MethodContainer::addFunctor(pFunctor); - return access::Function(m_namespace, m_record, m_function, functorId, TypeId<_recordType>::get(), TypeQ::Mute); - } - - - /* @method: buildMethodFunctor() - @return: 'Function', object associated with the given functor. - @param: 'pFunctor', function pointer with, '_recordType' (class/struct), - * '_returnType' & '_signature...'(auto deduced). - * adds the function pointer in 'MethodContainer' - * accepts only a const member function pointer. - * builds the 'Function' object containing hash-key & meta-data for the given functor. - */ template - inline const access::Function ReflectionBuilder::buildMethodFunctor(_returnType(_recordType::* pFunctor)(_signature...) const) const - { - const std::string& typeStr = detail::TypeId<_signature...>::toString(); - const detail::FunctorId functorId = detail::MethodContainer::addFunctor(pFunctor); - return access::Function(m_namespace, m_record, m_function, functorId, TypeId<_recordType>::get(), TypeQ::Const); - } - - - /* @method: buildConstructor() - @return: 'Function', object associated with the (specified parametrized) constructor. - @param: '_recordType'(class/struct type) & '_ctorSignature...' (explicitly specified), - * adds the lambda invoking constructor (type-erased) in 'FunctorContainer' - * builds the 'Function' object containing hash-key & meta-data for the constructor. - * also adds the lambda for invoking the destructor and returns its hash-key with the constructor's 'Function'. - */ template - inline const access::Function ReflectionBuilder::buildConstructor() const - { - const detail::FunctorId functorId = detail::FunctorContainer<_ctorSignature...>::template addConstructor<_recordType, _ctorSignature...>(); - const std::string& typeStr = detail::TypeId<_ctorSignature...>::toString(); - const access::Function constructor = access::Function(m_namespace, m_record, m_function, functorId, TypeId<_recordType>::get(), TypeQ::None); - //add the destructor's 'FunctorId' to the constructor's functorIds list. - constructor.getFunctorIds().emplace_back(detail::FunctorContainer::addDestructor<_recordType>()); - return constructor; - } - - - /* @method: buildCopyConstructor() - @return: 'Function', object associated with the copy constructor. - @param: '_recordType'(class/struct type) & '_ctorSignature...' ('_recordType&', explicitlly specified internally), - * adds the lambda invoking copy constructor (type-erased) in 'FunctorContainer' - * builds the 'Function' object containing hash-key & meta-data for the copy constructor. - * also adds the lambda for invoking the destructor and returns its hash-key with the constructor's 'Function'. - */ template - inline const access::Function ReflectionBuilder::buildCopyConstructor() const - { - const detail::FunctorId functorId = detail::FunctorContainer::addCopyConstructor<_recordType>(); - const std::string& typeStr = detail::TypeId<_ctorSignature...>::toString(); - const access::Function constructor = access::Function(m_namespace, m_record, m_function, functorId, TypeId<_recordType>::get(), TypeQ::None); - //add the destructor's 'FunctorId' to the constructor's functorIds list. - constructor.getFunctorIds().emplace_back(detail::FunctorContainer::addDestructor<_recordType>()); - return constructor; - } - - - /* @method: buildConstCopyConstructor() - @return: 'Function', object associated with the copy constructor. - @param: '_recordType'(class/struct type) & '_ctorSignature...' ('const _recordType&', explicitlly specified internally), - * adds the lambda invoking copy constructor (type-erased) taking const-ref in 'FunctorContainer' - * builds the 'Function' object containing hash-key & meta-data for the const-copy constructor. - * also adds the lambda for invoking the destructor and returns its hash-key with the constructor's 'Function'. - */ template - inline const access::Function ReflectionBuilder::buildConstCopyConstructor() const - { - const detail::FunctorId functorId = detail::FunctorContainer::addConstCopyConstructor<_recordType>(); - const std::string& typeStr = detail::TypeId<_ctorSignature...>::toString(); - const access::Function constructor = access::Function(m_namespace, m_record, m_function, functorId, TypeId<_recordType>::get(), TypeQ::None); - //add the destructor's 'FunctorId' to the constructor's functorIds list. - constructor.getFunctorIds().emplace_back(detail::FunctorContainer::addDestructor<_recordType>()); - return constructor; - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupConstructor.h b/ReflectionTemplateLib/detail/inc/SetupConstructor.h deleted file mode 100644 index bcd991cc..00000000 --- a/ReflectionTemplateLib/detail/inc/SetupConstructor.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "FunctorId.h" - -namespace rtl { - - namespace detail - { - /* @struct: SetupConstructor - @param: _derivedType ('FunctorContainer') - * creates a constructor-call-wrapped-lambda to perform constructor call. - * adds it to the functor-container, maintains the already added constructor set as well. - * called from 'ReflectionBuilder', as _derivedType member. - */ template - class SetupConstructor - { - protected: - - //adds the lambda wrapping destructor call to '_derivedType' (FunctorContainer) - template - static const detail::FunctorId addDestructor(); - - //adds the lambda, wrapping constructor call, recordType(_signature...), to '_derivedType' (FunctorContainer) - template - static const detail::FunctorId addConstructor(); - - //adds the lambda, wrapping constructor call, _recordType(_recordType&') to '_derivedType' (FunctorContainer) - template - static const detail::FunctorId addCopyConstructor(); - - //adds the lambda, wrapping constructor call, _recordType(const _recordType&'), to '_derivedType' (FunctorContainer) - template - static const detail::FunctorId addConstCopyConstructor(); - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp b/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp deleted file mode 100644 index b63d0833..00000000 --- a/ReflectionTemplateLib/detail/inc/SetupConstructor.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#pragma once -#include - -#include "RStatus.h" -#include "SetupConstructor.h" - -namespace rtl -{ - namespace detail - { - /* @method: addDestructor() - @param: '_derivedType' (FunctorContainer), '_recordType' (class/struct type) - @return: 'FunctorId' object, a hash-key to lookup the destructor (wrapped in lambda) in the _derivedType's lambda-table. - * adds lambda (destructor-call-wrapped) in '_derivedType' (FunctorContainer). - * maintains a static var for already registered destructor for a particular class/struct type. - * thread safe, this method is uniquely generated for each '_recordType' (class/struct type). - */ template - template - inline const detail::FunctorId SetupConstructor<_derivedType>::addDestructor() - { - //no destructor is registered yet for type '_recordType' if 'dctorIndex' is -1. - static std::size_t dctorIndex = -1; - - //will be called from '_derivedType' if the destructor not already registered. - const auto& updateIndex = [&](const std::size_t& pIndex) { - dctorIndex = pIndex; - }; - - //will be called from '_derivedType' to check if the destructor already registered. - const auto& getIndex = [&]()->const std::size_t { - return dctorIndex; - }; - - //destructor lambda. - const auto& functor = [](const std::any& pTarget)->access::RStatus - { - //cast will definitely succeed, will not throw since the object type is already validated. - _recordType* object = std::any_cast<_recordType*>(pTarget); - delete object; - return access::RStatus(Error::None); - }; - - //add the lambda in 'FunctorContainer'. - const std::size_t& index = _derivedType::pushBack(functor, getIndex, updateIndex); - return detail::FunctorId(index, TypeId<>::None, TypeId<_recordType>::get(), _derivedType::getContainerId(), - (std::string("~") + _derivedType::template getSignatureStr<_recordType>(true))); - } - - - /* @method: addConstructor() - @param: '_derivedType' (FunctorContainer), '_recordType' (class/struct), '_signature...' (ctor's args, explicitly specified) - @return: 'FunctorId' object, a hash-key to lookup the lambda in the _derivedType's lambda-table. - * adds lambda (wrapping constructor call) in '_derivedType' (FunctorContainer). - * maintains a static map to check for already registered constructor for a particular class/struct type. - * thread safe, this method is uniquely generated for each '_recordType' (class/struct type). - * adds constructor with any combination of arguments except, copy & const-ref copy constructors. - */ template - template - inline const detail::FunctorId SetupConstructor<_derivedType>::addConstructor() - { - const auto& recordId = TypeId<_recordType>::get(); - const auto& containerId = _derivedType::getContainerId(); - const auto& hashKey = std::stoull(std::to_string(containerId) + std::to_string(recordId)); - - //maintaining a set of already registered constructors. - static std::map ctorSet; - - //will be called from '_derivedType' if the constructor not already registered. - const auto& updateIndex = [&](const std::size_t& pIndex) { - ctorSet.insert(std::make_pair(hashKey, pIndex)); - }; - - //will be called from '_derivedType' to check if the constructor already registered. - const auto& getIndex = [&]()->const std::size_t { - const auto& itr = ctorSet.find(hashKey); - return (itr != ctorSet.end() ? itr->second : -1); - }; - - //lambda containing constructor call. - const auto& functor = [=](_signature...params)->access::RStatus - { - _recordType* retObj = new _recordType(params...); - return access::RStatus(std::make_any<_recordType*>(retObj), recordId, TypeQ::Mute); - }; - - //add the lambda in 'FunctorContainer'. - const std::size_t& index = _derivedType::pushBack(functor, getIndex, updateIndex); - return detail::FunctorId(index, TypeId<_recordType>::get(), recordId, containerId, - _derivedType::template getSignatureStr<_recordType>(true)); - } - - - /* @method: addCopyConstructor() - @param: '_derivedType' (FunctorContainer), '_recordType' (class/struct). - @return: 'FunctorId' object, a hash-key to lookup the lambda in the _derivedType's lambda-table. - * adds lambda (wrapping copy-constructor call) in '_derivedType' (FunctorContainer). - * maintains a static map to check for already registered constructor for a particular class/struct type. - * thread safe, this method is uniquely generated for each '_recordType' (class/struct type). - * adds copy constructor with argument '_recordType&'. - */ template - template - inline const detail::FunctorId SetupConstructor<_derivedType>::addCopyConstructor() - { - //no copy-constructor is registered yet for type '_recordType' if 'copyCtorIndex' is -1. - static std::size_t copyCtorIndex = -1; - - //will be called from '_derivedType' if the copy-constructor not already registered. - const auto& updateIndex = [&](const std::size_t& pIndex) { - copyCtorIndex = pIndex; - }; - - //will be called from '_derivedType' to check if the constructor already registered. - const auto& getIndex = [&]()->const std::size_t { - return copyCtorIndex; - }; - - const auto& recordId = TypeId<_recordType>::get(); - //lambda containing constructor call. - const auto& functor = [=](const std::any& pOther)->access::RStatus - { - //cast will definitely succeed, will not throw since the object type is already validated. - _recordType* srcObj = std::any_cast<_recordType*>(pOther); - _recordType* retObj = new _recordType(*srcObj); - return access::RStatus(std::make_any<_recordType*>(retObj), recordId, TypeQ::Mute); - }; - - //add the lambda in 'FunctorContainer'. - const std::size_t& index = _derivedType::pushBack(functor, getIndex, updateIndex); - return detail::FunctorId(index, TypeId<_recordType>::get(), recordId, _derivedType::getContainerId(), - _derivedType::template getSignatureStr<_recordType>(true)); - } - - - /* @method: addConstCopyConstructor() - @param: '_derivedType' (FunctorContainer), '_recordType' (class/struct). - @return: 'FunctorId' object, a hash-key to lookup the lambda in the _derivedType's lambda-table. - * adds lambda (wrapping copy-constructor with const-ref call) in '_derivedType' (FunctorContainer). - * maintains a static map to check for already registered constructor for a particular class/struct type. - * thread safe, this method is uniquely generated for each '_recordType' (class/struct type). - * adds copy constructor with argument 'const _recordType&'. - */ template - template - inline const detail::FunctorId SetupConstructor<_derivedType>::addConstCopyConstructor() - { - //no copy constructor with const-ref is registered yet for type '_recordType' if 'constCopyCtorIndex' is -1. - static std::size_t constCopyCtorIndex = -1; - - //will be called from '_derivedType' if the const-ref-copy-constructor not already registered. - const auto& updateIndex = [&](const std::size_t& pIndex) { - constCopyCtorIndex = pIndex; - }; - - //will be called from '_derivedType' to check if the const-ref-copy-constructor already registered. - const auto& getIndex = [&]()->const std::size_t { - return constCopyCtorIndex; - }; - - const auto& recordId = TypeId<_recordType>::get(); - //lambda containing constructor call. - const auto& functor = [=](const std::any& pOther)->access::RStatus - { - //cast will definitely succeed, will not throw since the object type is already validated. - const _recordType* srcObj = std::any_cast<_recordType*>(pOther); - _recordType* retObj = new _recordType(*srcObj); - return access::RStatus(std::make_any<_recordType*>(retObj), recordId, TypeQ::Mute); - }; - - //add the lambda in 'FunctorContainer'. - const std::size_t& index = _derivedType::pushBack(functor, getIndex, updateIndex); - return detail::FunctorId(index, TypeId<_recordType>::get(), recordId, _derivedType::getContainerId(), - _derivedType::template getSignatureStr<_recordType>(true)); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupFunction.h b/ReflectionTemplateLib/detail/inc/SetupFunction.h deleted file mode 100644 index 32080305..00000000 --- a/ReflectionTemplateLib/detail/inc/SetupFunction.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "FunctorId.h" - -namespace rtl { - - namespace detail - { - /* @struct: SetupFunction - @param: _derivedType (type which inherits this class) - * creates a functor-wrapped-lambda to perform call on the registered functor. - * adds it to the functor-container, maintains the already added functor set as well. - * deriving classes is FunctorContainer<...>, which must implement - - - std::size_t& _derived::getContainerId(); - - std::string _derivedType::getSignatureStr(); - - std::size_t& _derived::pushBack(std::function < access::RStatus(_signature...) >, - std::function, - std::function); - * sets up only non-member or static-member-function functors in table. - * called from 'ReflectionBuilder', as _derivedType member. - */ template - class SetupFunction - { - protected: - - template - static const detail::FunctorId addFunctor(_returnType(*pFunctor)(_signature...)); - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupFunction.hpp b/ReflectionTemplateLib/detail/inc/SetupFunction.hpp deleted file mode 100644 index ad6aee7b..00000000 --- a/ReflectionTemplateLib/detail/inc/SetupFunction.hpp +++ /dev/null @@ -1,80 +0,0 @@ - -#include "RStatus.h" -#include "SetupFunction.h" - -namespace rtl -{ - namespace detail - { - /* @method: addFunctor(). - @param: 'pFuntor' (a non-member or static-member function pointer). - '_derivedType' : class deriving this class ('FunctionContainer<...>'). - '_returnType' : return type deduced from 'pFunctor'. - '_signature...' : function signature deduced from 'pFunctor'. - @return: 'FunctorId' object, a hash-key to lookup the functor in the _derivedType's lambda-table. - * adds functor in _derivedType ('FunctionContainer<...>') and maintains functorSet of already registered functors. - * thread safe, multiple functors can be registered simultaneously. - */ template - template - inline const detail::FunctorId SetupFunction<_derivedType>::addFunctor(_returnType(*pFunctor)(_signature...)) - { - - /* set of already registered functors. (static life time). - used std::vector, since std::set/map are not designed for function pointers - */ static std::vector> functorSet; - - /* adds the generated functor index to the 'functorSet'. (thread safe). - called from '_derivedType' ('FunctorContainer') - */ const auto& updateIndex = [&](const std::size_t& pIndex) - { - functorSet.emplace_back(pFunctor, pIndex); - }; - - /* checks if the 'pFunctor' is already present in 'functorSet'. (thread safe). - called from '_derivedType' ('FunctorContainer') - */ const auto& getIndex = [&]()->const std::size_t - { - //linear search, efficient for small set. - for (const auto& fptr : functorSet) { - if (fptr.first == pFunctor) { - //functor already registered, return its 'index'. - return fptr.second; - } - } - //functor is not already registered, return '-1'. - return -1; - }; - - //generate a type-id of '_returnType'. - const auto& retTypeId = TypeId<_returnType>::get(); - - /* a variable arguments lambda, which finally calls the 'pFunctor' with 'params...'. - this is stored in _derivedType's (FunctorContainer) vector holding lambda's. - */ const auto functor = [=](_signature...params)->access::RStatus - { - //if functor does not returns anything, this 'if' block is retained and else block is omitted by compiler. - if constexpr (std::is_same_v<_returnType, void>) { - - //call will definitely be successful, since the signature type has alrady been validated. - (*pFunctor)(params...); - return access::RStatus(Error::None); - } - //if functor returns value, this 'else' block is retained and 'if' block is omitted by compiler. - else { - //call will definitely be successful, since the signature type has alrady been validated. - const _returnType& retObj = (*pFunctor)(params...); - const TypeQ& qualifier = std::is_const<_returnType>::value ? TypeQ::Const : TypeQ::Mute; - //return 'RStatus' with return value wrapped in it as std::any. - return access::RStatus(std::make_any<_returnType>(retObj), retTypeId, qualifier); - } - }; - - //finally add the lambda 'functor' in 'FunctorContainer' lambda vector and get the index. - const std::size_t& index = _derivedType::pushBack(functor, getIndex, updateIndex); - - //construct the hash-key 'FunctorId' and return. - return detail::FunctorId(index, retTypeId, TypeId<>::None, _derivedType::getContainerId(), - _derivedType::template getSignatureStr<_returnType>()); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupMethod.h b/ReflectionTemplateLib/detail/inc/SetupMethod.h deleted file mode 100644 index 88fd55c0..00000000 --- a/ReflectionTemplateLib/detail/inc/SetupMethod.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "FunctorId.h" - -namespace rtl { - - namespace detail - { - /* @struct: SetupMethod - @param: _derivedType (type which inherits this class) - * creates a lambda to perform call on the registered functor. - * adds it to the functor-container, maintains the already added functor set as well. - * deriving classes is MethodContainer & - MethodContainer, which must implement - - - std::size_t& _derived::getContainerId(); - - std::string _derivedType::getSignatureStr(); - - std::size_t& _derived::pushBack(std::function < access::RStatus(_signature...) >, - std::function, - std::function); - * sets up only non-static-member-function functors in lambda table. - * called from 'ReflectionBuilder', as _derivedType member. - */ template - class SetupMethod - { - protected: - - template - static const detail::FunctorId addFunctor(_retType(_recordType::* pFunctor)(_signature...)); - - template - static const detail::FunctorId addFunctor(_retType(_recordType::* pFunctor)(_signature...) const); - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp b/ReflectionTemplateLib/detail/inc/SetupMethod.hpp deleted file mode 100644 index afc1f219..00000000 --- a/ReflectionTemplateLib/detail/inc/SetupMethod.hpp +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#include "RStatus.h" -#include "TypeId.hpp" -#include "SetupMethod.h" - -namespace rtl -{ - namespace detail - { - /* @method: addFunctor(). - @param: 'pFuntor' (a non-const, non-static-member function pointer). - '_derivedType' : class deriving this class ('MethodContainer'). - '_recordType' : the owner 'class/stuct' type of the functor. - '_returnType' : return type deduced from 'pFunctor'. - '_signature...' : function signature deduced from 'pFunctor'. - @return: 'FunctorId' object, a hash-key to lookup the lambda (functor-wrapped) in the _derivedType's lambda-table. - * adds lambda (functor-wrapped) in '_derivedType' (MethodContainer) and maintains functorSet. - * thread safe, multiple functors can be registered simultaneously. - */ template - template - inline const detail::FunctorId SetupMethod<_derivedType>::addFunctor(_retType(_recordType::* pFunctor)(_signature...)) - { - /* set of already registered functors. (static life time). - used std::vector, efficient for small sets. std::set/map will be overhead. - */ static std::vector> functorSet; - - /* adds the generated functor index to the 'functorSet'. (thread safe). - called from '_derivedType' (MethodContainer) - */ const auto& updateIndex = [&](const std::size_t& pIndex) { - functorSet.emplace_back(pFunctor, pIndex); - }; - - /* checks if the 'pFunctor' is already present in 'functorSet'. (thread safe). - called from '_derivedType' ('FunctorContainer') - */ const auto& getIndex = [&]()->const std::size_t - { - //linear search, efficient for small set. - for (const auto& fptr : functorSet) { - if (fptr.first == pFunctor) { - //functor already registered, return its 'index'. - return fptr.second; - } - } - //functor is not already registered, return '-1'. - return -1; - }; - - //generate a type-id of '_returnType'. - const std::size_t retTypeId = TypeId<_retType>::get(); - - /* a variable arguments lambda, which finally calls the 'pFunctor' with 'params...'. - this is stored in _derivedType's (MethodContainer) vector holding lambda's. - */ const auto functor = [=](const std::any& pTargetObj, _signature...params)->access::RStatus - { - //cast would not fail, since the type has already been validated. - _recordType* target = std::any_cast<_recordType*>(pTargetObj); - - //if functor does not returns anything, this 'if' block is retained and else block is omitted by compiler. - if constexpr (std::is_same_v<_retType, void>) { - //call will definitely be successful, since the object type, signature type has already been validated. - (target->*pFunctor)(params...); - return access::RStatus(Error::None); - } - //if functor returns value, this 'else' block is retained and 'if' block is omitted by compiler. - else { - - //call will definitely be successful, since the object type, signature type has already been validated. - const _retType& retObj = (target->*pFunctor)(params...); - const TypeQ& qualifier = std::is_const<_retType>::value ? TypeQ::Const : TypeQ::Mute; - - //return 'RStatus' with return value wrapped in it as std::any. - return access::RStatus(std::make_any<_retType>(retObj), retTypeId, qualifier); - } - }; - - //finally add the lambda 'functor' in 'MethodContainer' lambda vector and get the index. - const std::size_t& index = _derivedType::pushBack(functor, getIndex, updateIndex); - - //construct the hash-key 'FunctorId' and return. - return detail::FunctorId(index, retTypeId, TypeId<_recordType>::get(), _derivedType::getContainerId(), - _derivedType::template getSignatureStr<_recordType, _retType>()); - } - - - /* @method: addFunctor(). - @param: 'pFuntor' (a const, non-static-member function pointer). - '_derivedType' : class deriving this class ('MethodContainer'). - '_recordType' : the owner 'class/stuct' type of the functor. - '_returnType' : return type deduced from 'pFunctor'. - '_signature...' : function signature deduced from 'pFunctor'. - @return: 'FunctorId' object, a hash-key to lookup the lambda (containing functor) in the _derivedType's lambda table. - * adds lambda (containing functor) in '_derivedType' (MethodContainer) and maintains a functorSet. - * thread safe, multiple functors can be registered simultaneously. - */ template - template - inline const detail::FunctorId SetupMethod<_derivedType>::addFunctor(_retType(_recordType::* pFunctor)(_signature...) const) - { - /* set of already registered functors. (static life time). - used std::vector, efficient for small sets. std::set/map will be overhead. - */ static std::vector> functorSet; - const auto& updateIndex = [&](const std::size_t& pIndex) { - functorSet.emplace_back(pFunctor, pIndex); - }; - - /* adds the generated functor index to the 'functorSet'. (thread safe). - called from '_derivedType' (MethodContainer) - */ const auto& getIndex = [&]()->const std::size_t - { - //linear search, efficient for small set. - for (const auto& fptr : functorSet) { - if (fptr.first == pFunctor) { - //functor already registered, return its 'index'. - return fptr.second; - } - } - //functor is not already registered, return '-1'. - return -1; - }; - - //generate a type-id of '_retType'. - const std::size_t retTypeId = TypeId<_retType>::get(); - - /* a variable arguments lambda, which finally calls the 'pFunctor' with 'params...'. - this is stored in _derivedType's (MethodContainer) vector holding lambda's. - */ const auto functor = [=](const std::any& pTargetObj, _signature...params)->access::RStatus - { - //cast would not fail, since the type has already been validated. - _recordType* target = std::any_cast<_recordType*>(pTargetObj); - - //if functor does not returns anything, this 'if' block is retained and else block is omitted by compiler. - if constexpr (std::is_same_v<_retType, void>) { - - //call will definitely be successful, since the object type, signature type has already been validated. - ((static_cast(target))->*pFunctor)(params...); - return access::RStatus(Error::None); - } - else { - const TypeQ& qualifier = std::is_const<_retType>::value ? TypeQ::Const : TypeQ::Mute; - - //call will definitely be successful, since the object type, signature type has already been validated. - const _retType& retObj = ((static_cast(target))->*pFunctor)(params...); - - //return 'RStatus' with return value wrapped in it as std::any. - return access::RStatus(std::make_any<_retType>(retObj), retTypeId, qualifier); - } - }; - - //finally add the lambda 'functor' in 'MethodContainer' lambda vector and get the index. - const std::size_t& index = _derivedType::pushBack(functor, getIndex, updateIndex); - - //construct the hash-key 'FunctorId' and return. - return detail::FunctorId(index, retTypeId, TypeId<_recordType>::get(), _derivedType::getContainerId(), - _derivedType::template getSignatureStr<_recordType, _retType>()); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/TypeId.h b/ReflectionTemplateLib/detail/inc/TypeId.h deleted file mode 100644 index 12e4833e..00000000 --- a/ReflectionTemplateLib/detail/inc/TypeId.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include -#include - -namespace rtl { - - namespace detail - { - //class to generate unique type-id for a type or combination of types. - template - struct TypeId; - - //class to generate unique type-id a type. - template - struct TypeId<_type> - { - //represents '_type' or 'std::nullptr_t' for TypeId<> (empty). - using HEAD = _type; - - //'0' represents no type. - static constexpr const std::size_t None = 0; - - static const std::size_t get() { - return m_typeId; - } - - //returns the type-list as string. - static const std::string toString() - { - if constexpr (std::is_same_v<_type, void>) { - return std::string("void"); - } - if constexpr (std::is_same_v<_type, std::string>) { - return std::string("std::string"); - } - if constexpr (!std::is_same_v<_type, std::nullptr_t>) { - return std::string(typeid(_type).name()); - } - else return std::string(); - } - - private: - static const std::size_t m_typeId; - }; - - - //class to generate unique type-id for a combination of types. - template - struct TypeId - { - //represents the first type in given list. - using HEAD = _first; - - //represents a new list created excluding '_first'. - using TAIL = TypeId<_rest...>; - - //returns the type-list as string. - static const std::string toString() - { - const std::string& tailStr = TAIL::toString(); - if (std::is_same::value) { - return std::string("std::string") + ", " + tailStr; - } - return (std::string(typeid(HEAD).name()) + ", " + tailStr); - } - }; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/inc/TypeId.hpp b/ReflectionTemplateLib/detail/inc/TypeId.hpp deleted file mode 100644 index d187dc46..00000000 --- a/ReflectionTemplateLib/detail/inc/TypeId.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -#include "TypeId.h" - -namespace rtl { - - namespace detail - { - extern std::atomic g_typeIdCounter; - - //statically initialize a unique-id. - template - const std::size_t TypeId<_type>::m_typeId = g_typeIdCounter.fetch_add(1); - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/src/CMakeLists.txt b/ReflectionTemplateLib/detail/src/CMakeLists.txt deleted file mode 100644 index 83dc4255..00000000 --- a/ReflectionTemplateLib/detail/src/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -# Create a variable containing the source files for your target -set(LOCAL_SOURCES - "${CMAKE_CURRENT_LIST_DIR}/CxxReflection.cpp" - "${CMAKE_CURRENT_LIST_DIR}/FunctorId.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TypeIdInitializer.cpp" -) - - -SET(LOCAL_HEADERS - "${PROJECT_SOURCE_DIR}/detail/inc/CallReflector.h" - "${PROJECT_SOURCE_DIR}/detail/inc/CxxReflection.h" - "${PROJECT_SOURCE_DIR}/detail/inc/FunctorContainer.h" - "${PROJECT_SOURCE_DIR}/detail/inc/FunctorId.h" - "${PROJECT_SOURCE_DIR}/detail/inc/MethodContainer.h" - "${PROJECT_SOURCE_DIR}/detail/inc/ReflectionBuilder.h" - "${PROJECT_SOURCE_DIR}/detail/inc/ReflectionBuilder.hpp" - "${PROJECT_SOURCE_DIR}/detail/inc/SetupConstructor.h" - "${PROJECT_SOURCE_DIR}/detail/inc/SetupConstructor.hpp" - "${PROJECT_SOURCE_DIR}/detail/inc/SetupFunction.h" - "${PROJECT_SOURCE_DIR}/detail/inc/SetupFunction.hpp" - "${PROJECT_SOURCE_DIR}/detail/inc/SetupMethod.h" - "${PROJECT_SOURCE_DIR}/detail/inc/SetupMethod.hpp" - "${PROJECT_SOURCE_DIR}/detail/inc/TypeId.h" - "${PROJECT_SOURCE_DIR}/detail/inc/TypeId.hpp" -) - - -# Add any additional source files if needed -target_sources(ReflectionTemplateLib - PRIVATE - "${LOCAL_HEADERS}" - "${LOCAL_SOURCES}" -) - - -SOURCE_GROUP("Source Files\\Detail" FILES ${LOCAL_SOURCES}) -SOURCE_GROUP("Header Files\\Detail" FILES ${LOCAL_HEADERS}) \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/src/CxxReflection.cpp b/ReflectionTemplateLib/detail/src/CxxReflection.cpp deleted file mode 100644 index 536e698e..00000000 --- a/ReflectionTemplateLib/detail/src/CxxReflection.cpp +++ /dev/null @@ -1,127 +0,0 @@ - -#include "TypeId.h" -#include "Record.h" -#include "Method.h" -#include "CxxReflection.h" - -namespace rtl { - - namespace detail - { - /* @Constructor: CxxMirror - @params: 'const std::vector&' - * recieves vector of 'Function' objects, forwarded from 'CxxMirror' constructor. - * initiates grouping of each 'Function' object under namespace, class/struct. - */ CxxReflection::CxxReflection(const std::vector& pFunctions) - { - for (const auto& function : pFunctions) { - organizeFunctorsMetaData(function); - } - } - - - /* @method: addRecord - @params: RecordMap, Function - * constructs the 'Record'(class/struct) object & adds 'Function' as 'Method' to it. - * if the 'Record' already exists in the map, the 'Function' object is added as 'Method' to it. - */ void CxxReflection::addRecord(RecordMap& pRecordMap, const access::Function& pFunction) - { - const auto& recordName = pFunction.getRecordName(); - const auto& itr = pRecordMap.find(recordName); - if (itr == pRecordMap.end()) { - const auto& recordItr = pRecordMap.emplace(recordName, access::Record(recordName)); - addMethod(recordItr.first->second.getFunctionsMap(),pFunction); - } - else { - addMethod(itr->second.getFunctionsMap(), pFunction); - } - } - - - /* @method: addFunction - @params: FunctionMap, Function - * adds the 'Function' object as non-member function mapped to the given namespace name. - */ void CxxReflection::addFunction(FunctionMap& pFunctionMap, const access::Function& pFunction) - { - const auto& fname = pFunction.getFunctionName(); - const auto& itr = pFunctionMap.find(fname); - if (itr == pFunctionMap.end()) { - pFunctionMap.emplace(fname, pFunction); - } - else { - const auto& function = itr->second; - //if the function is already present, add its 'FunctorId' as overload. - function.addOverload(pFunction); - } - } - - - /* @method: addMethod - @params: MethodMap, Function - * adds the 'Function' object as 'Method' object in MethodMap, contained by 'Record' object. - * if the function name already exists in the map, then 'FunctorId' from the param 'pFunction' is added to already existing 'Function'. - * if a 'Function' object represents a Constructor, it might have the destructor 'FunctorId' as well. - * if destructor 'FunctorId' is found, destructor 'Function' object is created and added to the 'MethodMap'. - */ void CxxReflection::addMethod(MethodMap& pMethodMap, const access::Function& pFunction) - { - const auto& fname = pFunction.getFunctionName(); - const auto& itr = pMethodMap.find(fname); - if (itr == pMethodMap.end()) - { - auto& functorIds = pFunction.getFunctorIds(); - /* This condition will be true only in case that 'Function' object represents a constructor - and has more than one 'FunctorId'. every other function registered will have only one 'FunctorId'. - */ if (functorIds.size() > 1) - { - const auto& dctorName = CtorName::dctor(pFunction.getRecordName()); - if (pMethodMap.find(dctorName) == pMethodMap.end()) { - //destructor 'FunctorId' will always be the second in the constructor's FunctorId's vector. - access::Method method = access::Method::getDestructorMethod(pFunction, functorIds[1]); - pMethodMap.insert(std::make_pair(method.getFunctionName(), method)); - } - //remove the destructor 'FunctorId' from the constructor's 'FunctorId' vector. - functorIds.pop_back(); - } - //construct 'Method' obejct and add. - pMethodMap.emplace(fname, access::Method(pFunction)); - } - else { - const auto& function = itr->second; - //if the method is already present, add as overload. - function.addOverload(pFunction); - } - } - - - /* @method: organizeFunctorsMetaData - @params: Function - * seggregates all the 'Function' objects and builds 'Record' & 'Method' objects. - */ void CxxReflection::organizeFunctorsMetaData(const access::Function& pFunction) - { - const auto& nameSpace = pFunction.getNamespace(); - - //if the record-name is empty, 'Function' object is considered as non-member function. - if (pFunction.getRecordName().empty()) { - const auto& itr = m_nsFunctionsMap.find(nameSpace); - if (itr == m_nsFunctionsMap.end()) { - const auto& funcMapItr = m_nsFunctionsMap.emplace(nameSpace, FunctionMap()); - addFunction(funcMapItr.first->second, pFunction); - } - else { - addFunction(itr->second, pFunction); - } - } - //if the record-name is not-empty, 'Function' object is considered as member function, a 'Method'. - else { - const auto& itr = m_nsRecordsMap.find(nameSpace); - if (itr == m_nsRecordsMap.end()) { - const auto& recordMapItr = m_nsRecordsMap.emplace(nameSpace, RecordMap()); - addRecord(recordMapItr.first->second, pFunction); - } - else { - addRecord(itr->second, pFunction); - } - } - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/src/FunctorId.cpp b/ReflectionTemplateLib/detail/src/FunctorId.cpp deleted file mode 100644 index 72ecc1f3..00000000 --- a/ReflectionTemplateLib/detail/src/FunctorId.cpp +++ /dev/null @@ -1,26 +0,0 @@ - -#include "FunctorId.h" - -namespace rtl -{ - namespace detail - { - /* @method: getHashCode() - @return: std::size_t (a unique hash-code for a functor) - * 'm_containerId' will be same for functors(non-member) with same signatures. - * for member functions, a functor will have three atrributes - - signature - - whether it is const or non-const - - class/struct type - 'm_containerId' will be same for functors with same above attributes. - * every functor will have a distinct index in the functor-wrapped-lambda-table. - * so, combination of m_containerId & m_index is unique for every functor. - */ std::size_t FunctorId::getHashCode() const - { - return std::stoull(std::to_string(m_containerId) + - std::to_string(m_index) + - std::to_string(m_recordId) + - std::to_string(m_returnId)); - } - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/detail/src/TypeIdInitializer.cpp b/ReflectionTemplateLib/detail/src/TypeIdInitializer.cpp deleted file mode 100644 index 1040c84c..00000000 --- a/ReflectionTemplateLib/detail/src/TypeIdInitializer.cpp +++ /dev/null @@ -1,17 +0,0 @@ - -#include - -#include "TypeId.h" -#include "ReflectionBuilder.h" - -namespace rtl -{ - namespace detail - { - //type id counter, statically initializes a unique-id to TypeId<...>. - std::atomic g_typeIdCounter = TypeId<>::None + 1; - - //type id counter, statically initializes a unique-id to FunctorContainer<...> and MethodContainer<...>. - std::atomic g_containerIdCounter = TypeId<>::None + 1; - } -} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/CMakeLists.txt b/ReflectionTemplateLib/rtl/CMakeLists.txt new file mode 100644 index 00000000..f038536f --- /dev/null +++ b/ReflectionTemplateLib/rtl/CMakeLists.txt @@ -0,0 +1,30 @@ +# ReflectionTemplateLibrary-CPP/ReflectionTemplateLib/rtl/CMakeLists.txt + +# Top-level headers in rtl/ (absolute paths) +set(LOCAL_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_errors.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_traits.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_typeid.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_constants.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_forward_decls.h" + + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_constructor.h" + + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_function.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_function_erased_return.h" + + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_method.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_method_const.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_method_erased.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_method_erased_return.h" + "${CMAKE_CURRENT_SOURCE_DIR}/rtl_method_erased_target.h" +) + +target_sources(ReflectionTemplateLib PRIVATE ${LOCAL_HEADERS}) +source_group("Header Files\\RTL" FILES ${LOCAL_HEADERS}) + +add_subdirectory(inc) +add_subdirectory(src) +add_subdirectory(builder) +add_subdirectory(detail) +add_subdirectory(dispatch) diff --git a/ReflectionTemplateLib/rtl/builder/Builder.h b/ReflectionTemplateLib/rtl/builder/Builder.h new file mode 100644 index 00000000..b3f6ae25 --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/Builder.h @@ -0,0 +1,322 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::builder +{ + struct CtorBuilder : protected ReflectionBuilder + { + CtorBuilder(const std::string& pNamespace, const std::string& pRecordStr, + const std::string& pFunction, traits::uid_t pRecordUid) + : ReflectionBuilder(pFunction, pRecordUid, pRecordStr, pNamespace) + { } + + /* @method: build() + @param: none + @return: 'Function' object. + * accepts no arguments, builds copy constructor which takes const object source. + * called on object returned by 'RecordBuilder::constructor<...>()' + * template params <...>, explicitly specified. + * calling with zero template params will build the default constructor ie, 'RecordBuilder::constructor()' + */ template + const Function build() const + { + return buildConstructor(); + } + }; + + +/* @struct: Builder + @param: specialized with member, + * member::NonConst - provides interface to register member funtion. + * member::Const - provides interface to register const-member funtions. + * member::Static - provides interface to register static member funtions. + * member::None - provides interface to register non-member funtions. + @param: + * signature_t: arguments types of functions pointers or constructors (auto-deduced/explicitly-specified). + * provides interface to register all sort of functions, methods & constructors. + * every specialization has a 'build()' function, which accepts a function pointer. + * function pointer can be non-member or member(static/const/non-const) functions. +*/ template + struct Builder; +} + + +namespace rtl::builder +{ + template<> + struct Builder : protected ReflectionBuilder + { + Builder(traits::uid_t pRecordUid, const std::string& pFunction, const std::string& pNamespace) + : ReflectionBuilder(pFunction, pRecordUid, detail::RECORD_NONE, pNamespace) + { } + + /* @method: build() + @param: return_t(*)() + @return: 'Function' object. + * accepts a non-member or static-member function pointer with no arguments. + * called on objects returned by 'type::function(..)' & 'RecordBuilder::methodStatic(..)' + * template param 'void' is explicitly specified. + */ template + const Function build(return_t(*pFunctor)()) const + { + return buildFunctor(pFunctor, detail::member::None); + } + }; + + + template + struct Builder : protected ReflectionBuilder + { + Builder(traits::uid_t pRecordUid, const std::string& pFunction, const std::string& pNamespace) + : ReflectionBuilder(pFunction, pRecordUid, detail::RECORD_NONE, pNamespace) + { } + + /* @method: build() + @param: return_t(*)(signature_t...) + @return: 'Function' object. + * it accepts a non-member or static-member function pointer. + * called on objects returned by 'type::function<...>(..)' & 'RecordBuilder::methodStatic<...>(..)'. + * template params are explicitly specified. + */ template + const Function build(return_t(*pFunctor)(signature_t...)) const + { + return buildFunctor(pFunctor, detail::member::None); + } + }; + + + template<> + struct Builder : protected ReflectionBuilder + { + Builder(traits::uid_t pRecordUid, const std::string& pFunction, const std::string& pNamespace) + : ReflectionBuilder(pFunction, pRecordUid, detail::RECORD_NONE, pNamespace) + { } + + /* @method: build() + @param: return_t(*)(signature_t...) + @return: 'Function' object. + * accepts all non-member and static-member function pointer. + * called on the objects returned by 'type::function()' & 'RecordBuilder::methodStatic(..)'. + * template params are auto deduced from the function pointer passed. + */ template + const Function build(return_t(*pFunctor)(signature_t...)) const + { + return buildFunctor(pFunctor, detail::member::None); + } + }; +} + + +namespace rtl::builder +{ + template<> + struct Builder : protected ReflectionBuilder + { + Builder(traits::uid_t pRecordUid, const std::string& pFunction, + const std::string& pRecordStr, const std::string& pNamespace) + : ReflectionBuilder(pFunction, pRecordUid, pRecordStr, pNamespace) + { } + + /* @method: build() + @param: return_t(*)() + @return: 'Function' object. + * accepts a non-member or static-member function pointer with no arguments. + * called on objects returned by 'type::function(..)' & 'RecordBuilder::methodStatic(..)' + * template param 'void' is explicitly specified. + */ template + const Function build(return_t(*pFunctor)()) const + { + return buildFunctor(pFunctor, detail::member::Static); + } + }; + + + template + struct Builder : protected ReflectionBuilder + { + Builder(traits::uid_t pRecordUid, const std::string& pFunction, + const std::string& pRecordStr, const std::string& pNamespace) + : ReflectionBuilder(pFunction, pRecordUid, pRecordStr, pNamespace) + { } + + /* @method: build() + @param: return_t(*)(signature_t...) + @return: 'Function' object. + * it accepts a non-member or static-member function pointer. + * called on objects returned by 'type::function<...>(..)' & 'RecordBuilder::methodStatic<...>(..)'. + * template params are explicitly specified. + */ template + inline const Function build(return_t(*pFunctor)(signature_t...)) const + { + return buildFunctor(pFunctor, detail::member::Static); + } + }; + + + template<> + struct Builder : protected ReflectionBuilder + { + Builder(traits::uid_t pRecordUid, const std::string& pFunction, + const std::string& pRecordStr, const std::string& pNamespace) + : ReflectionBuilder(pFunction, pRecordUid, pRecordStr, pNamespace) + { } + + /* @method: build() + @param: return_t(*)(signature_t...) + @return: 'Function' object. + * accepts all non-member and static-member function pointer. + * called on the objects returned by 'type::function()' & 'RecordBuilder::methodStatic(..)'. + * template params are auto deduced from the function pointer passed. + */ template + const Function build(return_t(*pFunctor)(signature_t...)) const + { + return buildFunctor(pFunctor, detail::member::Static); + } + }; +} + + +namespace rtl::builder +{ + template<> + struct Builder : protected ReflectionBuilder + { + Builder(const std::string& pFunction, traits::uid_t pRecordUid) + : ReflectionBuilder(pFunction, pRecordUid, detail::INIT_LATER, detail::INIT_LATER) + { } + + /* @method: build() + @param: return_t(record_t::*)() const. + @return: 'Function' object. + * accepts a const-member-function pointer with no arguments. + * called on object returned by 'RecordBuilder::methodConst()' + * template param 'void' is explicitly specified. + */ template + const Function build(return_t(record_t::* pFunctor)() const) const + { + return buildMethodFunctor(pFunctor); + } + }; + + + template + struct Builder : protected ReflectionBuilder + { + Builder(const std::string& pFunction, traits::uid_t pRecordUid) + : ReflectionBuilder(pFunction, pRecordUid, detail::INIT_LATER, detail::INIT_LATER) + { } + + /* @method: build() + @param: return_t(record_t::*)(signature_t...) const. + @return: 'Function' object. + * accepts a const-member-function pointer with any arguments. + * called on object returned by 'RecordBuilder::methodConst<...>()' + * template param are explicitly specified. + */ template + const Function build(return_t(record_t::* pFunctor)(signature_t...) const) const + { + return buildMethodFunctor(pFunctor); + } + }; + + + template<> + struct Builder : protected ReflectionBuilder + { + Builder(const std::string& pFunction, traits::uid_t pRecordUid) + : ReflectionBuilder(pFunction, pRecordUid, detail::INIT_LATER, detail::INIT_LATER) + { } + + /* @method: build() + @param: return_t(record_t::*)(signature_t...) const. + @return: 'Function' object. + * accepts function pointer of a const-member-function with any signature. + * called on object returned by 'RecordBuilder::methodConst()' + * template params will be auto deduced from the function pointer passed. + */ template + const Function build(return_t(record_t::* pFunctor)(signature_t...) const) const + { + return buildMethodFunctor(pFunctor); + } + }; +} + + +namespace rtl::builder +{ + template<> + struct Builder : protected ReflectionBuilder + { + Builder(const std::string& pFunction, traits::uid_t pRecordUid) + : ReflectionBuilder(pFunction, pRecordUid, detail::INIT_LATER, detail::INIT_LATER) + { } + + /* @method: build() + @param: return_t(record_t::*)() + @return: 'Function' object. + * accepts a non-const-member-function pointer with no arguments. + * called on object returned by 'RecordBuilder::method()' + * template param 'void' is explicitly specified. + */ template + const Function build(return_t(record_t::* pFunctor)()) const + { + return buildMethodFunctor(pFunctor); + } + }; + + + template + struct Builder : protected ReflectionBuilder + { + Builder(const std::string& pFunction, traits::uid_t pRecordUid) + : ReflectionBuilder(pFunction, pRecordUid, detail::INIT_LATER, detail::INIT_LATER) + { } + + /* @method: build() + @param: return_t(record_t::*)(signature_t...) + @return: 'Function' object. + * accepts a non-const-member-function pointer with any arguments. + * called on object returned by 'RecordBuilder::method<...>()' + * template params are explicitly specified. + */ template + const Function build(return_t(record_t::* pFunctor)(signature_t...)) const + { + return buildMethodFunctor(pFunctor); + } + }; + + + template<> + struct Builder : protected ReflectionBuilder + { + Builder(const std::string& pFunction, traits::uid_t pRecordUid) + : ReflectionBuilder(pFunction, pRecordUid, detail::INIT_LATER, detail::INIT_LATER) + { } + + + /* @method: build() + @param: return_t(record_t::*)(signature_t...) + @return: 'Function' object. + * accepts a non-const-member-function pointer with any arguments. + * called on object returned by 'RecordBuilder::method()' + * template params are auto deduced from the pointer passed. + */ template + const Function build(return_t(record_t::* pFunctor)(signature_t...)) const + { + return buildMethodFunctor(pFunctor); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/CMakeLists.txt b/ReflectionTemplateLib/rtl/builder/CMakeLists.txt new file mode 100644 index 00000000..b8ec8a48 --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/CMakeLists.txt @@ -0,0 +1,17 @@ +# ReflectionTemplateLibrary-CPP/ReflectionTemplateLib/builder/CMakeLists.txt + +# Collect all headers in builder/ (absolute paths) +set(LOCAL_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/Builder.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ConstructorBuilder.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RecordBuilder.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Reflect.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ReflectionBuilder.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RegisterCtor.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RegisterMethod.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RegisterFunction.h" + "${CMAKE_CURRENT_SOURCE_DIR}/SetupDispatch.h" +) + +target_sources(ReflectionTemplateLib PRIVATE ${LOCAL_HEADERS}) +source_group("Header Files\\Builder" FILES ${LOCAL_HEADERS}) \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/ConstructorBuilder.h b/ReflectionTemplateLib/rtl/builder/ConstructorBuilder.h new file mode 100644 index 00000000..f79f389a --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/ConstructorBuilder.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::builder +{ +/* @class: ConstructorBuilder + @param: record_t - struct/class type. + * signature_t...- constructor args type (none/_record&/const _record& or any combination of parameters) + * provides interface to register constructors of a class/struct. + * when the very first constructor(any- default/parametrized) is registered, copy-constructor gets registered implicitly. + * all the objects are created via reflection are on heap, using 'new'. + * the constructed objects are returned wrapped in 'Instance' object, with type erased. + * lifetime of created objects are managed using 'shared_ptr'. +*/ template + struct ConstructorBuilder + { + //given name of the class/struct. + const std::string m_recordStr; + + //given name of the namespace. + const std::string m_namespaceStr; + + public: + + ConstructorBuilder() + : m_recordStr("") + , m_namespaceStr("") + { } + + ConstructorBuilder(const std::string& pNamespace, const std::string& pRecord) + : m_recordStr(pRecord) + , m_namespaceStr(pNamespace) + { } + + /* @method: build() + @param: none + @return: 'Function' object. + * constructs temparory object of class Builder with given class/struct, namespace name & constructor type. + * forwards the call to Builder::build(). + */ const Function build() const + { + // Check if the constructor is not deleted and publicly accessible (excluding default constructor). + const bool isAccessible = (sizeof...(signature_t) == 0 || std::is_constructible_v); + static_assert(isAccessible, "The specified constructor is either deleted or not publicly accessible."); + + return CtorBuilder( m_namespaceStr, m_recordStr, + std::string(detail::ctor_name(m_recordStr)), + traits::uid::value ).build(); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/RecordBuilder.h b/ReflectionTemplateLib/rtl/builder/RecordBuilder.h new file mode 100644 index 00000000..7cc279cf --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/RecordBuilder.h @@ -0,0 +1,149 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +namespace rtl::builder +{ +/* @class: RecordBuilder + @param: , a struct/class type. + * provides interface to register member-function & constructors of a class/struct. +*/ template + class RecordBuilder + { + const std::string m_recordStr; + const std::string m_namespaceStr; + const traits::uid_t m_recordId; + + public: + + RecordBuilder(const std::string& pNamespace, const std::string& pRecord, traits::uid_t pRecordId) + : m_recordStr(pRecord) + , m_namespaceStr(pNamespace) + , m_recordId(pRecordId) + { } + + constexpr const Function build() const + { + return ConstructorBuilder(m_namespaceStr, m_recordStr).build(); + } + }; + + +/* @class: RecordBuilder + @param: , a struct/class type. + * provides interface to register member-function & constructors of a class/struct. +*/ template + struct MethodBuilder + { + /* @method: constructor<...>() + @param: none + @return: ConstructorBuilder + * the copy constructors params are detected at compile time only. + * template params <...> - any combination of parameters. + */ template + constexpr const ConstructorBuilder constructor() const + { + constexpr bool isDefaultCtor = (sizeof...(signature_t) == 0); + constexpr bool isCopyOrMoveCtor = (sizeof...(signature_t) == 1 && traits::is_first_type_same_v); + constexpr bool isDeclearedCtor = rtl::traits::has_constructor; + + static_assert(!isDefaultCtor, "Default-constructor registration detected! It is implicitly registered with the Type."); + static_assert(!isCopyOrMoveCtor, "Copy/Move-constructor registration detected! It is implicitly registered with the Type."); + static_assert(isDeclearedCtor, "Constructor with given signature is not valid or declearation not found."); + + return ConstructorBuilder(); + } + + /* @method: methodStatic() + @param: std::string, name of function as string. + @return: Builder + * registers only static member functions. + * used for registering unique static member function, if overload exists, use templated version 'methodStatic<...>()'. + * the 'build(..)' called on return object will accepts static member function pointer only. + * compiler error on 'build(..)' if non-static member or non-member function pointer is passed. + */ const Builder methodStatic(const std::string& pFunction) const + { + return Builder(traits::uid::value, pFunction, detail::INIT_LATER, detail::INIT_LATER); + } + + /* @method: methodStatic<...>() + @param: std::string, name of function as string. + @return: Builder + * registers only static member functions. + * used for registering overloads, if unique member function, use non-templated version 'methodStatic()'. + * template parameters must be explicitly specified, should be exactly same as the member-function being registered. + * the 'build(..)' called on return object will accepts static member function pointer only. + * compiler error on 'build(..)' if const member or non-member function pointer is passed. + */ template + const Builder methodStatic(const std::string& pFunction) const + { + return Builder(traits::uid::value, pFunction, detail::INIT_LATER, detail::INIT_LATER); + } + + + /* @method: method() + @param: std::string, name of function as string. + @return: Builder + * registers non-const, non-static member functions. + * the 'build(..)' called on return object will accepts non-const, non-static member-function-pointer only. + * compiler error on 'build(..)' if const, static member or non-member function pointer is passed. + */ const Builder method(const std::string& pFunction) const + { + return Builder(pFunction, traits::uid::value); + } + + /* @method: methodConst() + @param: std::string, name of function as string. + @return: Builder + * registers const member functions. + * used for registering unique member function, if overload exists, use templated version 'methodConst<...>()'. + * template parameters must be explicitly specified, should be exactly same as the member-function being registered. + * the 'build(..)' called on return object will accepts non-const member-function-pointer only. + * compiler error 'build(..)' if non-const, static member or non-member function pointer is passed. + */ const Builder methodConst(const std::string& pFunction) const + { + return Builder(pFunction, traits::uid::value); + } + + /* @method: method() + @param: std::string, name of function as string. + @return: Builder + * registers non-const member functions. + * used for registering overloads, for unique member function, use non-templated version 'method()'. + * template parameters must be explicitly specified, should be exactly same as the member-function being registered. + * the 'build(..)' called on return object will accepts non-const member-function-pointer only. + * compiler error on 'build(..)' if const, static member or non-member function pointer is passed. + */ template + const Builder method(const std::string& pFunction) const + { + return Builder(pFunction, traits::uid::value); + } + + /* @method: methodConst<...>() + @param: std::string, name of function as string. + @return: Builder + * registers const member functions. + * used for registering overloads, for unique member function, use non-templated version 'methodConst()'. + * template parameters must be explicitly specified, should be exactly same as the member-function being registered. + * the 'build(..)' called on return object will accepts const member-function-pointer only. + * compiler error on 'build(..)' if non-const, static member or non-member function pointer is passed. + */ template + const Builder methodConst(const std::string& pFunction) const + { + return Builder(pFunction, traits::uid::value); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/Reflect.h b/ReflectionTemplateLib/rtl/builder/Reflect.h new file mode 100644 index 00000000..8bf51b0c --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/Reflect.h @@ -0,0 +1,126 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ +/* @class: Reflect + * provides interface to register all kinds of functions (member/non-member). +*/ struct type_ns + { + type_ns() = delete; + type_ns(type_ns&&) = delete; + type_ns(const type_ns&) = delete; + type_ns& operator=(type_ns&&) = delete; + type_ns& operator=(const type_ns&) = delete; + + type_ns(const std::string& pNamespace) + : m_recordStr("") + , m_namespaceStr(pNamespace) + { } + + /* @function: record() + @param: std::string (name of class/struct) + @return: RecordBuilder + * provides object of 'RecordBuilder', which provides interface to registers member functions of class/struct of 'record_t'. + * the 'build(..)' called on return object accepts non-member function pointer only. + * compiler error on 'build(..)' if function pointer passed is not a member of class/struct- 'record_t'. + */ template + constexpr const builder::RecordBuilder record(const std::string& pClass) + { + return builder::RecordBuilder(m_namespaceStr, pClass, traits::uid::value); + } + + /* @method: function<...>() + @param: std::string (name of function) + @return: Builder + * registers only non-member functions. + * used for registering overloads, if unique member function, use non-templated version 'function()'. + * template parameters must be explicitly specified, should be exactly same as the function being registered. + * the 'build(..)' called on return object accepts non-member function pointer only. + * compiler error on 'build(..)' if any member function pointer is passed. + */ template + constexpr const builder::Builder function(const std::string& pFunction) + { + return builder::Builder(traits::uid<>::none, pFunction, m_namespaceStr); + } + + /* @function: function() + @param: std::string (name of the function). + @return: Builder + * registers only non-member functions. + * the 'build(..)' called on return object accepts non-member function pointer only. + * compiler error on 'build(..)' if member function pointer is passed. + */ const builder::Builder function(const std::string& pFunction) + { + return builder::Builder(traits::uid<>::none, pFunction, m_namespaceStr); + } + + private: + + //name of the class, struct being registered. + std::string m_recordStr; + + //name of the namespace being registered. + std::string m_namespaceStr; + }; + + + +/* @class: Reflect + * provides interface to register all kinds of functions (member/non-member). +*/ struct type + { + type() = default; + type(type&&) = delete; + type(const type&) = delete; + type& operator=(type&&) = delete; + type& operator=(const type&) = delete; + + /* @function: ns() + @param: std::string, name of the 'namespace' as string. + @return: '*this', Reflect. + * used to group registered function, class/struct under a namespace name. + * its an internal grouping of registered types under a 'namespace' name. + * providing a namespace is optional. registration can be done without a namespace name, even if a type exists in one. + * if types are registered with 'namespace' name, then it must be passed when retriving the objects from 'CxxMirror', + check functions, CxxMirror::getFunction("name_space", "func_name") & CxxMirror::getRecord("name_space","class_name"), + if no namespace is given, then CxxMirror::getFunction("func_name") & CxxMirror::getRecord("class_name") + */ type_ns ns(const std::string& pNamespace) + { + return type_ns(pNamespace); + } + + template + constexpr const builder::MethodBuilder member() + { + return builder::MethodBuilder(); + } + + template + constexpr const builder::RecordBuilder record(const std::string& pClass) + { + return ns(detail::NAMESPACE_GLOBAL).record(pClass); + } + + template + constexpr const builder::Builder function(const std::string& pFunction) + { + constexpr bool hasConstRValueRef = ((std::is_const_v> && std::is_rvalue_reference_v) || ...); + static_assert(!hasConstRValueRef, "Registration of functions with 'const T&&' parameters is not allowed."); + + return ns(detail::NAMESPACE_GLOBAL).function(pFunction); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/ReflectionBuilder.h b/ReflectionTemplateLib/rtl/builder/ReflectionBuilder.h new file mode 100644 index 00000000..6e6a4a0e --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/ReflectionBuilder.h @@ -0,0 +1,72 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include +#include + +namespace rtl::builder { + +/* @class: ReflectionBuilder + * adds the given non-member, static-member 'functor' to the 'FunctionContainer'. + * adds the given const/non-const member, non-static-member 'functor' to the 'MethodContainer'. + * adds the constructor to 'FunctionContainer'. +*/ struct ReflectionBuilder + { + protected: + + const traits::uid_t m_recordId; + const std::string m_recordStr; + const std::string m_function; + const std::string m_namespaceStr; + + ReflectionBuilder(const std::string& pFunction, std::size_t pRecordId, + const std::string& pRecordStr, const std::string& pNamespace) + : m_recordId(pRecordId) + , m_recordStr(pRecordStr) + , m_function(pFunction) + , m_namespaceStr(pNamespace) + { } + + template + const Function buildConstructor() const + { + type_meta fnMeta = RegisterCtor::template addConstructor(); + return Function(m_namespaceStr, m_recordStr, m_function, fnMeta, m_recordId, fnMeta.get_member_kind()); + } + + template + const Function buildFunctor(return_t(*pFunctor)(signature_t...), detail::member pMemberType) const + { + type_meta fnMeta = RegisterFunction::template addFunctor(pFunctor, m_recordId, pMemberType); + return Function(m_namespaceStr, m_recordStr, m_function, fnMeta, m_recordId, pMemberType); + } + + //adds 'pFunctor' to the 'MethodContainer'. + template + const Function buildMethodFunctor(return_t(record_t::* pFunctor)(signature_t...)) const + { + type_meta fnMeta = RegisterMethod::template addMethodFunctor(pFunctor); + return Function(m_namespaceStr, m_recordStr, m_function, fnMeta, m_recordId, detail::member::NonConst); + } + + //adds 'pFunctor' to the 'MethodContainer'. + template + const Function buildMethodFunctor(return_t(record_t::* pFunctor)(signature_t...) const) const + { + type_meta fnMeta = RegisterMethod::template addMethodFunctor(pFunctor); + return Function(m_namespaceStr, m_recordStr, m_function, fnMeta, m_recordId, detail::member::Const); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/RegisterCtor.h b/ReflectionTemplateLib/rtl/builder/RegisterCtor.h new file mode 100644 index 00000000..4dcafbeb --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/RegisterCtor.h @@ -0,0 +1,65 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +#include + +namespace rtl::builder +{ + class RegisterCtor : public SetupDispatch + { + template + static type_meta addConstructor() + { + using hash_t = std::pair; + static std::map ctorMetaSet; + + traits::uid_t recordId = traits::uid::value; + traits::uid_t signatureId = traits::uid>::value; + hash_t hashKey = hash_t(recordId, signatureId); + + const auto& doRegister = [&]()->type_meta { + + if constexpr (sizeof...(signature_t) == 0) { + auto typeMeta = type_meta::add_constructor(); + ctorMetaSet.insert(std::make_pair(hashKey, typeMeta)); + return typeMeta; + } + else { + auto typeMeta = type_meta::add_constructor(); + ctorMetaSet.insert(std::make_pair(hashKey, typeMeta)); + return typeMeta; + } + }; + + const auto& isRegistered = [&]()->type_meta { + + const auto& itr = ctorMetaSet.find(hashKey); + if (itr != ctorMetaSet.end()) { + return itr->second; + } + return type_meta(); + }; + + if constexpr (sizeof...(signature_t) == 0) { + return init(isRegistered, doRegister); + } + else { + return init(isRegistered, doRegister); + } + } + + friend ReflectionBuilder; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/RegisterFunction.h b/ReflectionTemplateLib/rtl/builder/RegisterFunction.h new file mode 100644 index 00000000..8003bbf6 --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/RegisterFunction.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::builder +{ + struct RegisterFunction : public SetupDispatch + { + template + static rtl::type_meta addFunctor(return_t(*pFunctor)(signature_t...), + traits::uid_t pRecordUid, detail::member pMemberType) + { + const auto& doRegister = [=]()->type_meta { + + return rtl::type_meta::add_function(pFunctor, pRecordUid, pMemberType); + }; + + const auto& isRegistered = [=]()->type_meta { + + auto& fnCache = cache::function_ptr::instance(); + auto functor = fnCache.find(pFunctor); + if (functor != nullptr) { + return rtl::type_meta(*functor); + } + return type_meta(); + }; + + return init(isRegistered, doRegister); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/RegisterMethod.h b/ReflectionTemplateLib/rtl/builder/RegisterMethod.h new file mode 100644 index 00000000..f7b5bfe2 --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/RegisterMethod.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::builder +{ + struct RegisterMethod : public SetupDispatch + { + template + static type_meta addMethodFunctor(return_t(record_t::* pMthFunctor)(args_t...)) + { + const auto& doRegister = [=]()->type_meta { + + return type_meta::add_method(pMthFunctor); + }; + + const auto& isRegistered = [=]()->type_meta { + + auto& fnCache = cache::method_ptr::instance(); + auto functor = fnCache.find(pMthFunctor); + if (functor != nullptr) { + return rtl::type_meta(*functor); + } + return type_meta(); + }; + + return init(isRegistered, doRegister); + } + + + template + static type_meta addMethodFunctor(return_t(record_t::* pMthFunctor)(args_t...) const) + { + const auto& doRegister = [=]()->type_meta { + + return type_meta::add_method(pMthFunctor); + }; + + const auto& isRegistered = [=]()->type_meta { + + auto& fnCache = cache::method_ptr::instance(); + auto functor = fnCache.find(pMthFunctor); + if (functor != nullptr) { + return rtl::type_meta(*functor); + } + return type_meta(); + }; + + return init(isRegistered, doRegister); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/builder/SetupDispatch.h b/ReflectionTemplateLib/rtl/builder/SetupDispatch.h new file mode 100644 index 00000000..62e208b5 --- /dev/null +++ b/ReflectionTemplateLib/rtl/builder/SetupDispatch.h @@ -0,0 +1,36 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +#include + +namespace rtl::builder +{ + struct SetupDispatch + { + template + static type_meta init( std::function isRegistered, + std::function doRegister ) { + + static std::mutex mtx; + std::lock_guard lock(mtx); + + auto typeMeta = isRegistered(); + if (typeMeta.is_empty()) { + return doRegister(); + } + return typeMeta; + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/CMakeLists.txt b/ReflectionTemplateLib/rtl/detail/CMakeLists.txt new file mode 100644 index 00000000..521d6876 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/CMakeLists.txt @@ -0,0 +1,10 @@ +# ReflectionTemplateLibrary-CPP/ReflectionTemplateLib/detail/CMakeLists.txt + +# Make the 'inc' folder visible as a public include dir +target_include_directories(ReflectionTemplateLib + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/inc" +) + +add_subdirectory(inc) +add_subdirectory(src) \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/CMakeLists.txt b/ReflectionTemplateLib/rtl/detail/inc/CMakeLists.txt new file mode 100644 index 00000000..c9711552 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/CMakeLists.txt @@ -0,0 +1,22 @@ +# ReflectionTemplateLibrary-CPP/ReflectionTemplateLib/detail/inc/CMakeLists.txt + +# All headers in this folder (absolute paths) +set(LOCAL_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/ConversionUtils.h" + "${CMAKE_CURRENT_SOURCE_DIR}/CxxReflection.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ReflectCast.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ReflectCast.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ReflectCastUtil.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RObjectId.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RObjectUPtr.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RObjExtracter.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RObjectBuilder.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RObjectBuilder.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/HopBuilderFunction.h" + "${CMAKE_CURRENT_SOURCE_DIR}/HopBuilderFunction.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/HopBuilderMethod.h" + "${CMAKE_CURRENT_SOURCE_DIR}/HopBuilderMethod.hpp" +) + +target_sources(ReflectionTemplateLib PRIVATE ${LOCAL_HEADERS}) +source_group("Header Files\\Detail" FILES ${LOCAL_HEADERS}) \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/ConversionUtils.h b/ReflectionTemplateLib/rtl/detail/inc/ConversionUtils.h new file mode 100644 index 00000000..8917c1a4 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/ConversionUtils.h @@ -0,0 +1,88 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +namespace rtl::traits { + + template + constexpr bool is_safe_conversion_v = [] { + // 1. Same type check (ignoring cv-qualifiers) + using NakedFrom = std::remove_cv_t; + using NakedTo = std::remove_cv_t; + + if constexpr (std::is_same_v) + return true; + + // 2. Boolean conversion handling + if constexpr (std::is_same_v) + return std::is_arithmetic_v; + if constexpr (std::is_same_v) + return std::is_arithmetic_v; + + // 3. Character type safety + constexpr bool from_char = std::is_same_v || + std::is_same_v || + std::is_same_v; + constexpr bool to_char = std::is_same_v || + std::is_same_v || + std::is_same_v; + + if constexpr (from_char || to_char) { + // Block sign changes between char types + if constexpr ((std::is_same_v && std::is_same_v) || + (std::is_same_v && std::is_same_v)) + return false; + + // Allow same-sign conversions between char types + if constexpr (from_char && to_char) + return (std::is_signed_v == std::is_signed_v); + + // For numeric->char, require size safety + if constexpr (to_char) + return sizeof(NakedFrom) < sizeof(NakedTo); + } + + // 4. Require both types to be arithmetic + if constexpr (!std::is_arithmetic_v || !std::is_arithmetic_v) + return false; + + // 5. Numeric conversion safety + // Floating-point to integer: never safe (truncation) + if constexpr (std::is_floating_point_v && std::is_integral_v) + return false; + + // Integer to floating-point: check mantissa precision + if constexpr (std::is_integral_v && std::is_floating_point_v) + return std::numeric_limits::digits >= std::numeric_limits::digits; + + // Floating-point to floating-point: check both digits and exponent + if constexpr (std::is_floating_point_v && std::is_floating_point_v) + return std::numeric_limits::digits >= std::numeric_limits::digits && + std::numeric_limits::max_exponent >= std::numeric_limits::max_exponent; + + // Integer to integer: + if constexpr (std::is_integral_v && std::is_integral_v) { + // Different signedness requires larger destination + if constexpr (std::is_signed_v != std::is_signed_v) + return sizeof(NakedTo) > sizeof(NakedFrom); + + // Same signedness requires equal or larger size + return sizeof(NakedTo) >= sizeof(NakedFrom); + } + + return false; + }(); +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/CxxReflection.h b/ReflectionTemplateLib/rtl/detail/inc/CxxReflection.h new file mode 100644 index 00000000..84d12f1c --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/CxxReflection.h @@ -0,0 +1,74 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include +#include + +namespace rtl::detail { + +/* @class: CxxReflection + * base class for main 'CxxMirror' interface. + * accepts 'Function' objects for construction, frowared from 'CxxMirror' constructor + * organizes the 'Function' objects by namespace, class/structs. +*/ class CxxReflection + { + using RecordRef = std::reference_wrapper; + using RecordMap = std::unordered_map ; + using MethodMap = std::unordered_map ; + using FunctionMap = std::unordered_map ; + + std::unordered_map m_recordIdMap; + //contains 'Record' (class/struct) objects, mapped with given namespace name. + std::unordered_map m_recordNamespaceMap; + //contains 'Function' (non-member-function) objects, mapped with given namespace name. + std::unordered_map m_functionNamespaceMap; + + void addInNamespaceMap(Record& pRecord); + void buildRecordIdMap(const std::vector& pFunctions); + void insertFunctionToNamespaceMap(const Function& pFunction); + bool insertMethodsToRecordIdMap(const Function& pFunction); + + static void addMethod(MethodMap& pMethodMap, const Function& pFunction); + static void addFunction(FunctionMap& pFunctionMap, const Function& pFunction); + static const bool validateMethodByRecordId(const Function& pFunction); + + protected: + + CxxReflection(const std::vector& pFunctions); + + public: + + CxxReflection() = delete; + CxxReflection(CxxReflection&&) = default; + CxxReflection(const CxxReflection&) = default; + CxxReflection& operator=(CxxReflection&&) = delete; + CxxReflection& operator=(const CxxReflection&) = delete; + + //returns the complete map of registered methods grouped by namespace, contained in 'Record' (class/struct) objects. + constexpr const std::unordered_map& getRecordIdMap() const { + return m_recordIdMap; + } + + //returns the complete map of registered methods grouped by namespace, contained in 'Record' (class/struct) objects. + constexpr const std::unordered_map& getNamespaceRecordMap() const { + return m_recordNamespaceMap; + } + + //returns the complete map of registered functions ('Function' objects) under a namespace. + constexpr const std::unordered_map& getNamespaceFunctionsMap() const { + return m_functionNamespaceMap; + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/HopBuilderFunction.h b/ReflectionTemplateLib/rtl/detail/inc/HopBuilderFunction.h new file mode 100644 index 00000000..fe286c3c --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/HopBuilderFunction.h @@ -0,0 +1,48 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::detail +{ + template + struct InitFunctionHop + { + const std::size_t m_fnIndex; + const std::vector m_overloadsMeta = {}; + + void init(function& pFn) const; + + template requires (member_kind == member::None && std::is_same_v) + constexpr function returnT() const; + + template requires (member_kind == member::None && !std::is_same_v) + constexpr const function returnT() const; + + template requires (member_kind == member::Static && std::is_same_v) + constexpr const static_method returnT() const; + + template requires (member_kind == member::Static && !std::is_same_v) + constexpr const static_method returnT() const; + }; + + + template + struct HopBuilder + { + const std::vector& m_functorsMeta; + + template + constexpr const InitFunctionHop argsT() const; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/HopBuilderFunction.hpp b/ReflectionTemplateLib/rtl/detail/inc/HopBuilderFunction.hpp new file mode 100644 index 00000000..03a8bced --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/HopBuilderFunction.hpp @@ -0,0 +1,168 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace rtl::detail +{ + template + template requires (member_kind == member::None && std::is_same_v) + inline constexpr function InitFunctionHop::returnT() const + { + function...)> fn; + init(fn); + return fn; + } + + + template + template requires (member_kind == member::Static && std::is_same_v) + inline constexpr const static_method InitFunctionHop::returnT() const + { + static_method...)> mth; + init(mth); + return mth; + } + + + template + template requires (member_kind == member::Static && !std::is_same_v) + inline constexpr const static_method InitFunctionHop::returnT() const + { + static_method mth; + if (m_fnIndex == rtl::index_none) { + mth.set_init_error(error::SignatureMismatch); + return mth; + } + + auto& ty_meta = m_overloadsMeta[m_fnIndex]; + if (ty_meta.get_member_kind() != member::Static) { + mth.set_init_error(error::InvalidNonStaticMethodCaller); + } + else if (ty_meta.get_member_kind() == member::Static){ + if (traits::uid::value == ty_meta.get_return_id()) + { + using function_t = dispatch::function_ptr; + auto fptr = static_cast(ty_meta.get_functor()).f_ptr(); + return static_method(fptr); + } + mth.set_init_error(error::ReturnTypeMismatch); + } + return mth; + } + + + template + template requires (member_kind == member::None && !std::is_same_v) + inline constexpr const function InitFunctionHop::returnT() const + { + function fn; + if (m_fnIndex == rtl::index_none) { + fn.set_init_error(error::SignatureMismatch); + return fn; + } + + auto& ty_meta = m_overloadsMeta[m_fnIndex]; + if (ty_meta.get_member_kind() == member::Static) { + fn.set_init_error(error::InvalidStaticMethodCaller); + } + else if (ty_meta.get_member_kind() == member::None) { + if (traits::uid::value == ty_meta.get_return_id()) + { + using function_t = dispatch::function_ptr; + auto fptr = static_cast(ty_meta.get_functor()).f_ptr(); + return function(fptr); + } + fn.set_init_error(error::ReturnTypeMismatch); + } + return fn; + } + + + template + template + inline constexpr const InitFunctionHop HopBuilder::argsT() const + { + std::size_t index = rtl::index_none; + std::vector fnTyMetas(call_by::ncref); + auto normalId = traits::uid>::value; + auto strictId = traits::uid>::value; + + for (auto& ty_meta : m_functorsMeta) + { + if (normalId == ty_meta.get_normal_args_id()) + { + if (normalId == ty_meta.get_strict_args_id()) { + fnTyMetas[call_by::value] = ty_meta; + } + else if (!ty_meta.is_any_arg_ncref()) { + fnTyMetas[call_by::cref] = ty_meta; + } + else fnTyMetas.push_back(ty_meta); + } + } + for (int i = 0; i < fnTyMetas.size(); i++) + { + auto& ty_meta = fnTyMetas[i]; + if (!ty_meta.is_empty() && ty_meta.get_strict_args_id() == strictId) { + index = i; + break; + } + } + return { index, fnTyMetas }; + } + + + template + inline void InitFunctionHop::init(function& pHopper) const + { + for (auto& ty_meta : m_overloadsMeta) + { + if (ty_meta.is_empty()) { + pHopper.get_hopper().push_back(nullptr); + pHopper.get_overloads().push_back(nullptr); + continue; + } + //TODO: simplifiy these errors. confusing! + if constexpr (member_kind == member::Static) { + if (ty_meta.get_member_kind() != member::Static) { + pHopper.set_init_error(error::InvalidNonStaticMethodCaller); + return; + } + } + else if constexpr (member_kind == member::None) { + if (ty_meta.get_member_kind() == member::Static) { + pHopper.set_init_error(error::InvalidStaticMethodCaller); + return; + } + } + + using fn_cast = dispatch::functor_cast...>; + auto fn = fn_cast(ty_meta.get_functor()).template to_function(); + + pHopper.get_hopper().push_back(fn.f_ptr()); + pHopper.get_overloads().push_back(&ty_meta.get_functor()); + pHopper.set_init_error(error::None); + } + + if (pHopper.get_init_error() != error::None) { + pHopper.set_init_error(error::SignatureMismatch); + } + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/HopBuilderMethod.h b/ReflectionTemplateLib/rtl/detail/inc/HopBuilderMethod.h new file mode 100644 index 00000000..476a3bee --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/HopBuilderMethod.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::detail +{ + template + struct InitMethodHop + { + const Method& m_method; + const std::vector m_overloadsMeta; + + template + static void init(const traits::uid_t pRecordId, + const std::vector& pRefOverloads, + typename method::hopper_t& pMth); + + template + using method_t = std::conditional_t< member_kind == member::Const, + const_method, + method >; + + template requires (traits::type_aware_v) + constexpr method_t returnT() const; + + template requires (!traits::type_aware_v) + constexpr method returnT() const; + }; +} + + +namespace rtl::detail +{ + template + struct HopBuilder + { + const Method& m_method; + + static std::vector getRefAndValueOverloads(const Method& pMethod, + const traits::uid_t pNormalId); + + template requires (member_kind != member::None) + constexpr InitMethodHop argsT() const; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/HopBuilderMethod.hpp b/ReflectionTemplateLib/rtl/detail/inc/HopBuilderMethod.hpp new file mode 100644 index 00000000..ec87fdf6 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/HopBuilderMethod.hpp @@ -0,0 +1,216 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace rtl::detail +{ + template + template requires (member_kind != member::None) + inline constexpr InitMethodHop HopBuilder::argsT() const + { + auto normalId = traits::uid>::value; + return { m_method, getRefAndValueOverloads(m_method, normalId) }; + } + + + template + inline std::vectorHopBuilder ::getRefAndValueOverloads(const Method& pMethod, + const traits::uid_t pNormalId) + { + std::vector fnTypeMetas(call_by::ncref); + for (auto& typeMeta : pMethod.getFunctorsMeta()) + { + if constexpr (!std::is_same_v) + { + if (traits::uid::value != typeMeta.get_record_id()) { + return fnTypeMetas; + } + } + if (member_kind != typeMeta.get_member_kind()) { + continue; + } + if (pNormalId == typeMeta.get_normal_args_id()) + { + if (pNormalId == typeMeta.get_strict_args_id()) { + fnTypeMetas[call_by::value] = typeMeta; + } + else if (!typeMeta.is_any_arg_ncref()) { + fnTypeMetas[call_by::cref] = typeMeta; + } + else fnTypeMetas.push_back(typeMeta); + } + } + return fnTypeMetas; + } +} + + + +namespace rtl::detail +{ + template + template requires (!traits::type_aware_v) + inline constexpr method InitMethodHop::returnT() const + { + using hopper_t = typename method::hopper_t; + + auto validateReturn = [](const std::vector& overloadsMeta, hopper_t& pHopper)-> bool { + if constexpr (!std::is_same_v ) { + for (auto& tyMeta : overloadsMeta) { + if (!tyMeta.is_empty() && tyMeta.is_void()) { // Temporary Quick Fix. + //TODO: needs to be fixed for erased-target-known-return. specifically for 'void'. + return true; + } + if (!tyMeta.is_empty()) + { + if (tyMeta.get_return_id() != traits::uid::value) { + //TODO: Not tested yet. + pHopper.set_init_error(error::ReturnTypeMismatch); + return false; + } + } + } + } + return true; + }; + + auto mth = method(); + auto normalId = traits::uid>::value; + auto recordId = m_method.getRecordTypeId(); + + if constexpr (member_kind == member::Const) { + + if (validateReturn(m_overloadsMeta, mth.get_c_hops())) { + init(recordId, m_overloadsMeta, mth.get_c_hops()); + } + auto overloadsMeta = HopBuilder::getRefAndValueOverloads(m_method, normalId); + if (validateReturn(overloadsMeta, mth.get_nc_hops())) { + init(recordId, overloadsMeta, mth.get_nc_hops()); + } + } + else if constexpr (member_kind == member::NonConst) { + + if (validateReturn(m_overloadsMeta, mth.get_nc_hops())) { + init(recordId, m_overloadsMeta, mth.get_nc_hops()); + } + auto overloadsMeta = HopBuilder::getRefAndValueOverloads(m_method, normalId); + if (validateReturn(overloadsMeta, mth.get_c_hops())) { + init(recordId, overloadsMeta, mth.get_c_hops()); + } + } + + if (mth.get_nc_hops().get_init_error() == error::None && + mth.get_c_hops().get_init_error() != error::None) { + mth.get_c_hops().set_init_error(error::ConstOverloadMissing); + } + else if (mth.get_c_hops().get_init_error() == error::None && + mth.get_nc_hops().get_init_error() != error::None) { + mth.get_nc_hops().set_init_error(error::NonConstOverloadMissing); + } + return mth; + } + + + template + template requires (traits::type_aware_v) + inline constexpr typename InitMethodHop::template method_t + InitMethodHop::returnT() const + { + auto mth = []()->decltype(auto) { + if constexpr (member_kind == member::Const) { + return const_method(); + } + else { + return method(); + } + }(); + + auto strictId = traits::uid>::value; + using rec_t = std::conditional_t; + using method_ptr_t = dispatch::method_ptr; + + for (auto& tyMeta : m_overloadsMeta) { + if (!tyMeta.is_empty()) + { + if (tyMeta.get_return_id() != traits::uid::value) { + mth.set_init_error(error::ReturnTypeMismatch); + return mth; + } + if (tyMeta.get_strict_args_id() == strictId) { + auto fptr = static_cast(tyMeta.get_functor()).f_ptr(); + return method_t(fptr); + } + } + } + mth.set_init_error(error::SignatureMismatch); + return mth; + } + + + template + template + inline void InitMethodHop::init(const traits::uid_t pRecordId, + const std::vector& pRefOverloads, + typename method::hopper_t& pHopper) + { + for (auto& typeMeta : pRefOverloads) + { + if (typeMeta.is_empty()) { + pHopper.get_hopper().push_back(nullptr); + pHopper.get_overloads().push_back(nullptr); + continue; + } + + auto fn = [&]()-> decltype(auto) { + if constexpr (traits::type_erased_v) { + + using fn_cast = dispatch::functor_cast...>; + return fn_cast(typeMeta.get_functor()).to_method(); + } + else if constexpr (traits::target_erased_v) { + + using fn_cast = dispatch::functor_cast...>; + return fn_cast(typeMeta.get_functor()).template to_method(); + } + else if constexpr (traits::return_erased_v) { + + using fn_cast = dispatch::functor_cast...>; + return fn_cast(typeMeta.get_functor()).template to_method(); + } + }(); + + pHopper.get_hopper().push_back(fn.f_ptr()); + pHopper.get_overloads().push_back(&typeMeta.get_functor()); + pHopper.set_init_error(error::None); + } + + if (pHopper.get_init_error() != error::None) { + pHopper.set_init_error(error::SignatureMismatch); + } + else { + pHopper.set_record_id(pRecordId); + } + } +} diff --git a/ReflectionTemplateLib/rtl/detail/inc/RObjExtracter.h b/ReflectionTemplateLib/rtl/detail/inc/RObjExtracter.h new file mode 100644 index 00000000..b916bd91 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/RObjExtracter.h @@ -0,0 +1,151 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::detail +{ + struct RObjExtractor + { + friend RObject; + + const RObject* m_rObj; + + template + ForceInline static const T* getPointer(const std::any& pObject, const EntityKind pEntityKind) noexcept + { + switch (pEntityKind) + { + case EntityKind::Ptr: { + return *(std::any_cast(&pObject)); + } + case EntityKind::Value: { + return std::any_cast(&pObject); + } + default: return nullptr; + } + return nullptr; + } + + + template + ForceInline const T* getPointer() const noexcept + { + switch (m_rObj->m_objectId.m_containsAs) + { + case EntityKind::Ptr: { + return *(std::any_cast(&(m_rObj->m_object.value()))); + } + case EntityKind::Wrapper: { + return getFromWrapper(); + } + case EntityKind::Value: { + return std::any_cast(&(m_rObj->m_object.value())); + } + default: return nullptr; + } + return nullptr; + } + + + template = 0> + ForceInline auto getWrapper() const noexcept -> const RObjectUPtr::value_type>* + { + 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) + { + using U = detail::RObjectUPtr; + return std::any_cast(&(m_rObj->m_object.value())); + } + } + else + { + using U = detail::RObjectUPtr<_T>; + return std::any_cast(&(m_rObj->m_object.value())); + } + } + return nullptr; + } + + + template = 0> + ForceInline const T* getWrapper() const noexcept + { + 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) { + using U = std::shared_ptr; + return std::any_cast(&(m_rObj->m_object.value())); + } + } + else + { + using U = std::shared_ptr<_T>; + return std::any_cast(&(m_rObj->m_object.value())); + } + } + return nullptr; + } + + + template + ForceInline const T* getFromWrapper() const noexcept + { + if constexpr (std::is_destructible_v) + { + if (m_rObj->m_objectId.m_wrapperType == detail::Wrapper::Unique) + { + if (m_rObj->m_objectId.m_isWrappingConst) { + using U = detail::RObjectUPtr; + const U* uptr = std::any_cast(&(m_rObj->m_object.value())); + if (uptr != nullptr) { + return uptr->get(); + } + } + else { + using U = detail::RObjectUPtr; + const U* uptr = std::any_cast(&(m_rObj->m_object.value())); + if (uptr != nullptr) { + return uptr->get(); + } + } + } + if (m_rObj->m_objectId.m_wrapperType == detail::Wrapper::Shared) + { + if (m_rObj->m_objectId.m_isWrappingConst) { + using U = std::shared_ptr; + const U* sptr = std::any_cast(&(m_rObj->m_object.value())); + if (sptr != nullptr) { + return sptr->get(); + } + } + else { + using U = std::shared_ptr; + const U* sptr = std::any_cast(&(m_rObj->m_object.value())); + if (sptr != nullptr) { + return sptr->get(); + } + } + } + } + return nullptr; + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/RObjectBuilder.h b/ReflectionTemplateLib/rtl/detail/inc/RObjectBuilder.h new file mode 100644 index 00000000..91974aec --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/RObjectBuilder.h @@ -0,0 +1,72 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::detail +{ + template + struct RObjectBuilder + { + RObjectBuilder() = delete; + RObjectBuilder(const RObjectBuilder&) = delete; + + template requires (_allocOn == alloc::Heap) + static RObject build(T&& pVal, traits::cloner_t pClonerFn, bool pIsConstCastSafe) noexcept; + + template requires (_allocOn == alloc::Stack) + static RObject build(T&& pVal, traits::cloner_t pClonerFn, bool pIsConstCastSafe) noexcept; + + template + static RObject build(T&& pVal, bool pIsConstCastSafe) noexcept; + }; +} + + +namespace rtl +{ + static inline std::size_t getRtlManagedHeapInstanceCount() + { + return RObject::getInstanceCounter(); + } + + template + static inline RObject reflect(T(&pArr)[N]) noexcept + { + if constexpr (std::is_same_v, char>) { + return detail::RObjectBuilder::template + build(std::string_view(pArr, N - 1), !traits::is_const_v); + } + else { + return detail::RObjectBuilder>::template + build(std::vector(pArr, pArr + N), !traits::is_const_v); + } + } + + template + static inline RObject reflect(T&& pVal) noexcept + { + using _T = traits::raw_t; + if constexpr (traits::std_wrapper<_T>::type == detail::Wrapper::None) + { + 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::template + build(std::forward(pVal), isConstCastSafe); + } + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/RObjectBuilder.hpp b/ReflectionTemplateLib/rtl/detail/inc/RObjectBuilder.hpp new file mode 100644 index 00000000..ce4c1770 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/RObjectBuilder.hpp @@ -0,0 +1,122 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +namespace rtl::detail +{ + template + struct Cloner + { + static Return copyCtor(alloc p_alloc_on, const RObject& p_other) + { + if constexpr (std::is_copy_constructible_v) + { + const auto& srcObj = p_other.view()->get(); + switch (p_alloc_on) + { + case alloc::Stack: + return { + error::None, + RObjectBuilder::template build(T(srcObj), ©Ctor, true) + }; + case alloc::Heap: + return { + error::None, + RObjectBuilder::template build(new T(srcObj), ©Ctor, true) + }; + default: + return { error::EmptyRObject, RObject{} }; + } + } + else + { + return { error::TypeNotCopyConstructible, RObject{} }; + } + } + }; +} + + +namespace rtl::detail +{ + template + template requires (_allocOn == alloc::Heap) + inline RObject RObjectBuilder::build(T&& pVal, traits::cloner_t pClonerFn, bool pIsConstCastSafe) noexcept + { + using _T = traits::raw_t; + return RObject( std::any{ + std::in_place_type>, + RObjectUPtr<_T>(std::unique_ptr<_T>(static_cast<_T*>(pVal))) + }, + RObjectId::create, alloc::Heap>(pIsConstCastSafe, pClonerFn) ); + } + + + template + template + inline RObject rtl::detail::RObjectBuilder::build(T&& pVal, bool pIsConstCastSafe) noexcept + { + using _T = traits::raw_t; + if constexpr (traits::std_wrapper<_T>::type == Wrapper::None) + { + return RObjectBuilder::template build<_allocOn>( + std::forward(pVal), &Cloner<_T>::copyCtor, pIsConstCastSafe + ); + } + else + { + return RObjectBuilder::template build<_allocOn>( + std::forward(pVal), &Cloner::value_type>::copyCtor, pIsConstCastSafe + ); + } + } + + + template + template requires (_allocOn == alloc::Stack) + inline RObject RObjectBuilder::build(T&& pVal, traits::cloner_t pClonerFn, bool pIsConstCastSafe) noexcept + { + using _T = traits::raw_t; + constexpr bool isRawPointer = std::is_pointer_v>; + + if constexpr (isRawPointer) + { + return RObject( std::any { static_cast(pVal) }, + RObjectId::create(pIsConstCastSafe, pClonerFn) ); + } + else + { + if constexpr (traits::std_wrapper<_T>::type == Wrapper::Unique) + { + using U = traits::std_wrapper<_T>::value_type; + return RObject( std::any { + std::in_place_type>, + RObjectUPtr(std::move(pVal)) + }, + RObjectId::create(pIsConstCastSafe, pClonerFn) ); + } + else + { + static_assert(std::is_copy_constructible_v<_T>, "T must be copy-constructible (std::any requires this)."); + return RObject( std::any { + std::in_place_type, + std::forward(pVal) + }, + RObjectId::create(pIsConstCastSafe, pClonerFn) ); + } + } + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/RObjectId.h b/ReflectionTemplateLib/rtl/detail/inc/RObjectId.h new file mode 100644 index 00000000..7943655a --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/RObjectId.h @@ -0,0 +1,93 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::detail +{ + struct RObjectId + { + bool m_isWrappingConst; + bool m_isConstCastSafe; + + traits::uid_t m_typeId; + std::size_t m_wrapperTypeId; + + alloc m_allocatedOn; + Wrapper m_wrapperType; + EntityKind m_containsAs; + + traits::cloner_t m_clonerFn; + + const std::vector* m_converters = nullptr; + + GETTER(traits::uid_t, TypeId, m_typeId) + GETTER(EntityKind, ContainedAs, m_containsAs) + + template + static constexpr const std::vector& getConverters() noexcept + { + // extract wrapper info. + using _W = traits::std_wrapper>; + // extract Un-Qualified raw type. + using _T = traits::raw_t>; + return ReflectCast<_T>::getConversions(); + } + + template + static constexpr EntityKind getEntityKind() noexcept + { + using W = traits::std_wrapper>; + using _T = traits::raw_t>; + constexpr bool isRawPtr = traits::is_raw_ptr_v; + constexpr bool isWrapper = (W::type != Wrapper::None); + + if constexpr (isWrapper && !isRawPtr) { + return EntityKind::Wrapper; + } + else if constexpr (isRawPtr && !isWrapper) { + return EntityKind::Ptr; + } + else if constexpr (!isWrapper && !isRawPtr) { + return EntityKind::Value; + } + } + + template + ForceInline static RObjectId create(bool pIsConstCastSafe, traits::cloner_t pClonerFn) noexcept + { + // extract wrapper info. + using _W = traits::std_wrapper>; + // extract Un-Qualified raw type. + using _T = traits::raw_t>; + constexpr EntityKind entityKind = getEntityKind(); + + const std::size_t wrapperId = _W::id(); + const traits::uid_t typeId = traits::uid<_T>::value; + + constexpr bool isWrappingConst = (_W::type != Wrapper::None && traits::is_const_v); + return RObjectId { + + isWrappingConst, + pIsConstCastSafe, + typeId, + wrapperId, + _allocOn, + _W::type, + entityKind, + pClonerFn, + &getConverters() + }; + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/RObjectUPtr.h b/ReflectionTemplateLib/rtl/detail/inc/RObjectUPtr.h new file mode 100644 index 00000000..98af8df2 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/RObjectUPtr.h @@ -0,0 +1,93 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +/*------------------------------------------------------------------------------------------ + RObjectUPtr + + Purpose: + -------- + MSVC's std::any refuses to store std::unique_ptr directly because + std::unique_ptr is *not copy-constructible*. This restriction makes sense + for safety, but it prevents us from using std::any to hold unique_ptr-managed + objects in a reflection context. + + GCC/Clang technically allow it in certain cases by relying on moves, but + their behavior isn't guaranteed consistent across all standards. + We need *predictable cross-compiler behavior*. + + Solution: + --------- + RObjectUPtr is a thin, move-only wrapper that *pretends* to be copyable, + but its "copy constructor" does nothing and RTL makes sure its never called. + This satisfies std::any's requirement for a copy constructor, while ensuring + only one instance ever truly owns the resource. + + Key Properties: + --------------- + 1. Copy constructor - never gets called. + 2. Move constructor works as expected. + 3. Deleted copy/move assignment operators to prevent post-construction reassignment. + 4. Tracks heap allocation count via RObject's internal counter for lifetime diagnostics. + +--------------------------------------------------------------------------------------------*/ + +#include + +namespace rtl::detail +{ + template + struct RObjectUPtr + { + RObjectUPtr() = delete; + RObjectUPtr& operator=(const RObjectUPtr&) = delete; + RObjectUPtr& operator=(RObjectUPtr&& other) = delete; + + // Copy constructor: empty, just to trick the 'std::any'. NEVER GETS CALLED!! + RObjectUPtr(const RObjectUPtr& pOther) { + assert(false && "RObjectUPtr(const RObjectUPtr&) must never get called."); + } + + // Move constructor: transfers ownership as usual. + RObjectUPtr(RObjectUPtr&& pOther) noexcept + : m_uniquePtr(std::move(pOther.m_uniquePtr)) { + pOther.m_uniquePtr = nullptr; + } + + // Construct directly from std::unique_ptr, tracking RTL-owned heap allocations. + RObjectUPtr(std::unique_ptr&& pUniquePtr) + : m_uniquePtr(std::move(pUniquePtr)) { + RObject::getInstanceCounter()++;//.fetch_add(1, std::memory_order_relaxed); + } + + // Destructor: decrements allocation count if we still own the object. + ~RObjectUPtr() { + if (m_uniquePtr) { + RObject::getInstanceCounter()--;//.fetch_sub(1, std::memory_order_relaxed); + } + } + + const T* get() const { + return m_uniquePtr.get(); + } + + const std::unique_ptr& cref() const { + return m_uniquePtr; + } + + private: + + mutable std::unique_ptr m_uniquePtr; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/ReflectCast.h b/ReflectionTemplateLib/rtl/detail/inc/ReflectCast.h new file mode 100644 index 00000000..154a5b0a --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/ReflectCast.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::detail +{ + class ReflectedConversions + { + static void init(); + + friend rtl::CxxMirror; + }; + + + template + class ReflectCast + { + ForceInline static std::vector>& conversions() { + static std::vector> converters; + return converters; + } + + public: + + template static void pushConversion(); + + ForceInline static const std::vector>& getConversions() { + return conversions(); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/ReflectCast.hpp b/ReflectionTemplateLib/rtl/detail/inc/ReflectCast.hpp new file mode 100644 index 00000000..dbac8a42 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/ReflectCast.hpp @@ -0,0 +1,60 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +namespace rtl::detail +{ + template + template + inline void ReflectCast<_fromType>::pushConversion() + { +// if constexpr (traits::is_safe_conversion_v<_fromType, _toType>) + { + const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind) -> std::any + { + try + { + bool isPointer = (pSrcEntityKind == EntityKind::Ptr); + const _fromType& srcRef = (isPointer ? *(std::any_cast(pSrc)) : std::any_cast(pSrc)); + + if constexpr (std::is_convertible_v<_fromType*, _toType*>) + { + pNewEntityKind = pSrcEntityKind; + return std::any(std::in_place_type, static_cast(srcRef)); + } + else if constexpr ((std::is_convertible_v<_fromType, _toType> && + !std::is_convertible_v<_fromType&, const _toType&>) || + std::is_constructible_v<_toType, const _fromType&>) { + + pNewEntityKind = EntityKind::Value; + return std::any(std::in_place_type<_toType>, _toType(srcRef)); + } + else { + + pNewEntityKind = EntityKind::None; + return std::any(); + } + } + catch (const std::bad_any_cast&) + { + pNewEntityKind = EntityKind::None; + return std::any(); + } + }; + conversions().emplace_back(std::pair(traits::uid<_toType>::value, conversion)); + } + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/inc/ReflectCastUtil.h b/ReflectionTemplateLib/rtl/detail/inc/ReflectCastUtil.h new file mode 100644 index 00000000..3c434e37 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/inc/ReflectCastUtil.h @@ -0,0 +1,80 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace +{ + template + struct TypeConversion + { + using from = From; + using to = To; + }; + + + template + auto make_pairs_for_index(std::index_sequence) + { + using From = std::tuple_element_t; + return std::tuple>...>{}; + } + + + template + auto make_all_pairs(std::index_sequence) + { + return std::tuple_cat( + make_pairs_for_index + ( + std::make_index_sequence::value>{} + )... + ); + } + + + template + constexpr auto make_conversion_pairs() + { + return make_all_pairs( + std::make_index_sequence::value>{} + ); + } + + + template + void register_all_conversions_impl(std::index_sequence) + { + (..., + ( + []{ + using Conversion = std::tuple_element_t; + using From = typename Conversion::from; + using To = typename Conversion::to; + if constexpr (!std::is_same_v) { + rtl::detail::ReflectCast::template pushConversion(); + } + }() + ) + ); + } + + + template + void register_all_conversions() + { + register_all_conversions_impl( + std::make_index_sequence::value> { } + ); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/src/CMakeLists.txt b/ReflectionTemplateLib/rtl/detail/src/CMakeLists.txt new file mode 100644 index 00000000..668c6728 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/src/CMakeLists.txt @@ -0,0 +1,11 @@ +# ReflectionTemplateLibrary-CPP/ReflectionTemplateLib/detail/src/CMakeLists.txt + +# All .cpp files in this folder (absolute paths) +set(LOCAL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/CxxReflection.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ReflectCast.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RObjectConverters_string.cpp" +) + +target_sources(ReflectionTemplateLib PRIVATE ${LOCAL_SOURCES}) +source_group("Source Files\\Detail" FILES ${LOCAL_SOURCES}) \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/src/CxxReflection.cpp b/ReflectionTemplateLib/rtl/detail/src/CxxReflection.cpp new file mode 100644 index 00000000..27d00905 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/src/CxxReflection.cpp @@ -0,0 +1,230 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#include + +#include +#include +#include +#include + +namespace rtl { + + namespace detail + { + /* @Constructor: CxxReflection + @params: 'const std::vector&' + * recieves vector of 'Function' objects, forwarded from 'CxxMirror' constructor. + * initiates grouping of each 'Function' object under namespace, class/struct. + */ CxxReflection::CxxReflection(const std::vector& pFunctions) + { + // First, map all record (could be any type, not just class/struct) registered using interface- + // 'rtl::type().record("...")' with its type-id (i.e, rtl::traits::uid). + // every such registration will always have a default-constructor metadata. + // Simultaneously, register any other user-defined constructor, if given. + buildRecordIdMap(pFunctions); + + for (const auto& function : pFunctions) + { + if (// Validate, if the member-function-pointer belongs to the 'TYPE' given using interface- + // rtl::type().member("...")', if not ignore this registration. + validateMethodByRecordId(function) && // Returns false if this 'function' is ignored. + // Once validated, try inserting 'function' as a member to its Record (i.e, to its class/struct metadata descriptor) + // returns 'false' if the 'function' represents a non-member function (C-Style function). + !insertMethodsToRecordIdMap(function) ) + { + // Finally, register the 'function' as a non-member function under the given or global namespace. + insertFunctionToNamespaceMap(function); + } + } + } + + + /* @method: addFunction + @params: FunctionMap, Function + * adds the 'Function' object as non-member function mapped to the given namespace name. + */ void CxxReflection::addFunction(FunctionMap& pFunctionMap, const Function& pFunction) + { + const auto& fname = pFunction.getFunctionName(); + const auto& itr = pFunctionMap.find(fname); + if (itr == pFunctionMap.end()) { + pFunctionMap.emplace(fname, pFunction); + } + else { + const auto& function = itr->second; + //if the function is already present, add its 'FunctorId' as overload. + // TODO: Make sure every overload has identical return type/id. + function.addOverload(pFunction); + } + } + + + /* @method: addMethod + @params: MethodMap, Function + * adds the 'Function' object as 'Method' object in MethodMap, contained by 'Record' object. + * if the function name already exists in the map, then 'FunctorId' from the param 'pFunction' is added to already existing 'Function'. + * if a 'Function' object represents a Constructor, it might have the copy-constructor 'FunctorId' as well. + * if copy-constructor 'FunctorId' is found, 'Function' object is created and added to the 'MethodMap' for the same. + */ void CxxReflection::addMethod(MethodMap& pMethodMap, const Function& pFunction) + { + const auto& fname = pFunction.getFunctionName(); + const auto& itr = pMethodMap.find(fname); + if (itr == pMethodMap.end()) { + //construct 'Method' obejct and add. + pMethodMap.emplace(fname, Method(pFunction)); + } + else { + const auto& function = itr->second; + //if the method is already present, add as overload. + // TODO: Make sure every overload has identical return type/id. + function.addOverload(pFunction); + } + } + + + /* @method: organizeFunctorsMetaData + @params: Function + * seggregates all the 'Function' objects and builds 'Record' & 'Method' objects. + */ void CxxReflection::insertFunctionToNamespaceMap(const Function& pFunction) + { + const std::string& nameSpace = pFunction.getNamespace(); + const std::string& recordName = pFunction.getRecordName(); + const traits::uid_t recordId = pFunction.getRecordTypeId(); + //if the recordId(class/struct's type-id) is TypeId<>::None, 'Function' object is considered as non-member function. + if (recordId == traits::uid<>::none) + { + const auto& itr = m_functionNamespaceMap.find(nameSpace); + if (itr == m_functionNamespaceMap.end()) { + const auto& funcMapItr = m_functionNamespaceMap.emplace(nameSpace, FunctionMap()); + addFunction(funcMapItr.first->second, pFunction); + } + else { + addFunction(itr->second, pFunction); + } + } + } + + + void CxxReflection::addInNamespaceMap(Record& pRecord) + { + const auto& itr = m_recordNamespaceMap.find(pRecord.m_namespaceStr); + if (itr == m_recordNamespaceMap.end()) + { + RecordMap& recordStrMap = m_recordNamespaceMap.emplace(pRecord.m_namespaceStr, RecordMap()).first->second; + recordStrMap.emplace(pRecord.m_recordName, std::ref(pRecord)); + } + else + { + RecordMap& recordStrMap = itr->second; + const auto& itr0 = recordStrMap.find(pRecord.m_recordName); + if (itr0 == recordStrMap.end()) { + recordStrMap.emplace(pRecord.m_recordName, std::ref(pRecord)); + } + } + } + + + void CxxReflection::buildRecordIdMap(const std::vector& pFunctions) + { + for (auto& function : pFunctions) { + + const auto& recordName = function.getRecordName(); + const traits::uid_t recordId = function.getRecordTypeId(); + const member memberKind = function.getMemberKind(); + if (memberKind == member::UserCtor || memberKind == member::DefaultCtor) + { + bool isRegistrationIgnored = false; + auto& record = [&]()->const Record& { + const auto& itr = m_recordIdMap.find(recordId); + if (itr == m_recordIdMap.end()) { + auto& record = m_recordIdMap.emplace(recordId, Record(recordName, recordId, function.m_namespaceStr)).first->second; + addInNamespaceMap(record); + return record; + } + else { + auto& record = itr->second; + isRegistrationIgnored = (memberKind == member::DefaultCtor); + if (isRegistrationIgnored) { + std::cout << "\n[WARNING] Multiple registrations of the same type detected." + << "\n Type already registered as \"" << record.m_recordName << "\"" + << "\n Attempted re-registration as \"" << recordName << "\"" + << "\n This registration is ignored.\n"; + } + return record; + } + }(); + + if (!isRegistrationIgnored) { + Function constructor = function; + constructor.m_recordStr = record.m_recordName; + constructor.m_namespaceStr = record.m_namespaceStr; + constructor.m_function = ctor_name(record.m_recordName); + addMethod(record.getFunctionsMap(), constructor); + } + } + } + } + + + /* During registration of a method using: + * rtl::type().member().methodConst("empty").build(&std::string::empty), + * the `givenRecordId` is generated by the `rtl::type().member()` call (T = `std::string`), + * and the `actualRecordId` is extracted from the type of the function pointer passed to `build(...)`. + * + * - If the function is a non-member function, both `givenRecordId` and `actualRecordId` are 'rtl::traits::uid<>::none'. + * - If it's a member-function, both IDs **must** match - this check helps catch registration errors + * where the member function belongs to a different class than the one being registered. + * + * Example of incorrect usage (caught by this validation): + * rtl::type().member().methodConst("empty").build(&std::string::empty); + * Here, the record-type is `std::string_view`, but the method pointer belongs to `std::string`. + */ const bool CxxReflection::validateMethodByRecordId(const Function& pFunction) + { + const auto& functor = pFunction.getFunctors().back(); + const traits::uid_t givenRecordId = pFunction.getRecordTypeId(); + const traits::uid_t actualRecordId = functor.get_record_id(); + if (givenRecordId != actualRecordId) { + std::cout << "\n[WARNING] Member function pointer does not belong to the class/struct being registered." + << "\n Member function: " << functor.get_signature_str() + << "\n This function is ignored and not registered.\n"; + return false; + } + return true; + } + + + bool CxxReflection::insertMethodsToRecordIdMap(const Function& pFunction) + { + const member memberKind = pFunction.getMemberKind(); + if (memberKind == member::Const || memberKind == member::NonConst || memberKind == member::Static) + { + const auto& itr = m_recordIdMap.find(pFunction.getRecordTypeId()); + if (itr != m_recordIdMap.end()) { + + const auto& record = itr->second; + Function memberFunc = pFunction; + + memberFunc.m_recordStr = record.m_recordName; + memberFunc.m_namespaceStr = record.m_namespaceStr; + addMethod(record.getFunctionsMap(), memberFunc); + } + else { + std::cout << "\n[WARNING] The class/struct for this member-function is not registered." + << "\n While registering \"" << pFunction.m_function << "\"" + << "\n Make sure to register the 'Type' (struct/class) as well." + << "\n This registration is ignored.\n"; + } + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp b/ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp new file mode 100644 index 00000000..d3e2738f --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp @@ -0,0 +1,113 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#include +#include +#include + +namespace rtl::detail +{ + template<> + template<> + void ReflectCast::pushConversion() + { + const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any + { + try { + pNewEntityKind = EntityKind::Ptr; + const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr); + // GCOVR_EXCL_START + if (pSrcEntityKind == EntityKind::Wrapper) { + //TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'. + const auto& srcRUptr = std::any_cast&>(pSrc); + return std::any(srcRUptr.get()->c_str()); + } + // GCOVR_EXCL_STOP + else { + const auto& srcObj = (isPtr ? *std::any_cast(pSrc) : std::any_cast(pSrc)); + return std::any(srcObj.c_str()); + } + } + // GCOVR_EXCL_START + catch (const std::exception&) { + pNewEntityKind = EntityKind::None; + return std::any(); + } + // GCOVR_EXCL_STOP + }; + conversions().emplace_back(std::pair(traits::uid::value, conversion)); + } + + + template<> + template<> + void ReflectCast::pushConversion() + { + const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any + { + try { + pNewEntityKind = EntityKind::Ptr; + const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr); + // GCOVR_EXCL_START + if (pSrcEntityKind == EntityKind::Wrapper) { + //TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'. + const auto& srcRUptr = std::any_cast&>(pSrc); + return std::any(srcRUptr.get()->data()); + } + // GCOVR_EXCL_STOP + else { + const auto& srcObj = (isPtr ? *std::any_cast(pSrc) : std::any_cast(pSrc)); + return std::any(srcObj.data()); + } + } + // GCOVR_EXCL_START + catch (const std::exception&) { + pNewEntityKind = EntityKind::None; + return std::any(); + } + // GCOVR_EXCL_STOP + }; + conversions().emplace_back(std::pair(traits::uid::value, conversion)); + } + + + template<> + template<> + void ReflectCast::pushConversion() + { + using _toType = std::string; + const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any + { + try { + pNewEntityKind = EntityKind::Value; + const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr); + // GCOVR_EXCL_START + if (pSrcEntityKind == EntityKind::Wrapper) { + //TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'. + const auto& srcRUptr = std::any_cast&>(pSrc); + return std::any(_toType(*srcRUptr.get())); + } + // GCOVR_EXCL_STOP + else { + const auto& srcObj = (isPtr ? *std::any_cast(pSrc) : std::any_cast(pSrc)); + return std::any(_toType(srcObj)); + } + } + // GCOVR_EXCL_START + catch (const std::exception&) { + pNewEntityKind = EntityKind::None; + return std::any(); + } + // GCOVR_EXCL_STOP + }; + conversions().emplace_back(std::pair(traits::uid<_toType>::value, conversion)); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/detail/src/ReflectCast.cpp b/ReflectionTemplateLib/rtl/detail/src/ReflectCast.cpp new file mode 100644 index 00000000..49d2acc6 --- /dev/null +++ b/ReflectionTemplateLib/rtl/detail/src/ReflectCast.cpp @@ -0,0 +1,52 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#include +#include + +namespace rtl::detail +{ + template<> + template<> + void ReflectCast::pushConversion(); + + template<> + template<> + void ReflectCast::pushConversion(); + + template<> + template<> + void ReflectCast::pushConversion(); +} + + +namespace rtl::detail +{ + void ReflectedConversions::init() + { + static const bool _= []() + { + ReflectCast::pushConversion(); + ReflectCast::pushConversion(); + + ReflectCast::pushConversion(); + ReflectCast::pushConversion(); + + using _safePODTypes = std::tuple + ; + + auto conversions = make_conversion_pairs<_safePODTypes>(); + register_all_conversions(); + + return true; + }(); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/CMakeLists.txt b/ReflectionTemplateLib/rtl/dispatch/CMakeLists.txt new file mode 100644 index 00000000..85da238f --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/CMakeLists.txt @@ -0,0 +1,30 @@ +# ReflectionTemplateLibrary-CPP/ReflectionTemplateLib/dispatch/CMakeLists.txt + +# Collect headers in this folder (absolute paths) +set(LOCAL_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/functor.h" + "${CMAKE_CURRENT_SOURCE_DIR}/functor_cast.h" + "${CMAKE_CURRENT_SOURCE_DIR}/forward_call.h" + + "${CMAKE_CURRENT_SOURCE_DIR}/cache_method_ptr.h" + "${CMAKE_CURRENT_SOURCE_DIR}/cache_function_ptr.h" + "${CMAKE_CURRENT_SOURCE_DIR}/cache_method_ptr_const.h" + + "${CMAKE_CURRENT_SOURCE_DIR}/method_ptr.h" + "${CMAKE_CURRENT_SOURCE_DIR}/method_ptr.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/method_lambda.h" + "${CMAKE_CURRENT_SOURCE_DIR}/method_ptr_const.h" + "${CMAKE_CURRENT_SOURCE_DIR}/method_ptr_const.hpp" + + "${CMAKE_CURRENT_SOURCE_DIR}/function_ptr.h" + "${CMAKE_CURRENT_SOURCE_DIR}/function_ptr.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/function_lambda.h" + + "${CMAKE_CURRENT_SOURCE_DIR}/aware_return.h" + "${CMAKE_CURRENT_SOURCE_DIR}/aware_constructor.h" + "${CMAKE_CURRENT_SOURCE_DIR}/aware_return_n_target.h" + "${CMAKE_CURRENT_SOURCE_DIR}/aware_return_n_target_const.h" +) + +target_sources(ReflectionTemplateLib PRIVATE ${LOCAL_HEADERS}) +source_group("Header Files\\Dispatch" FILES ${LOCAL_HEADERS}) \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/aware_constructor.h b/ReflectionTemplateLib/rtl/dispatch/aware_constructor.h new file mode 100644 index 00000000..7218e702 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/aware_constructor.h @@ -0,0 +1,78 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::dispatch +{ + template + struct aware_constructor + { + static Return overloaded_ctor(alloc p_alloc_on, traits::normal_sign_t&&...params) + { + if (p_alloc_on == alloc::Stack) + { + if constexpr (std::is_copy_constructible_v) + { + return { + error::None, + detail::RObjectBuilder::template + build(record_t(std::forward(params)...), true) + }; + } + } + else if (p_alloc_on == alloc::Heap) + { + return { + error::None, + detail::RObjectBuilder::template + build(new record_t(std::forward(params)...), true) + }; + } + return { error::EmptyRObject, RObject{} }; //dead code. compiler warning omitted. + } + + + static Return default_ctor(alloc p_alloc_on) + { + if constexpr (std::is_default_constructible_v) + { + switch (p_alloc_on) + { + case alloc::Stack: + if constexpr (std::is_copy_constructible_v) + { + return { + error::None, + detail::RObjectBuilder::template + build(record_t(), true) + }; + } + else return { error::TypeNotCopyConstructible, RObject{} }; + case alloc::Heap: + return { + error::None, + detail::RObjectBuilder::template + build(new record_t(), true) + }; + default: + return { error::EmptyRObject, RObject{} }; + } + } + else + { + return { error::TypeNotDefaultConstructible, RObject{} }; + } + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/aware_return.h b/ReflectionTemplateLib/rtl/dispatch/aware_return.h new file mode 100644 index 00000000..d5e120bd --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/aware_return.h @@ -0,0 +1,54 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::dispatch +{ + template + struct aware_return + { + constexpr static Return get_lambda_any_return(const functor& fn, traits::normal_sign_t&&... params) noexcept + { + auto fptr = static_cast&>(fn).f_ptr(); + + if constexpr (std::is_void_v) + { + (*fptr)(std::forward(params)...); + return { error::None, RObject{} }; + } + else + { + constexpr bool isConstCastSafe = (!traits::is_const_v); + if constexpr (std::is_reference_v) { + + using raw_t = traits::raw_t; + const raw_t& ret_v = (*fptr)(std::forward(params)...); + return { error::None, + detail::RObjectBuilder::template + build(&ret_v, isConstCastSafe) + }; + } + else { + + auto&& ret_v = (*fptr)(std::forward(params)...); + return { error::None, + detail::RObjectBuilder::template + build(std::forward(ret_v), isConstCastSafe) + }; + } + } + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target.h b/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target.h new file mode 100644 index 00000000..9ee6c86d --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target.h @@ -0,0 +1,108 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::dispatch +{ + template + struct aware_return_n_target + { + constexpr static auto erased_target_aware_return(const functor& fn, const RObject& p_target, + traits::normal_sign_t&&... params) noexcept + { + const auto& target = p_target.view()->get(); + auto mptr = static_cast&>(fn).f_ptr(); + + if constexpr (std::is_void_v) + { + (const_cast(target).*mptr)(std::forward(params)...); + return std::make_pair(error::None, std::optional()); + } + else + { + auto&& ret_v = (const_cast(target).*mptr)(std::forward(params)...); + if constexpr (std::is_reference_v) { + return std::make_pair(error::None, std::optional*>(&ret_v)); + } + else { + return std::make_pair(error::None, std::optional(std::in_place, std::move(ret_v))); + } + } + } + + + constexpr static Return erased_return_aware_target(const functor& fn, const record_t& p_target, + traits::normal_sign_t&&...params) noexcept + { + auto mptr = static_cast&>(fn).f_ptr(); + + if constexpr (std::is_void_v) + { + (const_cast(p_target).*mptr)(std::forward(params)...); + return { error::None, RObject{} }; + } + else + { + constexpr bool isConstCastSafe = (!traits::is_const_v); + auto&& ret_v = (const_cast(p_target).*mptr)(std::forward(params)...); + + if constexpr (std::is_reference_v) { + return { error::None, + detail::RObjectBuilder*>::template + build(&ret_v, isConstCastSafe) + }; + } + else { + return { error::None, + detail::RObjectBuilder::template + build(std::forward(ret_v), isConstCastSafe) + }; + } + } + } + + + constexpr static Return erased_return_and_target(const functor& fn, const RObject& p_target, + traits::normal_sign_t&&... params) noexcept + { + const auto& target = p_target.view()->get(); + auto mptr = static_cast&>(fn).f_ptr(); + + if constexpr (std::is_void_v) + { + (const_cast(target).*mptr)(std::forward(params)...); + return { error::None, RObject{} }; + } + else + { + constexpr bool isConstCastSafe = (!traits::is_const_v); + auto&& ret_v = (const_cast(target).*mptr)(std::forward(params)...); + + if constexpr (std::is_reference_v) { + return { error::None, + detail::RObjectBuilder*>::template + build(&ret_v, isConstCastSafe) + }; + } + else { + return { error::None, + detail::RObjectBuilder::template + build(std::forward(ret_v), isConstCastSafe) + }; + } + } + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target_const.h b/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target_const.h new file mode 100644 index 00000000..3874f3a4 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target_const.h @@ -0,0 +1,107 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::dispatch +{ + template + struct aware_return_n_target + { + constexpr static auto erased_target_aware_return(const functor& fn, const RObject& p_target, + traits::normal_sign_t&&... params) noexcept + { + const auto& target = p_target.view()->get(); + auto mptr = static_cast&>(fn).f_ptr(); + + if constexpr (std::is_void_v) + { + (target.*mptr)(std::forward(params)...); + return std::make_pair(error::None, std::optional()); + } + else + { + auto&& ret_v = (target.*mptr)(std::forward(params)...); + if constexpr (std::is_reference_v) { + return std::make_pair(error::None, std::optional*>(&ret_v)); + } + else { + return std::make_pair(error::None, std::optional(std::in_place, std::move(ret_v))); + } + } + } + + + constexpr static Return erased_return_aware_target(const functor& fn, const record_t& p_target, + traits::normal_sign_t&&...params) noexcept + { + auto mptr = static_cast&>(fn).f_ptr(); + + if constexpr (std::is_void_v) + { + (p_target.*mptr)(std::forward(params)...); + return { error::None, RObject{} }; + } + else + { + constexpr bool isConstCastSafe = (!traits::is_const_v); + auto&& ret_v = (p_target.*mptr)(std::forward(params)...); + + if constexpr (std::is_reference_v) { + return { error::None, + detail::RObjectBuilder*>::template + build(&ret_v, isConstCastSafe) + }; + } + else { + return { error::None, + detail::RObjectBuilder::template + build(std::forward(ret_v), isConstCastSafe) + }; + } + } + } + + + constexpr static Return erased_return_and_target(const functor& fn, const RObject& p_target, + traits::normal_sign_t&&... params) noexcept + { + const auto& target = p_target.view()->get(); + auto mptr = static_cast&>(fn).f_ptr(); + + if constexpr (std::is_void_v) + { + (target.*mptr)(std::forward(params)...); + return { error::None, RObject{} }; + } + else + { + constexpr bool isConstCastSafe = (!traits::is_const_v); + auto&& ret_v = (target.*mptr)(std::forward(params)...); + + if constexpr (std::is_reference_v) { + return { error::None, + detail::RObjectBuilder*>::template + build(&ret_v, isConstCastSafe) + }; + } + else { + return { error::None, + detail::RObjectBuilder::template + build(std::forward(ret_v), isConstCastSafe) + }; + } + } + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/cache_function_ptr.h b/ReflectionTemplateLib/rtl/dispatch/cache_function_ptr.h new file mode 100644 index 00000000..ed21f357 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/cache_function_ptr.h @@ -0,0 +1,74 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::cache +{ + template + struct function_ptr + { + using function_t = dispatch::function_ptr; + + static const function_ptr& instance() + { + static function_ptr instance_; + return instance_; + } + + template + const dispatch::functor& push_ctor(traits::uid_t p_record_uid) const + { + m_cache.emplace_back(function_t(nullptr, p_record_uid, mem_kind)); + function_t& fn = m_cache.back(); + fn.template init_lambda(); + return fn; + } + + const dispatch::functor& push(return_t(*fptr)(signature_t...), traits::uid_t p_record_uid, + detail::member member_kind) const + { + m_cache.emplace_back(function_t(fptr, p_record_uid, member_kind)); + + function_t& fn = m_cache.back(); + if (member_kind == detail::member::None || member_kind == detail::member::Static) { + fn.init_lambda(); + } + return fn; + } + + const dispatch::functor* find(return_t(*fptr)(signature_t...)) const + { + for (auto& functor : m_cache) + { + if (functor.is_same(fptr)) { + return &functor; + } + } + return nullptr; + } + + function_ptr(function_ptr&&) = delete; + function_ptr(const function_ptr&) = delete; + function_ptr& operator=(function_ptr&&) = delete; + function_ptr& operator=(const function_ptr&) = delete; + + private: + + // No reallocation occurs; original objects stay intact + mutable std::list m_cache; + + function_ptr() = default; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/cache_method_ptr.h b/ReflectionTemplateLib/rtl/dispatch/cache_method_ptr.h new file mode 100644 index 00000000..cc09fb92 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/cache_method_ptr.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::cache +{ + template + struct method_ptr + { + using method_t = dispatch::method_ptr; + + using functor_t = return_t(record_t::*)(signature_t...); + + static const method_ptr& instance() + { + static const method_ptr instance_; + return instance_; + } + + const dispatch::functor& push(functor_t fptr) const + { + m_cache.emplace_back(method_t(fptr)); + method_t& fn = m_cache.back(); + fn.init_lambda(); + return fn; + } + + const dispatch::functor* find(functor_t fptr) const + { + for (auto& functor : m_cache) + { + if (functor.is_same(fptr)) { + return &functor; + } + } + return nullptr; + } + + method_ptr(method_ptr&&) = delete; + method_ptr(const method_ptr&) = delete; + method_ptr& operator=(method_ptr&&) = delete; + method_ptr& operator=(const method_ptr&) = delete; + + private: + + // No reallocation occurs; original objects stay intact + mutable std::list m_cache; + + method_ptr() = default; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/cache_method_ptr_const.h b/ReflectionTemplateLib/rtl/dispatch/cache_method_ptr_const.h new file mode 100644 index 00000000..1a893d45 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/cache_method_ptr_const.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::cache +{ + template + struct method_ptr + { + using method_t = dispatch::method_ptr; + + using functor_t = return_t(record_t::*)(signature_t...) const; + + static const method_ptr& instance() + { + static const method_ptr instance_; + return instance_; + } + + const dispatch::functor& push(functor_t fptr) const + { + m_cache.emplace_back(method_t(fptr)); + method_t& fn = m_cache.back(); + fn.init_lambda(); + return fn; + } + + const dispatch::functor* find(functor_t fptr) const + { + for (auto& functor : m_cache) + { + if (functor.is_same(fptr)) { + return &functor; + } + } + return nullptr; + } + + method_ptr(method_ptr&&) = delete; + method_ptr(const method_ptr&) = delete; + method_ptr& operator=(method_ptr&&) = delete; + method_ptr& operator=(const method_ptr&) = delete; + + private: + + // No reallocation occurs; original objects stay intact + mutable std::list m_cache; + + method_ptr() = default; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/forward_call.h b/ReflectionTemplateLib/rtl/dispatch/forward_call.h new file mode 100644 index 00000000..915bbfaa --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/forward_call.h @@ -0,0 +1,101 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::dispatch +{ + template + struct forward_call + { + constexpr operator bool() const noexcept { + + return !( m_init_err != error::None || m_functors.empty() || + (m_functors.size() == 1 && m_functors[0] == nullptr) ); + } + + constexpr bool must_bind_refs() const noexcept { + + return ( m_functors[detail::call_by::value] == nullptr && + m_functors.size() > detail::call_by::ncref ); + } + + template + [[gnu::hot]] [[gnu::flatten]] + constexpr return_t operator()(args_t&&...params) const noexcept + { + if (must_bind_refs()) [[unlikely]] { + if constexpr (std::is_same_v) { + return { error::ExplicitRefBindingRequired, RObject{} }; + } + else { + return { error::ExplicitRefBindingRequired, std::nullopt }; + } + } + auto index = ( m_functors[detail::call_by::value] != nullptr ? + detail::call_by::value : detail::call_by::cref ); + + return m_hopper[index](*m_functors[index], std::forward(params)...); + } + + template + [[gnu::hot]] [[gnu::flatten]] + constexpr return_t perfect_forward(const traits::uid_t p_sign_id, args_t&&...params) const noexcept + { + for (int index = 0; index < m_functors.size(); index++) + { + if (m_functors[index] != nullptr && + m_functors[index]->get_strict_sign_id() == p_sign_id) { + + return m_hopper[index](*m_functors[index], std::forward(params)...); + } + } + if constexpr (std::is_same_v) { + return { error::RefBindingMismatch, RObject{} }; + } + else { + return { error::RefBindingMismatch, std::nullopt }; + } + } + + GETTER(error, _init_error, m_init_err) + GETTER(traits::uid_t, _record_id, m_record_id) + + private: + + using lambda_t = std::function; + + error m_init_err = error::InvalidCaller; + traits::uid_t m_record_id = traits::uid<>::none; + + std::vector m_hopper = {}; + std::vector m_functors = {}; + + GETTER_REF(std::vector, _hopper, m_hopper) + GETTER_REF(std::vector, _overloads, m_functors) + + void set_init_error(error p_err) { + m_init_err = p_err; + } + + constexpr void set_record_id(const traits::uid_t p_recid) { + m_record_id = p_recid; + } + + template + friend struct detail::InitFunctionHop; + + template + friend struct detail::InitMethodHop; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/function_lambda.h b/ReflectionTemplateLib/rtl/dispatch/function_lambda.h new file mode 100644 index 00000000..f91d4ae2 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/function_lambda.h @@ -0,0 +1,88 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::dispatch +{ + template + struct function_lambda : lambda + { + using fptr_t = Return(*)(alloc, traits::normal_sign_t&&...); + + const fptr_t& f_ptr() const { + return m_fptr; + } + + private: + + void init(const fptr_t& fptr) { + m_fptr = fptr; + } + + fptr_t m_fptr; + + template + friend struct dispatch::function_ptr; + }; +} + + +namespace rtl::dispatch +{ + template + struct function_lambda : lambda + { + using fptr_t = Return(*)(const functor&, traits::normal_sign_t&&...); + + const fptr_t& f_ptr() const { + return m_fptr; + } + + private: + + void init(const fptr_t& fptr) { + m_fptr = fptr; + } + + fptr_t m_fptr; + + template + friend struct dispatch::function_ptr; + }; +} + + +namespace rtl::dispatch +{ + template + struct function_lambda : lambda + { + using fptr_t = Return(*)(const functor&, const RObject&, traits::normal_sign_t&&...); + + const fptr_t& f_ptr() const { + return m_fptr; + } + + private: + + void init(const fptr_t& fptr) { + m_fptr = fptr; + } + + fptr_t m_fptr; + + template + friend struct dispatch::method_ptr; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/function_ptr.h b/ReflectionTemplateLib/rtl/dispatch/function_ptr.h new file mode 100644 index 00000000..6fd4f653 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/function_ptr.h @@ -0,0 +1,65 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +namespace rtl::dispatch +{ + template + struct function_ptr: functor + { + using functor_t = return_t(*)(signature_t...); + + constexpr auto f_ptr() const { + return m_functor; + } + + constexpr bool is_same(functor_t fptr) const { + return (fptr == m_functor); + } + + function_ptr(functor_t fptr, traits::uid_t p_record_uid, detail::member member_kind) + : m_functor(fptr) + { + m_record_id = p_record_uid; + m_is_void = std::is_void_v; + m_return_id = traits::uid::value; + + m_member_kind = member_kind; + m_is_any_arg_ncref = (traits::is_nonconst_ref_v || ...); + m_normal_args_id = traits::uid>::value; + m_strict_args_id = traits::uid>::value; + + m_signature_str = detail::TypeId::toString() + " (" + + detail::TypeId::toString() + ")"; + } + + private: + + using ctor_t = function_lambda; + using func_t = function_lambda; + + functor_t m_functor = nullptr; + std::variant m_lambda; + + void init_lambda(); + + template + void init_lambda(); + + template + friend struct cache::function_ptr; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/function_ptr.hpp b/ReflectionTemplateLib/rtl/dispatch/function_ptr.hpp new file mode 100644 index 00000000..ebef97e5 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/function_ptr.hpp @@ -0,0 +1,50 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include +#include + +namespace rtl::dispatch +{ + template + template + void function_ptr::init_lambda() + { + m_lambda = ctor_t(); + ctor_t& fn = m_lambda.template emplace(); + if constexpr (mem_kind == detail::member::DefaultCtor) { + m_functor = &aware_constructor::default_ctor; + } + else { + fn.init(&aware_constructor::overloaded_ctor); + } + + functor::m_lambdas = std::vector(1); + functor::m_lambdas[index::erased_ctor] = (&fn); + } + + + template + void function_ptr::init_lambda() + { + m_lambda = func_t(); + func_t& fn = m_lambda.template emplace(); + + fn.init(&aware_return::get_lambda_any_return); + + functor::m_lambdas = std::vector(1); + functor::m_lambdas[index::erased_return] = (&fn); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/functor.h b/ReflectionTemplateLib/rtl/dispatch/functor.h new file mode 100644 index 00000000..e87cad4e --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/functor.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::dispatch +{ + struct functor + { + GETTER_BOOL(_void, m_is_void) + GETTER_BOOL(_any_arg_ncref, m_is_any_arg_ncref) + GETTER(traits::uid_t, _record_id, m_record_id) + GETTER(traits::uid_t, _strict_sign_id, m_strict_args_id) + GETTER(traits::uid_t, _normal_sign_id, m_normal_args_id) + + protected: + + enum index { + erased_ctor = 0, + erased_return = 0, + erased_target = 1, + erased_method = 2 + }; + + std::string m_signature_str; + + traits::uid_t m_record_id = traits::uid<>::none; + traits::uid_t m_return_id = traits::uid<>::none; + + traits::uid_t m_normal_args_id = traits::uid<>::none; + traits::uid_t m_strict_args_id = traits::uid<>::none; + + bool m_is_void = false; + bool m_is_any_arg_ncref = false; + + detail::member m_member_kind = detail::member::None; + + std::vector m_lambdas; + std::vector m_args_type_ids = {}; + + friend rtl::type_meta; + + template + friend struct functor_cast; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/functor_cast.h b/ReflectionTemplateLib/rtl/dispatch/functor_cast.h new file mode 100644 index 00000000..394533b7 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/functor_cast.h @@ -0,0 +1,57 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::dispatch +{ + template + struct functor_cast + { + const functor& m_functor; + + constexpr auto to_method() + { + using lambda_t = function_lambda; + return static_cast(*m_functor.m_lambdas[functor::index::erased_method]); + } + + template + constexpr auto to_method() + { + using lambda_t = method_lambda; + if constexpr (erase_v == erase::t_return) + { + return static_cast(*m_functor.m_lambdas[functor::index::erased_return]); + } + else if constexpr (erase_v == erase::t_target) + { + return static_cast(*m_functor.m_lambdas[functor::index::erased_target]); + } + } + + template + constexpr auto to_function() + { + using lambda_t = function_lambda; + if constexpr (erase_v == erase::t_ctor) + { + return static_cast(*m_functor.m_lambdas[functor::index::erased_ctor]); + } + else if constexpr (erase_v == erase::t_return) + { + return static_cast(*m_functor.m_lambdas[functor::index::erased_return]); + } + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/method_lambda.h b/ReflectionTemplateLib/rtl/dispatch/method_lambda.h new file mode 100644 index 00000000..a019517c --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/method_lambda.h @@ -0,0 +1,70 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl::dispatch +{ + template + struct method_lambda : lambda + { + using record_t = known_t; + using fptr_t = Return(*)(const functor&, const record_t&, traits::normal_sign_t&&...); + + const fptr_t& f_ptr() const { + return m_fptr; + } + + private: + + void init(const fptr_t& fptr) { + m_fptr = fptr; + } + + fptr_t m_fptr; + + template + friend struct method_ptr; + }; +} + + +namespace rtl::dispatch +{ + template + struct method_lambda : lambda + { + using if_ref_t = std::conditional_t, std::remove_reference_t*, known_t>; + + using if_void_t = std::conditional_t, std::nullptr_t, if_ref_t>; + + using return_t = std::pair>; + + using fptr_t = return_t(*)(const functor&, const rtl::RObject&, traits::normal_sign_t&&...); + + const fptr_t& f_ptr() const { + return m_fptr; + } + + private: + + void init(const fptr_t& fptr) { + m_fptr = fptr; + } + + fptr_t m_fptr; + + template + friend struct method_ptr; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/method_ptr.h b/ReflectionTemplateLib/rtl/dispatch/method_ptr.h new file mode 100644 index 00000000..ec235d77 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/method_ptr.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +namespace rtl::dispatch +{ + template + struct method_ptr : functor + { + using functor_t = return_t(record_t::*)(signature_t...); + + constexpr auto f_ptr() const { + return m_functor; + } + + constexpr bool is_same(functor_t fptr) const { + return (fptr == m_functor); + } + + method_ptr(functor_t fptr): m_functor(fptr) + { + m_member_kind = detail::member::NonConst; + + m_is_void = std::is_void_v; + m_return_id = traits::uid::value; + m_record_id = traits::uid::value; + + m_is_any_arg_ncref = (traits::is_nonconst_ref_v || ...); + m_normal_args_id = traits::uid>::value; + m_strict_args_id = traits::uid>::value; + + m_signature_str = detail::TypeId::toString() + " [" + + detail::TypeId::toString() + "]::(" + + detail::TypeId::toString() + ")"; + } + + private: + + const functor_t m_functor = nullptr; + + function_lambda m_erased_method; + method_lambda m_erased_return; + method_lambda m_erased_target; + + void init_lambda(); + + template + friend struct cache::method_ptr; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/method_ptr.hpp b/ReflectionTemplateLib/rtl/dispatch/method_ptr.hpp new file mode 100644 index 00000000..1ed918e5 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/method_ptr.hpp @@ -0,0 +1,33 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::dispatch +{ + template + void method_ptr::init_lambda() + { + using lambda_t = aware_return_n_target; + + m_erased_method.init(&lambda_t::erased_return_and_target); + m_erased_target.init(&lambda_t::erased_target_aware_return); + m_erased_return.init(&lambda_t::erased_return_aware_target); + + functor::m_lambdas = std::vector(3); + functor::m_lambdas[index::erased_return] = (&m_erased_return); + functor::m_lambdas[index::erased_target] = (&m_erased_target); + functor::m_lambdas[index::erased_method] = (&m_erased_method); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/method_ptr_const.h b/ReflectionTemplateLib/rtl/dispatch/method_ptr_const.h new file mode 100644 index 00000000..fe6e226e --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/method_ptr_const.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +namespace rtl::dispatch +{ + template + struct method_ptr : functor + { + using functor_t = return_t(record_t::*)(signature_t...) const; + + constexpr auto f_ptr() const { + return m_functor; + } + + constexpr bool is_same(functor_t fptr) const { + return (fptr == m_functor); + } + + method_ptr(functor_t fptr) : m_functor(fptr) + { + m_member_kind = detail::member::Const; + + m_is_void = std::is_void_v; + m_return_id = traits::uid::value; + m_record_id = traits::uid::value; + + m_is_any_arg_ncref = (traits::is_nonconst_ref_v || ...); + m_normal_args_id = traits::uid>::value; + m_strict_args_id = traits::uid>::value; + + m_signature_str = detail::TypeId::toString() + " [" + + detail::TypeId::toString() + "]::(" + + detail::TypeId::toString() + ") const"; + } + + private: + + const functor_t m_functor; + + function_lambda m_erased_method; + method_lambda m_erased_return; + method_lambda m_erased_target; + + void init_lambda(); + + template + friend struct cache::method_ptr; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/dispatch/method_ptr_const.hpp b/ReflectionTemplateLib/rtl/dispatch/method_ptr_const.hpp new file mode 100644 index 00000000..8daf2c38 --- /dev/null +++ b/ReflectionTemplateLib/rtl/dispatch/method_ptr_const.hpp @@ -0,0 +1,33 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::dispatch +{ + template + void method_ptr::init_lambda() + { + using lambda_t = aware_return_n_target; + + m_erased_method.init(&lambda_t::erased_return_and_target); + m_erased_target.init(&lambda_t::erased_target_aware_return); + m_erased_return.init(&lambda_t::erased_return_aware_target); + + functor::m_lambdas = std::vector(3); + functor::m_lambdas[index::erased_return] = (&m_erased_return); + functor::m_lambdas[index::erased_target] = (&m_erased_target); + functor::m_lambdas[index::erased_method] = (&m_erased_method); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/CMakeLists.txt b/ReflectionTemplateLib/rtl/inc/CMakeLists.txt new file mode 100644 index 00000000..7fb77622 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/CMakeLists.txt @@ -0,0 +1,22 @@ +# ReflectionTemplateLibrary-CPP/ReflectionTemplateLib/rtl/inc/CMakeLists.txt + +# Collect local headers (absolute paths) +set(LOCAL_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/CxxMirror.h" + "${CMAKE_CURRENT_SOURCE_DIR}/CxxMirrorToJson.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Function.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Function.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Method.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Method.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Record.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Record.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RObject.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RObject.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/type_meta.h" + "${CMAKE_CURRENT_SOURCE_DIR}/type_meta.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/view.h" + "${CMAKE_CURRENT_SOURCE_DIR}/view.hpp" +) + +target_sources(ReflectionTemplateLib PRIVATE ${LOCAL_HEADERS}) +source_group("Header Files\\RTL" FILES ${LOCAL_HEADERS}) diff --git a/ReflectionTemplateLib/rtl/inc/CxxMirror.h b/ReflectionTemplateLib/rtl/inc/CxxMirror.h new file mode 100644 index 00000000..a7982ab3 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/CxxMirror.h @@ -0,0 +1,71 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + /** + * @class CxxMirror + * + * @brief Primary interface for accessing all registered types, functions, and methods by name. + * + * CxxMirror serves as the single point of entry to the entire reflection system. + * All type, function, and method registrations occur during object construction. + * + * Instances of this class are regular, stack-allocated value-type objects. + * The copy constructor is explicit, and the assignment operator is deleted. + * + * 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. + * + * 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. + explicit CxxMirror(const std::vector& pFunctions); + + // 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 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 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 valid Function if found by name in default namespace group; otherwise, std::nullopt. + std::optional getFunction(const std::string& pFunctionName) const; + + // 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/inc/CxxMirrorToJson.h b/ReflectionTemplateLib/rtl/inc/CxxMirrorToJson.h new file mode 100644 index 00000000..002b3a26 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/CxxMirrorToJson.h @@ -0,0 +1,23 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +namespace rtl { + + class CxxMirror; + + struct CxxMirrorToJson + { + static const std::string toJson(const CxxMirror& pCxxMirror); + static void dump(const CxxMirror& pCxxMirror, const std::string& pFilePathStr); + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/Function.h b/ReflectionTemplateLib/rtl/inc/Function.h new file mode 100644 index 00000000..e3d63278 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/Function.h @@ -0,0 +1,82 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ +/* @class: Function, (callable object) + * every functor (function/method pointer), constructor registered will produce a 'Function' object + * it contains the meta-data of the functor along with 'FunctorId' to lookup for the same in functor-table. + * once the Function object is obtained, it can be called with the correct set of arguments, which will finally + * perform call on the functor represented by this object. +*/ class Function + { + //member::Const/Mute represents the const/non-const member-function, Type::None for non-member & static-member functions. + detail::member m_member_kind; + + //type id of class/struct (if it represents a member-function, else always '0') + traits::uid_t m_recordTypeId; + + //name of the class/struct it belongs to, empty for non-member function. + std::string m_recordStr; + + //name of the function as supplied by the user. + std::string m_function; + + //name of the namespace as supplied by the user. + std::string m_namespaceStr; + + mutable std::vector m_functorsMeta; + + private: + + Function(const std::string& pNamespace, const std::string& pClassName, + const std::string& pFuncName, const type_meta& pFunctorsMeta, + const traits::uid_t pRecordTypeId, const detail::member pQualifier); + + void addOverload(const Function& pOtherFunc) const; + + protected: + + bool hasSignatureId(const traits::uid_t pSignatureId) const; + + GETTER_REF_C(std::vector, Functors, m_functorsMeta) + + public: + + //simple inlined getters. + GETTER(detail::member, MemberKind, m_member_kind); + GETTER(traits::uid_t, RecordTypeId, m_recordTypeId); + + GETTER_CREF(std::string, RecordName, m_recordStr); + GETTER_CREF(std::string, Namespace, m_namespaceStr); + GETTER_CREF(std::string, FunctionName, m_function); + GETTER_CREF(std::vector, FunctorsMeta, m_functorsMeta) + + Function() = default; + Function(Function&&) = default; + Function(const Function&) = default; + Function& operator=(Function&&) = default; + Function& operator=(const Function&) = default; + + template + constexpr const detail::InitFunctionHop argsT() const; + + template + constexpr bool hasSignature() const; + + friend detail::CxxReflection; + friend builder::ReflectionBuilder; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/Function.hpp b/ReflectionTemplateLib/rtl/inc/Function.hpp new file mode 100644 index 00000000..448e4ab8 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/Function.hpp @@ -0,0 +1,48 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl +{ + template + inline constexpr const detail::InitFunctionHop Function::argsT() const + { + return detail::HopBuilder{ m_functorsMeta }.argsT(); + } + + +/* @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 against all registered overloads, returns true if matched with any one. +*/ template + inline constexpr bool Function::hasSignature() const + { + return hasSignatureId(traits::uid>::value); + } + + + inline bool Function::hasSignatureId(const traits::uid_t pSignatureId) const + { + //simple linear-search, efficient for small set of elements. + for (const auto& fnMeta : m_functorsMeta) { + if (fnMeta.get_strict_args_id() == pSignatureId) [[likely]] { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/Method.h b/ReflectionTemplateLib/rtl/inc/Method.h new file mode 100644 index 00000000..c959988e --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/Method.h @@ -0,0 +1,57 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl { + + class Record; + +/* @class: Method + * extends 'Function' class and adds interfaces to call member function. + * invokes only static & non-static member functions via reflection. + * deletes the base's 'operator()()'. + * redefines 'operator()()', to accept only target object and returns lambda. + * the returned lambda is then called with the arguments corresponding to the functor associated with it. +*/ class Method : public Function + { + //private ctor, called by 'Record' class. + Method(const Function& pFunction) + : Function(pFunction) + { } + + public: + + Method() = default; + Method(Method&&) = default; + Method(const Method&) = default; + Method& operator=(Method&&) = default; + Method& operator=(const Method&) = default; + + template + constexpr const detail::InitFunctionHop argsT() const; + + template requires (!std::is_const_v) + constexpr detail::HopBuilder targetT() const; + + template requires (std::is_const_v) + constexpr detail::HopBuilder> targetT() const; + + //indicates if a particular set of arguments accepted by the functor associated with it. + template + bool hasSignature() const; + + friend Record; + friend detail::CxxReflection; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/Method.hpp b/ReflectionTemplateLib/rtl/inc/Method.hpp new file mode 100644 index 00000000..2d3ef6ca --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/Method.hpp @@ -0,0 +1,50 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once +#include +#include + +namespace rtl +{ + template requires (!std::is_const_v) + inline constexpr detail::HopBuilder Method::targetT() const + { + return detail::HopBuilder{ *this }; + } + + template requires (std::is_const_v) + inline constexpr detail::HopBuilder> Method::targetT() const + { + return detail::HopBuilder >{ *this }; + } + + template + inline constexpr const detail::InitFunctionHop Method::argsT() const + { + return detail::HopBuilder{ getFunctorsMeta() }.argsT(); + } + + /* @method: hasSignature<...>() + @params: template params, <_arg0, ..._args> (expects at least one args- _args0) + @return: bool + * checks if the member-function functor associated with this 'Method', takes template specified arguments set or not. +*/ template + inline bool Method::hasSignature() const + { + if (getMemberKind() == detail::member::Static) { + return Function::hasSignature<_args...>(); + } + else { + return hasSignatureId(traits::uid>::value); + } + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/RObject.h b/ReflectionTemplateLib/rtl/inc/RObject.h new file mode 100644 index 00000000..1f45143f --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/RObject.h @@ -0,0 +1,107 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl::detail +{ + template + struct RObjectUPtr; + + class RObjExtractor; + + template + struct RObjectBuilder; +} + + +namespace rtl +{ + //Reflecting the object within. + class RObject + { + std::optional m_object = std::nullopt; + detail::RObjectId m_objectId = {}; + + RObject(const RObject&) = default; + RObject(std::any&& pObject, const detail::RObjectId& pRObjId) noexcept; + + std::size_t getConverterIndex(const std::size_t pToTypeId) const; + + template + Return createCopy() const; + + template + std::optional> performConversion(const std::size_t pIndex) const; + + GETTER_BOOL(ConstCastSafe, m_objectId.m_isConstCastSafe) + + public: + + RObject() = default; + ~RObject() = default; + RObject& operator=(const RObject&) = delete; + + RObject(RObject&&) noexcept; + RObject& operator=(RObject&&) noexcept; + + GETTER_BOOL(Empty, (m_object == std::nullopt || !m_object->has_value())) + 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) + GETTER_CREF(std::optional, Any, m_object) + + template + bool canViewAs() const; + + template + Return clone() const; + + template, int> = 0> + std::optional> view() const noexcept; + + template, int> = 0> + std::optional> view() const noexcept; + + template, int> = 0> + std::optional> view() const noexcept; + + static std::size_t& /*std::atomic&*/ getInstanceCounter() + { + static std::size_t/*std::atomic*/ instanceCounter = {0}; + return instanceCounter; + } + + //friends :) + friend CxxMirror; + friend detail::RObjExtractor; + + template + friend struct detail::RObjectUPtr; + + template + friend struct detail::RObjectBuilder; + + template + friend struct function; + + template + friend struct method; + }; + + struct [[nodiscard]] Return { + error err; + RObject robject; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/RObject.hpp b/ReflectionTemplateLib/rtl/inc/RObject.hpp new file mode 100644 index 00000000..bff5b7e4 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/RObject.hpp @@ -0,0 +1,239 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace rtl +{ + ForceInline RObject::RObject(std::any&& pObject, const detail::RObjectId& pRObjId) noexcept + : m_object(std::in_place, std::move(pObject)) + , m_objectId(pRObjId) + { } + + inline RObject::RObject(RObject&& pOther) noexcept + : m_object(std::move(pOther.m_object)) + , m_objectId(pOther.m_objectId) + { + // Explicitly clear moved-from source + pOther.m_object = std::nullopt; + pOther.m_objectId = {}; + } + + inline RObject& RObject::operator=(RObject&& pOther) noexcept + { + if (this == &pOther) { + return *this; + } + + m_object = std::move(pOther.m_object); + m_objectId = pOther.m_objectId; + + // Explicitly clear moved-from source + pOther.m_object = std::nullopt; + pOther.m_objectId = {}; + return *this; + } + + + inline std::size_t RObject::getConverterIndex(const std::size_t pToTypeId) const + { + if (m_objectId.m_containsAs != detail::EntityKind::None) { + for (std::size_t index = 0; index < m_objectId.m_converters->size(); index++) { + if ((*m_objectId.m_converters)[index].first == pToTypeId) { + return index; + } + } + } + return index_none; + } + + + template + inline bool RObject::canViewAs() const + { + if (isEmpty()) { + return false; + } + + if constexpr (traits::is_bare_type()) { + if constexpr (traits::std_wrapper::type != detail::Wrapper::None) { + if (m_objectId.m_wrapperTypeId == traits::std_wrapper::id()) { + return true; + } + } + const auto& typeId = traits::uid::value; + return (m_objectId.m_typeId == typeId || getConverterIndex(typeId) != index_none); + } + } + + + template + inline std::optional> RObject::performConversion(const std::size_t pIndex) const + { + detail::EntityKind newKind = detail::EntityKind::None; + const traits::Converter& convert = (*m_objectId.m_converters)[pIndex].second; + const std::any& viewObj = convert(m_object.value(), m_objectId.m_containsAs, newKind); + const T* viewRef = detail::RObjExtractor::getPointer(viewObj, newKind); + + if (viewRef != nullptr && newKind == detail::EntityKind::Ptr) { + return std::optional>(std::in_place, *viewRef); + } + else if (viewRef != nullptr && newKind == detail::EntityKind::Value) { + if constexpr (std::is_copy_constructible_v) { + return std::optional>(std::in_place, T(*viewRef)); + } + } + return std::nullopt; + } + + + template , int>> + ForceInline std::optional> RObject::view() const noexcept + { + if (isEmpty()) { + return std::nullopt; + } + + if constexpr (traits::is_bare_type()) + { + if (traits::uid::value == m_objectId.m_wrapperTypeId) [[likely]] + { + using U = detail::RObjectUPtr::value_type>; + const U& uptrRef = *(detail::RObjExtractor{ this }.getWrapper()); + return std::optional>(std::in_place, static_cast(uptrRef)); + } + } + return std::nullopt; + } + + + template , int>> + ForceInline std::optional> RObject::view() const noexcept + { + if (isEmpty()) { + return std::nullopt; + } + + if constexpr (traits::is_bare_type()) + { + if (traits::uid::value == m_objectId.m_wrapperTypeId) [[likely]] + { + const T* sptrRef = detail::RObjExtractor{ this }.getWrapper(); + if (sptrRef != nullptr) { + return std::optional>(std::in_place, const_cast(*sptrRef)); + } + } + } + return std::nullopt; + } + + + template , int>> + ForceInline std::optional> RObject::view() const noexcept + { + if (isEmpty()) { + return std::nullopt; + } + + if constexpr (traits::is_bare_type()) + { + const std::size_t asTypeId = traits::uid::value; + if (asTypeId == m_objectId.m_typeId) [[likely]] + { + const T* valRef = detail::RObjExtractor{ this }.getPointer(); + if (valRef != nullptr) { + return std::optional>(std::in_place, *valRef); + } + } + else + { + const std::size_t index = getConverterIndex(asTypeId); + if (index != index_none) { + return performConversion(index); + } + } + } + return std::nullopt; + } +} + + + +namespace rtl +{ + template<> + inline Return RObject::createCopy() const + { + return m_objectId.m_clonerFn(alloc::Heap, *this); + } + + + template<> + inline Return RObject::createCopy() const + { + return m_objectId.m_clonerFn(alloc::Stack, *this); + } + + + template<> + inline Return RObject::createCopy() const + { + return { error::StlWrapperHeapAllocForbidden, RObject{} }; + } + + + template<> + inline Return RObject::createCopy() const + { + if (m_objectId.m_wrapperType == detail::Wrapper::None) { + return { error::NotWrapperType, RObject{} }; + } + else if (m_objectId.m_wrapperType == detail::Wrapper::Unique) + { + return { error::TypeNotCopyConstructible, RObject{} }; + } + else { + return { error::None, RObject(*this) }; + } + } + + + template + inline Return RObject::clone() const + { + if (isEmpty()) { + return { error::EmptyRObject, RObject{} }; + } + if constexpr (_copyTarget == copy::Value) { + return createCopy<_allocOn, detail::EntityKind::Value>(); + } + else if constexpr (_copyTarget == copy::Wrapper) { + return createCopy<_allocOn, detail::EntityKind::Wrapper>(); + } + 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()) { + return createCopy<_allocOn, detail::EntityKind::Wrapper>(); + } + else { + return createCopy<_allocOn, detail::EntityKind::Value>(); + } + } + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/Record.h b/ReflectionTemplateLib/rtl/inc/Record.h new file mode 100644 index 00000000..40db8f88 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/Record.h @@ -0,0 +1,76 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +#include + +namespace rtl +{ +/* @class: Record + * represents a reflected class/struct. + * contains registered member-functions as 'Method' objects. + * provides interface to access methods by name. + * provides interface to construct instances of the class/struct using the registered constructors. +*/ class Record + { + using MethodMap = std::unordered_map< std::string, Method >; + + mutable traits::uid_t m_recordId; + mutable std::string m_namespaceStr; + mutable std::string m_recordName; + mutable MethodMap m_methods; + + private: + + Record(const std::string& pRecordName, const traits::uid_t pRecordId, const std::string& pNamespace) + : m_recordId(pRecordId) + , m_namespaceStr(pNamespace) + , m_recordName(pRecordName) + { } + + GETTER_REF_C(MethodMap, FunctionsMap, m_methods) + + public: + + Record() = delete; + Record(Record&&) = default; + Record(const Record&) = default; + Record& operator=(Record&&) = default; + Record& operator=(const Record&) = default; + + GETTER_CREF(MethodMap, MethodMap, m_methods) + GETTER_CREF(std::string, RecordName, m_recordName) + + template + constructor ctorT() const; + +/* @method: getMethod + @param: const std::string& (name of the method) + @return: std::optional + * if the method isn't found by the given name, std::nullopt is returned. +*/ std::optional getMethod(const std::string& pMethod) const + { + const auto& itr = m_methods.find(pMethod); + if (itr != m_methods.end()) { + return std::optional(itr->second); + } + return std::nullopt; + } + + //only class which can create objects of this class & manipulates 'm_methods'. + friend class detail::CxxReflection; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/Record.hpp b/ReflectionTemplateLib/rtl/inc/Record.hpp new file mode 100644 index 00000000..2e73f09c --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/Record.hpp @@ -0,0 +1,86 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + +namespace rtl +{ + template<> + inline constructor<> Record::ctorT() const + { + constructor<> fnCtor; + auto strictId = traits::uid>::value; + const auto& method = m_methods.at(detail::ctor_name(m_recordName)); + + for (auto& ty_meta : method.getFunctorsMeta()) + { + if (strictId == ty_meta.get_strict_args_id()) + { + using ctor_t = dispatch::function_ptr; + auto fptr = static_cast(ty_meta.get_functor()).f_ptr(); + fnCtor.get_hop().push_back(fptr); + fnCtor.get_overloads().push_back(&ty_meta.get_functor()); + fnCtor.set_init_error(error::None); + break; + } + } + return fnCtor; + } + + + template + inline constructor Record::ctorT() const + { + std::vector fnTyMetas(detail::call_by::ncref); + auto normalId = traits::uid>::value; + const auto& method = m_methods.at(detail::ctor_name(m_recordName)); + + for (auto& ty_meta : method.getFunctorsMeta()) + { + if (normalId == ty_meta.get_normal_args_id()) + { + if (normalId == ty_meta.get_strict_args_id()) { + fnTyMetas[detail::call_by::value] = ty_meta; + } + else if (!ty_meta.is_any_arg_ncref()) { + fnTyMetas[detail::call_by::cref] = ty_meta; + } + else fnTyMetas.push_back(ty_meta); + } + } + + constructor fnCtor; + for (auto& ty_meta : fnTyMetas) + { + if (ty_meta.is_empty()) { + fnCtor.get_hop().push_back(nullptr); + fnCtor.get_overloads().push_back(nullptr); + continue; + } + + using fn_cast = dispatch::functor_cast...>; + auto fn = fn_cast(ty_meta.get_functor()).template to_function(); + + fnCtor.get_hop().push_back(fn.f_ptr()); + fnCtor.get_overloads().push_back(&ty_meta.get_functor()); + fnCtor.set_init_error(error::None); + } + + if (fnCtor.get_init_error() != error::None) { + fnCtor.set_init_error(error::SignatureMismatch); + } + return fnCtor; + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/type_meta.h b/ReflectionTemplateLib/rtl/inc/type_meta.h new file mode 100644 index 00000000..f8abaed8 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/type_meta.h @@ -0,0 +1,75 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + struct type_meta + { + type_meta(const dispatch::functor& p_functor) + : m_functor(p_functor) + { } + + type_meta() = default; + type_meta(type_meta&&) = default; + type_meta(const type_meta&) = default; + type_meta& operator=(type_meta&&) = default; + type_meta& operator=(const type_meta&) = default; + + GETTER_BOOL(_empty, !m_functor.has_value()) + GETTER_BOOL(_void, m_functor->get().m_is_void) + GETTER_BOOL(_any_arg_ncref, m_functor->get().m_is_any_arg_ncref) + + GETTER(std::string, _signature_str, m_functor->get().m_signature_str) + GETTER_CREF(std::vector, _args_id_arr, m_functor->get().m_args_type_ids) + + GETTER(traits::uid_t, _return_id, m_functor->get().m_return_id) + GETTER(traits::uid_t, _record_id, m_functor->get().m_record_id) + GETTER(traits::uid_t, _normal_args_id, m_functor->get().m_normal_args_id) + GETTER(traits::uid_t, _strict_args_id, m_functor->get().m_strict_args_id) + + GETTER(detail::member, _member_kind, m_functor->get().m_member_kind) + + GETTER_CREF(dispatch::functor, _functor, m_functor->get()) + + template + static type_meta add_function(return_t(*p_fptr)(signature_t...), + traits::uid_t p_record_uid, detail::member p_member_kind); + + template + static type_meta add_method(return_t(record_t::* p_fptr)(signature_t...)); + + template + static type_meta add_method(return_t(record_t::* p_fptr)(signature_t...) const); + + template + static type_meta add_constructor(); + + const bool operator==(const type_meta& pOther) const { + return (!is_empty() && !pOther.is_empty() && + get_functor().m_return_id == pOther.get_functor().m_return_id && + get_functor().m_record_id == pOther.get_functor().m_record_id && + get_functor().m_strict_args_id == pOther.get_functor().m_strict_args_id && + get_functor().m_member_kind == pOther.get_functor().m_member_kind); + } + + private: + + using functor_t = std::optional>; + + functor_t m_functor = std::nullopt; + + friend detail::CxxReflection; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/type_meta.hpp b/ReflectionTemplateLib/rtl/inc/type_meta.hpp new file mode 100644 index 00000000..86771ae7 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/type_meta.hpp @@ -0,0 +1,56 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include +#include + +namespace rtl +{ + template + inline type_meta type_meta::add_function(return_t(*p_fptr)(signature_t...), + traits::uid_t p_record_uid, detail::member p_member_kind) + { + auto& fc = cache::function_ptr::instance(); + auto& functor = fc.push(p_fptr, p_record_uid, p_member_kind); + return type_meta(functor); + } + + + template + inline type_meta type_meta::add_method(return_t(record_t::* p_fptr)(signature_t...)) + { + auto& fc = cache::method_ptr::instance(); + auto& functor = fc.push(p_fptr); + return type_meta(functor); + } + + + template + inline type_meta type_meta::add_method(return_t(record_t::* p_fptr)(signature_t...) const) + { + auto& fc = cache::method_ptr::instance(); + auto& functor = fc.push(p_fptr); + return type_meta(functor); + } + + + template + inline type_meta type_meta::add_constructor() + { + auto& fc = cache::function_ptr::instance(); + auto& functor = fc.template push_ctor(traits::uid::value); + return type_meta(functor); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/view.h b/ReflectionTemplateLib/rtl/inc/view.h new file mode 100644 index 00000000..c9025f22 --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/view.h @@ -0,0 +1,128 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +/** + * @brief A lightweight immutable view of a const T object. + * + * rtl::view provides uniform access to either: + * - a non-owning const reference (borrowed), or + * - an internally stored const value (owned). + * + * Clients should treat this as a non-owning view: the semantics + * are always read-only, and ownership is abstracted away. + * ---------------------------------------------------------------------------- + * Purpose: + * rtl::view is specifically designed to provide read-only access to values + * reflected by an RObject. It abstracts whether the value is owned or + * referenced, allowing seamless access in both cases. + * + * Lifetime: + * A rtl::view instance is only valid as long as the associated RObject + * from which it was obtained remains alive. If the RObject is destroyed, + * any rtl::view referencing its data becomes invalid and must not be used. + * ---------------------------------------------------------------------------- + */ + + +#include + +namespace rtl { + + template + class view; +} + + +namespace rtl +{ + template + class view<_asType, std::enable_if_t || + traits::is_shared_ptr_v<_asType>> > + { + _asType& m_ref; + + public: + + // Construct from reference (no copy, no default init) + view(_asType& pRef) : m_ref(pRef) {} + + // Delete all forms of copying and moving, enforcing true immutablilty. + view(view&&) = delete; + view(const view&) = delete; + view& operator=(view&&) = delete; + view& operator=(const view&) = delete; + + const _asType& get() const { + return m_ref; + } + }; +} + + +namespace rtl +{ + template + class view<_asType, std::enable_if_t> > + { + const _asType& m_cref; + + public: + + // Construct from reference (no copy, no default init) + view(const _asType& ref) : m_cref(ref) {} + + // Delete all forms of copying and moving, enforcing true immutablilty. + view(view&&) = delete; + view(const view&) = delete; + view& operator=(view&&) = delete; + view& operator=(const view&) = delete; + + const _asType& get() const { + return m_cref; + } + }; +} + + +namespace rtl +{ + template + class view<_asType, std::enable_if_t && + traits::std_wrapper<_asType>::type == detail::Wrapper::None> > + { + /* only constructed if we own the value. + * order matters: m_value must be declared before m_cref + * because m_cref may bind to m_value during initialization + */ const std::optional<_asType> m_value; + + const _asType& m_cref; + + public: + + // Construct from reference (no copy, no default init) + view(const _asType& ref) : m_value(std::nullopt), m_cref(ref) {} + + // Construct from value (copy or move) + view(_asType&& val) : m_value(std::move(val)), m_cref(*m_value) {} + + // Delete all forms of copying and moving, enforcing true immutablilty. + view(view&&) = delete; + view(const view&) = delete; + view& operator=(view&&) = delete; + view& operator=(const view&) = delete; + + const _asType& get() const { + return m_cref; + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/inc/view.hpp b/ReflectionTemplateLib/rtl/inc/view.hpp new file mode 100644 index 00000000..2155f6fc --- /dev/null +++ b/ReflectionTemplateLib/rtl/inc/view.hpp @@ -0,0 +1,71 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +/** + * @brief A lightweight immutable view of a const T object. + * + * rtl::view provides uniform access to either: + * - a non-owning const reference (borrowed), or + * - an internally stored const value (owned). + * + * Clients should treat this as a non-owning view: the semantics + * are always read-only, and ownership is abstracted away. + * ---------------------------------------------------------------------------- + * Purpose: + * rtl::view is specifically designed to provide read-only access to values + * reflected by an RObject. It abstracts whether the value is owned or + * referenced, allowing seamless access in both cases. + * + * Lifetime: + * A rtl::view instance is only valid as long as the associated RObject + * from which it was obtained remains alive. If the RObject is destroyed, + * any rtl::view referencing its data becomes invalid and must not be used. + * ---------------------------------------------------------------------------- + */ + +namespace rtl +{ + template + class view<_asType, std::enable_if_t> > + { + using T = typename traits::std_wrapper<_asType>::value_type; + + const detail::RObjectUPtr& m_uptrRef; + + //_asType move() const { + // return std::move(m_uptrRef.release()); + //} + + //friend rtl::RObject; + + public: + + // Construct from reference (no copy, no default init) + explicit view(const detail::RObjectUPtr& pUptrRef): m_uptrRef(pUptrRef) { } + + // Delete all forms of copying and moving, enforcing true immutablilty. + view(view&&) = delete; + view(const view&) = delete; + view& operator=(view&&) = delete; + view& operator=(const view&) = delete; + + // UPDATE: MOVING DISALLOWED NOW. + // cannot move a std::unique_ptr out once its inside rtl::RObject. it can only be viewed. + // done for keeping the rtl::view strictly Read-only and a consistent interface. + const _asType& get() const { + return m_uptrRef.cref(); + } + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_constants.h b/ReflectionTemplateLib/rtl/rtl_constants.h new file mode 100644 index 00000000..b26e30b9 --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_constants.h @@ -0,0 +1,160 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +namespace rtl { + + // Allocation policy for rtl::RObject. + // + // Determines how the underlying object is created and managed at runtime. + // RTL enforces strict RAII semantics: no explicit destroy API exists, and + // cleanup is always automatic. + enum class alloc + { + None, /* + * Assigned to empty or moved-from RObjects. + * - Represents an invalid / non-owning state. + * - Any attempt to call or clone results in rtl::error::EmptyRObject. + */ + + Heap, /* + * Assigned to RTL-allocated heap objects. + * - Internally managed via std::unique_ptr. + * - Moving transfers ownership of the unique_ptr (cheap, no deep copy). + * - Destroyed automatically when the owning RObject goes out of scope. + * - User never sees the unique_ptr; wrapper details remain hidden. + */ + + Stack /* + * Assigned to return values and RTL-allocated stack objects. + * - The object instance lives directly inside the RObject. + * - Moving calls the reflected type's move constructor. + * - Destroyed automatically at scope exit (like any local variable). + */ + }; + + + // Cloning policy for rtl::RObject. + enum class copy + { + /* + * An rtl::RObject may internally hold value wrapped in std::optional, + * std::reference_wrapper, or smart pointers. The copy policy gives users + * control over whether cloning should duplicate the wrapper itself or + * perform a deep copy of the underlying object. + * + * Auto (default): + * - RTL first attempts a wrapper-level copy if the wrapper is copyable. + * - If the wrapper is an internal detail (e.g., heap objects created via + * RTL, stored in std::unique_ptr), RTL transparently performs a deep + * copy of the underlying object instead of copying the wrapper. + * - This ensures correct semantics even when the user is unaware of + * wrapper details (typical in reflection use cases). + * - When explicitly requested, users can still attempt Value or Wrapper + * cloning; RTL will return success or a detailed error as appropriate. + * + * Value: + * - Always perform an independent deep copy of the underlying object. + * + * Wrapper: + * - Copy the wrapper itself, without cloning the underlying object. + */ + Auto, + Value, + Wrapper + }; + + // Invalid number/index. + static constexpr std::size_t index_none = static_cast(-1); +} + + + +namespace rtl::detail +{ + enum class EntityKind + { + None, + Ptr, + Value, + Wrapper + }; + + enum class Wrapper + { + None, + Any, + Weak, + Unique, + Shared, //Planned. + Variant, //Planned. + Optional, //Planned. + Reference //Planned. + }; + + enum class member + { + None, // non-member functions. + Const, // Const-qualified instance method + NonConst, // Non-const instance method + Static, // Static methods + UserCtor, + DefaultCtor + }; + + constexpr const char* INIT_LATER = ""; + constexpr const char* RECORD_NONE = ""; + constexpr const char* NAMESPACE_GLOBAL = "rtl::global"; + + inline static const std::string ctor_name(const std::string_view pRecordName) { + // [critical] Must not change. Constructors are identified using this format. + return (std::string(pRecordName) + "::" + std::string(pRecordName) + "()"); + } + +#define GETTER(_varType, _name, _var) \ + inline constexpr const _varType get##_name() const { \ + return _var; \ + } + +#define GETTER_REF_C(_varType, _name, _var) \ + inline constexpr _varType& get##_name() const { \ + return _var; \ + } + +#define GETTER_REF(_varType, _name, _var) \ + inline constexpr _varType& get##_name() { \ + return _var; \ + } + +#define GETTER_CPTR(_varType, _name, _var) \ + inline constexpr const _varType* get##_name() const { \ + return _var; \ + } + +#define GETTER_CREF(_varType, _name, _var) \ + inline constexpr const _varType& get##_name() const { \ + return _var; \ + } + +#define GETTER_BOOL(_name, _var) \ + inline constexpr const bool is##_name() const { \ + return _var; \ + } + +#if defined(_MSC_VER) +#define ForceInline __forceinline +#elif defined(__GNUC__) || defined(__clang__) +#define ForceInline inline __attribute__((always_inline)) +#else +#define ForceInline inline +#endif +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_constructor.h b/ReflectionTemplateLib/rtl/rtl_constructor.h new file mode 100644 index 00000000..4163059d --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_constructor.h @@ -0,0 +1,103 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl +{ + template + class constructor + { + using lambda_t = std::function; + + error m_init_err = error::InvalidCaller; + + std::vector m_hop = {}; + + std::vector m_functors = {}; + + GETTER_REF(std::vector, _hop, m_hop) + GETTER_REF(std::vector, _overloads, m_functors) + + void set_init_error(error p_err) { + m_init_err = p_err; + } + + public: + + GETTER(rtl::error, _init_error, m_init_err) + + constexpr operator bool() const noexcept { + return !(m_init_err != error::None || m_functors.empty() || + (m_functors.size() == 1 && m_functors[0] == nullptr)); + } + + constexpr bool must_bind_refs() const noexcept { + return (m_functors[detail::call_by::value] == nullptr && + (m_functors.size() > detail::call_by::ncref || m_functors[detail::call_by::cref]->is_any_arg_ncref())); + } + + template + requires (sizeof...(args_t) == sizeof...(signature_t)) + constexpr Return operator()(alloc p_alloc_on, args_t&&...params) const noexcept + { + if (!(*this)) [[unlikely]] { + return { m_init_err, RObject{} }; + } + + if (must_bind_refs()) [[unlikely]] { + return { error::ExplicitRefBindingRequired, RObject{} }; + } + + auto index = (m_functors[detail::call_by::value] != nullptr ? detail::call_by::value : detail::call_by::cref); + return m_hop[index](p_alloc_on, std::forward(params)...); + } + + template + struct perfect_fwd + { + const constructor& fn; + + template + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr Return operator()(alloc p_alloc_on, args_t&&...params) const noexcept + { + if (!fn) [[unlikely]] { + return { fn.m_init_err, RObject{} }; + } + + auto signature_id = traits::uid>::value; + for (int index = 0; index < fn.m_functors.size(); index++) + { + if (fn.m_functors[index] != nullptr && + signature_id == fn.m_functors[index]->get_strict_sign_id()) { + return fn.m_hop[index](p_alloc_on, std::forward(params)...); + } + } + return { error::RefBindingMismatch, RObject{} }; + } + }; + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind() const noexcept { + return perfect_fwd{ *this }; + } + + friend Record; + + static_assert((!std::is_reference_v && ...), + "rtl::function<...>: any type cannot be specified as reference here"); + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_errors.h b/ReflectionTemplateLib/rtl/rtl_errors.h new file mode 100644 index 00000000..b8c0cebb --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_errors.h @@ -0,0 +1,84 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + constexpr const char* errstr_Unknown = "Unknown error."; + constexpr const char* errstr_None = "No error (operation successful)."; + constexpr const char* errstr_EmptyRObject = "Empty instance: RObject does not hold any reflected object."; + constexpr const char* errstr_InvalidCaller = "Invalid callable: rtl::function/rtl::method object being used is empty."; + constexpr const char* errstr_SignatureMismatch = "Signature mismatch: Function parameters do not match the expected signature."; + constexpr const char* errstr_TargetTypeMismatch = "The object you're trying to bind doesn't match the expected type of the method."; + constexpr const char* errstr_ReturnTypeMismatch = "returnT(): The specified TYPE do not match the expected function's return type."; + constexpr const char* errstr_RefBindingMismatch = "Reference binding mismatch: Argument references do not match the expected parameter bindings."; + constexpr const char* errstr_ExplicitRefBindingRequired = "Explicit reference binding required for correct overload resolution."; + constexpr const char* errstr_InvalidStaticMethodCaller = "Invalid callable: rtl::method being used to call a static method; use rtl::static_method instead."; + constexpr const char* errstr_InvalidNonStaticMethodCaller = "Invalid callable: rtl::static_method being used to call a non-static method; use rtl::method instead."; + constexpr const char* errstr_FunctionNotRegistered = "Function not registered: The requested erase_function/method is not registered in the Reflection system."; + constexpr const char* errstr_ConstOverloadMissing = "Cannot call non-const method on const target implicitly, bind methodQ::NonConst to override."; + constexpr const char* errstr_NonConstOverloadMissing = "Non-const method not found: The method does not have a non-const overload as explicitly requested."; + constexpr const char* errstr_InvalidCallOnConstTarget = "Cannot call a non-const method on an RObject that is reflecting a const object."; + constexpr const char* errstr_TypeNotCopyConstructible = "Copy constructor inaccessible: Underlying type has deleted or private copy constructor; cannot copy-construct reflected instance."; + constexpr const char* errstr_TypeNotDefaultConstructible = "Type cannot be default constructed - std::is_default_constructible validation failed."; + constexpr const char* errstr_StlWrapperHeapAllocForbidden = "Heap allocation forbidden for STL-wrapped objects (smart pointers/optionals/reference_wrappers). use alloc::Stack."; + + + enum class error + { + None, + EmptyRObject, + InvalidCaller, + NotWrapperType, + SignatureMismatch, + TargetTypeMismatch, + ReturnTypeMismatch, + RefBindingMismatch, + ExplicitRefBindingRequired, + InvalidStaticMethodCaller, + InvalidNonStaticMethodCaller, + FunctionNotRegistered, //Not used by RTL at all, for external purpose only. + ConstOverloadMissing, + NonConstOverloadMissing, + InvalidCallOnConstTarget, + TypeNotCopyConstructible, + TypeNotDefaultConstructible, + StlWrapperHeapAllocForbidden + }; + + + inline const std::string_view to_string(error err) + { + switch (err) { + case error::None: return std::string_view(errstr_None); + case error::EmptyRObject: return std::string_view(errstr_EmptyRObject); + case error::SignatureMismatch: return std::string_view(errstr_SignatureMismatch); + case error::ReturnTypeMismatch: return std::string_view(errstr_ReturnTypeMismatch); + case error::RefBindingMismatch: return std::string_view(errstr_RefBindingMismatch); + case error::ExplicitRefBindingRequired: return std::string_view(errstr_ExplicitRefBindingRequired); + case error::InvalidCaller: return std::string_view(errstr_InvalidCaller); + case error::InvalidStaticMethodCaller: return std::string_view(errstr_InvalidStaticMethodCaller); + case error::InvalidNonStaticMethodCaller: return std::string_view(errstr_InvalidNonStaticMethodCaller); + case error::FunctionNotRegistered: return std::string_view(errstr_FunctionNotRegistered); + case error::TargetTypeMismatch: return std::string_view(errstr_TargetTypeMismatch); + case error::NonConstOverloadMissing: return std::string_view(errstr_NonConstOverloadMissing); + case error::InvalidCallOnConstTarget: return std::string_view(errstr_InvalidCallOnConstTarget); + case error::TypeNotCopyConstructible: return std::string_view(errstr_TypeNotCopyConstructible); + case error::TypeNotDefaultConstructible: return std::string_view(errstr_TypeNotDefaultConstructible); + case error::ConstOverloadMissing: return std::string_view(errstr_ConstOverloadMissing); + case error::StlWrapperHeapAllocForbidden: return std::string_view(errstr_StlWrapperHeapAllocForbidden); + default: return std::string_view(errstr_Unknown); + } + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_forward_decls.h b/ReflectionTemplateLib/rtl/rtl_forward_decls.h new file mode 100644 index 00000000..eda0a100 --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_forward_decls.h @@ -0,0 +1,120 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +namespace rtl +{ + struct Return; + + class RObject; + + class Function; + + class Record; + + class Method; + + class CxxMirror; + + struct type_meta; + + template + class constructor; + + template + class function; + + template + struct method; + + template + struct const_method; + + template + struct static_method; + + namespace builder + { + struct ReflectionBuilder; + } + + namespace detail + { + enum call_by { + value = 0, + cref = 1, //const ref. + ncref = 2 //non-const ref. + }; + + struct FunctorId; + + struct RObjectId; + + class CxxReflection; + + template + struct HopBuilder; + + template + struct InitMethodHop; + + template + struct InitFunctionHop; + } + + namespace cache + { + template + struct function_ptr; + + template + struct method_ptr; + } + + namespace dispatch + { + struct functor; + + struct lambda {}; + + template + struct functor_cast; + + enum class erase { + t_ctor, + t_target, + t_return, + t_method + }; + + template + struct function_lambda; + + template + struct method_lambda; + + template + struct function_ptr; + + template + struct method_ptr; + + template + struct aware_return; + + template + struct aware_constructor; + + template + struct aware_return_n_target; + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_function.h b/ReflectionTemplateLib/rtl/rtl_function.h new file mode 100644 index 00000000..c7a4423e --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_function.h @@ -0,0 +1,88 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include + +namespace rtl +{ + template + struct function + { + using fptr_t = return_t(*)(signature_t...); + + constexpr auto f_ptr() const { + return m_functor; + } + + constexpr operator bool() const { + return (m_functor != nullptr); + } + + template + [[nodiscard]] [[gnu::hot]] + constexpr decltype(auto) operator()(args_t&&...params) const noexcept + { + return (*m_functor)(std::forward(params)...); + } + + function(fptr_t p_functor) + : m_init_err(error::None) + , m_functor(p_functor) + { } + + function() = default; + function(function&&) = default; + function(const function&) = default; + + function& operator=(function&&) = default; + function& operator=(const function&) = default; + + GETTER(rtl::error, _init_error, m_init_err) + + protected: + + fptr_t m_functor = nullptr; + error m_init_err = error::InvalidCaller; + + void set_init_error(error p_err) { + m_init_err = p_err; + } + + template + friend struct detail::InitFunctionHop; + }; +} + + +namespace rtl +{ + template + struct static_method : function + { + using base_t = function; + + static_method(base_t::fptr_t p_functor) : base_t(p_functor) + { } + + static_method() = default; + static_method(static_method&&) = default; + static_method(const static_method&) = default; + + static_method& operator=(static_method&&) = default; + static_method& operator=(const static_method&) = default; + + template + friend struct detail::InitFunctionHop; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_function_erased_return.h b/ReflectionTemplateLib/rtl/rtl_function_erased_return.h new file mode 100644 index 00000000..0202f36d --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_function_erased_return.h @@ -0,0 +1,69 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + template + struct function : public dispatch::forward_call + { + using base_t = dispatch::forward_call; + + template + requires (sizeof...(args_t) == sizeof...(signature_t)) + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr Return operator()(args_t&&...params) const noexcept + { + if (!(*this)) [[unlikely]] { + return { base_t::get_init_error(), RObject{}}; + } + return base_t::operator()(std::forward(params)...); + } + + template + struct perfect_fwd + { + const base_t& fn; + + template + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr Return operator()(args_t&&...params) const noexcept + { + if (!fn) [[unlikely]] { + return { fn.get_init_error(), RObject{}}; + } + + auto sign_id = traits::uid>::value; + return fn.perfect_forward(sign_id, std::forward(params)...); + } + }; + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind() const noexcept { + return perfect_fwd{ *this }; + } + + static_assert((!std::is_reference_v && ...), + "rtl::function<...>: any type cannot be specified as reference here."); + }; +} + + +namespace rtl +{ + template + struct static_method : function + { }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_method.h b/ReflectionTemplateLib/rtl/rtl_method.h new file mode 100644 index 00000000..e570d192 --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_method.h @@ -0,0 +1,84 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + template + requires (!std::is_same_v && !std::is_same_v) + struct method + { + using fptr_t = return_t (record_t::*)(signature_t...); + + constexpr auto f_ptr() const { + return m_functor; + } + + constexpr operator bool() const { + return (m_functor != nullptr); + } + + struct invoker + { + fptr_t functor; + const record_t& target; + + template + requires (sizeof...(args_t) == sizeof...(signature_t)) + [[nodiscard]] [[gnu::hot]] + constexpr decltype(auto) operator()(args_t&&...params) const noexcept + { + return (const_cast(target).*functor)(std::forward(params)...); + } + }; + + [[gnu::hot]] + constexpr const invoker operator()(record_t& p_target) const noexcept { + return invoker{ m_functor, p_target }; + } + + [[gnu::hot]] + constexpr const invoker operator()(record_t&& p_target) const noexcept { + return invoker{ m_functor, p_target }; + } + + explicit method(fptr_t p_functor) + : m_init_err(error::None) + , m_functor(p_functor) + { } + + method() = default; + method(method&&) = default; + method(const method&) = default; + + method& operator=(method&&) = default; + method& operator=(const method&) = default; + + GETTER(rtl::error, _init_error, m_init_err) + + private: + + fptr_t m_functor = nullptr; + error m_init_err = error::InvalidCaller; + + void set_record_id(const traits::uid_t) {} + + void set_init_error(error p_err) { + m_init_err = p_err; + } + + template + friend struct detail::InitMethodHop; + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_method_const.h b/ReflectionTemplateLib/rtl/rtl_method_const.h new file mode 100644 index 00000000..572513ab --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_method_const.h @@ -0,0 +1,81 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + template + requires (!std::is_same_v && !std::is_same_v) + struct const_method + { + using fptr_t = return_t(record_t::*)(signature_t...) const; + + constexpr auto f_ptr() const { + return m_functor; + } + + constexpr operator bool() const { + return (m_functor != nullptr); + } + + struct invoker + { + fptr_t functor; + const record_t& target; + + template + requires (sizeof...(args_t) == sizeof...(signature_t)) + [[nodiscard]] [[gnu::hot]] + constexpr decltype(auto) operator()(args_t&&...params) const noexcept + { + return (target.*functor)(std::forward(params)...); + } + }; + + [[gnu::hot]] + constexpr const invoker operator()(const record_t& p_target) const noexcept { + return invoker{ m_functor, p_target }; + } + + explicit const_method(fptr_t p_functor) + : m_init_err(error::None) + , m_functor(p_functor) + { } + + const_method() = default; + const_method(const_method&&) = default; + const_method(const const_method&) = default; + + const_method& operator=(const_method&&) = default; + const_method& operator=(const const_method&) = default; + + GETTER(rtl::error, _init_error, m_init_err) + + private: + + fptr_t m_functor = nullptr; + error m_init_err = error::InvalidCaller; + + void set_record_id(const traits::uid_t) {} + + void set_init_error(error p_err) { + m_init_err = p_err; + } + + template + friend struct detail::InitMethodHop; + + static_assert(!std::is_const_v, "rtl::const_method<...>: 'record_t' must not be specified as 'const'."); + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_method_erased.h b/ReflectionTemplateLib/rtl/rtl_method_erased.h new file mode 100644 index 00000000..3b4fe697 --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_method_erased.h @@ -0,0 +1,144 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + template + struct method + { + using hopper_t = dispatch::forward_call; + + struct invoker + { + const hopper_t& fn; + const RObject& target; + const error init_err; + + template + requires (sizeof...(args_t) == sizeof...(signature_t)) + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr Return operator()(args_t&&...params) const noexcept + { + if (init_err != error::None) [[unlikely]] { + return { init_err, RObject{} }; + } + return fn(target, std::forward(params)...); + } + }; + + template + struct perfect_fwd + { + const hopper_t& fn; + const RObject& target; + const error init_err; + + template + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr Return operator()(args_t&&...params) const noexcept + { + if (init_err != error::None) [[unlikely]] { + return { init_err, RObject{} }; + } + auto sign_id = traits::uid>::value; + return fn.perfect_forward(sign_id, target, std::forward(params)...); + } + }; + + template + requires (member_kind == detail::member::Const || member_kind == detail::member::NonConst) + constexpr const error validate(const hopper_t& pHopper, const RObject& p_target) const + { + if (pHopper.get_init_error() != error::None) { + return pHopper.get_init_error(); + } + else if (p_target.isEmpty()) { + return error::EmptyRObject; + } + else if (pHopper.get_record_id() != p_target.getTypeId()) { + return error::TargetTypeMismatch; + } + if constexpr (member_kind == detail::member::NonConst) { + if (!p_target.isConstCastSafe()) { + return error::InvalidCallOnConstTarget; + } + } + return error::None; + } + + constexpr invoker operator()(RObject& p_target) const noexcept { + return invoker{ m_non_const_hops, p_target, + validate(m_non_const_hops, p_target) }; + } + + constexpr invoker operator()(RObject&& p_target) const noexcept { + return invoker{ m_non_const_hops, p_target, + validate(m_non_const_hops, p_target) }; + } + + constexpr invoker operator()(const RObject& p_target) const noexcept { + return invoker{ m_const_hops, p_target, + validate(m_const_hops, p_target) }; + } + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind(RObject& p_target) const noexcept { + return perfect_fwd{ m_non_const_hops, p_target, + validate(m_non_const_hops, p_target) }; + } + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind(RObject&& p_target) const noexcept { + return perfect_fwd{ m_non_const_hops, p_target, + validate(m_non_const_hops, p_target) }; + } + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind(const RObject& p_target) const noexcept { + return perfect_fwd{ m_const_hops, p_target, + validate(m_const_hops, p_target) }; + } + + constexpr operator bool() const noexcept { + return (m_const_hops.operator bool() || m_non_const_hops.operator bool()); + } + + constexpr error get_init_error() const noexcept + { + if (m_const_hops.get_init_error() == error::None || + m_non_const_hops.get_init_error() == error::None) { + return error::None; + } + return m_non_const_hops.get_init_error(); + } + + private: + + hopper_t m_const_hops; + hopper_t m_non_const_hops; + + GETTER_REF(hopper_t, _c_hops, m_const_hops) + GETTER_REF(hopper_t, _nc_hops, m_non_const_hops) + + template + friend struct detail::InitMethodHop; + + static_assert((!std::is_reference_v && ...), + "rtl::method<...>: any type cannot be specified as reference here."); + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_method_erased_return.h b/ReflectionTemplateLib/rtl/rtl_method_erased_return.h new file mode 100644 index 00000000..81a55375 --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_method_erased_return.h @@ -0,0 +1,104 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + template requires (!std::is_same_v) + struct method + { + using hopper_t = dispatch::forward_call; + + struct invoker + { + const hopper_t& fn; + const record_t& target; + + template requires (sizeof...(args_t) == sizeof...(signature_t)) + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr Return operator()(args_t&&...params) const noexcept + { + if (!fn) [[unlikely]] { + return { fn.get_init_error(), RObject{}}; + } + return fn(target, std::forward(params)...); + } + }; + + template + struct perfect_fwd + { + const hopper_t& fn; + const record_t& target; + + template + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr Return operator()(args_t&&...params) const noexcept + { + if (!fn) [[unlikely]] { + return { fn.get_init_error(), RObject{}}; + } + auto sign_id = traits::uid>::value; + return fn.perfect_forward(sign_id, target, std::forward(params)...); + } + }; + + constexpr invoker operator()(record_t& p_target) const noexcept { + return invoker{ m_non_const_hops, p_target }; + } + + constexpr invoker operator()(record_t&& p_target) const noexcept { + return invoker{ m_non_const_hops, p_target }; + } + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind(record_t& p_target) const noexcept { + return perfect_fwd{ m_non_const_hops, p_target }; + } + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind(record_t&& p_target) const noexcept { + return perfect_fwd{ m_non_const_hops, p_target }; + } + + constexpr operator bool() const noexcept { + return (m_const_hops.operator bool() || m_non_const_hops.operator bool()); + } + + constexpr error get_init_error() const noexcept + { + if (m_const_hops.get_init_error() == error::None || + m_non_const_hops.get_init_error() == error::None) { + return error::None; + } + return m_non_const_hops.get_init_error(); + } + + private: + + hopper_t m_const_hops; + hopper_t m_non_const_hops; + + GETTER_REF(hopper_t, _c_hops, m_const_hops) + GETTER_REF(hopper_t, _nc_hops, m_non_const_hops) + + template + friend struct detail::InitMethodHop; + + static_assert((!std::is_reference_v && ...), + "rtl::method<...>: any type cannot be specified as reference here."); + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_method_erased_target.h b/ReflectionTemplateLib/rtl/rtl_method_erased_target.h new file mode 100644 index 00000000..26f3a843 --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_method_erased_target.h @@ -0,0 +1,143 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include + +namespace rtl +{ + template requires (!std::is_same_v) + struct method + { + using cond_ret_t = std::conditional_t, std::nullptr_t, return_t>; + + using hopper_t = dispatch::forward_call>, const RObject&, signature_t...>; + + struct invoker + { + const hopper_t& fn; + const error init_err; + const RObject& target; + + template + requires (sizeof...(args_t) == sizeof...(signature_t)) + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr std::pair> operator()(args_t&&...params) const noexcept + { + if (init_err != error::None) [[unlikely]] { + return { init_err, std::nullopt }; + } + + auto&& ret_v = fn(target, std::forward(params)...); + if constexpr (std::is_void_v) { + ret_v.second = std::nullopt; + } + return ret_v; + } + }; + + template + struct perfect_fwd + { + const hopper_t& fn; + const error init_err; + const RObject& target; + + template + [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] + constexpr std::pair> operator()(args_t&&...params) const noexcept + { + if (init_err != error::None) [[unlikely]] { + return { init_err, std::nullopt }; + } + + auto sign_id = traits::uid>::value; + auto&& ret_v = fn.perfect_forward(sign_id, target, std::forward(params)...); + if constexpr (std::is_void_v) { + ret_v.second = std::nullopt; + } + return ret_v; + } + }; + + constexpr const error validate(const hopper_t& pHopper, const RObject& p_target) const + { + if (pHopper.get_init_error() != error::None) { + return pHopper.get_init_error(); + } + else if (p_target.isEmpty()) { + return error::EmptyRObject; + } + else if (pHopper.get_record_id() != p_target.getTypeId()) { + return error::TargetTypeMismatch; + } + else return error::None; + } + + constexpr invoker operator()(RObject& p_target) const noexcept { + return invoker{ m_non_const_hops, validate(m_non_const_hops, p_target), p_target }; + } + + constexpr invoker operator()(RObject&& p_target) const noexcept { + return invoker{ m_non_const_hops, validate(m_non_const_hops, p_target), p_target }; + } + + constexpr invoker operator()(const RObject& p_target) const noexcept { + return invoker{ m_const_hops, validate(m_const_hops, p_target), p_target }; + } + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind(RObject& p_target) const noexcept { + return perfect_fwd{ m_non_const_hops, validate(m_non_const_hops, p_target), p_target }; + } + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind(RObject&& p_target) const noexcept { + return perfect_fwd{ m_non_const_hops, validate(m_non_const_hops, p_target), p_target }; + } + + template + requires (std::is_same_v, std::tuple>) + constexpr const perfect_fwd bind(const RObject& p_target) const noexcept { + return perfect_fwd{ m_const_hops, validate(m_const_hops, p_target), p_target }; + } + + constexpr operator bool() const noexcept { + return (m_const_hops.operator bool() || m_non_const_hops.operator bool()); + } + + constexpr error get_init_error() const noexcept + { + if (m_const_hops.get_init_error() == error::None || + m_non_const_hops.get_init_error() == error::None) { + return error::None; + } + return m_non_const_hops.get_init_error(); + } + + private: + + hopper_t m_const_hops; + hopper_t m_non_const_hops; + + GETTER_REF(hopper_t, _c_hops, m_const_hops) + GETTER_REF(hopper_t, _nc_hops, m_non_const_hops) + + template + friend struct detail::InitMethodHop; + + static_assert((!std::is_reference_v && ...), + "rtl::method<...>: any type cannot be specified as reference here."); + }; +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_traits.h b/ReflectionTemplateLib/rtl/rtl_traits.h new file mode 100644 index 00000000..af92ff79 --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_traits.h @@ -0,0 +1,199 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace rtl +{ + namespace traits + { + using Converter = std::function< std::any(const std::any&, const detail::EntityKind&, detail::EntityKind&) >; + + using ConverterPair = std::pair< std::size_t, Converter >; + + using cloner_t = Return(*)(alloc, const RObject&); + + template + struct raw_type { + using type = std::remove_cv_t>>>; + }; + + template + using raw_t = typename raw_type::type; + + // Utility: Remove const and reference qualifiers from T. + template + using remove_cref_t = std::remove_const_t>; + + // Utility: Remove const from T if T is not a reference; otherwise, leave as is. + template + using remove_const_if_not_reference = std::conditional_t< std::is_reference_v, T, std::remove_const_t>; + + // Utility: Remove const, reference, and pointer from T (after decay). + template + using remove_const_n_ref_n_ptr = std::remove_const_t>>>; + + template + inline constexpr bool is_raw_ptr_v = std::is_pointer_v>; + + template + inline constexpr bool is_const_v = (std::is_const_v> || (std::is_pointer_v && std::is_const_v>)); + + template + inline constexpr bool is_first_type_same_v = std::is_same_v::HEAD>, raw_t<_checkType>>; + } + + + namespace traits + { + using uid_t = std::uintptr_t; + + // Returns an opaque, unique identifier per type T. + // Must only be compared or hashed - never interpreted numerically. + template + class uid + { + static + #if __cpp_static_local_constexpr >= 202306L + constexpr + #endif + uid_t get() noexcept + { + if constexpr (!std::is_same_v) { + static const int unique_tag = 0; + return reinterpret_cast(&unique_tag); + } + return 0; + } + + public: + + static constexpr uid_t none = 0; + static inline const uid_t value = get(); + }; + } + + + namespace traits + { + template + struct std_wrapper + { + using value_type = std::nullptr_t; + static constexpr const auto type = detail::Wrapper::None; + static constexpr uid_t id() { return uid<>::none; } + }; + + + template + struct std_wrapper> + { + using value_type = T; + static constexpr const auto type = detail::Wrapper::Shared; + static constexpr uid_t id() { return uid>::value; } + }; + + + template + struct std_wrapper> + { + using value_type = T; + static constexpr const auto type = detail::Wrapper::Unique; + static constexpr uid_t id() { return uid>::value; } + }; + + + template + struct std_wrapper> + { + using value_type = T; + static constexpr const auto type = detail::Wrapper::Weak; + static constexpr uid_t id() { return uid>::value; } + }; + + template + constexpr auto wrapper_type_v = std_wrapper::type; + + template + constexpr bool is_weak_ptr_v = (wrapper_type_v == detail::Wrapper::Weak); + + template + constexpr bool is_unique_ptr_v = (wrapper_type_v == detail::Wrapper::Unique); + + template + constexpr bool is_shared_ptr_v = (wrapper_type_v == detail::Wrapper::Shared); + + template + constexpr bool is_not_any_wrapper_v = (wrapper_type_v == detail::Wrapper::None); + + template + using enable_if_unique_ptr = std::enable_if::type == detail::Wrapper::Unique, int>::type; + + template + using enable_if_shared_ptr = std::enable_if::type == detail::Wrapper::Shared, int>::type; + } + + + namespace traits + { + template + concept has_constructor = requires(signature_t&&... args) { + T{ std::forward(args)... }; + }; + + template + constexpr bool is_bare_type() + { + static_assert(!std::is_const_v, "Provide bare type (remove const)."); + static_assert(!std::is_pointer_v, "Provide bare type (remove pointer)."); + static_assert(!std::is_reference_v, "Provide bare type (remove reference)."); + + return !(std::is_const_v || std::is_pointer_v || std::is_reference_v); + } + + template + using normal_sign_t = std::remove_const_t>; + + template + using normal_sign_id_t = std::tuple...>; + + template + using strict_sign_id_t = std::tuple; + + template + inline constexpr bool is_nonconst_ref_v = ((std::is_lvalue_reference_v || std::is_rvalue_reference_v) && + !std::is_const_v>); + + template + constexpr static const bool type_aware_v = (!std::is_same_v && !std::is_same_v); + + template + constexpr static const bool return_erased_v = (!std::is_same_v && std::is_same_v); + + template + constexpr static const bool target_erased_v = (std::is_same_v && !std::is_same_v); + + template + constexpr static const bool type_erased_v = (std::is_same_v && std::is_same_v); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/rtl_typeid.h b/ReflectionTemplateLib/rtl/rtl_typeid.h new file mode 100644 index 00000000..ec3f7161 --- /dev/null +++ b/ReflectionTemplateLib/rtl/rtl_typeid.h @@ -0,0 +1,116 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +#include +#include +#include + + +namespace rtl { + + namespace detail + { + //class to generate unique type-id for a type or combination of types. + template + struct TypeId; + + //class to generate unique type-id a type. + template + struct TypeId<_type> + { + //represents '_type' or 'std::nullptr_t' for TypeId<> (empty). + using HEAD = _type; + + using TAIL = std::nullptr_t; + + //returns the type-list as string. + static std::string toString() + { + if constexpr (std::is_same_v<_type, void>) { + return std::string("void"); + } + if constexpr (std::is_same_v<_type, std::string*>) { + return std::string("std::string*"); + } + if constexpr (std::is_same_v<_type, const std::string*>) { + return std::string("const std::string*"); + } + if constexpr (std::is_same_v<_type, std::string&>) { + return std::string("std::string&"); + } + if constexpr (std::is_same_v<_type, const std::string&>) { + return std::string("const std::string&"); + } + if constexpr (std::is_same_v<_type, std::string&&>) { + return std::string("std::string&&"); + } + if constexpr (std::is_same_v<_type, const std::string>) { + return std::string("const std::string"); + } + if constexpr (std::is_same_v<_type, std::string>) { + return std::string("std::string"); + } + if constexpr (std::is_same_v<_type, std::string_view&>) { + return std::string("std::string_view&"); + } + if constexpr (std::is_same_v<_type, const std::string_view&>) { + return std::string("const std::string_view&"); + } + if constexpr (std::is_same_v<_type, std::string_view&&>) { + return std::string("std::string_view&&"); + } + if constexpr (std::is_same_v<_type, const std::string_view>) { + return std::string("const std::string_view"); + } + if constexpr (std::is_same_v<_type, std::string_view>) { + return std::string("std::string_view"); + } + if constexpr (!std::is_same_v<_type, std::nullptr_t>) { + return std::string(typeid(_type).name()); + } + if constexpr (std::is_same_v<_type, std::nullptr_t>) { + return ""; + } + else return std::string(); + } + }; + + + //class to generate unique type-id for a combination of types. + template + struct TypeId + { + //represents the first type in given list. + using HEAD = _first; + + //represents a new list created excluding '_first'. + using TAIL = TypeId<_rest...>; + + //returns the type-list as string. + static std::string toString() + { + const std::string& tailStr = TAIL::toString(); + if (std::is_same::value) { + return ""; + } + else if constexpr (std::is_same::value) { + return std::string("std::string") + ", " + tailStr; + } + else if constexpr (std::is_same::value) { + return std::string("std::string_view") + ", " + tailStr; + } + return (std::string(typeid(HEAD).name()) + ", " + tailStr); + } + }; + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/src/CMakeLists.txt b/ReflectionTemplateLib/rtl/src/CMakeLists.txt new file mode 100644 index 00000000..22a75169 --- /dev/null +++ b/ReflectionTemplateLib/rtl/src/CMakeLists.txt @@ -0,0 +1,11 @@ +# ReflectionTemplateLibrary-CPP/ReflectionTemplateLib/rtl/src/CMakeLists.txt + +# Collect local sources (absolute paths) +set(LOCAL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/CxxMirror.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/CxxMirrorToJson.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Function.cpp" +) + +target_sources(ReflectionTemplateLib PRIVATE ${LOCAL_SOURCES}) +source_group("Source Files\\RTL" FILES ${LOCAL_SOURCES}) \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/src/CxxMirror.cpp b/ReflectionTemplateLib/rtl/src/CxxMirror.cpp new file mode 100644 index 00000000..7ab2b0b6 --- /dev/null +++ b/ReflectionTemplateLib/rtl/src/CxxMirror.cpp @@ -0,0 +1,117 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#include +#include +#include + +namespace rtl +{ + CxxMirror::CxxMirror(const std::vector& pFunctions) : detail::CxxReflection(pFunctions) + { + rtl::detail::ReflectedConversions::init(); + } + + /** + * @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), pRecordName); + } + + /** + * @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), pFunctionName); + } + + /** + * @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 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(pNameSpaceName); + if (itr != nsRecordMap.end()) + { + const auto& recordMap = itr->second; + const auto& itr0 = recordMap.find(pRecordName); + if (itr0 != recordMap.end()) { + return std::make_optional(itr0->second); + } + } + return std::nullopt; + } + + /** + * @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(pNameSpaceName); + if (itr != nsFunctionMap.end()) + { + const auto& functionMap = itr->second; + const auto& itr0 = functionMap.find(pFunctionName); + if (itr0 != functionMap.end()) { + return std::make_optional(itr0->second); + } + } + return std::nullopt; + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl/src/CxxMirrorToJson.cpp b/ReflectionTemplateLib/rtl/src/CxxMirrorToJson.cpp new file mode 100644 index 00000000..62041847 --- /dev/null +++ b/ReflectionTemplateLib/rtl/src/CxxMirrorToJson.cpp @@ -0,0 +1,130 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace rtl; +using namespace rtl::detail; + +static const std::string toJson(const type_meta& pFnMeta) +{ + std::stringstream sout; + sout << "{\"recordId\": \"" << std::to_string(pFnMeta.get_record_id()) << "\","; + sout << "\"returnId\": \"" << std::to_string(pFnMeta.get_return_id()) << "\","; + sout << "\"signatureId\": \"" << std::to_string(pFnMeta.get_strict_args_id()) << "\","; + if (pFnMeta.get_record_id() != traits::uid<>::none) { + if (pFnMeta.get_member_kind() == member::Static) + sout << "\"memberKind\": \"static_function\","; + else if (pFnMeta.get_member_kind() == member::Const) + sout << "\"memberKind\": \"const_function\","; + else if (pFnMeta.get_member_kind() == member::NonConst) + sout << "\"memberKind\": \"mutable_function\","; + else if (pFnMeta.get_member_kind() == member::UserCtor) + sout << "\"memberKind\": \"overloaded_ctor\","; + else if (pFnMeta.get_member_kind() == member::DefaultCtor) + sout << "\"memberKind\": \"default_ctor\","; + } + sout << "\"signature\": \"" << pFnMeta.get_signature_str() << "\"}"; + return sout.str(); +} + + +static const std::string toJson(const Function& pFunction) +{ + std::stringstream sout; + const auto& functors = pFunction.getFunctorsMeta(); + const std::string& record = pFunction.getRecordName(); + const std::string& nmspace = pFunction.getNamespace(); + + sout << "{" << (record.empty() ? "\"function\"" : "\"method\"") << ": \"" << pFunction.getFunctionName() << "\","; + if (nmspace != rtl::detail::NAMESPACE_GLOBAL) { + sout << "\"namespace\": \"" << nmspace << "\","; + } + if (!record.empty()) { + sout << "\"record\": \"" << record << "\","; + } + + int index = 0; + sout << "\"functorMeta\": ["; + for (const auto& funtorId : functors) { + sout << toJson(funtorId); + if (++index < functors.size()) { + sout << ", "; + } + } + sout << "]}"; + return sout.str(); +} + + +namespace rtl +{ + void CxxMirrorToJson::dump(const CxxMirror& pCxxMirror, const std::string& pFilePathStr) + { + std::string fileStr = pFilePathStr; + std::replace(fileStr.begin(), fileStr.end(), '\\', '/'); + std::fstream fout(fileStr, std::ios::out); + if (!fout.is_open()) { + return; + } + fout << toJson(pCxxMirror); + fout.flush(); + fout.close(); + if (fout.fail() || fout.bad()) { + return; + } + } + + + const std::string CxxMirrorToJson::toJson(const CxxMirror& pCxxMirror) + { + std::stringstream sout; + sout << "["; + bool atLeastOne = false; + const auto& nsfuncMap = pCxxMirror.getNamespaceFunctionsMap(); + for (const auto& itr : nsfuncMap) + { + for (const auto& itr0 : itr.second) + { + const std::string& functionStr = ::toJson(itr0.second); + sout << functionStr << ","; + atLeastOne = true; + } + } + + const auto& recfuncMap = pCxxMirror.getNamespaceRecordMap(); + for (const auto& itr : recfuncMap) + { + for (const auto& itr0 : itr.second) + { + for (const auto& itr1 : itr0.second.get().getMethodMap()) + { + const std::string& methodStr = ::toJson(itr1.second); + sout << methodStr << ","; + atLeastOne = true; + } + } + } + + std::string str = sout.str(); + if (str.back() == ',') str.pop_back(); + str.push_back(']'); + return str; + } +} diff --git a/ReflectionTemplateLib/rtl/src/Function.cpp b/ReflectionTemplateLib/rtl/src/Function.cpp new file mode 100644 index 00000000..b654b7e0 --- /dev/null +++ b/ReflectionTemplateLib/rtl/src/Function.cpp @@ -0,0 +1,62 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#include +#include +#include + +namespace rtl +{ +/* @constructor: Function() + @params: pNamespace - given namespace while registering the type. + * pRecord - given class/struct name, empty if this 'Function' represents a non-member functor + * pFunction - given name of the function as string. + * pFunctorId - 'FunctorId', generated for every functor being registered. + * pRecordTypeId - type id of class/struct if the functor is member-function, '0' for non-member-functions. + * pQualifier - whether the member-function is const or non-const. member::None for non-member & static-member functions. + * 'Function' object is created for every functor (member/non-member) being registered. +*/ Function::Function(const std::string& pNamespace, const std::string& pRecord, + const std::string& pFunction, const type_meta& pFunctorsMeta, + const traits::uid_t pRecordTypeId, const detail::member pQualifier) + : m_member_kind(pQualifier) + , m_recordTypeId(pRecordTypeId) + , m_recordStr(pRecord) + , m_function(pFunction) + , m_namespaceStr(pNamespace) + , m_functorsMeta({ pFunctorsMeta }) { + } + + +/* @method: addOverload() + @param: 'Function' object + * every 'Function' object produced while registration will have a single 'FunctorId' object, except constructors. + * for overloads, registered with the same name, the 'FunctorId' from the 'pOtherFunc' object will be added to this. + * if the same functor is registered again with the same name, it will be ignored. +*/ void Function::addOverload(const Function& pOtherFunc) const + { + const auto& otherFnMeta = pOtherFunc.m_functorsMeta.back(); + //simple linear-search, efficient for small set of elements. + for (const auto& functorId : m_functorsMeta) + { + if (functorId.get_member_kind() == otherFnMeta.get_member_kind() && + functorId.get_strict_args_id() == otherFnMeta.get_strict_args_id()) { + + std::cout << "\n[WARNING] Multiple registrations of the same function-pointer detected." + << "\n function-pointer already registered as \"" << m_function << "\"" + << "\n This registration is ignored.\n"; + + return; //ignore and return since its already registered. + } + } + //add the 'type_meta' of the overloaded functor. + m_functorsMeta.push_back(pOtherFunc.m_functorsMeta.back()); + } +} \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl_access.h b/ReflectionTemplateLib/rtl_access.h new file mode 100644 index 00000000..ca4901dd --- /dev/null +++ b/ReflectionTemplateLib/rtl_access.h @@ -0,0 +1,84 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + +/* +* Interface for accessing user-defined classes/structs and their members +* (constructors, methods, and fields). +* +* A Record encapsulates all metadata for a reflected type and provides +* objects (Method, Function) to access its members. +* +* Record instances are retrieved from the global reflection mirror: +* std::optional rec = cxx::mirror().getRecord("MyClass"); +* +* Declared in namespace rtl. +*/ +#include + + +/* +* Provides the interface for invoking global functions (optionally within +* a namespace) and static member functions of classes/structs. +* +* The class overloads operator(), allowing direct invocation: +* auto [err, ret] = funcObj.bind().call(arg1, arg2); +* +* Global Function objects are obtained from the reflection mirror: +* std::optional func = cxx::mirror().getFunction("ns", "funcName"); +* +* Declared in namespace rtl. +*/ +#include + + +/* +* Provides the interface for invoking member functions on reflected objects. +* +* Like Function, it overloads operator(), but instead of taking arguments +* directly, it first binds a target object and then allows calling with +* invoke(..args..). +* +* Example usage: +* auto [err, ret] = methodObj.bind(targetObj).call(arg1, arg2); +* +* Difference between Function and Method: +* - Function: bind() -> call(..args..) +* Example -> funcObj.bind().call(..args..); +* +* - Method: bind(targetObj) -> call(..args..) +* Example -> methodObj.bind(targetObj).call(..args..); +* +* Declared in namespace rtl. +*/ +#include + + +/* +* The root reflection container that aggregates all registrations. +* example pattern- +* +* namespace cxx { +* const rtl::CxxMirror& mirror() { +* static rtl::CxxMirror m = rtl::CxxMirror({ +* // registrations here... +* }); +* return m; +* } +* } +* +* Declared in namespace rtl. +*/ +#include + + +#include \ No newline at end of file diff --git a/ReflectionTemplateLib/rtl_builder.h b/ReflectionTemplateLib/rtl_builder.h new file mode 100644 index 00000000..a6a6919d --- /dev/null +++ b/ReflectionTemplateLib/rtl_builder.h @@ -0,0 +1,51 @@ +/***************************************************************************** + * * + * Reflection Template Library (RTL) - A Run-Time Reflection System for C++ * + * https://github.com/ReflectCxx/ReflectionTemplateLibrary-CPP * + * * + * Copyright (c) 2026 Neeraj Singh * + * SPDX-License-Identifier: MIT * + * * + *****************************************************************************/ + + +#pragma once + + + /* + * Provides the interface to register types and functions with RTL. + * + * Example usage: + * rtl::type().ns("ns").function("func").build(&func); + * rtl::type().ns("ns").record("MyClass").build(); + * rtl::type().member().constructor().build(); + * rtl::type().member().method("setName").build(&MyClass::setName); + * + * Template parameters are required only for overload resolution: + * - If the function/method is unique, template parameters are optional. + * - If overloads exist and one of them has zero parameters, that overload + * must be registered with . + * - Constructor overloads never require , even if a zero-argument + * constructor exists. + * + * Declared in namespace rtl::builder. + */ +#include + + + /* + * The root reflection container that aggregates all registrations. + * example pattern- + * + * namespace cxx { + * const rtl::CxxMirror& mirror() { + * static rtl::CxxMirror m = rtl::CxxMirror({ + * // registrations here... + * }); + * return m; + * } + * } + * + * Declared in namespace rtl. + */ +#include \ No newline at end of file diff --git a/docs/DESIGN_PRINCIPLES_AND_FEATURES.md b/docs/DESIGN_PRINCIPLES_AND_FEATURES.md new file mode 100644 index 00000000..436eac68 --- /dev/null +++ b/docs/DESIGN_PRINCIPLES_AND_FEATURES.md @@ -0,0 +1,119 @@ +### 🪶 Registration Model and Metadata Lifetime + +RTL does not use macro-based reflection, implicit static initialization at program startup, or centralized global registries. +All registration is performed lazily and explicitly by user code, and registered metadata persists for the lifetime of the process. + +For every registered type, method, or function, RTL creates a **dedicated dispatch object** that encapsulates: + +* The callable function-pointer +* The associated reflection metadata + +These dispatch objects are defined in: + +``` +rtl/dispatch/function_ptr.h +rtl/dispatch/method_ptr.h +``` + +Each dispatch object is: + +* Created **exactly once per unique registration** +* Stored in a process-lifetime (`static std::list`) +* Reused across all `rtl::CxxMirror` instances + +Repeated registration attempts always resolve to the same existing object. This ensures deterministic behavior – +metadata identity is stable regardless of initialization order or how many translation units register the same type. + +`rtl::CxxMirror` does not own or duplicate this metadata. It encapsulates references to it as a lightweight, ordinary object. Mirrors may be created with different type sets, and the same registration statements can be materialized multiple times. + +For example: + +```cpp +rtl::type().member().method("getName").build(&Person::getName); +``` + +will always yield the same metadata and dispatch object for `Person::getName`. +The lifetime of registered metadata is independent of any individual `rtl::CxxMirror` instance and persists for the duration of the program. + +--- + +### ⚡ Reflective Call Materialization and Performance + +RTL employs a two-phase invocation model. Metadata queries return lightweight descriptors such as `rtl::Function` and `rtl::Method`, which must be explicitly **materialized** into callable entity by specifying the expected signature. + +This deferred materialization acts as a compile-time contract: the user declares the argument and return types they intend to use, and RTL validates and prepares an optimized invocation path accordingly. + +Performance depends on how much type information is provided: + +* Fully specified signatures compile to **direct function-pointer calls**, faster than `std::function`. +* Type-erased signatures invoke through a lightweight dispatch layer whose performance **is comparable** to `std::function` under real workloads. + +By requiring explicit materialization, RTL produces lightweight, reusable callable entity that behave like ordinary value-type objects and can be stored in standard containers. + +At call time, RTL performs no dynamic allocations, no RTTI lookups, no `void*` stuff, and no hidden metadata traversals. The runtime cost is explicit, minimal, and comparable to what a developer would implement manually for equivalent type safety and flexibility. + +--- + +### 🛡 Exception-Free Guarantee + +RTL is designed to be exception-free. In practice, any exceptions that occur are almost always introduced by user code and merely propagate through RTL. + +For all predictable failure cases, RTL reports errors through explicit error codes(`rtl::error`) rather than throwing exceptions. Critical assumptions are validated before execution, ensuring that failure conditions are detected early and handled in a controlled manner. + +This design promotes predictable behavior and avoids unexpected control flow during reflective operations. + +> *Exception-handling behavior has not yet been exhaustively stress-tested across all edge cases, but the system is architected to avoid exception-based control flow by design.* + +--- + +### 🎁 Smart Pointer Handling + +RTL supports working with objects managed by `std::unique_ptr` and `std::shared_ptr` in a manner consistent with standard C++ usage. + +Heap-allocated objects created through RTL are internally managed using smart pointers to ensure safe ownership and lifetime control. These details are not imposed on the user: reflected objects can be accessed either through their smart-pointer representation or through views of the underlying type `T`. + +When cloning or transferring reflected objects, RTL preserves the ownership semantics of the original type: + +* Objects intended to be shared can be accessed through shared ownership. +* Uniquely owned objects retain their uniqueness. +* Copyable values can be duplicated to produce independent instances. + +This design allows developers to work with reflected objects using the same ownership and lifetime expectations they would apply in ordinary C++ code, without requiring special handling for reflection-specific wrappers. + +Reflection semantics are aligned with standard C++ object semantics, ensuring consistent behavior regardless of whether an object is accessed directly or through a smart pointer. + +--- + +### 💡 Tooling-Friendly Architecture + +**RTL** separates the *generation* of reflection metadata from its *consumption*. This makes it ideal not just for runtime introspection, but also for external tools like: + +* Code generators +* Serialization pipelines +* Game or UI editors +* Live scripting or plugin systems + +#### ✨ The Mirror & The Reflection + +> *A client system hands off a `rtl::CxxMirror` to RTL — and RTL sees its reflection.* + +The mirror is a **single object**, typically returned from a function like: + +```cpp +extern const rtl::CxxMirror& MyReflection(); +``` + +This function is: + +* **Externally linkable** — can live in any translation unit or even dynamic module +* **Lazy** — doesn’t require metadata unless explicitly accessed +* **Pure** — returns a complete, immutable view of reflection metadata + +#### 📎 Why This Matters for Tooling + +This design turns RTL into a **pluggable, runtime-agnostic consumer** of metadata. You can: + +* Reflect types from external libraries +* Link in auto-generated metadata modules +* Expose your reflection system to scripts or tools without tight coupling +* Swap different `rtl::CxxMirror` sources depending on build mode (dev/editor/runtime) \ No newline at end of file diff --git a/docs/RTL_SYNTAX_AND_SEMANTICS.md b/docs/RTL_SYNTAX_AND_SEMANTICS.md new file mode 100644 index 00000000..3f16e07b --- /dev/null +++ b/docs/RTL_SYNTAX_AND_SEMANTICS.md @@ -0,0 +1,735 @@ +# RTL: Syntax & Semantics 🔍 + +RTL makes C++ reflection feel like a natural extension of the language. Let’s explore its syntax and the semantics it unlocks. + +### 📖 Index + +1. [The `rtl::CxxMirror`](#the-rtlcxxmirror) +2. [Getting Started with Registration](#getting-started-with-registration) +3. [Querying the Metadata](#querying-the-metadata) +4. [The `rtl::RObject`](#the-rtlrobject) +5. [The `rtl::view`](#the-rtlview) +6. [Reflective Invocations with RTL](#reflective-invocations-with-rtl) + - [`rtl::constructor`](#rtlconstructor) + - [`rtl::function` – Type Aware](#rtlfunction--type-aware) + - [`rtl::function` – Type Erased](#rtlfunction--type-erased) + - [`rtl::method` – Type Aware](#rtlmethod--type-aware) + - [`rtl::method` – Type Erased](#rtlmethod--type-erased) +7. [Perfect Forwarding](#perfect-forwarding) +8. [Error Taxonomy](#error-taxonomy) + +--- + +## The `rtl::CxxMirror` + +`rtl::CxxMirror` is the runtime entry point for querying reflection metadata registered with RTL. +It aggregates references to metadata descriptors produced by `rtl::type()...build();` registration expressions and exposes them through a unified lookup interface. + +```cpp +auto cxx_mirror = rtl::CxxMirror({ + // registration expressions +}); +``` + +Each registration expression contributes references to metadata objects that are lazily created on first use. +`rtl::CxxMirror` **does not own** this metadata and never duplicates it; it merely provides structured access to already-registered entities. + +Through the mirror, all registered types, functions, and methods can be queried, inspected, and materialized at runtime. The mirror itself is a lightweight facade and does not introduce centralized global state. + +#### Managing `rtl::CxxMirror` + +* **No hidden global state** – `rtl::CxxMirror` is dispensable by design. You may use a single global mirror, multiple mirrors, or construct mirrors on demand. All mirrors reference the same underlying metadata cache. + +* **Duplicate registration is benign** – Re-registering the same function pointer or type is safe. If matching metadata already exists, RTL reuses it; no duplicate entries are created. + +* **Thread-safe by construction** – Metadata registration and access are internally synchronized. Thread safety is guaranteed regardless of how many mirrors exist or where they are constructed. + +* **Registration cost is one-time** – Each registration performs: + * a synchronized lookup in the metadata cache + * conditional insertion if no match exists + + This cost is incurred only during registration and is negligible for normal initialization paths. Repeated registration in hot paths should be avoided. + +👉 Bottom Line +> *`rtl::CxxMirror` is a lightweight, non-owning access layer over RTL’s metadata. Its lifetime and multiplicity are entirely user-controlled, and its overhead is limited to initialization-time lookups.* + +--- + +## Getting Started with Registration + +Registration in RTL follows a builder-style composition pattern. Individual components are chained together to describe the reflected entity, and `.build()` finalizes the registration. The builder interface is exposed via the `rtl_builder.h` header. + +### Non-Member Functions + +```cpp +rtl::type().ns("ext").function("fn-name").build(fn-ptr); +``` + +* `ns("ext")` – Specifies the namespace under which the function is registered. + Omitting `.ns()` or passing an empty string (`.ns("")`) registers the function under `rtl::global`. This is not a declared C++ namespace; rather, it is a logical, string-based grouping used to prevent naming conflicts. + +* `function("fn-name")` – Declares the function by name. + If multiple overloads exist, the template parameter (`function<...>(..)`) disambiguates the selected overload. + +* `.build(fn-ptr)` – Supplies the function-pointer and completes the registration. + +### Handling Overloads + +If multiple overloads exist, the signature must be specified as a template argument. Otherwise, the compiler cannot resolve the intended function-pointer. + +For example: + +```cpp +namespace ext { + bool sendMessage(const char*); + void sendMessage(int, std::string); +} +``` +```c++ +rtl::type().ns("ext").function("sendMessage").build(ext::sendMessage); +rtl::type().ns("ext").function("sendMessage").build(ext::sendMessage); +``` + +### PODs / Classes / Structs + +```cpp +rtl::type().ns("ext").record("type-name").build(); +``` + +* Registers a type by name and associates it with the specified namespace. +* This type (`T`) registration is **mandatory** for any of its members to be registered. The order of registration does not matter. +* The default, copy, and move constructors, along with the destructor, are registered automatically. Explicit registration of these special members is disallowed and will result in a compile-time error. + +### Constructors + +```cpp +rtl::type().member().constructor<...>().build(); +``` + +* `.member()`: enters the scope of `T` (POD/class/struct). +* `.constructor<...>()`: registers a user-defined constructor. The template parameter `<..signature..>` must be provided since no function-pointer is available for type deduction, and this also disambiguates overloads. + +### Member Functions + +```cpp +rtl::type().member().method<...>("method-name").build(&T::f); +``` + +* `.method<...>(..)`: registers a non-const member function. The template parameter `<..signature..>` disambiguates overloads. +* Variants exist for const (`.methodConst`) and static (`.methodStatic`) methods. + +👉 Note +> *The `function<..signature..>` and `method<..signature..>` template parameters are primarily for overload resolution. They tell RTL exactly which overload of a function or method you mean to register.* + +--- + +## Querying the Metadata + +Once the Mirror is initialized with metadata references, it can be queried for registered entities and used to introspect types at runtime through RTL’s access interface, which is exposed via the `rtl_access.h` header. + +`rtl::CxxMirror` provides lookup APIs that return reflection metadata objects. +Registered types (`class`, `struct`, or POD) are queried as `rtl::Record`, while non-member functions are queried as `rtl::Function`. +For example: + +```cpp +// Function without a namespace +std::optional popMessage = cxx::mirror().getFunction("popMessage"); + +// Function registered with a namespace, e.g. "ext" +std::optional sendMessage = cxx::mirror().getFunction("ext", "sendMessage"); +``` + +These metadata are returned wrapped in `std::optional`, which is empty if the requested entity is not found by the name specified. + +```cpp +// Querying a type without a namespace +std::optional classPerson = cxx::mirror().getRecord("Person"); + +// Querying a type with a namespace, e.g. "model" +std::optional classPerson = cxx::mirror().getRecord("model", "Person"); +``` + +* If a type or function is registered without a namespace, it must be queried without specifying a namespace. +* If a type or function is registered with a namespace, it must be queried using the same namespace. + +`rtl::Record` represents any registered C++ type, including user-defined `class` and `struct` types, as well as POD types. +The term **Record** follows the naming convention used in the **LLVM** project (e.g. `CXXRecordDecl`). + +All registered member functions of a type can be obtained from its corresponding `rtl::Record` as `rtl::Method` objects. +For POD types such as `char`, the type can still be registered as an `rtl::Record`. +In this case, only the implicitly supported special members (copy/move constructors and the destructor) are available. +POD types do not have member functions. + +`rtl::CxxMirror` also provides an overload of `getRecord()` that accepts an `std::uintptr_t` instead of a string identifier. +This ID can be generated using `rtl::traits::uid`, where `T` is a compile time known type. +The generated ID may be cached and reused for runtime lookups without requiring a namespace or string-based queries. + +The `rtl::Method` and `rtl::Function` metadata objects can be further queried to determine whether a specific call signature is valid for a given function or method. This allows callers to validate argument compatibility before attempting materialization or invocation. + +```c++ +// Obtain metadata for the registered function. +std::optional sendMessage = cxx::mirror().getFunction("ext", "sendMessage"); + +// Query supported call signatures. +bool isSignature0 = sendMessage->hasSignature(); // true +bool isSignature1 = sendMessage->hasSignature(); // true +bool isSignature2 = sendMessage->hasSignature<>(); // false (no parameters) +``` +--- + +## The `rtl::RObject` + +`rtl::RObject` exists to wrap values or objects of any type in a type-erased form while providing safe access interfaces. +It can be returned from reflective function calls, method calls, and constructor calls. +It can also be created directly from a known value or object. + +Objects constructed on the **Heap** via a reflective constructor call are returned as an `rtl::RObject` and are internally managed using `std::unique_ptr` for automatic lifetime management. + +Objects returned from reflective function or method calls, as well as values directly wrapped in an `rtl::RObject`, are stored on the **Stack** using `std::any`. + +#### Accessing Values from `rtl::RObject`: + +When working with `rtl::RObject`, the following interfaces provide safe access to the stored value: + +| Function | Purpose | +| ------------------ | ---------------------------------------------------------------------- | +| `isEmpty()` | Checks whether the object contains a value. | +| `canViewAs()` | Returns `true` if the stored type is `T` or safely convertible to `T`. | +| `view()` | Returns a typed view of the stored value, or an empty `std::optional`. | +| `view()->get()` | Accesses the stored value as a `const T&`. | + +👉 Tip + +> *Use `.canViewAs()` for a lightweight boolean check when branching, and `.view()` when you need to access the value.* + +### Move Semantics with `rtl::RObject` + +`rtl::RObject` is a **move-only** type. Copying is disallowed, and ownership transfer is performed exclusively through move semantics. +The behavior differs internally based on whether the underlying object is stored on the **Stack** or on the **Heap**, without any impact on the public interface or user-visible behavior. + +#### Stack-Allocated Objects: + +When an object is created on **Stack**, the underlying instance is stored directly inside `rtl::RObject` using `std::any`. + +```cpp +rtl::RObject obj1 = rtl::RObject(std::string_view("Hello")); // No internal heap allocation, stored on the stack. +rtl::RObject obj2 = std::move(obj1); +``` + +**Behavior:** + +* The reflected type’s **move constructor** is invoked. +* Ownership transfers to `obj2`. +* The moved-from object (`obj1`) becomes empty. +* No duplication occurs. + +👉 Mental Note +> *Stack move semantics invoke the reflected type’s move constructor.* + +`rtl::RObject` itself does not perform heap allocation when wrapping stack-stored values. Any dynamic allocation that occurs is solely an implementation detail of `std::any`. By leveraging `std::any`, RTL provides controlled, type-erased storage with retained runtime type information as a safe alternative to `void*`, enforcing validated access and well-defined semantics while avoiding unchecked casts and undefined behavior. + +#### Heap-Allocated Objects: + +Objects on the **Heap** can only be created through a reflective constructor call. The returned instance is managed internally using `std::unique_ptr`. +Moving such an `rtl::RObject` transfers ownership of the pointer. + +**Behavior:** + +* The internal `std::unique_ptr` is moved. +* The reflected type’s move constructor is **not** invoked. +* Ownership transfers to the destination object. +* The moved-from object becomes empty. +* The underlying heap object remains valid until the final owner is destroyed. + +👉 Mental Note +> *Heap move semantics transfer the `unique_ptr` without moving the underlying object.* + +Across both **Stack** and **Heap** moves: + +* The moved-from `rtl::RObject` becomes empty. +* The destination `rtl::RObject` becomes the sole owner. +* Object destruction occurs exactly once. +* Cloning or invoking a moved-from object results in `rtl::error::EmptyRObject`. + +**Summary:** + +When an `rtl::RObject` is moved, RTL either: + +* Invokes the reflected type’s move constructor (**Stack** allocation), or +* Transfers ownership of the internal `std::unique_ptr` (**Heap** allocation). + +In both cases, the source object is invalidated and ownership remains well-defined. + +--- + +## The `rtl::view` + +`rtl::view` is a lightweight, immutable handle that provides safe, read-only access to a value stored inside an `rtl::RObject`. + +It exists to bridge the gap between: + +* type-erased storage (`rtl::RObject`), and +* typed access (`const T&`). + +A `rtl::view` never exposes ownership. It only exposes **observation**. + +#### Properties: + +* **Read-only** – A `rtl::view` only provides access as `const T&`. +* **Non-owning abstraction** – Whether the underlying value is owned or referenced is intentionally hidden. +* **Non-copyable and non-movable** – A `rtl::view` cannot be copied or moved and must be consumed immediately. +* **Lifetime-bound** – A `rtl::view` is only valid as long as the originating `rtl::RObject` remains alive. Using a `rtl::view` after the `rtl::RObject` is destroyed results in undefined behavior. + +#### Access Pattern: + +```cpp +auto view = robj.view(); +if (view) { + const T& value = view->get(); +} +``` + +This contract is uniform across all reflected types, including PODs, user-defined types, and standard library wrappers and smart pointers. + +👉 Ongoing + +> *RTL is designed to support seamless and transparent access to standard library wrapper types (such as `std::optional`, `std::variant`, `std::weak_ptr`, and others) while preserving their native semantics. At present, this behavior is fully implemented and validated only for `std::shared_ptr` and `std::unique_ptr`.* + +### Smart Pointer Semantics with `rtl::view` + +RTL treats smart pointers as **first-class reflected values** while preserving their native ownership rules. +No implicit deep copies are ever performed. + +#### `std::shared_ptr`: + +When an `rtl::RObject` reflects a `std::shared_ptr`, it can be viewed either as `T` directly or as `std::shared_ptr`. + +While viewing directly as `T`, a `const T&` access is provided. The user may either observe the value or create copies, depending on what liberties are provided by `T`’s copy semantics. + +```cpp +rtl::RObject robj = rtl::reflect(std::make_shared(20438)); // std::shared_ptr is on Stack. + +if (robj.canViewAs()) { // true + int viewCpy = robj.view(); // Creates a copy of int. + const int& viewCRef = robj.view(); // References the underlying value. +} +``` + +The same object can also be accessed as `std::shared_ptr`, in which case native shared ownership semantics are preserved: + +```cpp +if (robj.canViewAs>()) { // true + auto view = robj.view>(); + { + const std::shared_ptr& sptrRef = view->get(); + bool hasSingleOwner = (sptrRef.use_count() == 1); // true + } { + std::shared_ptr sptrCpy = view->get(); + bool hasTwoOwners = (sptrCpy.use_count() == 2); // true + } + // After temporary copies go out of scope, ownership returns to robj alone. + bool backToSingleOwner = (view->get().use_count() == 1); // true (robj is still alive) +} +``` + +Accessing a reflected `std::shared_ptr` through `rtl::RObject` preserves native shared ownership semantics: observing it does not change the reference count, and copying it produces a shallow, ref-counted copy exactly as in normal C++. + +#### `std::unique_ptr`: + +The behavior of `std::unique_ptr` differs from `std::shared_ptr` only in its ownership model. + +When an `rtl::RObject` reflects a `std::unique_ptr`, it can likewise be viewed as `T` directly or as `std::unique_ptr`. Viewing it as `T` provides the same `const T&` access as described earlier, and the user may observe or copy the value according to `T`’s copy semantics. + +However, unlike `std::shared_ptr`, a reflected `std::unique_ptr` does **not** permit ownership transfer through a view: + +```c++ + +// This is NOT allowed, std::unique_ptr is move-only +auto view = robj.view>(); +std::unique_ptr uptrCpy = view->get(); // ERROR: cannot copy unique_ptr + +// the pointee can be accessed +if (robj.canViewAs()) { + int value = robj.view()->get(); // Creates a copy of int. +} + +``` + +* Access is always provided as `const std::unique_ptr&`. +* No move operation is possible through `rtl::view`. +* Ownership remains exclusively with the `rtl::RObject`. +* The pointee can still be accessed safely via `view()`. + +In other words, within RTL: + +* `std::shared_ptr` exposes shared-ownership semantics because it is copy-constructible and reference-counted. +* `std::unique_ptr` is treated as an exclusive-ownership wrapper whose lifetime is managed entirely by `rtl::RObject`, because it is not copy-constructible and represents unique ownership. + +--- + +## Reflective Invocations with RTL + +`rtl::Method` and `rtl::Function` are metadata descriptors. Functions and methods cannot be directly called through these objects. Instead, RTL uses a materialization model to produce callable entities. + +Callable entities are materialized by explicitly specifying the argument and return types. This design avoids a single, fully type-erased invocation path for all use cases. By requiring the user to declare the intended call signature, RTL can validate the request and select an invocation path optimized for the available type information. + +When full type information is provided, materialized callables compile to **direct function-pointer** calls with near-zero overhead. When type erasure is required (for example, for an unknown return or target type), invocation proceeds through a lightweight dispatch layer with performance **comparable** to `std::function`. + +👉 The Idea +> *In RTL, materialization makes the performance–flexibility trade-off explicit at each call site.* + +Every type-erased reflective call returns either `std::pair` or `std::pair>`. + +* `rtl::error` indicates whether the call was successful (`rtl::error::None`) or if an error occurred. +* `rtl::RObject` or `std::optional` contains the return value if the function returns something, or is empty if the function returns `void`. + +Fully type-specified callables do not return an error code (except constructors). Once materialized successfully, they are guaranteed to be safe to call. + +RTL provides the following callable entities: + +### `rtl::constructor` + +Constructors can be materialized directly from an `rtl::Record`. +For example, an overloaded constructor can be materialized as follows: + +```cpp +// classPerson is of type std::optional. +rtl::constructor personCtor = classPerson->ctorT(); +if (personCtor) { // Constructor successfully materialized + auto [err, person] = personCtor(rtl::alloc::Stack, "Waldo", 42); // Safe to call. +} +``` + +If no constructor is registered with the specified signature, the callable is not initialized. Calling it without validation does not throw an exception; instead, it returns `rtl::error::SignatureMismatch` in the `err` variable. + +A default constructor can be materialized as follows: + +```cpp +rtl::constructor<> personCtor = classPerson->ctorT(); +// No validation required +auto [err, person] = personCtor(rtl::alloc::Heap); // Safe to call. +``` + +The default constructor for a type `T` is implicitly registered when the type is registered using `rtl::type().record()`. It is guaranteed to be materializable and safe to call. If the default constructor is not publicly accessible or is deleted, +`rtl::error::TypeNotDefaultConstructible` is returned in the `err` variable. + +Objects can be constructed by specifying `rtl::alloc::Stack` or `rtl::alloc::Heap` as the first parameter. The constructed object is returned as an `rtl::RObject`, which type-erases the underlying object. + +* `Heap` allocated objects are managed using `std::unique_ptr`. +* `Stack` allocated objects are stored directly in `std::any`. + +### `rtl::function` – Type Aware + +Non-member functions can be materialized from an `rtl::Function`: + +```c++ +rtl::function cToStr = cxx::mirror().getFunction("complexToStr") + ->argsT() + .returnT(); +if(cToStr) { // Function successfully materialized + std::string result = cToStr(61, 35); +} +else { + std::cerr << rtl::to_string(cToStr.get_init_err()); +} +``` + +Here, the return type and argument types are fully specified at compile time. +This allows RTL to resolve the function pointer by signature and provide it wrapped in a thin callable layer that effectively reduces to a single **function-pointer hop** at runtime. The overhead is comparable to a native C-style function pointer call. + +The materialized `rtl::function` must be validated before invocation. Calling it without validation may result in undefined behavior. +If materialization fails, the error can be retrieved using `get_init_err()`. +Possible error values include: + +* `rtl::error::InvalidCaller` +* `rtl::error::SignatureMismatch` +* `rtl::error::ReturnTypeMismatch` + +### `rtl::function` – Type Erased + +If the return type is not known at compile time, `rtl::Return` can be used as the return type. +In this case, the `.returnT()` template parameter can be omitted, and `rtl::Return` will be selected automatically. + +```c++ +rtl::function cToStr = cxx::mirror().getFunction("complexToStr") + ->argsT() + .returnT(); +auto [err, ret] = cToStr(61, 35); +if(err != rtl::error::None && ret.canViewAs()) { + std::string resultStr = ret.view()->get(); // Safely view the returned std::string. +} +else { + std::cerr << rtl::to_string(err); +} +``` + +Validation of the materialized `rtl::function` is optional in this case. Calling it without validation does not result in undefined behavior; instead, an appropriate `rtl::error` is returned. If the callable was not successfully materialized, invoking it returns the same error as `get_init_err()` on the callable, typically `rtl::error::SignatureMismatch`. + +If materialization succeeds but the call fails, possible error values include: + +* `rtl::error::InvalidCaller` +* `rtl::error::RefBindingMismatch` +* `rtl::error::ExplicitRefBindingRequired` + +👉 Mental Note +> *Fully type-specified callables must be validated before invocation to avoid undefined behavior; type-erased callables are safe to invoke without prior validation and report errors at runtime.* + +### `rtl::method` – Type Aware + +To materialize a member function, the corresponding `rtl::Method` metadata must first be obtained. +This requires querying the `rtl::CxxMirror` for the desired `class` or `struct` as an `rtl::Record`. + +```c++ +std::optional classPerson = cxx::mirror().getRecord("Person"); +if (!classPerson) { /* Type not registered. */ } + +// From rtl::Record, fetch the desired member-function metadata +std::optional oGetName = classPerson->getMethod("getName"); +if (!oGetName) { /* Member function not registered */ } +``` + +Once the `rtl::Method` is available, member functions can be materialized from it. + +```c++ +rtl::method getName = oGetName->targetT().argsT() + .returnT(); +if (!getName) { // Member-function with expected signature not found. + std::cerr << rtl::to_string(getName.get_init_err()); +} +else { + Person person("Alex", 23); + std::string nameStr = getName(person)(); // Returns string 'Alex'. +} +``` + +#### `rtl::const_method`: + +The `rtl::method` can only invoke non-`const` member functions. To invoke a `const` qualified member function, `rtl::const_method` must be used. + +An `rtl::const_method` is materialized by specifying a `const` target type in the `.targetT<>()` call: +```c++ +rtl::const_method getName = oGetName->targetT().argsT() + .returnT(); +if (getName) { + const Person person("Alex", 23); + std::string nameStr = getName(person)(); // Returns string 'Alex'. +} +``` + +Here, the target type is marked `const` via the template argument to `.targetT()`. As a result, `rtl::const_method` only accepts a `const Person` object as its invocation target. + +#### `rtl::static_method`: + +To invoke a `static` member function, `rtl::static_method` is used. Static methods do not require a target object, so the `.targetT()` call is omitted: + +```c++ +// Assume Person::getName() is a static function registered under the same name. +rtl::static_method getName = oGetName->argsT().returnT(); +if (getName) { + std::string nameStr = getName()(); // Returns a default std::string. +} +``` + +When the return type, target type, and argument types are fully specified, these materialized callables reduce to a **direct function-pointer** invocation at runtime. + +If materialization fails, calling `rtl::method`, `rtl::const_method`, or `rtl::static_method` without validation results in undefined behavior. +The initialization error can be retrieved using `get_init_err()`. + +Possible error values include: + +* `rtl::error::InvalidCaller` +* `rtl::error::SignatureMismatch` +* `rtl::error::ReturnTypeMismatch` +* `rtl::error::InvalidNonStaticMethodCaller` + +`rtl::error::InvalidNonStaticMethodCaller` is returned when a non-static member function is materialized without specifying a target type using `.targetT<>()`, causing it to be treated as a static function. + +### `rtl::method` – Type Erased + +When the concrete target type is not available at compile time, `rtl::method` can be materialized without specifying a target type. +Calling `.targetT()` without a template parameter defaults the target type to `rtl::RObject`. + +```c++ + +// Materializing a default constructor +rtl::constructor<> personCtor = classPerson->ctorT(); + +// No validation required +auto [err, personObj] = personCtor(rtl::alloc::Stack); // Safe to call + +rtl::method getName = oGetName->targetT().argsT() + .returnT(); +auto [err0, ret] = getName(personObj)(); // Invoke and receive return as std::optional. +if (err0 == rtl::error::None && ret.has_value()) { + std::string nameStr = ret.value(); +} +``` +In this case, the typed return value is wrapped in `std::optional`. If the member function returns `void`, the optional is empty. + +Along with the target type, the return type can also be erased. Leaving the `.returnT()` template parameter empty defaults the return type to `rtl::Return`. + +```c++ + +rtl::method getName = oGetName->targetT().argsT().returnT(); + +auto [err0, ret] = getName(personObj)(); // Invoke and receive return as rtl::RObject. +if (err0 == rtl::error::None && ret.canViewAs()) { + std::string nameStr = ret.view()->get(); // Safely view the returned std::string. +} +``` + +And finally, If the target type is known but the return type is erased: + +```c++ +rtl::method getName = oGetName->targetT().argsT().returnT(); +``` +For static methods, `rtl::static_method` is used and `.targetT()` is omitted: + +```c++ +rtl::static_method getName = oGetName->argsT().returnT(); +``` + +All of these variants follow the same invocation semantics. The only difference is the return representation: + +* Known return types are returned as `std::optional` +* Erased return types are returned as `rtl::RObject` + +#### `const` and non-`const` Member Functions with Type-Erased Targets: + +There is no separate callable entity such as `rtl::const_method` for type-erased invocation of `const`-qualified member function overloads. +The same `rtl::method` is used for both `const` and non-`const` member functions. +To invoke a `const` member function, the target must be passed as a `const` reference: + +```c++ +auto [err, ret] = getName(std::cref(personObj))(); +``` +This call will succeed only if a `const`-qualified overload of `Person::getName()` exists. If it does not, the call returns `rtl::error::ConstOverloadMissing`. + +If only a `const` overload exists and a non-`const` target is provided, the call returns `rtl::error::NonConstOverloadMissing`. + +When both `const` and non-`const` overloads are registered, the following rules apply: + +* Passing a non-`const` target binds to the non-`const` overload. +* Passing a `const` target (`std::cref(personObj)`) binds to the `const` overload. + +👉 Note +> *RTL does not perform automatic `const`/non-`const` overload resolution. The intended overload must be selected explicitly by the user through the target’s `const` qualification.* + +As with `rtl::function`, validation of the materialized `rtl::method` is optional in this case. +Calling it without validation does not result in undefined behavior; instead, an appropriate `rtl::error` is returned. If the callable was not successfully materialized, invoking it returns the same error as `get_init_err()` on the callable, typically `rtl::error::SignatureMismatch`. + +If materialization succeeds but the call fails, possible error values include: + +* `rtl::error::InvalidCaller` +* `rtl::error::ConstOverloadMissing` +* `rtl::error::NonConstOverloadMissing` +* `rtl::error::RefBindingMismatch` +* `rtl::error::ExplicitRefBindingRequired` +* `rtl::error::EmptyRObject` + +--- + +## Perfect Forwarding + +When multiple reference-based overloads of the same function signature exist, for example: + +```c++ +std::string reverse(std::string); // (1) by value +std::string reverse(std::string&); // (2) lvalue ref +std::string reverse(const std::string&); // (3) const lvalue ref +std::string reverse(std::string&&); // (4) rvalue ref + +``` + +In standard C++, invoking `reverse` by name with such an overload set results in a compile-time ambiguity error. +This occurs because the pass-by-value overload conflicts with every reference-based overload, and overload resolution cannot establish a single best match. + +If these functions are not invoked by name, but instead referenced through explicitly typed function-pointers, each overload can be selected unambiguously: + +```c++ +auto fptr0 = static_cast(reverseString); +auto fptr1 = static_cast(reverseString); +auto fptr3 = static_cast(reverseString); +auto fptr2 = static_cast(reverseString); +``` +Here, the explicit function-pointer type fully specifies the intended overload, bypassing overload resolution ambiguity. +Since RTL requires only a distinct function-pointer to register a function or method, all of the above overloads can be registered without ambiguity. + +During invocation, where the compiler would reject a direct call due to pass-by-value overload ambiguity, RTL instead deterministically defaults to the **pass-by-value** overload unless a more specific intent is explicitly expressed by the user. + +Meaning, if all such overloads are registered and an `rtl::function` is materialized and invoked, the call will unambiguously bind to the **pass-by-value** overload. + +This behavior follows directly from the fact that RTL invocation is equivalent to calling through a fully specified function-pointer, which is explicitly permitted by standard C++. + +#### Reference Binding: + +Each overload shown above can be invoked by explicitly providing the intended call signature as a template parameter to `bind<>()`. RTL then perfect-forwards the arguments to the selected overload: + +```c++ +rtl::function reverseStr = cxx::mirror().getFunction("reverseString") + .argsT().returnT(); + +auto [err0, ret0] = reverseStr("Hello"); // calls by-value overload (1) +auto [err1, ret1] = reverseStr.bind()("Hello"); // calls lvalue-ref overload (2) +auto [err2, ret2] = reverseStr.bind()("Hello"); // calls const lvalue-ref overload (3) +auto [err3, ret3] = reverseStr.bind()("Hello"); // calls rvalue-ref overload (4) +``` + +If no pass-by-value overload is registered, explicit binding is required to invoke the desired overload. Otherwise, the call results in `rtl::error::ExplicitRefBindingRequired`. + +Now consider a case where only overloads (2) and (3) are registered: + +```c++ +std::string reverse(std::string&); // (2) +std::string reverse(const std::string&); // (3) +``` + +Both overloads can be invoked explicitly using `bind<>()`. However, if the user attempts to bind a signature that has not been registered, for example: + +```c++ +auto [err, ret] = reverseStr.bind()("Hello"); +``` + +the invocation fails with `rtl::error::RefBindingMismatch`, as no rvalue-reference overload exists in the registered overload set. Now consider the case where only overload (3) is registered: + +```c++ +std::string reverse(const std::string&); // (3) +``` + +In this case, no explicit binding is required, as there is no overload ambiguity and the function guarantees that the argument will not be modified. If only overload (2) or only overload (4) is registered: + +```c++ +std::string reverse(std::string&); // (2) +std::string reverse(std::string&&); // (4) +``` + +explicit binding is required, even when these overloads exist in isolation. This is because both signatures permit mutation of the argument, and RTL requires such intent to be expressed explicitly by the user. + +👉 Rationale +> *RTL’s philosophy is to make mutating calls loud and explicit, as reflection inherently hides type information.* + +--- + +## Error Taxonomy + +The table below lists RTL errors with brief, intent-focused descriptions, providing a direct mapping from failure conditions to their semantic meaning. + +| Error | semantic meaning | +| ------------------------------ | ------------------------------------------------------------------------------- | +| `None` | Operation completed successfully; no error occurred. | +| `EmptyRObject` | The `RObject` is empty, typically due to a move or invalidation. | +| `InvalidCaller` | The callable was never successfully materialized or is otherwise invalid. | +| `SignatureMismatch` | No registered overload matches the requested call signature. | +| `TargetTypeMismatch` | The bound target object type is incompatible with the method’s expected target. | +| `ReturnTypeMismatch` | The specified return type does not match the function’s actual return type. | +| `RefBindingMismatch` | Reference qualifiers of the arguments do not match any registered overload. | +| `ExplicitRefBindingRequired` | Overload set allows mutation; binding intent must be stated explicitly. | +| `InvalidNonStaticMethodCaller` | A non-static method was invoked without providing a valid target object. | +| `ConstOverloadMissing` | A const-qualified overload does not exist for the given invocation. | +| `NonConstOverloadMissing` | A non-const overload does not exist as explicitly requested. | +| `InvalidCallOnConstTarget` | A non-const method was invoked on an object reflecting const state. | +| `TypeNotCopyConstructible` | The reflected type cannot be copy-constructed due to access or deletion. | +| `TypeNotDefaultConstructible` | The reflected type cannot be default-constructed. | + +--- +***More to come...*** diff --git a/docs/benchmark_runs_string.log b/docs/benchmark_runs_string.log new file mode 100644 index 00000000..2cbe9a25 --- /dev/null +++ b/docs/benchmark_runs_string.log @@ -0,0 +1,3167 @@ +Starting benchmark runs... +Binary: ./bin/RTLBenchmarkApp +Log: ./benchmark_runs.log +=================================== +[2026-01-19 23:00:30] >>> Run 1: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T23:00:30+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 1167.28 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.83, 0.71, 0.51 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 9.81 ns 9.81 ns 71490262 + +bm_call::via_function_ptr__Function::set_string 10.6 ns 10.6 ns 66175516 +bm_call::via_function_ptr____Method::set_string 10.5 ns 10.5 ns 65825819 + +bm_std::function_calls__Function::set_string 10.7 ns 10.7 ns 65252218 +bm_std::function_calls____Method::set_string 10.6 ns 10.6 ns 66308995 + +bm_rtl::function_calls__Function::set_string 10.2 ns 10.2 ns 70267504 +bm_rtl::method_calls______Method::set_string 10.5 ns 10.5 ns 66588972 + +bm_rtl::function__ErasedReturnType::set_string 14.2 ns 14.2 ns 49256488 +bm_rtl::method____ErasedReturnType::set_string 13.6 ns 13.6 ns 51807316 +bm_rtl::method____ErasedTargetType::set_string 14.5 ns 14.5 ns 48461435 +bm_rtl::method____ErasedTargetAndReturnType::set_string 15.3 ns 15.3 ns 45341839 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 12.8 ns 12.8 ns 55715198 + +bm_call::via_function_ptr__Function::get_string 12.7 ns 12.7 ns 55284583 +bm_call::via_function_ptr____Method::get_string 12.4 ns 12.4 ns 56197664 + +bm_std::function_calls__Function::get_string 12.5 ns 12.5 ns 56330937 +bm_std::function_calls____Method::get_string 13.1 ns 13.1 ns 53156802 + +bm_rtl::function_calls__Function::get_string 12.1 ns 12.1 ns 57911838 +bm_rtl::method_calls______Method::get_string 12.5 ns 12.5 ns 55429760 + +bm_rtl::function__ErasedReturnType::get_string 30.0 ns 30.0 ns 23256364 +bm_rtl::method____ErasedReturnType::get_string 30.8 ns 30.8 ns 22557648 +bm_rtl::method____ErasedTargetType::get_string 25.1 ns 25.1 ns 27722734 +bm_rtl::method____ErasedTargetAndReturnType::get_string 32.1 ns 32.1 ns 21698776 +----------------------------------- +[2026-01-19 23:00:49] >>> Run 2: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T23:00:49+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.88, 0.73, 0.52 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 9.74 ns 9.74 ns 71535521 + +bm_call::via_function_ptr__Function::set_string 10.5 ns 10.5 ns 66143823 +bm_call::via_function_ptr____Method::set_string 10.7 ns 10.7 ns 65023900 + +bm_std::function_calls__Function::set_string 10.6 ns 10.6 ns 65354399 +bm_std::function_calls____Method::set_string 10.5 ns 10.5 ns 65453839 + +bm_rtl::function_calls__Function::set_string 10.1 ns 10.1 ns 69712198 +bm_rtl::method_calls______Method::set_string 10.4 ns 10.4 ns 66905737 + +bm_rtl::function__ErasedReturnType::set_string 14.2 ns 14.2 ns 49078487 +bm_rtl::method____ErasedReturnType::set_string 13.8 ns 13.8 ns 50624940 +bm_rtl::method____ErasedTargetType::set_string 14.6 ns 14.6 ns 48083655 +bm_rtl::method____ErasedTargetAndReturnType::set_string 15.1 ns 15.1 ns 46102091 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 12.8 ns 12.8 ns 55815763 + +bm_call::via_function_ptr__Function::get_string 12.6 ns 12.6 ns 55774749 +bm_call::via_function_ptr____Method::get_string 12.6 ns 12.6 ns 56928113 + +bm_std::function_calls__Function::get_string 12.7 ns 12.7 ns 55895179 +bm_std::function_calls____Method::get_string 13.1 ns 13.1 ns 52615650 + +bm_rtl::function_calls__Function::get_string 12.1 ns 12.1 ns 57938812 +bm_rtl::method_calls______Method::get_string 12.5 ns 12.5 ns 55570876 + +bm_rtl::function__ErasedReturnType::get_string 30.1 ns 30.1 ns 23389099 +bm_rtl::method____ErasedReturnType::get_string 30.9 ns 30.9 ns 22546410 +bm_rtl::method____ErasedTargetType::get_string 25.3 ns 25.3 ns 27502524 +bm_rtl::method____ErasedTargetAndReturnType::get_string 32.2 ns 32.2 ns 21576033 +----------------------------------- +[2026-01-19 23:01:08] >>> Run 3: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T23:01:08+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.99, 0.76, 0.54 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 9.77 ns 9.76 ns 71887826 + +bm_call::via_function_ptr__Function::set_string 10.7 ns 10.7 ns 66604739 +bm_call::via_function_ptr____Method::set_string 10.8 ns 10.7 ns 65976848 + +bm_std::function_calls__Function::set_string 10.7 ns 10.7 ns 66028009 +bm_std::function_calls____Method::set_string 10.6 ns 10.6 ns 66566271 + +bm_rtl::function_calls__Function::set_string 10.2 ns 10.2 ns 69416123 +bm_rtl::method_calls______Method::set_string 10.5 ns 10.5 ns 67401327 + +bm_rtl::function__ErasedReturnType::set_string 14.1 ns 14.1 ns 49227860 +bm_rtl::method____ErasedReturnType::set_string 13.6 ns 13.6 ns 52058823 +bm_rtl::method____ErasedTargetType::set_string 14.9 ns 14.9 ns 47060682 +bm_rtl::method____ErasedTargetAndReturnType::set_string 15.1 ns 15.1 ns 46447515 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 12.8 ns 12.8 ns 54718500 + +bm_call::via_function_ptr__Function::get_string 12.6 ns 12.6 ns 55763290 +bm_call::via_function_ptr____Method::get_string 12.4 ns 12.4 ns 56477323 + +bm_std::function_calls__Function::get_string 12.6 ns 12.6 ns 55878651 +bm_std::function_calls____Method::get_string 13.2 ns 13.1 ns 54078767 + +bm_rtl::function_calls__Function::get_string 12.1 ns 12.1 ns 57732783 +bm_rtl::method_calls______Method::get_string 12.2 ns 12.2 ns 56825956 + +bm_rtl::function__ErasedReturnType::get_string 30.1 ns 30.1 ns 23149525 +bm_rtl::method____ErasedReturnType::get_string 30.8 ns 30.8 ns 22499692 +bm_rtl::method____ErasedTargetType::get_string 24.9 ns 24.9 ns 27926147 +bm_rtl::method____ErasedTargetAndReturnType::get_string 32.0 ns 32.0 ns 21748751 +----------------------------------- +[2026-01-19 23:01:27] >>> Run 4: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T23:01:27+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.99, 0.78, 0.55 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 9.79 ns 9.79 ns 71522140 + +bm_call::via_function_ptr__Function::set_string 10.6 ns 10.6 ns 66283611 +bm_call::via_function_ptr____Method::set_string 10.7 ns 10.7 ns 64284489 + +bm_std::function_calls__Function::set_string 10.7 ns 10.7 ns 66729049 +bm_std::function_calls____Method::set_string 10.5 ns 10.5 ns 65897765 + +bm_rtl::function_calls__Function::set_string 10.3 ns 10.3 ns 66838298 +bm_rtl::method_calls______Method::set_string 10.5 ns 10.5 ns 66750769 + +bm_rtl::function__ErasedReturnType::set_string 14.1 ns 14.1 ns 49234894 +bm_rtl::method____ErasedReturnType::set_string 13.6 ns 13.5 ns 51084203 +bm_rtl::method____ErasedTargetType::set_string 14.8 ns 14.8 ns 46993007 +bm_rtl::method____ErasedTargetAndReturnType::set_string 15.0 ns 15.0 ns 46202093 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 12.8 ns 12.8 ns 55437558 + +bm_call::via_function_ptr__Function::get_string 12.5 ns 12.5 ns 56136811 +bm_call::via_function_ptr____Method::get_string 12.3 ns 12.3 ns 56979768 + +bm_std::function_calls__Function::get_string 12.6 ns 12.6 ns 56259152 +bm_std::function_calls____Method::get_string 13.1 ns 13.1 ns 53971590 + +bm_rtl::function_calls__Function::get_string 12.1 ns 12.1 ns 57898696 +bm_rtl::method_calls______Method::get_string 12.4 ns 12.4 ns 56814167 + +bm_rtl::function__ErasedReturnType::get_string 30.0 ns 30.0 ns 23184768 +bm_rtl::method____ErasedReturnType::get_string 31.0 ns 31.0 ns 22508828 +bm_rtl::method____ErasedTargetType::get_string 24.9 ns 24.9 ns 27847260 +bm_rtl::method____ErasedTargetAndReturnType::get_string 31.8 ns 31.8 ns 21567547 +----------------------------------- +[2026-01-19 23:01:47] >>> Run 5: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T23:01:47+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.79, 0.56 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 9.71 ns 9.71 ns 71721418 + +bm_call::via_function_ptr__Function::set_string 10.5 ns 10.5 ns 66177847 +bm_call::via_function_ptr____Method::set_string 10.6 ns 10.6 ns 65397237 + +bm_std::function_calls__Function::set_string 10.7 ns 10.7 ns 65548379 +bm_std::function_calls____Method::set_string 10.5 ns 10.5 ns 66242899 + +bm_rtl::function_calls__Function::set_string 10.2 ns 10.2 ns 69346305 +bm_rtl::method_calls______Method::set_string 10.5 ns 10.5 ns 66803592 + +bm_rtl::function__ErasedReturnType::set_string 14.2 ns 14.2 ns 49742575 +bm_rtl::method____ErasedReturnType::set_string 13.5 ns 13.5 ns 51315601 +bm_rtl::method____ErasedTargetType::set_string 14.6 ns 14.6 ns 48287521 +bm_rtl::method____ErasedTargetAndReturnType::set_string 15.1 ns 15.1 ns 46820399 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 12.7 ns 12.7 ns 53727435 + +bm_call::via_function_ptr__Function::get_string 12.5 ns 12.5 ns 56306509 +bm_call::via_function_ptr____Method::get_string 12.5 ns 12.5 ns 55548656 + +bm_std::function_calls__Function::get_string 12.5 ns 12.5 ns 56331555 +bm_std::function_calls____Method::get_string 13.2 ns 13.2 ns 53912395 + +bm_rtl::function_calls__Function::get_string 12.1 ns 12.1 ns 57788395 +bm_rtl::method_calls______Method::get_string 12.4 ns 12.4 ns 55455755 + +bm_rtl::function__ErasedReturnType::get_string 29.9 ns 29.9 ns 23344757 +bm_rtl::method____ErasedReturnType::get_string 30.7 ns 30.7 ns 22917165 +bm_rtl::method____ErasedTargetType::get_string 24.7 ns 24.7 ns 28207240 +bm_rtl::method____ErasedTargetAndReturnType::get_string 31.5 ns 31.5 ns 21664753 +----------------------------------- +[2026-01-19 23:02:06] >>> Run 1: workload scale = 1 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 1 iterations +============================================= + +2026-01-19T23:02:06+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 822.243 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.81, 0.57 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 22.9 ns 22.9 ns 30455310 + +bm_call::via_function_ptr__Function::set_string 23.3 ns 23.3 ns 29973903 +bm_call::via_function_ptr____Method::set_string 24.4 ns 24.4 ns 28682167 + +bm_std::function_calls__Function::set_string 24.4 ns 24.4 ns 28786177 +bm_std::function_calls____Method::set_string 24.1 ns 24.1 ns 29498356 + +bm_rtl::function_calls__Function::set_string 23.5 ns 23.5 ns 29535454 +bm_rtl::method_calls______Method::set_string 24.1 ns 24.1 ns 28929366 + +bm_rtl::function__ErasedReturnType::set_string 27.7 ns 27.7 ns 25356353 +bm_rtl::method____ErasedReturnType::set_string 28.0 ns 28.0 ns 25219914 +bm_rtl::method____ErasedTargetType::set_string 28.7 ns 28.7 ns 24158357 +bm_rtl::method____ErasedTargetAndReturnType::set_string 29.2 ns 29.2 ns 24256140 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 45.3 ns 45.3 ns 15459028 + +bm_call::via_function_ptr__Function::get_string 44.7 ns 44.6 ns 15646357 +bm_call::via_function_ptr____Method::get_string 45.3 ns 45.3 ns 15492658 + +bm_std::function_calls__Function::get_string 45.6 ns 45.6 ns 15370690 +bm_std::function_calls____Method::get_string 46.9 ns 46.9 ns 14968996 + +bm_rtl::function_calls__Function::get_string 45.2 ns 45.2 ns 15494849 +bm_rtl::method_calls______Method::get_string 45.7 ns 45.7 ns 15233822 + +bm_rtl::function__ErasedReturnType::get_string 59.8 ns 59.8 ns 11773379 +bm_rtl::method____ErasedReturnType::get_string 61.2 ns 61.2 ns 11420534 +bm_rtl::method____ErasedTargetType::get_string 51.6 ns 51.6 ns 13552861 +bm_rtl::method____ErasedTargetAndReturnType::get_string 61.9 ns 61.9 ns 11233344 +----------------------------------- +[2026-01-19 23:02:28] >>> Run 2: workload scale = 1 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 1 iterations +============================================= + +2026-01-19T23:02:28+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.82, 0.58 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 22.9 ns 22.9 ns 30573465 + +bm_call::via_function_ptr__Function::set_string 23.3 ns 23.3 ns 30164807 +bm_call::via_function_ptr____Method::set_string 24.3 ns 24.3 ns 28476945 + +bm_std::function_calls__Function::set_string 24.4 ns 24.4 ns 28790697 +bm_std::function_calls____Method::set_string 23.9 ns 23.9 ns 29364194 + +bm_rtl::function_calls__Function::set_string 23.7 ns 23.7 ns 29697609 +bm_rtl::method_calls______Method::set_string 24.2 ns 24.2 ns 29116922 + +bm_rtl::function__ErasedReturnType::set_string 27.7 ns 27.7 ns 25144828 +bm_rtl::method____ErasedReturnType::set_string 27.7 ns 27.7 ns 25387533 +bm_rtl::method____ErasedTargetType::set_string 28.5 ns 28.5 ns 24641155 +bm_rtl::method____ErasedTargetAndReturnType::set_string 28.8 ns 28.8 ns 24383208 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 45.0 ns 45.0 ns 15538373 + +bm_call::via_function_ptr__Function::get_string 44.7 ns 44.7 ns 15574842 +bm_call::via_function_ptr____Method::get_string 45.1 ns 45.1 ns 15547513 + +bm_std::function_calls__Function::get_string 45.3 ns 45.3 ns 15505394 +bm_std::function_calls____Method::get_string 45.9 ns 45.9 ns 15301532 + +bm_rtl::function_calls__Function::get_string 45.6 ns 45.6 ns 15359388 +bm_rtl::method_calls______Method::get_string 45.1 ns 45.1 ns 15555156 + +bm_rtl::function__ErasedReturnType::get_string 60.2 ns 60.2 ns 11620355 +bm_rtl::method____ErasedReturnType::get_string 61.8 ns 61.8 ns 11321576 +bm_rtl::method____ErasedTargetType::get_string 51.9 ns 51.9 ns 13385317 +bm_rtl::method____ErasedTargetAndReturnType::get_string 62.2 ns 62.2 ns 11353544 +----------------------------------- +[2026-01-19 23:02:50] >>> Run 3: workload scale = 1 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 1 iterations +============================================= + +2026-01-19T23:02:50+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.83, 0.59 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 22.9 ns 22.9 ns 30171191 + +bm_call::via_function_ptr__Function::set_string 23.3 ns 23.3 ns 30353005 +bm_call::via_function_ptr____Method::set_string 24.1 ns 24.1 ns 28744923 + +bm_std::function_calls__Function::set_string 24.3 ns 24.3 ns 28783840 +bm_std::function_calls____Method::set_string 23.9 ns 23.9 ns 29180247 + +bm_rtl::function_calls__Function::set_string 23.5 ns 23.5 ns 29891004 +bm_rtl::method_calls______Method::set_string 23.9 ns 23.9 ns 28932461 + +bm_rtl::function__ErasedReturnType::set_string 27.7 ns 27.7 ns 25245560 +bm_rtl::method____ErasedReturnType::set_string 27.6 ns 27.6 ns 24913705 +bm_rtl::method____ErasedTargetType::set_string 28.9 ns 28.9 ns 24395606 +bm_rtl::method____ErasedTargetAndReturnType::set_string 28.9 ns 28.9 ns 23972582 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 46.3 ns 46.3 ns 15148491 + +bm_call::via_function_ptr__Function::get_string 45.8 ns 45.8 ns 15294280 +bm_call::via_function_ptr____Method::get_string 46.0 ns 46.0 ns 15228762 + +bm_std::function_calls__Function::get_string 47.0 ns 47.0 ns 14879735 +bm_std::function_calls____Method::get_string 47.1 ns 47.1 ns 14831304 + +bm_rtl::function_calls__Function::get_string 46.6 ns 46.6 ns 15034283 +bm_rtl::method_calls______Method::get_string 46.6 ns 46.6 ns 15014229 + +bm_rtl::function__ErasedReturnType::get_string 60.7 ns 60.7 ns 11616969 +bm_rtl::method____ErasedReturnType::get_string 62.3 ns 62.3 ns 11216128 +bm_rtl::method____ErasedTargetType::get_string 52.1 ns 52.1 ns 13440738 +bm_rtl::method____ErasedTargetAndReturnType::get_string 63.0 ns 62.9 ns 11210745 +----------------------------------- +[2026-01-19 23:03:13] >>> Run 1: workload scale = 5 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 5 iterations +============================================= + +2026-01-19T23:03:13+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.85, 0.60 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 114 ns 114 ns 6150689 + +bm_call::via_function_ptr__Function::set_string 115 ns 115 ns 6120408 +bm_call::via_function_ptr____Method::set_string 114 ns 114 ns 6096091 + +bm_std::function_calls__Function::set_string 115 ns 115 ns 6153189 +bm_std::function_calls____Method::set_string 114 ns 114 ns 6142978 + +bm_rtl::function_calls__Function::set_string 114 ns 114 ns 6186381 +bm_rtl::method_calls______Method::set_string 114 ns 114 ns 6147215 + +bm_rtl::function__ErasedReturnType::set_string 117 ns 117 ns 6004976 +bm_rtl::method____ErasedReturnType::set_string 116 ns 116 ns 6002059 +bm_rtl::method____ErasedTargetType::set_string 118 ns 118 ns 5952044 +bm_rtl::method____ErasedTargetAndReturnType::set_string 118 ns 118 ns 5904788 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 185 ns 185 ns 3776514 + +bm_call::via_function_ptr__Function::get_string 185 ns 185 ns 3774660 +bm_call::via_function_ptr____Method::get_string 191 ns 191 ns 3675448 + +bm_std::function_calls__Function::get_string 186 ns 186 ns 3765692 +bm_std::function_calls____Method::get_string 189 ns 189 ns 3699608 + +bm_rtl::function_calls__Function::get_string 185 ns 185 ns 3767600 +bm_rtl::method_calls______Method::get_string 188 ns 188 ns 3713718 + +bm_rtl::function__ErasedReturnType::get_string 200 ns 200 ns 3517235 +bm_rtl::method____ErasedReturnType::get_string 201 ns 201 ns 3490550 +bm_rtl::method____ErasedTargetType::get_string 194 ns 194 ns 3621561 +bm_rtl::method____ErasedTargetAndReturnType::get_string 201 ns 201 ns 3473829 +----------------------------------- +[2026-01-19 23:03:32] >>> Run 2: workload scale = 5 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 5 iterations +============================================= + +2026-01-19T23:03:32+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.86, 0.61 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 115 ns 115 ns 6101534 + +bm_call::via_function_ptr__Function::set_string 114 ns 114 ns 6087851 +bm_call::via_function_ptr____Method::set_string 114 ns 114 ns 6121086 + +bm_std::function_calls__Function::set_string 115 ns 115 ns 6129096 +bm_std::function_calls____Method::set_string 115 ns 115 ns 6110410 + +bm_rtl::function_calls__Function::set_string 114 ns 114 ns 6138724 +bm_rtl::method_calls______Method::set_string 114 ns 114 ns 6128080 + +bm_rtl::function__ErasedReturnType::set_string 121 ns 121 ns 5790978 +bm_rtl::method____ErasedReturnType::set_string 121 ns 121 ns 5753753 +bm_rtl::method____ErasedTargetType::set_string 123 ns 123 ns 5694073 +bm_rtl::method____ErasedTargetAndReturnType::set_string 121 ns 121 ns 5768724 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 211 ns 211 ns 3322602 + +bm_call::via_function_ptr__Function::get_string 212 ns 212 ns 3302320 +bm_call::via_function_ptr____Method::get_string 214 ns 214 ns 3267708 + +bm_std::function_calls__Function::get_string 212 ns 212 ns 3300344 +bm_std::function_calls____Method::get_string 213 ns 213 ns 3296294 + +bm_rtl::function_calls__Function::get_string 211 ns 211 ns 3312103 +bm_rtl::method_calls______Method::get_string 212 ns 212 ns 3289616 + +bm_rtl::function__ErasedReturnType::get_string 224 ns 224 ns 3138855 +bm_rtl::method____ErasedReturnType::get_string 224 ns 224 ns 3109100 +bm_rtl::method____ErasedTargetType::get_string 220 ns 220 ns 3186412 +bm_rtl::method____ErasedTargetAndReturnType::get_string 224 ns 224 ns 3125628 +----------------------------------- +[2026-01-19 23:03:51] >>> Run 3: workload scale = 5 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 5 iterations +============================================= + +2026-01-19T23:03:51+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.87, 0.62 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 114 ns 114 ns 6132649 + +bm_call::via_function_ptr__Function::set_string 114 ns 114 ns 6142191 +bm_call::via_function_ptr____Method::set_string 114 ns 114 ns 6141152 + +bm_std::function_calls__Function::set_string 115 ns 115 ns 6068904 +bm_std::function_calls____Method::set_string 115 ns 115 ns 6098069 + +bm_rtl::function_calls__Function::set_string 113 ns 113 ns 6166440 +bm_rtl::method_calls______Method::set_string 114 ns 114 ns 6132392 + +bm_rtl::function__ErasedReturnType::set_string 117 ns 117 ns 5984139 +bm_rtl::method____ErasedReturnType::set_string 117 ns 117 ns 6008851 +bm_rtl::method____ErasedTargetType::set_string 118 ns 118 ns 5935050 +bm_rtl::method____ErasedTargetAndReturnType::set_string 119 ns 119 ns 5906698 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 214 ns 214 ns 3274422 + +bm_call::via_function_ptr__Function::get_string 214 ns 214 ns 3221626 +bm_call::via_function_ptr____Method::get_string 217 ns 217 ns 3219416 + +bm_std::function_calls__Function::get_string 215 ns 215 ns 3258831 +bm_std::function_calls____Method::get_string 216 ns 215 ns 3248424 + +bm_rtl::function_calls__Function::get_string 215 ns 215 ns 3128220 +bm_rtl::method_calls______Method::get_string 215 ns 215 ns 3238895 + +bm_rtl::function__ErasedReturnType::get_string 225 ns 225 ns 3133131 +bm_rtl::method____ErasedReturnType::get_string 225 ns 225 ns 3107999 +bm_rtl::method____ErasedTargetType::get_string 222 ns 222 ns 3153094 +bm_rtl::method____ErasedTargetAndReturnType::get_string 225 ns 225 ns 3109784 +----------------------------------- +[2026-01-19 23:04:11] >>> Run 1: workload scale = 10 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 10 iterations +============================================= + +2026-01-19T23:04:11+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800.325 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.88, 0.63 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 184 ns 184 ns 3777733 + +bm_call::via_function_ptr__Function::set_string 184 ns 184 ns 3785782 +bm_call::via_function_ptr____Method::set_string 184 ns 184 ns 3807719 + +bm_std::function_calls__Function::set_string 184 ns 184 ns 3814668 +bm_std::function_calls____Method::set_string 184 ns 184 ns 3809985 + +bm_rtl::function_calls__Function::set_string 184 ns 184 ns 3817093 +bm_rtl::method_calls______Method::set_string 184 ns 184 ns 3818075 + +bm_rtl::function__ErasedReturnType::set_string 189 ns 189 ns 3698101 +bm_rtl::method____ErasedReturnType::set_string 188 ns 188 ns 3734841 +bm_rtl::method____ErasedTargetType::set_string 189 ns 189 ns 3697316 +bm_rtl::method____ErasedTargetAndReturnType::set_string 188 ns 188 ns 3720922 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 299 ns 299 ns 2330036 + +bm_call::via_function_ptr__Function::get_string 298 ns 298 ns 2348216 +bm_call::via_function_ptr____Method::get_string 298 ns 298 ns 2337354 + +bm_std::function_calls__Function::get_string 299 ns 299 ns 2334440 +bm_std::function_calls____Method::get_string 299 ns 299 ns 2335303 + +bm_rtl::function_calls__Function::get_string 297 ns 297 ns 2353177 +bm_rtl::method_calls______Method::get_string 299 ns 299 ns 2342282 + +bm_rtl::function__ErasedReturnType::get_string 311 ns 311 ns 2252004 +bm_rtl::method____ErasedReturnType::get_string 313 ns 313 ns 2236406 +bm_rtl::method____ErasedTargetType::get_string 305 ns 305 ns 2299083 +bm_rtl::method____ErasedTargetAndReturnType::get_string 312 ns 312 ns 2244346 +----------------------------------- +[2026-01-19 23:04:32] >>> Run 2: workload scale = 10 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 10 iterations +============================================= + +2026-01-19T23:04:32+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 4758.38 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.89, 0.64 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 184 ns 184 ns 3819930 + +bm_call::via_function_ptr__Function::set_string 177 ns 177 ns 3948053 +bm_call::via_function_ptr____Method::set_string 177 ns 177 ns 3922201 + +bm_std::function_calls__Function::set_string 178 ns 178 ns 3939696 +bm_std::function_calls____Method::set_string 178 ns 178 ns 3950022 + +bm_rtl::function_calls__Function::set_string 177 ns 177 ns 3928694 +bm_rtl::method_calls______Method::set_string 178 ns 177 ns 3953717 + +bm_rtl::function__ErasedReturnType::set_string 180 ns 180 ns 3888139 +bm_rtl::method____ErasedReturnType::set_string 180 ns 180 ns 3885087 +bm_rtl::method____ErasedTargetType::set_string 183 ns 183 ns 3845699 +bm_rtl::method____ErasedTargetAndReturnType::set_string 181 ns 181 ns 3875406 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 294 ns 294 ns 2384603 + +bm_call::via_function_ptr__Function::get_string 293 ns 293 ns 2393415 +bm_call::via_function_ptr____Method::get_string 293 ns 293 ns 2391860 + +bm_std::function_calls__Function::get_string 294 ns 294 ns 2382741 +bm_std::function_calls____Method::get_string 293 ns 293 ns 2385674 + +bm_rtl::function_calls__Function::get_string 292 ns 292 ns 2397954 +bm_rtl::method_calls______Method::get_string 293 ns 293 ns 2395882 + +bm_rtl::function__ErasedReturnType::get_string 307 ns 307 ns 2281723 +bm_rtl::method____ErasedReturnType::get_string 309 ns 309 ns 2272152 +bm_rtl::method____ErasedTargetType::get_string 299 ns 299 ns 2340064 +bm_rtl::method____ErasedTargetAndReturnType::get_string 307 ns 307 ns 2281982 +----------------------------------- +[2026-01-19 23:04:53] >>> Run 3: workload scale = 10 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 10 iterations +============================================= + +2026-01-19T23:04:53+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.11, 0.93, 0.66 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 183 ns 183 ns 3824216 + +bm_call::via_function_ptr__Function::set_string 178 ns 178 ns 3959660 +bm_call::via_function_ptr____Method::set_string 177 ns 177 ns 3948511 + +bm_std::function_calls__Function::set_string 177 ns 177 ns 3967769 +bm_std::function_calls____Method::set_string 179 ns 179 ns 3900356 + +bm_rtl::function_calls__Function::set_string 178 ns 178 ns 3918698 +bm_rtl::method_calls______Method::set_string 179 ns 179 ns 3899680 + +bm_rtl::function__ErasedReturnType::set_string 181 ns 181 ns 3851517 +bm_rtl::method____ErasedReturnType::set_string 180 ns 180 ns 3878815 +bm_rtl::method____ErasedTargetType::set_string 181 ns 181 ns 3889425 +bm_rtl::method____ErasedTargetAndReturnType::set_string 181 ns 181 ns 3881658 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 296 ns 296 ns 2366399 + +bm_call::via_function_ptr__Function::get_string 295 ns 295 ns 2374439 +bm_call::via_function_ptr____Method::get_string 294 ns 294 ns 2384224 + +bm_std::function_calls__Function::get_string 295 ns 295 ns 2364076 +bm_std::function_calls____Method::get_string 294 ns 294 ns 2370526 + +bm_rtl::function_calls__Function::get_string 294 ns 294 ns 2385620 +bm_rtl::method_calls______Method::get_string 293 ns 293 ns 2389281 + +bm_rtl::function__ErasedReturnType::get_string 307 ns 307 ns 2278302 +bm_rtl::method____ErasedReturnType::get_string 308 ns 308 ns 2271193 +bm_rtl::method____ErasedTargetType::get_string 299 ns 299 ns 2343702 +bm_rtl::method____ErasedTargetAndReturnType::get_string 306 ns 306 ns 2283153 +----------------------------------- +[2026-01-19 23:05:15] >>> Run 1: workload scale = 15 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 15 iterations +============================================= + +2026-01-19T23:05:15+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.08, 0.93, 0.67 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 226 ns 226 ns 3089610 + +bm_call::via_function_ptr__Function::set_string 222 ns 222 ns 3153870 +bm_call::via_function_ptr____Method::set_string 221 ns 221 ns 3175215 + +bm_std::function_calls__Function::set_string 223 ns 223 ns 3117008 +bm_std::function_calls____Method::set_string 220 ns 220 ns 3173515 + +bm_rtl::function_calls__Function::set_string 220 ns 220 ns 3194400 +bm_rtl::method_calls______Method::set_string 220 ns 220 ns 3140247 + +bm_rtl::function__ErasedReturnType::set_string 222 ns 222 ns 3147549 +bm_rtl::method____ErasedReturnType::set_string 225 ns 225 ns 3142824 +bm_rtl::method____ErasedTargetType::set_string 224 ns 224 ns 3124349 +bm_rtl::method____ErasedTargetAndReturnType::set_string 222 ns 222 ns 3152685 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 409 ns 409 ns 1709662 + +bm_call::via_function_ptr__Function::get_string 408 ns 408 ns 1719343 +bm_call::via_function_ptr____Method::get_string 408 ns 408 ns 1714648 + +bm_std::function_calls__Function::get_string 409 ns 409 ns 1709610 +bm_std::function_calls____Method::get_string 410 ns 410 ns 1708052 + +bm_rtl::function_calls__Function::get_string 407 ns 407 ns 1684885 +bm_rtl::method_calls______Method::get_string 407 ns 407 ns 1716993 + +bm_rtl::function__ErasedReturnType::get_string 420 ns 420 ns 1665371 +bm_rtl::method____ErasedReturnType::get_string 420 ns 420 ns 1663095 +bm_rtl::method____ErasedTargetType::get_string 416 ns 416 ns 1683688 +bm_rtl::method____ErasedTargetAndReturnType::get_string 422 ns 422 ns 1657701 +----------------------------------- +[2026-01-19 23:05:38] >>> Run 2: workload scale = 15 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 15 iterations +============================================= + +2026-01-19T23:05:38+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.05, 0.94, 0.67 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 215 ns 215 ns 3251791 + +bm_call::via_function_ptr__Function::set_string 215 ns 215 ns 3250360 +bm_call::via_function_ptr____Method::set_string 216 ns 216 ns 3245971 + +bm_std::function_calls__Function::set_string 215 ns 215 ns 3263158 +bm_std::function_calls____Method::set_string 216 ns 216 ns 3214634 + +bm_rtl::function_calls__Function::set_string 217 ns 217 ns 3235199 +bm_rtl::method_calls______Method::set_string 216 ns 216 ns 3255549 + +bm_rtl::function__ErasedReturnType::set_string 219 ns 219 ns 3205308 +bm_rtl::method____ErasedReturnType::set_string 217 ns 217 ns 3223213 +bm_rtl::method____ErasedTargetType::set_string 218 ns 218 ns 3198103 +bm_rtl::method____ErasedTargetAndReturnType::set_string 219 ns 219 ns 3208427 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 389 ns 389 ns 1801150 + +bm_call::via_function_ptr__Function::get_string 367 ns 367 ns 1906149 +bm_call::via_function_ptr____Method::get_string 366 ns 366 ns 1911347 + +bm_std::function_calls__Function::get_string 367 ns 367 ns 1907044 +bm_std::function_calls____Method::get_string 368 ns 368 ns 1906042 + +bm_rtl::function_calls__Function::get_string 365 ns 365 ns 1917571 +bm_rtl::method_calls______Method::get_string 366 ns 366 ns 1913051 + +bm_rtl::function__ErasedReturnType::get_string 379 ns 379 ns 1842696 +bm_rtl::method____ErasedReturnType::get_string 380 ns 380 ns 1841381 +bm_rtl::method____ErasedTargetType::get_string 372 ns 372 ns 1878324 +bm_rtl::method____ErasedTargetAndReturnType::get_string 381 ns 381 ns 1818358 +----------------------------------- +[2026-01-19 23:06:00] >>> Run 3: workload scale = 15 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 15 iterations +============================================= + +2026-01-19T23:06:00+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.04, 0.95, 0.68 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 215 ns 215 ns 3253799 + +bm_call::via_function_ptr__Function::set_string 216 ns 216 ns 3249440 +bm_call::via_function_ptr____Method::set_string 217 ns 217 ns 3227746 + +bm_std::function_calls__Function::set_string 213 ns 213 ns 3296572 +bm_std::function_calls____Method::set_string 213 ns 213 ns 3277342 + +bm_rtl::function_calls__Function::set_string 213 ns 213 ns 3280935 +bm_rtl::method_calls______Method::set_string 214 ns 214 ns 3268047 + +bm_rtl::function__ErasedReturnType::set_string 216 ns 216 ns 3252538 +bm_rtl::method____ErasedReturnType::set_string 228 ns 228 ns 3254612 +bm_rtl::method____ErasedTargetType::set_string 230 ns 230 ns 3064649 +bm_rtl::method____ErasedTargetAndReturnType::set_string 230 ns 230 ns 3026544 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 418 ns 418 ns 1679672 + +bm_call::via_function_ptr__Function::get_string 413 ns 413 ns 1674254 +bm_call::via_function_ptr____Method::get_string 413 ns 413 ns 1696505 + +bm_std::function_calls__Function::get_string 416 ns 416 ns 1684761 +bm_std::function_calls____Method::get_string 416 ns 416 ns 1682074 + +bm_rtl::function_calls__Function::get_string 412 ns 412 ns 1697759 +bm_rtl::method_calls______Method::get_string 412 ns 412 ns 1692481 + +bm_rtl::function__ErasedReturnType::get_string 424 ns 424 ns 1652039 +bm_rtl::method____ErasedReturnType::get_string 424 ns 424 ns 1649284 +bm_rtl::method____ErasedTargetType::get_string 419 ns 419 ns 1667856 +bm_rtl::method____ErasedTargetAndReturnType::get_string 424 ns 424 ns 1650836 +----------------------------------- +[2026-01-19 23:06:24] >>> Run 1: workload scale = 20 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 20 iterations +============================================= + +2026-01-19T23:06:24+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 4849.08 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.02, 0.95, 0.69 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 291 ns 291 ns 2418278 + +bm_call::via_function_ptr__Function::set_string 292 ns 292 ns 2424822 +bm_call::via_function_ptr____Method::set_string 286 ns 286 ns 2402039 + +bm_std::function_calls__Function::set_string 287 ns 287 ns 2465734 +bm_std::function_calls____Method::set_string 291 ns 291 ns 2441376 + +bm_rtl::function_calls__Function::set_string 311 ns 311 ns 2236358 +bm_rtl::method_calls______Method::set_string 311 ns 311 ns 2265730 + +bm_rtl::function__ErasedReturnType::set_string 311 ns 311 ns 2245428 +bm_rtl::method____ErasedReturnType::set_string 308 ns 308 ns 2264057 +bm_rtl::method____ErasedTargetType::set_string 311 ns 310 ns 2257890 +bm_rtl::method____ErasedTargetAndReturnType::set_string 311 ns 311 ns 2244261 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 590 ns 590 ns 1182058 + +bm_call::via_function_ptr__Function::get_string 590 ns 590 ns 1185424 +bm_call::via_function_ptr____Method::get_string 590 ns 590 ns 1185900 + +bm_std::function_calls__Function::get_string 593 ns 593 ns 1177543 +bm_std::function_calls____Method::get_string 596 ns 596 ns 1179929 + +bm_rtl::function_calls__Function::get_string 589 ns 589 ns 1182819 +bm_rtl::method_calls______Method::get_string 589 ns 589 ns 1187964 + +bm_rtl::function__ErasedReturnType::get_string 606 ns 606 ns 1157909 +bm_rtl::method____ErasedReturnType::get_string 607 ns 607 ns 1159297 +bm_rtl::method____ErasedTargetType::get_string 600 ns 600 ns 1160673 +bm_rtl::method____ErasedTargetAndReturnType::get_string 608 ns 608 ns 1153514 +----------------------------------- +[2026-01-19 23:06:43] >>> Run 2: workload scale = 20 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 20 iterations +============================================= + +2026-01-19T23:06:43+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.02, 0.95, 0.70 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 283 ns 283 ns 2496763 + +bm_call::via_function_ptr__Function::set_string 284 ns 284 ns 2467014 +bm_call::via_function_ptr____Method::set_string 282 ns 282 ns 2495436 + +bm_std::function_calls__Function::set_string 286 ns 286 ns 2441347 +bm_std::function_calls____Method::set_string 280 ns 280 ns 2487991 + +bm_rtl::function_calls__Function::set_string 283 ns 283 ns 2469977 +bm_rtl::method_calls______Method::set_string 284 ns 284 ns 2497314 + +bm_rtl::function__ErasedReturnType::set_string 281 ns 281 ns 2483595 +bm_rtl::method____ErasedReturnType::set_string 285 ns 285 ns 2441698 +bm_rtl::method____ErasedTargetType::set_string 285 ns 285 ns 2457468 +bm_rtl::method____ErasedTargetAndReturnType::set_string 284 ns 284 ns 2472081 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 513 ns 513 ns 1363089 + +bm_call::via_function_ptr__Function::get_string 513 ns 513 ns 1359811 +bm_call::via_function_ptr____Method::get_string 515 ns 515 ns 1353957 + +bm_std::function_calls__Function::get_string 522 ns 522 ns 1339690 +bm_std::function_calls____Method::get_string 516 ns 516 ns 1344580 + +bm_rtl::function_calls__Function::get_string 513 ns 513 ns 1367161 +bm_rtl::method_calls______Method::get_string 513 ns 513 ns 1369286 + +bm_rtl::function__ErasedReturnType::get_string 530 ns 530 ns 1302691 +bm_rtl::method____ErasedReturnType::get_string 539 ns 539 ns 1297240 +bm_rtl::method____ErasedTargetType::get_string 534 ns 534 ns 1314364 +bm_rtl::method____ErasedTargetAndReturnType::get_string 541 ns 541 ns 1294039 +----------------------------------- +[2026-01-19 23:07:03] >>> Run 3: workload scale = 20 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 20 iterations +============================================= + +2026-01-19T23:07:03+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.01, 0.96, 0.71 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 280 ns 280 ns 2516712 + +bm_call::via_function_ptr__Function::set_string 281 ns 281 ns 2482011 +bm_call::via_function_ptr____Method::set_string 279 ns 279 ns 2503584 + +bm_std::function_calls__Function::set_string 281 ns 281 ns 2480554 +bm_std::function_calls____Method::set_string 281 ns 281 ns 2518718 + +bm_rtl::function_calls__Function::set_string 281 ns 281 ns 2502456 +bm_rtl::method_calls______Method::set_string 281 ns 281 ns 2500633 + +bm_rtl::function__ErasedReturnType::set_string 284 ns 283 ns 2477449 +bm_rtl::method____ErasedReturnType::set_string 281 ns 281 ns 2487763 +bm_rtl::method____ErasedTargetType::set_string 289 ns 289 ns 2443654 +bm_rtl::method____ErasedTargetAndReturnType::set_string 283 ns 283 ns 2474642 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 512 ns 512 ns 1370543 + +bm_call::via_function_ptr__Function::get_string 512 ns 511 ns 1372544 +bm_call::via_function_ptr____Method::get_string 512 ns 512 ns 1356469 + +bm_std::function_calls__Function::get_string 513 ns 513 ns 1363349 +bm_std::function_calls____Method::get_string 514 ns 514 ns 1365830 + +bm_rtl::function_calls__Function::get_string 512 ns 512 ns 1370684 +bm_rtl::method_calls______Method::get_string 511 ns 511 ns 1372313 + +bm_rtl::function__ErasedReturnType::get_string 527 ns 527 ns 1327641 +bm_rtl::method____ErasedReturnType::get_string 527 ns 527 ns 1313459 +bm_rtl::method____ErasedTargetType::get_string 525 ns 525 ns 1335873 +bm_rtl::method____ErasedTargetAndReturnType::get_string 530 ns 530 ns 1321480 +----------------------------------- +[2026-01-19 23:07:22] >>> Run 1: workload scale = 25 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 25 iterations +============================================= + +2026-01-19T23:07:22+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.01, 0.96, 0.72 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 352 ns 352 ns 1986306 + +bm_call::via_function_ptr__Function::set_string 355 ns 354 ns 1970032 +bm_call::via_function_ptr____Method::set_string 355 ns 355 ns 1975489 + +bm_std::function_calls__Function::set_string 362 ns 362 ns 1947671 +bm_std::function_calls____Method::set_string 348 ns 348 ns 2015214 + +bm_rtl::function_calls__Function::set_string 356 ns 356 ns 1960779 +bm_rtl::method_calls______Method::set_string 356 ns 356 ns 1970573 + +bm_rtl::function__ErasedReturnType::set_string 355 ns 355 ns 1967083 +bm_rtl::method____ErasedReturnType::set_string 363 ns 363 ns 1931290 +bm_rtl::method____ErasedTargetType::set_string 357 ns 357 ns 1956980 +bm_rtl::method____ErasedTargetAndReturnType::set_string 357 ns 357 ns 1961696 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 741 ns 741 ns 946428 + +bm_call::via_function_ptr__Function::get_string 744 ns 744 ns 939247 +bm_call::via_function_ptr____Method::get_string 749 ns 748 ns 934680 + +bm_std::function_calls__Function::get_string 761 ns 761 ns 920792 +bm_std::function_calls____Method::get_string 752 ns 752 ns 931714 + +bm_rtl::function_calls__Function::get_string 745 ns 745 ns 931761 +bm_rtl::method_calls______Method::get_string 745 ns 745 ns 936980 + +bm_rtl::function__ErasedReturnType::get_string 765 ns 765 ns 915979 +bm_rtl::method____ErasedReturnType::get_string 776 ns 776 ns 902448 +bm_rtl::method____ErasedTargetType::get_string 768 ns 768 ns 910555 +bm_rtl::method____ErasedTargetAndReturnType::get_string 781 ns 781 ns 895862 +----------------------------------- +[2026-01-19 23:07:43] >>> Run 2: workload scale = 25 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 25 iterations +============================================= + +2026-01-19T23:07:43+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.97, 0.72 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 352 ns 352 ns 1982071 + +bm_call::via_function_ptr__Function::set_string 355 ns 355 ns 1970296 +bm_call::via_function_ptr____Method::set_string 356 ns 356 ns 1963515 + +bm_std::function_calls__Function::set_string 342 ns 342 ns 2044461 +bm_std::function_calls____Method::set_string 344 ns 344 ns 2043629 + +bm_rtl::function_calls__Function::set_string 345 ns 345 ns 2032898 +bm_rtl::method_calls______Method::set_string 345 ns 345 ns 2030104 + +bm_rtl::function__ErasedReturnType::set_string 347 ns 347 ns 2003550 +bm_rtl::method____ErasedReturnType::set_string 347 ns 347 ns 2018317 +bm_rtl::method____ErasedTargetType::set_string 348 ns 348 ns 2001122 +bm_rtl::method____ErasedTargetAndReturnType::set_string 357 ns 357 ns 1968473 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 735 ns 735 ns 949993 + +bm_call::via_function_ptr__Function::get_string 737 ns 737 ns 948580 +bm_call::via_function_ptr____Method::get_string 743 ns 743 ns 940417 + +bm_std::function_calls__Function::get_string 742 ns 742 ns 942789 +bm_std::function_calls____Method::get_string 759 ns 759 ns 924306 + +bm_rtl::function_calls__Function::get_string 739 ns 739 ns 948214 +bm_rtl::method_calls______Method::get_string 739 ns 739 ns 947757 + +bm_rtl::function__ErasedReturnType::get_string 763 ns 763 ns 912115 +bm_rtl::method____ErasedReturnType::get_string 763 ns 763 ns 917643 +bm_rtl::method____ErasedTargetType::get_string 761 ns 761 ns 920593 +bm_rtl::method____ErasedTargetAndReturnType::get_string 767 ns 767 ns 913033 +----------------------------------- +[2026-01-19 23:08:04] >>> Run 3: workload scale = 25 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 25 iterations +============================================= + +2026-01-19T23:08:04+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 4239.17 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.97, 0.73 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 318 ns 318 ns 2209791 + +bm_call::via_function_ptr__Function::set_string 320 ns 320 ns 2194462 +bm_call::via_function_ptr____Method::set_string 318 ns 318 ns 2200705 + +bm_std::function_calls__Function::set_string 330 ns 330 ns 2105129 +bm_std::function_calls____Method::set_string 317 ns 317 ns 2214509 + +bm_rtl::function_calls__Function::set_string 320 ns 320 ns 2196336 +bm_rtl::method_calls______Method::set_string 319 ns 319 ns 2193113 + +bm_rtl::function__ErasedReturnType::set_string 326 ns 326 ns 2153096 +bm_rtl::method____ErasedReturnType::set_string 334 ns 334 ns 2109094 +bm_rtl::method____ErasedTargetType::set_string 327 ns 327 ns 2126213 +bm_rtl::method____ErasedTargetAndReturnType::set_string 329 ns 329 ns 2135549 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 676 ns 676 ns 1033968 + +bm_call::via_function_ptr__Function::get_string 684 ns 684 ns 1024490 +bm_call::via_function_ptr____Method::get_string 699 ns 699 ns 1001694 + +bm_std::function_calls__Function::get_string 696 ns 696 ns 1007881 +bm_std::function_calls____Method::get_string 686 ns 686 ns 1022139 + +bm_rtl::function_calls__Function::get_string 682 ns 681 ns 1029656 +bm_rtl::method_calls______Method::get_string 680 ns 680 ns 1029375 + +bm_rtl::function__ErasedReturnType::get_string 691 ns 691 ns 1004599 +bm_rtl::method____ErasedReturnType::get_string 711 ns 711 ns 984643 +bm_rtl::method____ErasedTargetType::get_string 716 ns 715 ns 978554 +bm_rtl::method____ErasedTargetAndReturnType::get_string 715 ns 715 ns 978719 +----------------------------------- +[2026-01-19 23:08:24] >>> Run 1: workload scale = 30 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 30 iterations +============================================= + +2026-01-19T23:08:24+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 2476.53 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.97, 0.74 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 396 ns 396 ns 1770525 + +bm_call::via_function_ptr__Function::set_string 394 ns 394 ns 1782096 +bm_call::via_function_ptr____Method::set_string 395 ns 395 ns 1773848 + +bm_std::function_calls__Function::set_string 400 ns 399 ns 1754344 +bm_std::function_calls____Method::set_string 401 ns 401 ns 1730094 + +bm_rtl::function_calls__Function::set_string 401 ns 401 ns 1739081 +bm_rtl::method_calls______Method::set_string 401 ns 401 ns 1745860 + +bm_rtl::function__ErasedReturnType::set_string 403 ns 403 ns 1745498 +bm_rtl::method____ErasedReturnType::set_string 394 ns 394 ns 1778868 +bm_rtl::method____ErasedTargetType::set_string 398 ns 398 ns 1764951 +bm_rtl::method____ErasedTargetAndReturnType::set_string 395 ns 395 ns 1776625 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 928 ns 928 ns 754696 + +bm_call::via_function_ptr__Function::get_string 929 ns 929 ns 753468 +bm_call::via_function_ptr____Method::get_string 928 ns 928 ns 754762 + +bm_std::function_calls__Function::get_string 933 ns 933 ns 742321 +bm_std::function_calls____Method::get_string 932 ns 932 ns 751071 + +bm_rtl::function_calls__Function::get_string 931 ns 930 ns 753258 +bm_rtl::method_calls______Method::get_string 928 ns 928 ns 753388 + +bm_rtl::function__ErasedReturnType::get_string 966 ns 966 ns 724498 +bm_rtl::method____ErasedReturnType::get_string 947 ns 946 ns 732009 +bm_rtl::method____ErasedTargetType::get_string 952 ns 952 ns 735704 +bm_rtl::method____ErasedTargetAndReturnType::get_string 950 ns 950 ns 736736 +----------------------------------- +[2026-01-19 23:08:45] >>> Run 2: workload scale = 30 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 30 iterations +============================================= + +2026-01-19T23:08:45+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.97, 0.74 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 399 ns 399 ns 1758978 + +bm_call::via_function_ptr__Function::set_string 399 ns 399 ns 1760800 +bm_call::via_function_ptr____Method::set_string 397 ns 397 ns 1751423 + +bm_std::function_calls__Function::set_string 401 ns 401 ns 1756623 +bm_std::function_calls____Method::set_string 398 ns 398 ns 1748346 + +bm_rtl::function_calls__Function::set_string 397 ns 397 ns 1758430 +bm_rtl::method_calls______Method::set_string 399 ns 399 ns 1754744 + +bm_rtl::function__ErasedReturnType::set_string 401 ns 401 ns 1755050 +bm_rtl::method____ErasedReturnType::set_string 394 ns 394 ns 1782942 +bm_rtl::method____ErasedTargetType::set_string 409 ns 409 ns 1722123 +bm_rtl::method____ErasedTargetAndReturnType::set_string 385 ns 385 ns 1768735 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 857 ns 857 ns 817452 + +bm_call::via_function_ptr__Function::get_string 859 ns 859 ns 815751 +bm_call::via_function_ptr____Method::get_string 856 ns 856 ns 817710 + +bm_std::function_calls__Function::get_string 870 ns 870 ns 804960 +bm_std::function_calls____Method::get_string 869 ns 868 ns 797056 + +bm_rtl::function_calls__Function::get_string 858 ns 858 ns 816875 +bm_rtl::method_calls______Method::get_string 857 ns 857 ns 817853 + +bm_rtl::function__ErasedReturnType::get_string 902 ns 902 ns 776365 +bm_rtl::method____ErasedReturnType::get_string 885 ns 885 ns 791981 +bm_rtl::method____ErasedTargetType::get_string 891 ns 891 ns 781450 +bm_rtl::method____ErasedTargetAndReturnType::get_string 882 ns 882 ns 793685 +----------------------------------- +[2026-01-19 23:09:07] >>> Run 3: workload scale = 30 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 30 iterations +============================================= + +2026-01-19T23:09:07+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 4883.24 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.98, 0.75 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 368 ns 368 ns 1907536 + +bm_call::via_function_ptr__Function::set_string 367 ns 367 ns 1908381 +bm_call::via_function_ptr____Method::set_string 365 ns 365 ns 1910674 + +bm_std::function_calls__Function::set_string 367 ns 367 ns 1896507 +bm_std::function_calls____Method::set_string 382 ns 382 ns 1831001 + +bm_rtl::function_calls__Function::set_string 382 ns 381 ns 1831892 +bm_rtl::method_calls______Method::set_string 380 ns 380 ns 1825582 + +bm_rtl::function__ErasedReturnType::set_string 380 ns 380 ns 1837083 +bm_rtl::method____ErasedReturnType::set_string 370 ns 370 ns 1887118 +bm_rtl::method____ErasedTargetType::set_string 374 ns 374 ns 1875803 +bm_rtl::method____ErasedTargetAndReturnType::set_string 371 ns 371 ns 1887326 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 860 ns 859 ns 816446 + +bm_call::via_function_ptr__Function::get_string 861 ns 861 ns 813585 +bm_call::via_function_ptr____Method::get_string 860 ns 860 ns 813318 + +bm_std::function_calls__Function::get_string 862 ns 862 ns 810967 +bm_std::function_calls____Method::get_string 861 ns 861 ns 813011 + +bm_rtl::function_calls__Function::get_string 861 ns 861 ns 814070 +bm_rtl::method_calls______Method::get_string 860 ns 860 ns 814315 + +bm_rtl::function__ErasedReturnType::get_string 896 ns 896 ns 780048 +bm_rtl::method____ErasedReturnType::get_string 882 ns 882 ns 797878 +bm_rtl::method____ErasedTargetType::get_string 883 ns 883 ns 793282 +bm_rtl::method____ErasedTargetAndReturnType::get_string 879 ns 879 ns 790735 +----------------------------------- +[2026-01-19 23:09:28] >>> Run 1: workload scale = 35 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 35 iterations +============================================= + +2026-01-19T23:09:28+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 801.76 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.98, 0.76 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 705 ns 705 ns 985733 + +bm_call::via_function_ptr__Function::set_string 701 ns 701 ns 1000348 +bm_call::via_function_ptr____Method::set_string 701 ns 701 ns 1000636 + +bm_std::function_calls__Function::set_string 721 ns 720 ns 967545 +bm_std::function_calls____Method::set_string 708 ns 708 ns 991569 + +bm_rtl::function_calls__Function::set_string 700 ns 700 ns 1001086 +bm_rtl::method_calls______Method::set_string 700 ns 700 ns 998814 + +bm_rtl::function__ErasedReturnType::set_string 714 ns 714 ns 974752 +bm_rtl::method____ErasedReturnType::set_string 728 ns 728 ns 959111 +bm_rtl::method____ErasedTargetType::set_string 719 ns 719 ns 975492 +bm_rtl::method____ErasedTargetAndReturnType::set_string 723 ns 723 ns 969915 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1284 ns 1284 ns 545119 + +bm_call::via_function_ptr__Function::get_string 1286 ns 1286 ns 544229 +bm_call::via_function_ptr____Method::get_string 1287 ns 1287 ns 544270 + +bm_std::function_calls__Function::get_string 1297 ns 1296 ns 539804 +bm_std::function_calls____Method::get_string 1283 ns 1283 ns 545848 + +bm_rtl::function_calls__Function::get_string 1284 ns 1284 ns 544814 +bm_rtl::method_calls______Method::get_string 1284 ns 1284 ns 544804 + +bm_rtl::function__ErasedReturnType::get_string 1325 ns 1325 ns 528647 +bm_rtl::method____ErasedReturnType::get_string 1334 ns 1333 ns 525192 +bm_rtl::method____ErasedTargetType::get_string 1337 ns 1337 ns 523963 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1335 ns 1335 ns 524821 +----------------------------------- +[2026-01-19 23:09:46] >>> Run 2: workload scale = 35 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 35 iterations +============================================= + +2026-01-19T23:09:46+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.98, 0.76 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 705 ns 705 ns 986633 + +bm_call::via_function_ptr__Function::set_string 704 ns 704 ns 987788 +bm_call::via_function_ptr____Method::set_string 704 ns 704 ns 997143 + +bm_std::function_calls__Function::set_string 706 ns 706 ns 997719 +bm_std::function_calls____Method::set_string 709 ns 709 ns 986989 + +bm_rtl::function_calls__Function::set_string 701 ns 701 ns 987483 +bm_rtl::method_calls______Method::set_string 703 ns 703 ns 997777 + +bm_rtl::function__ErasedReturnType::set_string 711 ns 711 ns 986143 +bm_rtl::method____ErasedReturnType::set_string 712 ns 712 ns 981320 +bm_rtl::method____ErasedTargetType::set_string 729 ns 729 ns 953478 +bm_rtl::method____ErasedTargetAndReturnType::set_string 721 ns 721 ns 972637 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1292 ns 1292 ns 542071 + +bm_call::via_function_ptr__Function::get_string 1295 ns 1295 ns 540984 +bm_call::via_function_ptr____Method::get_string 1295 ns 1295 ns 541118 + +bm_std::function_calls__Function::get_string 1295 ns 1295 ns 540968 +bm_std::function_calls____Method::get_string 1292 ns 1292 ns 539948 + +bm_rtl::function_calls__Function::get_string 1292 ns 1292 ns 541902 +bm_rtl::method_calls______Method::get_string 1294 ns 1294 ns 541265 + +bm_rtl::function__ErasedReturnType::get_string 1327 ns 1327 ns 527659 +bm_rtl::method____ErasedReturnType::get_string 1329 ns 1329 ns 527155 +bm_rtl::method____ErasedTargetType::get_string 1331 ns 1331 ns 525723 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1328 ns 1328 ns 527175 +----------------------------------- +[2026-01-19 23:10:03] >>> Run 3: workload scale = 35 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 35 iterations +============================================= + +2026-01-19T23:10:03+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.98, 0.77 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 711 ns 711 ns 981009 + +bm_call::via_function_ptr__Function::set_string 706 ns 706 ns 991650 +bm_call::via_function_ptr____Method::set_string 707 ns 707 ns 993046 + +bm_std::function_calls__Function::set_string 711 ns 711 ns 987427 +bm_std::function_calls____Method::set_string 722 ns 722 ns 965591 + +bm_rtl::function_calls__Function::set_string 718 ns 718 ns 980439 +bm_rtl::method_calls______Method::set_string 716 ns 716 ns 981915 + +bm_rtl::function__ErasedReturnType::set_string 732 ns 732 ns 955957 +bm_rtl::method____ErasedReturnType::set_string 729 ns 729 ns 960114 +bm_rtl::method____ErasedTargetType::set_string 732 ns 732 ns 954898 +bm_rtl::method____ErasedTargetAndReturnType::set_string 732 ns 732 ns 955316 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1294 ns 1294 ns 541024 + +bm_call::via_function_ptr__Function::get_string 1294 ns 1294 ns 541047 +bm_call::via_function_ptr____Method::get_string 1295 ns 1295 ns 540770 + +bm_std::function_calls__Function::get_string 1291 ns 1291 ns 542197 +bm_std::function_calls____Method::get_string 1293 ns 1293 ns 541524 + +bm_rtl::function_calls__Function::get_string 1293 ns 1293 ns 541127 +bm_rtl::method_calls______Method::get_string 1295 ns 1294 ns 540828 + +bm_rtl::function__ErasedReturnType::get_string 1331 ns 1331 ns 526054 +bm_rtl::method____ErasedReturnType::get_string 1324 ns 1324 ns 528304 +bm_rtl::method____ErasedTargetType::get_string 1328 ns 1327 ns 527006 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1326 ns 1325 ns 528118 +----------------------------------- +[2026-01-19 23:10:21] >>> Run 1: workload scale = 40 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 40 iterations +============================================= + +2026-01-19T23:10:21+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.98, 0.77 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 782 ns 782 ns 891703 + +bm_call::via_function_ptr__Function::set_string 773 ns 772 ns 906560 +bm_call::via_function_ptr____Method::set_string 773 ns 773 ns 907685 + +bm_std::function_calls__Function::set_string 786 ns 786 ns 892166 +bm_std::function_calls____Method::set_string 794 ns 794 ns 882725 + +bm_rtl::function_calls__Function::set_string 773 ns 773 ns 906587 +bm_rtl::method_calls______Method::set_string 773 ns 773 ns 905399 + +bm_rtl::function__ErasedReturnType::set_string 781 ns 781 ns 895361 +bm_rtl::method____ErasedReturnType::set_string 802 ns 802 ns 871618 +bm_rtl::method____ErasedTargetType::set_string 807 ns 807 ns 868612 +bm_rtl::method____ErasedTargetAndReturnType::set_string 798 ns 798 ns 875806 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1386 ns 1386 ns 504769 + +bm_call::via_function_ptr__Function::get_string 1388 ns 1388 ns 504508 +bm_call::via_function_ptr____Method::get_string 1389 ns 1389 ns 503908 + +bm_std::function_calls__Function::get_string 1393 ns 1392 ns 502344 +bm_std::function_calls____Method::get_string 1401 ns 1401 ns 499474 + +bm_rtl::function_calls__Function::get_string 1388 ns 1388 ns 504285 +bm_rtl::method_calls______Method::get_string 1389 ns 1389 ns 503768 + +bm_rtl::function__ErasedReturnType::get_string 1432 ns 1431 ns 489025 +bm_rtl::method____ErasedReturnType::get_string 1441 ns 1441 ns 485874 +bm_rtl::method____ErasedTargetType::get_string 1437 ns 1437 ns 487198 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1429 ns 1429 ns 489805 +----------------------------------- +[2026-01-19 23:10:39] >>> Run 2: workload scale = 40 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 40 iterations +============================================= + +2026-01-19T23:10:39+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.99, 0.78 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 785 ns 785 ns 888235 + +bm_call::via_function_ptr__Function::set_string 783 ns 783 ns 895909 +bm_call::via_function_ptr____Method::set_string 784 ns 784 ns 892181 + +bm_std::function_calls__Function::set_string 808 ns 807 ns 867107 +bm_std::function_calls____Method::set_string 791 ns 791 ns 886305 + +bm_rtl::function_calls__Function::set_string 785 ns 784 ns 895366 +bm_rtl::method_calls______Method::set_string 785 ns 785 ns 893743 + +bm_rtl::function__ErasedReturnType::set_string 789 ns 789 ns 884109 +bm_rtl::method____ErasedReturnType::set_string 799 ns 799 ns 877237 +bm_rtl::method____ErasedTargetType::set_string 796 ns 796 ns 878299 +bm_rtl::method____ErasedTargetAndReturnType::set_string 795 ns 795 ns 880145 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1390 ns 1390 ns 503885 + +bm_call::via_function_ptr__Function::get_string 1392 ns 1392 ns 503087 +bm_call::via_function_ptr____Method::get_string 1393 ns 1393 ns 502484 + +bm_std::function_calls__Function::get_string 1403 ns 1402 ns 499273 +bm_std::function_calls____Method::get_string 1397 ns 1396 ns 501051 + +bm_rtl::function_calls__Function::get_string 1392 ns 1392 ns 503291 +bm_rtl::method_calls______Method::get_string 1394 ns 1394 ns 502404 + +bm_rtl::function__ErasedReturnType::get_string 1429 ns 1429 ns 489928 +bm_rtl::method____ErasedReturnType::get_string 1443 ns 1443 ns 485194 +bm_rtl::method____ErasedTargetType::get_string 1444 ns 1444 ns 484882 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1445 ns 1444 ns 484828 +----------------------------------- +[2026-01-19 23:10:57] >>> Run 3: workload scale = 40 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 40 iterations +============================================= + +2026-01-19T23:10:57+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.99, 0.78 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 793 ns 792 ns 877198 + +bm_call::via_function_ptr__Function::set_string 781 ns 781 ns 897556 +bm_call::via_function_ptr____Method::set_string 782 ns 782 ns 895656 + +bm_std::function_calls__Function::set_string 808 ns 808 ns 867700 +bm_std::function_calls____Method::set_string 794 ns 793 ns 881778 + +bm_rtl::function_calls__Function::set_string 783 ns 783 ns 894163 +bm_rtl::method_calls______Method::set_string 782 ns 782 ns 896569 + +bm_rtl::function__ErasedReturnType::set_string 788 ns 787 ns 889379 +bm_rtl::method____ErasedReturnType::set_string 804 ns 803 ns 873015 +bm_rtl::method____ErasedTargetType::set_string 789 ns 789 ns 886401 +bm_rtl::method____ErasedTargetAndReturnType::set_string 800 ns 800 ns 875673 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1391 ns 1391 ns 503452 + +bm_call::via_function_ptr__Function::get_string 1393 ns 1393 ns 502459 +bm_call::via_function_ptr____Method::get_string 1395 ns 1395 ns 502068 + +bm_std::function_calls__Function::get_string 1409 ns 1409 ns 497129 +bm_std::function_calls____Method::get_string 1397 ns 1397 ns 501255 + +bm_rtl::function_calls__Function::get_string 1392 ns 1392 ns 502897 +bm_rtl::method_calls______Method::get_string 1394 ns 1394 ns 502374 + +bm_rtl::function__ErasedReturnType::get_string 1429 ns 1429 ns 489871 +bm_rtl::method____ErasedReturnType::get_string 1445 ns 1445 ns 484141 +bm_rtl::method____ErasedTargetType::get_string 1447 ns 1447 ns 483724 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1446 ns 1446 ns 483729 +----------------------------------- +[2026-01-19 23:11:16] >>> Run 1: workload scale = 45 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 45 iterations +============================================= + +2026-01-19T23:11:16+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800.791 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.99, 0.79 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 870 ns 870 ns 802924 + +bm_call::via_function_ptr__Function::set_string 858 ns 858 ns 815437 +bm_call::via_function_ptr____Method::set_string 859 ns 859 ns 815933 + +bm_std::function_calls__Function::set_string 874 ns 874 ns 798507 +bm_std::function_calls____Method::set_string 885 ns 885 ns 793864 + +bm_rtl::function_calls__Function::set_string 873 ns 873 ns 797727 +bm_rtl::method_calls______Method::set_string 876 ns 875 ns 802078 + +bm_rtl::function__ErasedReturnType::set_string 883 ns 883 ns 791520 +bm_rtl::method____ErasedReturnType::set_string 870 ns 869 ns 807324 +bm_rtl::method____ErasedTargetType::set_string 878 ns 878 ns 797789 +bm_rtl::method____ErasedTargetAndReturnType::set_string 872 ns 872 ns 799885 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1584 ns 1584 ns 442078 + +bm_call::via_function_ptr__Function::get_string 1585 ns 1584 ns 441731 +bm_call::via_function_ptr____Method::get_string 1582 ns 1582 ns 442494 + +bm_std::function_calls__Function::get_string 1576 ns 1576 ns 444173 +bm_std::function_calls____Method::get_string 1577 ns 1577 ns 443790 + +bm_rtl::function_calls__Function::get_string 1580 ns 1580 ns 442964 +bm_rtl::method_calls______Method::get_string 1581 ns 1581 ns 442876 + +bm_rtl::function__ErasedReturnType::get_string 1600 ns 1600 ns 437508 +bm_rtl::method____ErasedReturnType::get_string 1595 ns 1595 ns 439061 +bm_rtl::method____ErasedTargetType::get_string 1595 ns 1595 ns 438882 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1597 ns 1597 ns 438309 +----------------------------------- +[2026-01-19 23:11:34] >>> Run 2: workload scale = 45 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 45 iterations +============================================= + +2026-01-19T23:11:34+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.99, 0.79 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 872 ns 872 ns 801839 + +bm_call::via_function_ptr__Function::set_string 862 ns 862 ns 811605 +bm_call::via_function_ptr____Method::set_string 864 ns 864 ns 811446 + +bm_std::function_calls__Function::set_string 869 ns 868 ns 804505 +bm_std::function_calls____Method::set_string 861 ns 861 ns 812636 + +bm_rtl::function_calls__Function::set_string 865 ns 865 ns 807848 +bm_rtl::method_calls______Method::set_string 865 ns 865 ns 809801 + +bm_rtl::function__ErasedReturnType::set_string 859 ns 859 ns 814420 +bm_rtl::method____ErasedReturnType::set_string 855 ns 855 ns 820098 +bm_rtl::method____ErasedTargetType::set_string 866 ns 866 ns 808728 +bm_rtl::method____ErasedTargetAndReturnType::set_string 861 ns 861 ns 810431 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1584 ns 1584 ns 441922 + +bm_call::via_function_ptr__Function::get_string 1591 ns 1591 ns 439923 +bm_call::via_function_ptr____Method::get_string 1580 ns 1580 ns 442731 + +bm_std::function_calls__Function::get_string 1578 ns 1578 ns 444219 +bm_std::function_calls____Method::get_string 1577 ns 1577 ns 443864 + +bm_rtl::function_calls__Function::get_string 1589 ns 1589 ns 440690 +bm_rtl::method_calls______Method::get_string 1583 ns 1582 ns 442763 + +bm_rtl::function__ErasedReturnType::get_string 1591 ns 1591 ns 439944 +bm_rtl::method____ErasedReturnType::get_string 1592 ns 1592 ns 439921 +bm_rtl::method____ErasedTargetType::get_string 1591 ns 1591 ns 439971 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1598 ns 1598 ns 435789 +----------------------------------- +[2026-01-19 23:11:52] >>> Run 3: workload scale = 45 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 45 iterations +============================================= + +2026-01-19T23:11:52+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.99, 0.80 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 869 ns 868 ns 803084 + +bm_call::via_function_ptr__Function::set_string 871 ns 871 ns 804343 +bm_call::via_function_ptr____Method::set_string 871 ns 871 ns 804572 + +bm_std::function_calls__Function::set_string 870 ns 870 ns 804950 +bm_std::function_calls____Method::set_string 884 ns 884 ns 791010 + +bm_rtl::function_calls__Function::set_string 886 ns 886 ns 793192 +bm_rtl::method_calls______Method::set_string 885 ns 885 ns 792897 + +bm_rtl::function__ErasedReturnType::set_string 879 ns 879 ns 799665 +bm_rtl::method____ErasedReturnType::set_string 868 ns 868 ns 807084 +bm_rtl::method____ErasedTargetType::set_string 876 ns 876 ns 797585 +bm_rtl::method____ErasedTargetAndReturnType::set_string 869 ns 869 ns 806557 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1652 ns 1652 ns 423648 + +bm_call::via_function_ptr__Function::get_string 1652 ns 1652 ns 423806 +bm_call::via_function_ptr____Method::get_string 1668 ns 1667 ns 419958 + +bm_std::function_calls__Function::get_string 1649 ns 1649 ns 424602 +bm_std::function_calls____Method::get_string 1649 ns 1649 ns 424942 + +bm_rtl::function_calls__Function::get_string 1661 ns 1661 ns 421345 +bm_rtl::method_calls______Method::get_string 1659 ns 1659 ns 417122 + +bm_rtl::function__ErasedReturnType::get_string 1675 ns 1674 ns 418135 +bm_rtl::method____ErasedReturnType::get_string 1666 ns 1665 ns 421033 +bm_rtl::method____ErasedTargetType::get_string 1669 ns 1668 ns 419528 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1671 ns 1671 ns 419526 +----------------------------------- +[2026-01-19 23:12:11] >>> Run 1: workload scale = 50 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 50 iterations +============================================= + +2026-01-19T23:12:11+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.99, 0.80 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 941 ns 941 ns 742656 + +bm_call::via_function_ptr__Function::set_string 932 ns 932 ns 750908 +bm_call::via_function_ptr____Method::set_string 932 ns 932 ns 751864 + +bm_std::function_calls__Function::set_string 940 ns 940 ns 744365 +bm_std::function_calls____Method::set_string 944 ns 944 ns 744594 + +bm_rtl::function_calls__Function::set_string 931 ns 931 ns 752321 +bm_rtl::method_calls______Method::set_string 931 ns 930 ns 752576 + +bm_rtl::function__ErasedReturnType::set_string 933 ns 933 ns 751301 +bm_rtl::method____ErasedReturnType::set_string 933 ns 933 ns 749838 +bm_rtl::method____ErasedTargetType::set_string 947 ns 947 ns 743833 +bm_rtl::method____ErasedTargetAndReturnType::set_string 932 ns 932 ns 750030 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1826 ns 1826 ns 383413 + +bm_call::via_function_ptr__Function::get_string 1825 ns 1825 ns 381343 +bm_call::via_function_ptr____Method::get_string 1841 ns 1841 ns 380366 + +bm_std::function_calls__Function::get_string 1829 ns 1829 ns 383133 +bm_std::function_calls____Method::get_string 1829 ns 1828 ns 382798 + +bm_rtl::function_calls__Function::get_string 1826 ns 1826 ns 384168 +bm_rtl::method_calls______Method::get_string 1825 ns 1825 ns 383462 + +bm_rtl::function__ErasedReturnType::get_string 1845 ns 1845 ns 380179 +bm_rtl::method____ErasedReturnType::get_string 1844 ns 1844 ns 379553 +bm_rtl::method____ErasedTargetType::get_string 1846 ns 1846 ns 379999 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1844 ns 1844 ns 379675 +----------------------------------- +[2026-01-19 23:12:30] >>> Run 2: workload scale = 50 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 50 iterations +============================================= + +2026-01-19T23:12:30+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.81 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 933 ns 933 ns 747023 + +bm_call::via_function_ptr__Function::set_string 926 ns 926 ns 756314 +bm_call::via_function_ptr____Method::set_string 926 ns 926 ns 755547 + +bm_std::function_calls__Function::set_string 938 ns 938 ns 747825 +bm_std::function_calls____Method::set_string 940 ns 940 ns 745786 + +bm_rtl::function_calls__Function::set_string 925 ns 925 ns 756240 +bm_rtl::method_calls______Method::set_string 927 ns 927 ns 756178 + +bm_rtl::function__ErasedReturnType::set_string 933 ns 933 ns 749774 +bm_rtl::method____ErasedReturnType::set_string 935 ns 935 ns 749882 +bm_rtl::method____ErasedTargetType::set_string 941 ns 941 ns 745341 +bm_rtl::method____ErasedTargetAndReturnType::set_string 937 ns 937 ns 746139 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1726 ns 1726 ns 405922 + +bm_call::via_function_ptr__Function::get_string 1726 ns 1726 ns 405314 +bm_call::via_function_ptr____Method::get_string 1728 ns 1728 ns 405268 + +bm_std::function_calls__Function::get_string 1727 ns 1727 ns 405436 +bm_std::function_calls____Method::get_string 1735 ns 1735 ns 403964 + +bm_rtl::function_calls__Function::get_string 1723 ns 1722 ns 406561 +bm_rtl::method_calls______Method::get_string 1727 ns 1726 ns 405472 + +bm_rtl::function__ErasedReturnType::get_string 1756 ns 1756 ns 396426 +bm_rtl::method____ErasedReturnType::get_string 1757 ns 1756 ns 398483 +bm_rtl::method____ErasedTargetType::get_string 1756 ns 1756 ns 399103 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1759 ns 1758 ns 397872 +----------------------------------- +[2026-01-19 23:12:48] >>> Run 3: workload scale = 50 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 50 iterations +============================================= + +2026-01-19T23:12:48+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.81 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 943 ns 943 ns 743159 + +bm_call::via_function_ptr__Function::set_string 929 ns 929 ns 756283 +bm_call::via_function_ptr____Method::set_string 934 ns 934 ns 755878 + +bm_std::function_calls__Function::set_string 949 ns 949 ns 738684 +bm_std::function_calls____Method::set_string 950 ns 950 ns 735773 + +bm_rtl::function_calls__Function::set_string 936 ns 936 ns 749057 +bm_rtl::method_calls______Method::set_string 931 ns 931 ns 749496 + +bm_rtl::function__ErasedReturnType::set_string 931 ns 931 ns 751200 +bm_rtl::method____ErasedReturnType::set_string 942 ns 942 ns 750312 +bm_rtl::method____ErasedTargetType::set_string 946 ns 946 ns 734994 +bm_rtl::method____ErasedTargetAndReturnType::set_string 949 ns 949 ns 738347 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1729 ns 1729 ns 404989 + +bm_call::via_function_ptr__Function::get_string 1731 ns 1731 ns 404924 +bm_call::via_function_ptr____Method::get_string 1731 ns 1730 ns 404859 + +bm_std::function_calls__Function::get_string 1738 ns 1738 ns 404856 +bm_std::function_calls____Method::get_string 1744 ns 1744 ns 403238 + +bm_rtl::function_calls__Function::get_string 1729 ns 1729 ns 405316 +bm_rtl::method_calls______Method::get_string 1728 ns 1727 ns 405900 + +bm_rtl::function__ErasedReturnType::get_string 1740 ns 1740 ns 401698 +bm_rtl::method____ErasedReturnType::get_string 1744 ns 1744 ns 402000 +bm_rtl::method____ErasedTargetType::get_string 1743 ns 1743 ns 401434 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1743 ns 1743 ns 401534 +----------------------------------- +[2026-01-19 23:13:07] >>> Run 1: workload scale = 58 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 58 iterations +============================================= + +2026-01-19T23:13:07+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 1208.8 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.82 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1036 ns 1036 ns 673890 + +bm_call::via_function_ptr__Function::set_string 1034 ns 1034 ns 677703 +bm_call::via_function_ptr____Method::set_string 1035 ns 1035 ns 677912 + +bm_std::function_calls__Function::set_string 1038 ns 1038 ns 673043 +bm_std::function_calls____Method::set_string 1049 ns 1049 ns 670179 + +bm_rtl::function_calls__Function::set_string 1043 ns 1043 ns 671982 +bm_rtl::method_calls______Method::set_string 1044 ns 1044 ns 669684 + +bm_rtl::function__ErasedReturnType::set_string 1052 ns 1052 ns 665822 +bm_rtl::method____ErasedReturnType::set_string 1052 ns 1052 ns 665002 +bm_rtl::method____ErasedTargetType::set_string 1054 ns 1054 ns 665921 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1051 ns 1050 ns 666979 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2135 ns 2134 ns 328156 + +bm_call::via_function_ptr__Function::get_string 2135 ns 2135 ns 326430 +bm_call::via_function_ptr____Method::get_string 2138 ns 2137 ns 327594 + +bm_std::function_calls__Function::get_string 2134 ns 2134 ns 328582 +bm_std::function_calls____Method::get_string 2130 ns 2130 ns 328683 + +bm_rtl::function_calls__Function::get_string 2137 ns 2137 ns 328106 +bm_rtl::method_calls______Method::get_string 2136 ns 2136 ns 327721 + +bm_rtl::function__ErasedReturnType::get_string 2174 ns 2174 ns 322539 +bm_rtl::method____ErasedReturnType::get_string 2155 ns 2155 ns 324740 +bm_rtl::method____ErasedTargetType::get_string 2169 ns 2169 ns 322686 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2156 ns 2156 ns 324664 +----------------------------------- +[2026-01-19 23:13:26] >>> Run 2: workload scale = 58 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 58 iterations +============================================= + +2026-01-19T23:13:26+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.82 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1035 ns 1034 ns 674626 + +bm_call::via_function_ptr__Function::set_string 1043 ns 1043 ns 669988 +bm_call::via_function_ptr____Method::set_string 1043 ns 1043 ns 672110 + +bm_std::function_calls__Function::set_string 1037 ns 1037 ns 677404 +bm_std::function_calls____Method::set_string 1034 ns 1034 ns 679051 + +bm_rtl::function_calls__Function::set_string 1042 ns 1042 ns 671296 +bm_rtl::method_calls______Method::set_string 1041 ns 1041 ns 672638 + +bm_rtl::function__ErasedReturnType::set_string 1046 ns 1046 ns 669870 +bm_rtl::method____ErasedReturnType::set_string 1045 ns 1045 ns 669132 +bm_rtl::method____ErasedTargetType::set_string 1056 ns 1056 ns 663154 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1044 ns 1044 ns 669553 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2044 ns 2044 ns 342513 + +bm_call::via_function_ptr__Function::get_string 2042 ns 2042 ns 342924 +bm_call::via_function_ptr____Method::get_string 2046 ns 2045 ns 341909 + +bm_std::function_calls__Function::get_string 2048 ns 2047 ns 341946 +bm_std::function_calls____Method::get_string 2050 ns 2050 ns 341378 + +bm_rtl::function_calls__Function::get_string 2042 ns 2042 ns 342913 +bm_rtl::method_calls______Method::get_string 2044 ns 2044 ns 342229 + +bm_rtl::function__ErasedReturnType::get_string 2072 ns 2072 ns 337809 +bm_rtl::method____ErasedReturnType::get_string 2073 ns 2073 ns 338112 +bm_rtl::method____ErasedTargetType::get_string 2070 ns 2070 ns 338166 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2074 ns 2074 ns 337414 +----------------------------------- +[2026-01-19 23:13:46] >>> Run 3: workload scale = 58 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 58 iterations +============================================= + +2026-01-19T23:13:46+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.83 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1044 ns 1044 ns 670022 + +bm_call::via_function_ptr__Function::set_string 1052 ns 1052 ns 665303 +bm_call::via_function_ptr____Method::set_string 1053 ns 1053 ns 664751 + +bm_std::function_calls__Function::set_string 1035 ns 1035 ns 677148 +bm_std::function_calls____Method::set_string 1035 ns 1035 ns 676481 + +bm_rtl::function_calls__Function::set_string 1044 ns 1044 ns 670259 +bm_rtl::method_calls______Method::set_string 1045 ns 1045 ns 669178 + +bm_rtl::function__ErasedReturnType::set_string 1045 ns 1045 ns 671882 +bm_rtl::method____ErasedReturnType::set_string 1050 ns 1050 ns 666690 +bm_rtl::method____ErasedTargetType::set_string 1050 ns 1050 ns 666725 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1052 ns 1052 ns 664907 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2120 ns 2120 ns 330220 + +bm_call::via_function_ptr__Function::get_string 2121 ns 2121 ns 330103 +bm_call::via_function_ptr____Method::get_string 2122 ns 2122 ns 329772 + +bm_std::function_calls__Function::get_string 2121 ns 2121 ns 329881 +bm_std::function_calls____Method::get_string 2131 ns 2131 ns 328635 + +bm_rtl::function_calls__Function::get_string 2120 ns 2120 ns 330342 +bm_rtl::method_calls______Method::get_string 2121 ns 2121 ns 329984 + +bm_rtl::function__ErasedReturnType::get_string 2148 ns 2147 ns 326030 +bm_rtl::method____ErasedReturnType::get_string 2138 ns 2138 ns 327419 +bm_rtl::method____ErasedTargetType::get_string 2140 ns 2140 ns 327116 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2143 ns 2143 ns 326651 +----------------------------------- +[2026-01-19 23:14:05] >>> Run 1: workload scale = 66 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 66 iterations +============================================= + +2026-01-19T23:14:05+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.83 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1644 ns 1644 ns 425244 + +bm_call::via_function_ptr__Function::set_string 1646 ns 1645 ns 425948 +bm_call::via_function_ptr____Method::set_string 1644 ns 1644 ns 425773 + +bm_std::function_calls__Function::set_string 1643 ns 1643 ns 425435 +bm_std::function_calls____Method::set_string 1645 ns 1644 ns 425697 + +bm_rtl::function_calls__Function::set_string 1646 ns 1646 ns 425217 +bm_rtl::method_calls______Method::set_string 1646 ns 1645 ns 424786 + +bm_rtl::function__ErasedReturnType::set_string 1650 ns 1650 ns 424522 +bm_rtl::method____ErasedReturnType::set_string 1649 ns 1648 ns 424894 +bm_rtl::method____ErasedTargetType::set_string 1656 ns 1656 ns 422916 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1647 ns 1647 ns 425320 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2773 ns 2773 ns 252410 + +bm_call::via_function_ptr__Function::get_string 2773 ns 2773 ns 251796 +bm_call::via_function_ptr____Method::get_string 2777 ns 2777 ns 252131 + +bm_std::function_calls__Function::get_string 2772 ns 2772 ns 252502 +bm_std::function_calls____Method::get_string 2772 ns 2771 ns 252584 + +bm_rtl::function_calls__Function::get_string 2773 ns 2773 ns 252563 +bm_rtl::method_calls______Method::get_string 2774 ns 2773 ns 252472 + +bm_rtl::function__ErasedReturnType::get_string 2792 ns 2791 ns 250676 +bm_rtl::method____ErasedReturnType::get_string 2792 ns 2791 ns 250735 +bm_rtl::method____ErasedTargetType::get_string 2785 ns 2785 ns 251378 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2794 ns 2794 ns 250478 +----------------------------------- +[2026-01-19 23:14:26] >>> Run 2: workload scale = 66 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 66 iterations +============================================= + +2026-01-19T23:14:26+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.83 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1668 ns 1667 ns 419315 + +bm_call::via_function_ptr__Function::set_string 1664 ns 1664 ns 420753 +bm_call::via_function_ptr____Method::set_string 1664 ns 1664 ns 420532 + +bm_std::function_calls__Function::set_string 1680 ns 1680 ns 416510 +bm_std::function_calls____Method::set_string 1680 ns 1680 ns 416744 + +bm_rtl::function_calls__Function::set_string 1688 ns 1687 ns 415205 +bm_rtl::method_calls______Method::set_string 1687 ns 1687 ns 414846 + +bm_rtl::function__ErasedReturnType::set_string 1664 ns 1664 ns 420397 +bm_rtl::method____ErasedReturnType::set_string 1668 ns 1668 ns 419490 +bm_rtl::method____ErasedTargetType::set_string 1664 ns 1664 ns 420688 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1676 ns 1676 ns 417822 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2882 ns 2882 ns 242896 + +bm_call::via_function_ptr__Function::get_string 2884 ns 2883 ns 242700 +bm_call::via_function_ptr____Method::get_string 2880 ns 2879 ns 243154 + +bm_std::function_calls__Function::get_string 2874 ns 2873 ns 243477 +bm_std::function_calls____Method::get_string 2857 ns 2856 ns 244960 + +bm_rtl::function_calls__Function::get_string 2877 ns 2876 ns 243281 +bm_rtl::method_calls______Method::get_string 2877 ns 2877 ns 243243 + +bm_rtl::function__ErasedReturnType::get_string 2876 ns 2876 ns 243445 +bm_rtl::method____ErasedReturnType::get_string 2862 ns 2862 ns 244590 +bm_rtl::method____ErasedTargetType::get_string 2855 ns 2855 ns 245189 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2858 ns 2858 ns 244872 +----------------------------------- +[2026-01-19 23:14:47] >>> Run 3: workload scale = 66 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 66 iterations +============================================= + +2026-01-19T23:14:47+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.84 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1664 ns 1664 ns 419877 + +bm_call::via_function_ptr__Function::set_string 1661 ns 1661 ns 421577 +bm_call::via_function_ptr____Method::set_string 1659 ns 1659 ns 420994 + +bm_std::function_calls__Function::set_string 1655 ns 1655 ns 422552 +bm_std::function_calls____Method::set_string 1657 ns 1656 ns 423207 + +bm_rtl::function_calls__Function::set_string 1655 ns 1655 ns 422801 +bm_rtl::method_calls______Method::set_string 1656 ns 1655 ns 422724 + +bm_rtl::function__ErasedReturnType::set_string 1656 ns 1656 ns 422506 +bm_rtl::method____ErasedReturnType::set_string 1655 ns 1655 ns 423293 +bm_rtl::method____ErasedTargetType::set_string 1660 ns 1659 ns 421827 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1664 ns 1664 ns 420188 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2781 ns 2781 ns 251706 + +bm_call::via_function_ptr__Function::get_string 2782 ns 2782 ns 251750 +bm_call::via_function_ptr____Method::get_string 2785 ns 2785 ns 251488 + +bm_std::function_calls__Function::get_string 2782 ns 2782 ns 251453 +bm_std::function_calls____Method::get_string 2788 ns 2788 ns 250872 + +bm_rtl::function_calls__Function::get_string 2780 ns 2780 ns 251731 +bm_rtl::method_calls______Method::get_string 2784 ns 2784 ns 251526 + +bm_rtl::function__ErasedReturnType::get_string 2790 ns 2790 ns 250718 +bm_rtl::method____ErasedReturnType::get_string 2795 ns 2795 ns 250540 +bm_rtl::method____ErasedTargetType::get_string 2788 ns 2787 ns 251050 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2793 ns 2793 ns 250457 +----------------------------------- +[2026-01-19 23:15:07] >>> Run 1: workload scale = 74 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 74 iterations +============================================= + +2026-01-19T23:15:07+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 2068.8 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.84 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1728 ns 1728 ns 403699 + +bm_call::via_function_ptr__Function::set_string 1728 ns 1728 ns 405095 +bm_call::via_function_ptr____Method::set_string 1730 ns 1730 ns 404936 + +bm_std::function_calls__Function::set_string 1717 ns 1717 ns 407293 +bm_std::function_calls____Method::set_string 1719 ns 1719 ns 407683 + +bm_rtl::function_calls__Function::set_string 1715 ns 1715 ns 408399 +bm_rtl::method_calls______Method::set_string 1716 ns 1716 ns 408228 + +bm_rtl::function__ErasedReturnType::set_string 1728 ns 1727 ns 405282 +bm_rtl::method____ErasedReturnType::set_string 1732 ns 1732 ns 404288 +bm_rtl::method____ErasedTargetType::set_string 1728 ns 1728 ns 405001 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1744 ns 1744 ns 401021 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3057 ns 3057 ns 229029 + +bm_call::via_function_ptr__Function::get_string 3059 ns 3059 ns 228889 +bm_call::via_function_ptr____Method::get_string 3059 ns 3059 ns 228980 + +bm_std::function_calls__Function::get_string 3064 ns 3064 ns 228677 +bm_std::function_calls____Method::get_string 3067 ns 3066 ns 228268 + +bm_rtl::function_calls__Function::get_string 3058 ns 3057 ns 228868 +bm_rtl::method_calls______Method::get_string 3058 ns 3058 ns 228956 + +bm_rtl::function__ErasedReturnType::get_string 3100 ns 3100 ns 226068 +bm_rtl::method____ErasedReturnType::get_string 3089 ns 3088 ns 226605 +bm_rtl::method____ErasedTargetType::get_string 3092 ns 3092 ns 226468 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3091 ns 3090 ns 226632 +----------------------------------- +[2026-01-19 23:15:29] >>> Run 2: workload scale = 74 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 74 iterations +============================================= + +2026-01-19T23:15:29+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 2971.96 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.85 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1717 ns 1717 ns 407373 + +bm_call::via_function_ptr__Function::set_string 1717 ns 1717 ns 407868 +bm_call::via_function_ptr____Method::set_string 1716 ns 1716 ns 407960 + +bm_std::function_calls__Function::set_string 1728 ns 1728 ns 405438 +bm_std::function_calls____Method::set_string 1719 ns 1719 ns 407465 + +bm_rtl::function_calls__Function::set_string 1717 ns 1717 ns 407801 +bm_rtl::method_calls______Method::set_string 1718 ns 1717 ns 407906 + +bm_rtl::function__ErasedReturnType::set_string 1727 ns 1727 ns 405269 +bm_rtl::method____ErasedReturnType::set_string 1732 ns 1732 ns 403650 +bm_rtl::method____ErasedTargetType::set_string 1724 ns 1724 ns 406393 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1724 ns 1724 ns 405598 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3054 ns 3054 ns 229183 + +bm_call::via_function_ptr__Function::get_string 3059 ns 3058 ns 228889 +bm_call::via_function_ptr____Method::get_string 3057 ns 3057 ns 229051 + +bm_std::function_calls__Function::get_string 3064 ns 3064 ns 228533 +bm_std::function_calls____Method::get_string 3057 ns 3057 ns 229042 + +bm_rtl::function_calls__Function::get_string 3058 ns 3058 ns 229069 +bm_rtl::method_calls______Method::get_string 3058 ns 3058 ns 228955 + +bm_rtl::function__ErasedReturnType::get_string 3090 ns 3090 ns 226512 +bm_rtl::method____ErasedReturnType::get_string 3100 ns 3099 ns 225959 +bm_rtl::method____ErasedTargetType::get_string 3090 ns 3090 ns 226608 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3113 ns 3113 ns 225676 +----------------------------------- +[2026-01-19 23:15:50] >>> Run 3: workload scale = 74 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 74 iterations +============================================= + +2026-01-19T23:15:50+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 1226.86 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.85 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1747 ns 1747 ns 394391 + +bm_call::via_function_ptr__Function::set_string 1736 ns 1735 ns 403290 +bm_call::via_function_ptr____Method::set_string 1732 ns 1732 ns 404263 + +bm_std::function_calls__Function::set_string 1732 ns 1732 ns 404399 +bm_std::function_calls____Method::set_string 1742 ns 1742 ns 401864 + +bm_rtl::function_calls__Function::set_string 1740 ns 1739 ns 402145 +bm_rtl::method_calls______Method::set_string 1741 ns 1741 ns 401844 + +bm_rtl::function__ErasedReturnType::set_string 1747 ns 1746 ns 400854 +bm_rtl::method____ErasedReturnType::set_string 1736 ns 1736 ns 403429 +bm_rtl::method____ErasedTargetType::set_string 1737 ns 1737 ns 403093 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1739 ns 1738 ns 402717 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3176 ns 3176 ns 220460 + +bm_call::via_function_ptr__Function::get_string 3177 ns 3176 ns 220349 +bm_call::via_function_ptr____Method::get_string 3179 ns 3178 ns 220255 + +bm_std::function_calls__Function::get_string 3176 ns 3176 ns 220394 +bm_std::function_calls____Method::get_string 3177 ns 3176 ns 220423 + +bm_rtl::function_calls__Function::get_string 3177 ns 3177 ns 220295 +bm_rtl::method_calls______Method::get_string 3181 ns 3181 ns 220150 + +bm_rtl::function__ErasedReturnType::get_string 3210 ns 3210 ns 218065 +bm_rtl::method____ErasedReturnType::get_string 3205 ns 3205 ns 218381 +bm_rtl::method____ErasedTargetType::get_string 3196 ns 3196 ns 219058 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3204 ns 3204 ns 218448 +----------------------------------- +[2026-01-19 23:16:11] >>> Run 1: workload scale = 82 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 82 iterations +============================================= + +2026-01-19T23:16:11+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.85 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1794 ns 1794 ns 389505 + +bm_call::via_function_ptr__Function::set_string 1790 ns 1790 ns 390845 +bm_call::via_function_ptr____Method::set_string 1790 ns 1790 ns 390651 + +bm_std::function_calls__Function::set_string 1809 ns 1808 ns 387130 +bm_std::function_calls____Method::set_string 1812 ns 1812 ns 386533 + +bm_rtl::function_calls__Function::set_string 1784 ns 1784 ns 392616 +bm_rtl::method_calls______Method::set_string 1784 ns 1784 ns 392461 + +bm_rtl::function__ErasedReturnType::set_string 1797 ns 1796 ns 389855 +bm_rtl::method____ErasedReturnType::set_string 1803 ns 1802 ns 388490 +bm_rtl::method____ErasedTargetType::set_string 1792 ns 1792 ns 390157 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1795 ns 1795 ns 390045 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3375 ns 3375 ns 207424 + +bm_call::via_function_ptr__Function::get_string 3374 ns 3374 ns 207361 +bm_call::via_function_ptr____Method::get_string 3377 ns 3376 ns 207215 + +bm_std::function_calls__Function::get_string 3415 ns 3414 ns 204995 +bm_std::function_calls____Method::get_string 3412 ns 3412 ns 205212 + +bm_rtl::function_calls__Function::get_string 3372 ns 3372 ns 207524 +bm_rtl::method_calls______Method::get_string 3376 ns 3375 ns 207464 + +bm_rtl::function__ErasedReturnType::get_string 3383 ns 3383 ns 206960 +bm_rtl::method____ErasedReturnType::get_string 3390 ns 3389 ns 206533 +bm_rtl::method____ErasedTargetType::get_string 3388 ns 3388 ns 206603 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3394 ns 3394 ns 206249 +----------------------------------- +[2026-01-19 23:16:33] >>> Run 2: workload scale = 82 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 82 iterations +============================================= + +2026-01-19T23:16:33+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.86 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1789 ns 1788 ns 390994 + +bm_call::via_function_ptr__Function::set_string 1785 ns 1784 ns 392122 +bm_call::via_function_ptr____Method::set_string 1785 ns 1785 ns 392243 + +bm_std::function_calls__Function::set_string 1790 ns 1790 ns 390820 +bm_std::function_calls____Method::set_string 1790 ns 1790 ns 391136 + +bm_rtl::function_calls__Function::set_string 1787 ns 1787 ns 392034 +bm_rtl::method_calls______Method::set_string 1788 ns 1787 ns 391689 + +bm_rtl::function__ErasedReturnType::set_string 1798 ns 1798 ns 389411 +bm_rtl::method____ErasedReturnType::set_string 1796 ns 1796 ns 389638 +bm_rtl::method____ErasedTargetType::set_string 1813 ns 1813 ns 386506 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1794 ns 1794 ns 390498 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3369 ns 3369 ns 207893 + +bm_call::via_function_ptr__Function::get_string 3368 ns 3368 ns 207860 +bm_call::via_function_ptr____Method::get_string 3371 ns 3370 ns 207743 + +bm_std::function_calls__Function::get_string 3368 ns 3368 ns 207977 +bm_std::function_calls____Method::get_string 3370 ns 3369 ns 207658 + +bm_rtl::function_calls__Function::get_string 3366 ns 3366 ns 207915 +bm_rtl::method_calls______Method::get_string 3368 ns 3367 ns 207876 + +bm_rtl::function__ErasedReturnType::get_string 3394 ns 3393 ns 206327 +bm_rtl::method____ErasedReturnType::get_string 3395 ns 3395 ns 206213 +bm_rtl::method____ErasedTargetType::get_string 3388 ns 3388 ns 206518 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3398 ns 3397 ns 206045 +----------------------------------- +[2026-01-19 23:16:55] >>> Run 3: workload scale = 82 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 82 iterations +============================================= + +2026-01-19T23:16:55+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.86 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1811 ns 1810 ns 386087 + +bm_call::via_function_ptr__Function::set_string 1809 ns 1809 ns 387440 +bm_call::via_function_ptr____Method::set_string 1812 ns 1811 ns 386622 + +bm_std::function_calls__Function::set_string 1802 ns 1802 ns 388402 +bm_std::function_calls____Method::set_string 1799 ns 1799 ns 388973 + +bm_rtl::function_calls__Function::set_string 1798 ns 1797 ns 389077 +bm_rtl::method_calls______Method::set_string 1799 ns 1798 ns 389305 + +bm_rtl::function__ErasedReturnType::set_string 1805 ns 1805 ns 387952 +bm_rtl::method____ErasedReturnType::set_string 1805 ns 1805 ns 387977 +bm_rtl::method____ErasedTargetType::set_string 1807 ns 1807 ns 387510 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1814 ns 1813 ns 386017 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3502 ns 3501 ns 199872 + +bm_call::via_function_ptr__Function::get_string 3502 ns 3502 ns 199921 +bm_call::via_function_ptr____Method::get_string 3502 ns 3501 ns 199939 + +bm_std::function_calls__Function::get_string 3501 ns 3501 ns 199951 +bm_std::function_calls____Method::get_string 3508 ns 3508 ns 199587 + +bm_rtl::function_calls__Function::get_string 3501 ns 3501 ns 199876 +bm_rtl::method_calls______Method::get_string 3503 ns 3502 ns 199842 + +bm_rtl::function__ErasedReturnType::get_string 3519 ns 3519 ns 199068 +bm_rtl::method____ErasedReturnType::get_string 3516 ns 3516 ns 199083 +bm_rtl::method____ErasedTargetType::get_string 3517 ns 3517 ns 199293 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3519 ns 3518 ns 199016 +----------------------------------- +[2026-01-19 23:17:17] >>> Run 1: workload scale = 90 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 90 iterations +============================================= + +2026-01-19T23:17:17+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.87 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1863 ns 1863 ns 375638 + +bm_call::via_function_ptr__Function::set_string 1857 ns 1857 ns 376944 +bm_call::via_function_ptr____Method::set_string 1859 ns 1859 ns 376768 + +bm_std::function_calls__Function::set_string 1879 ns 1879 ns 371755 +bm_std::function_calls____Method::set_string 1867 ns 1866 ns 374396 + +bm_rtl::function_calls__Function::set_string 1858 ns 1858 ns 376844 +bm_rtl::method_calls______Method::set_string 1858 ns 1858 ns 376799 + +bm_rtl::function__ErasedReturnType::set_string 1876 ns 1876 ns 373607 +bm_rtl::method____ErasedReturnType::set_string 1886 ns 1886 ns 370976 +bm_rtl::method____ErasedTargetType::set_string 1873 ns 1872 ns 373713 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1873 ns 1873 ns 374113 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3659 ns 3658 ns 191514 + +bm_call::via_function_ptr__Function::get_string 3651 ns 3650 ns 191687 +bm_call::via_function_ptr____Method::get_string 3651 ns 3650 ns 191718 + +bm_std::function_calls__Function::get_string 3662 ns 3661 ns 191309 +bm_std::function_calls____Method::get_string 3655 ns 3655 ns 191385 + +bm_rtl::function_calls__Function::get_string 3648 ns 3648 ns 191878 +bm_rtl::method_calls______Method::get_string 3651 ns 3651 ns 191753 + +bm_rtl::function__ErasedReturnType::get_string 3688 ns 3688 ns 189767 +bm_rtl::method____ErasedReturnType::get_string 3685 ns 3685 ns 190062 +bm_rtl::method____ErasedTargetType::get_string 3685 ns 3685 ns 189945 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3693 ns 3692 ns 189633 +----------------------------------- +[2026-01-19 23:17:39] >>> Run 2: workload scale = 90 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 90 iterations +============================================= + +2026-01-19T23:17:39+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.87 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1901 ns 1901 ns 368162 + +bm_call::via_function_ptr__Function::set_string 1900 ns 1900 ns 368222 +bm_call::via_function_ptr____Method::set_string 1903 ns 1903 ns 368462 + +bm_std::function_calls__Function::set_string 1933 ns 1933 ns 362276 +bm_std::function_calls____Method::set_string 1932 ns 1932 ns 362124 + +bm_rtl::function_calls__Function::set_string 1882 ns 1882 ns 371779 +bm_rtl::method_calls______Method::set_string 1881 ns 1881 ns 372490 + +bm_rtl::function__ErasedReturnType::set_string 1884 ns 1884 ns 371491 +bm_rtl::method____ErasedReturnType::set_string 1884 ns 1884 ns 371247 +bm_rtl::method____ErasedTargetType::set_string 1886 ns 1886 ns 371278 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1902 ns 1901 ns 368129 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3778 ns 3777 ns 185389 + +bm_call::via_function_ptr__Function::get_string 3756 ns 3756 ns 186385 +bm_call::via_function_ptr____Method::get_string 3781 ns 3780 ns 185102 + +bm_std::function_calls__Function::get_string 3739 ns 3739 ns 187219 +bm_std::function_calls____Method::get_string 3732 ns 3731 ns 187576 + +bm_rtl::function_calls__Function::get_string 3755 ns 3754 ns 186509 +bm_rtl::method_calls______Method::get_string 3779 ns 3778 ns 185306 + +bm_rtl::function__ErasedReturnType::get_string 3763 ns 3763 ns 186150 +bm_rtl::method____ErasedReturnType::get_string 3754 ns 3754 ns 186567 +bm_rtl::method____ErasedTargetType::get_string 3752 ns 3752 ns 186761 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3757 ns 3757 ns 186314 +----------------------------------- +[2026-01-19 23:18:01] >>> Run 3: workload scale = 90 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 90 iterations +============================================= + +2026-01-19T23:18:01+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.88 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1920 ns 1919 ns 364839 + +bm_call::via_function_ptr__Function::set_string 1916 ns 1916 ns 365320 +bm_call::via_function_ptr____Method::set_string 1916 ns 1915 ns 365777 + +bm_std::function_calls__Function::set_string 1902 ns 1902 ns 368265 +bm_std::function_calls____Method::set_string 1899 ns 1899 ns 368618 + +bm_rtl::function_calls__Function::set_string 1903 ns 1902 ns 368541 +bm_rtl::method_calls______Method::set_string 1910 ns 1910 ns 367711 + +bm_rtl::function__ErasedReturnType::set_string 1877 ns 1877 ns 372914 +bm_rtl::method____ErasedReturnType::set_string 1886 ns 1885 ns 371486 +bm_rtl::method____ErasedTargetType::set_string 1888 ns 1887 ns 370679 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1897 ns 1897 ns 368599 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3692 ns 3692 ns 189447 + +bm_call::via_function_ptr__Function::get_string 3689 ns 3688 ns 189708 +bm_call::via_function_ptr____Method::get_string 3689 ns 3689 ns 189672 + +bm_std::function_calls__Function::get_string 3695 ns 3694 ns 189731 +bm_std::function_calls____Method::get_string 3694 ns 3694 ns 189470 + +bm_rtl::function_calls__Function::get_string 3689 ns 3689 ns 189854 +bm_rtl::method_calls______Method::get_string 3692 ns 3692 ns 189660 + +bm_rtl::function__ErasedReturnType::get_string 3685 ns 3685 ns 190024 +bm_rtl::method____ErasedReturnType::get_string 3686 ns 3686 ns 189881 +bm_rtl::method____ErasedTargetType::get_string 3686 ns 3685 ns 189939 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3678 ns 3678 ns 190331 +----------------------------------- +[2026-01-19 23:18:24] >>> Run 1: workload scale = 100 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 100 iterations +============================================= + +2026-01-19T23:18:24+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 953.464 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.88 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1983 ns 1983 ns 352153 + +bm_call::via_function_ptr__Function::set_string 1982 ns 1982 ns 353132 +bm_call::via_function_ptr____Method::set_string 1982 ns 1982 ns 352949 + +bm_std::function_calls__Function::set_string 2006 ns 2006 ns 349040 +bm_std::function_calls____Method::set_string 1988 ns 1988 ns 351879 + +bm_rtl::function_calls__Function::set_string 1983 ns 1982 ns 353365 +bm_rtl::method_calls______Method::set_string 1983 ns 1982 ns 353211 + +bm_rtl::function__ErasedReturnType::set_string 1999 ns 1999 ns 350179 +bm_rtl::method____ErasedReturnType::set_string 2021 ns 2021 ns 344890 +bm_rtl::method____ErasedTargetType::set_string 1999 ns 1999 ns 350645 +bm_rtl::method____ErasedTargetAndReturnType::set_string 2003 ns 2002 ns 349382 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3946 ns 3945 ns 177472 + +bm_call::via_function_ptr__Function::get_string 3949 ns 3948 ns 177365 +bm_call::via_function_ptr____Method::get_string 3954 ns 3954 ns 177081 + +bm_std::function_calls__Function::get_string 3948 ns 3948 ns 177318 +bm_std::function_calls____Method::get_string 3946 ns 3945 ns 177368 + +bm_rtl::function_calls__Function::get_string 3949 ns 3949 ns 177379 +bm_rtl::method_calls______Method::get_string 3951 ns 3951 ns 177153 + +bm_rtl::function__ErasedReturnType::get_string 3963 ns 3963 ns 176629 +bm_rtl::method____ErasedReturnType::get_string 3974 ns 3974 ns 176103 +bm_rtl::method____ErasedTargetType::get_string 3959 ns 3959 ns 176758 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3972 ns 3972 ns 176227 +----------------------------------- +[2026-01-19 23:18:46] >>> Run 2: workload scale = 100 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 100 iterations +============================================= + +2026-01-19T23:18:46+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.88 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1963 ns 1962 ns 356872 + +bm_call::via_function_ptr__Function::set_string 1965 ns 1965 ns 356959 +bm_call::via_function_ptr____Method::set_string 1961 ns 1961 ns 356856 + +bm_std::function_calls__Function::set_string 1965 ns 1965 ns 356972 +bm_std::function_calls____Method::set_string 1985 ns 1985 ns 353072 + +bm_rtl::function_calls__Function::set_string 1977 ns 1977 ns 353606 +bm_rtl::method_calls______Method::set_string 1979 ns 1979 ns 352091 + +bm_rtl::function__ErasedReturnType::set_string 1999 ns 1999 ns 349499 +bm_rtl::method____ErasedReturnType::set_string 1979 ns 1979 ns 354224 +bm_rtl::method____ErasedTargetType::set_string 1980 ns 1980 ns 353401 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1982 ns 1982 ns 353521 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3952 ns 3951 ns 177102 + +bm_call::via_function_ptr__Function::get_string 3953 ns 3952 ns 176786 +bm_call::via_function_ptr____Method::get_string 3958 ns 3958 ns 176907 + +bm_std::function_calls__Function::get_string 3942 ns 3941 ns 177129 +bm_std::function_calls____Method::get_string 3954 ns 3953 ns 177506 + +bm_rtl::function_calls__Function::get_string 3951 ns 3951 ns 177178 +bm_rtl::method_calls______Method::get_string 3958 ns 3958 ns 177075 + +bm_rtl::function__ErasedReturnType::get_string 3973 ns 3972 ns 176053 +bm_rtl::method____ErasedReturnType::get_string 3968 ns 3967 ns 176677 +bm_rtl::method____ErasedTargetType::get_string 3960 ns 3959 ns 177029 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3963 ns 3963 ns 176044 +----------------------------------- +[2026-01-19 23:19:09] >>> Run 3: workload scale = 100 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 100 iterations +============================================= + +2026-01-19T23:19:09+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.89 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1968 ns 1968 ns 355257 + +bm_call::via_function_ptr__Function::set_string 1966 ns 1965 ns 355344 +bm_call::via_function_ptr____Method::set_string 1966 ns 1966 ns 356102 + +bm_std::function_calls__Function::set_string 1975 ns 1975 ns 354670 +bm_std::function_calls____Method::set_string 1975 ns 1975 ns 354660 + +bm_rtl::function_calls__Function::set_string 1968 ns 1968 ns 356032 +bm_rtl::method_calls______Method::set_string 1968 ns 1968 ns 355469 + +bm_rtl::function__ErasedReturnType::set_string 1985 ns 1985 ns 352756 +bm_rtl::method____ErasedReturnType::set_string 1986 ns 1986 ns 352599 +bm_rtl::method____ErasedTargetType::set_string 2008 ns 2008 ns 348721 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1985 ns 1984 ns 353073 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3957 ns 3957 ns 176887 + +bm_call::via_function_ptr__Function::get_string 3961 ns 3960 ns 176806 +bm_call::via_function_ptr____Method::get_string 3961 ns 3961 ns 176756 + +bm_std::function_calls__Function::get_string 3953 ns 3953 ns 176961 +bm_std::function_calls____Method::get_string 3954 ns 3953 ns 177120 + +bm_rtl::function_calls__Function::get_string 3958 ns 3958 ns 176943 +bm_rtl::method_calls______Method::get_string 3960 ns 3959 ns 176821 + +bm_rtl::function__ErasedReturnType::get_string 3978 ns 3978 ns 176017 +bm_rtl::method____ErasedReturnType::get_string 3982 ns 3982 ns 175814 +bm_rtl::method____ErasedTargetType::get_string 3973 ns 3972 ns 176287 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3982 ns 3981 ns 175813 +----------------------------------- +[2026-01-19 23:19:32] >>> Run 1: workload scale = 120 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 120 iterations +============================================= + +2026-01-19T23:19:32+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 2306.47 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.89 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 2159 ns 2159 ns 324744 + +bm_call::via_function_ptr__Function::set_string 2155 ns 2154 ns 324974 +bm_call::via_function_ptr____Method::set_string 2157 ns 2157 ns 324813 + +bm_std::function_calls__Function::set_string 2160 ns 2160 ns 324000 +bm_std::function_calls____Method::set_string 2165 ns 2165 ns 323682 + +bm_rtl::function_calls__Function::set_string 2155 ns 2155 ns 324669 +bm_rtl::method_calls______Method::set_string 2156 ns 2155 ns 324478 + +bm_rtl::function__ErasedReturnType::set_string 2176 ns 2175 ns 320756 +bm_rtl::method____ErasedReturnType::set_string 2174 ns 2174 ns 321889 +bm_rtl::method____ErasedTargetType::set_string 2200 ns 2200 ns 317433 +bm_rtl::method____ErasedTargetAndReturnType::set_string 2176 ns 2176 ns 321629 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 4621 ns 4621 ns 151211 + +bm_call::via_function_ptr__Function::get_string 4626 ns 4626 ns 151508 +bm_call::via_function_ptr____Method::get_string 4622 ns 4622 ns 151424 + +bm_std::function_calls__Function::get_string 4632 ns 4632 ns 151238 +bm_std::function_calls____Method::get_string 4626 ns 4625 ns 151353 + +bm_rtl::function_calls__Function::get_string 4619 ns 4618 ns 151221 +bm_rtl::method_calls______Method::get_string 4625 ns 4625 ns 151564 + +bm_rtl::function__ErasedReturnType::get_string 4645 ns 4644 ns 150711 +bm_rtl::method____ErasedReturnType::get_string 4655 ns 4655 ns 150667 +bm_rtl::method____ErasedTargetType::get_string 4641 ns 4640 ns 150806 +bm_rtl::method____ErasedTargetAndReturnType::get_string 4651 ns 4651 ns 150168 +----------------------------------- +[2026-01-19 23:19:55] >>> Run 2: workload scale = 120 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 120 iterations +============================================= + +2026-01-19T23:19:55+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.90 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 2246 ns 2245 ns 311778 + +bm_call::via_function_ptr__Function::set_string 2244 ns 2244 ns 312238 +bm_call::via_function_ptr____Method::set_string 2243 ns 2243 ns 312122 + +bm_std::function_calls__Function::set_string 2162 ns 2162 ns 323973 +bm_std::function_calls____Method::set_string 2164 ns 2164 ns 323396 + +bm_rtl::function_calls__Function::set_string 2220 ns 2219 ns 315305 +bm_rtl::method_calls______Method::set_string 2221 ns 2220 ns 315210 + +bm_rtl::function__ErasedReturnType::set_string 2188 ns 2188 ns 320033 +bm_rtl::method____ErasedReturnType::set_string 2191 ns 2190 ns 319572 +bm_rtl::method____ErasedTargetType::set_string 2176 ns 2175 ns 321473 +bm_rtl::method____ErasedTargetAndReturnType::set_string 2208 ns 2207 ns 316933 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 4619 ns 4619 ns 151620 + +bm_call::via_function_ptr__Function::get_string 4637 ns 4636 ns 150938 +bm_call::via_function_ptr____Method::get_string 4622 ns 4622 ns 151513 + +bm_std::function_calls__Function::get_string 4621 ns 4621 ns 151473 +bm_std::function_calls____Method::get_string 4630 ns 4630 ns 151236 + +bm_rtl::function_calls__Function::get_string 4637 ns 4636 ns 151049 +bm_rtl::method_calls______Method::get_string 4620 ns 4619 ns 151561 + +bm_rtl::function__ErasedReturnType::get_string 4650 ns 4650 ns 150571 +bm_rtl::method____ErasedReturnType::get_string 4648 ns 4647 ns 150593 +bm_rtl::method____ErasedTargetType::get_string 4641 ns 4640 ns 150876 +bm_rtl::method____ErasedTargetAndReturnType::get_string 4650 ns 4650 ns 150607 +----------------------------------- +[2026-01-19 23:20:19] >>> Run 3: workload scale = 120 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 120 iterations +============================================= + +2026-01-19T23:20:19+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.90 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 2156 ns 2156 ns 324715 + +bm_call::via_function_ptr__Function::set_string 2156 ns 2155 ns 324995 +bm_call::via_function_ptr____Method::set_string 2155 ns 2154 ns 325332 + +bm_std::function_calls__Function::set_string 2184 ns 2184 ns 320585 +bm_std::function_calls____Method::set_string 2162 ns 2161 ns 324033 + +bm_rtl::function_calls__Function::set_string 2154 ns 2153 ns 325083 +bm_rtl::method_calls______Method::set_string 2154 ns 2154 ns 324786 + +bm_rtl::function__ErasedReturnType::set_string 2176 ns 2176 ns 321714 +bm_rtl::method____ErasedReturnType::set_string 2204 ns 2204 ns 317451 +bm_rtl::method____ErasedTargetType::set_string 2176 ns 2176 ns 321731 +bm_rtl::method____ErasedTargetAndReturnType::set_string 2179 ns 2179 ns 321077 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 4620 ns 4620 ns 151475 + +bm_call::via_function_ptr__Function::get_string 4620 ns 4619 ns 151555 +bm_call::via_function_ptr____Method::get_string 4626 ns 4625 ns 151381 + +bm_std::function_calls__Function::get_string 4628 ns 4628 ns 151209 +bm_std::function_calls____Method::get_string 4618 ns 4619 ns 151486 + +bm_rtl::function_calls__Function::get_string 4621 ns 4621 ns 151490 +bm_rtl::method_calls______Method::get_string 4619 ns 4619 ns 151593 + +bm_rtl::function__ErasedReturnType::get_string 4647 ns 4647 ns 150680 +bm_rtl::method____ErasedReturnType::get_string 4654 ns 4655 ns 150375 +bm_rtl::method____ErasedTargetType::get_string 4648 ns 4647 ns 150602 +bm_rtl::method____ErasedTargetAndReturnType::get_string 4657 ns 4657 ns 150364 +----------------------------------- +[2026-01-19 23:20:43] >>> Run 1: workload scale = 150 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 150 iterations +============================================= + +2026-01-19T23:20:43+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.91 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 3535 ns 3535 ns 197933 + +bm_call::via_function_ptr__Function::set_string 3532 ns 3532 ns 198392 +bm_call::via_function_ptr____Method::set_string 3533 ns 3533 ns 198165 + +bm_std::function_calls__Function::set_string 3543 ns 3543 ns 197567 +bm_std::function_calls____Method::set_string 3578 ns 3578 ns 195738 + +bm_rtl::function_calls__Function::set_string 3562 ns 3562 ns 196466 +bm_rtl::method_calls______Method::set_string 3562 ns 3563 ns 196443 + +bm_rtl::function__ErasedReturnType::set_string 3619 ns 3620 ns 193386 +bm_rtl::method____ErasedReturnType::set_string 3642 ns 3642 ns 192226 +bm_rtl::method____ErasedTargetType::set_string 3564 ns 3564 ns 196370 +bm_rtl::method____ErasedTargetAndReturnType::set_string 3646 ns 3646 ns 192007 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 6783 ns 6783 ns 103274 + +bm_call::via_function_ptr__Function::get_string 6798 ns 6799 ns 102812 +bm_call::via_function_ptr____Method::get_string 6800 ns 6800 ns 102962 + +bm_std::function_calls__Function::get_string 6784 ns 6784 ns 103177 +bm_std::function_calls____Method::get_string 6783 ns 6783 ns 103199 + +bm_rtl::function_calls__Function::get_string 6796 ns 6797 ns 103001 +bm_rtl::method_calls______Method::get_string 6798 ns 6798 ns 102869 + +bm_rtl::function__ErasedReturnType::get_string 6878 ns 6878 ns 101790 +bm_rtl::method____ErasedReturnType::get_string 6825 ns 6825 ns 102576 +bm_rtl::method____ErasedTargetType::get_string 6800 ns 6800 ns 102981 +bm_rtl::method____ErasedTargetAndReturnType::get_string 6892 ns 6893 ns 101517 +----------------------------------- +[2026-01-19 23:21:03] >>> Run 2: workload scale = 150 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 150 iterations +============================================= + +2026-01-19T23:21:03+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.91 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 3596 ns 3596 ns 194415 + +bm_call::via_function_ptr__Function::set_string 3595 ns 3595 ns 194577 +bm_call::via_function_ptr____Method::set_string 3595 ns 3595 ns 194709 + +bm_std::function_calls__Function::set_string 3570 ns 3570 ns 195823 +bm_std::function_calls____Method::set_string 3567 ns 3567 ns 196258 + +bm_rtl::function_calls__Function::set_string 3558 ns 3558 ns 196659 +bm_rtl::method_calls______Method::set_string 3560 ns 3560 ns 196795 + +bm_rtl::function__ErasedReturnType::set_string 3577 ns 3577 ns 195584 +bm_rtl::method____ErasedReturnType::set_string 3581 ns 3580 ns 195594 +bm_rtl::method____ErasedTargetType::set_string 3582 ns 3583 ns 195321 +bm_rtl::method____ErasedTargetAndReturnType::set_string 3621 ns 3622 ns 193209 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 6610 ns 6611 ns 105907 + +bm_call::via_function_ptr__Function::get_string 6624 ns 6624 ns 105696 +bm_call::via_function_ptr____Method::get_string 6622 ns 6622 ns 105724 + +bm_std::function_calls__Function::get_string 6615 ns 6616 ns 105759 +bm_std::function_calls____Method::get_string 6628 ns 6627 ns 105578 + +bm_rtl::function_calls__Function::get_string 6618 ns 6619 ns 105749 +bm_rtl::method_calls______Method::get_string 6619 ns 6619 ns 105730 + +bm_rtl::function__ErasedReturnType::get_string 6639 ns 6639 ns 105406 +bm_rtl::method____ErasedReturnType::get_string 6631 ns 6632 ns 105574 +bm_rtl::method____ErasedTargetType::get_string 6627 ns 6628 ns 105646 +bm_rtl::method____ErasedTargetAndReturnType::get_string 6630 ns 6630 ns 105509 +----------------------------------- +[2026-01-19 23:21:24] >>> Run 3: workload scale = 150 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 150 iterations +============================================= + +2026-01-19T23:21:24+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.91 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 3514 ns 3514 ns 199066 + +bm_call::via_function_ptr__Function::set_string 3515 ns 3514 ns 199130 +bm_call::via_function_ptr____Method::set_string 3514 ns 3514 ns 199175 + +bm_std::function_calls__Function::set_string 3526 ns 3526 ns 198508 +bm_std::function_calls____Method::set_string 3524 ns 3524 ns 198536 + +bm_rtl::function_calls__Function::set_string 3516 ns 3516 ns 199092 +bm_rtl::method_calls______Method::set_string 3518 ns 3518 ns 198918 + +bm_rtl::function__ErasedReturnType::set_string 3539 ns 3539 ns 197865 +bm_rtl::method____ErasedReturnType::set_string 3540 ns 3540 ns 197836 +bm_rtl::method____ErasedTargetType::set_string 3579 ns 3579 ns 195608 +bm_rtl::method____ErasedTargetAndReturnType::set_string 3537 ns 3538 ns 198024 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 6601 ns 6600 ns 106079 + +bm_call::via_function_ptr__Function::get_string 6610 ns 6611 ns 105837 +bm_call::via_function_ptr____Method::get_string 6611 ns 6612 ns 105817 + +bm_std::function_calls__Function::get_string 6605 ns 6603 ns 106033 +bm_std::function_calls____Method::get_string 6604 ns 6603 ns 105956 + +bm_rtl::function_calls__Function::get_string 6609 ns 6609 ns 106000 +bm_rtl::method_calls______Method::get_string 6610 ns 6609 ns 105922 + +bm_rtl::function__ErasedReturnType::get_string 6632 ns 6632 ns 105525 +bm_rtl::method____ErasedReturnType::get_string 6634 ns 6633 ns 105489 +bm_rtl::method____ErasedTargetType::get_string 6622 ns 6622 ns 105723 +bm_rtl::method____ErasedTargetAndReturnType::get_string 6631 ns 6631 ns 105505 +----------------------------------- +All benchmarks completed. diff --git a/docs/benchmark_runs_string_view.log b/docs/benchmark_runs_string_view.log new file mode 100644 index 00000000..ceb8d40a --- /dev/null +++ b/docs/benchmark_runs_string_view.log @@ -0,0 +1,3167 @@ +Starting benchmark runs... +Binary: ./bin/RTLBenchmarkApp +Log: ./benchmark_runs.log +=================================== +[2026-01-19 22:16:59] >>> Run 1: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T22:16:59+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 2685.07 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.63, 0.46, 0.19 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 0.614 ns 0.614 ns 1000000000 + +bm_call::via_function_ptr__Function::set_string 1.02 ns 1.02 ns 683568677 +bm_call::via_function_ptr____Method::set_string 1.23 ns 1.23 ns 576541050 + +bm_std::function_calls__Function::set_string 1.23 ns 1.23 ns 569030602 +bm_std::function_calls____Method::set_string 1.52 ns 1.52 ns 467624796 + +bm_rtl::function_calls__Function::set_string 1.02 ns 1.02 ns 684146847 +bm_rtl::method_calls______Method::set_string 1.43 ns 1.43 ns 488587084 + +bm_rtl::function__ErasedReturnType::set_string 2.82 ns 2.82 ns 249372110 +bm_rtl::method____ErasedReturnType::set_string 3.31 ns 3.31 ns 212147428 +bm_rtl::method____ErasedTargetType::set_string 3.89 ns 3.89 ns 180614166 +bm_rtl::method____ErasedTargetAndReturnType::set_string 4.54 ns 4.54 ns 155811336 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1.44 ns 1.44 ns 488611796 + +bm_call::via_function_ptr__Function::get_string 2.66 ns 2.66 ns 263520027 +bm_call::via_function_ptr____Method::get_string 2.46 ns 2.46 ns 285111058 + +bm_std::function_calls__Function::get_string 2.46 ns 2.46 ns 285121216 +bm_std::function_calls____Method::get_string 3.20 ns 3.20 ns 219769186 + +bm_rtl::function_calls__Function::get_string 2.26 ns 2.26 ns 310201816 +bm_rtl::method_calls______Method::get_string 2.76 ns 2.76 ns 260137507 + +bm_rtl::function__ErasedReturnType::get_string 13.7 ns 13.7 ns 51217947 +bm_rtl::method____ErasedReturnType::get_string 14.0 ns 14.0 ns 49918633 +bm_rtl::method____ErasedTargetType::get_string 6.75 ns 6.75 ns 103663468 +bm_rtl::method____ErasedTargetAndReturnType::get_string 15.5 ns 15.5 ns 45414826 +----------------------------------- +[2026-01-19 22:17:19] >>> Run 2: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T22:17:19+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.74, 0.50, 0.21 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 0.615 ns 0.615 ns 1000000000 + +bm_call::via_function_ptr__Function::set_string 1.03 ns 1.03 ns 684181498 +bm_call::via_function_ptr____Method::set_string 1.21 ns 1.21 ns 569642730 + +bm_std::function_calls__Function::set_string 1.23 ns 1.23 ns 569800978 +bm_std::function_calls____Method::set_string 1.52 ns 1.52 ns 450875649 + +bm_rtl::function_calls__Function::set_string 1.02 ns 1.02 ns 683995818 +bm_rtl::method_calls______Method::set_string 1.43 ns 1.43 ns 488611687 + +bm_rtl::function__ErasedReturnType::set_string 2.83 ns 2.83 ns 246485658 +bm_rtl::method____ErasedReturnType::set_string 3.30 ns 3.30 ns 214354534 +bm_rtl::method____ErasedTargetType::set_string 3.89 ns 3.89 ns 180045506 +bm_rtl::method____ErasedTargetAndReturnType::set_string 4.51 ns 4.51 ns 154404330 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1.44 ns 1.44 ns 487781988 + +bm_call::via_function_ptr__Function::get_string 2.66 ns 2.66 ns 263194125 +bm_call::via_function_ptr____Method::get_string 2.46 ns 2.46 ns 285136636 + +bm_std::function_calls__Function::get_string 2.46 ns 2.46 ns 285136994 +bm_std::function_calls____Method::get_string 3.18 ns 3.18 ns 228110017 + +bm_rtl::function_calls__Function::get_string 2.26 ns 2.26 ns 310208330 +bm_rtl::method_calls______Method::get_string 2.72 ns 2.72 ns 256333628 + +bm_rtl::function__ErasedReturnType::get_string 13.8 ns 13.8 ns 51058389 +bm_rtl::method____ErasedReturnType::get_string 14.1 ns 14.1 ns 49524008 +bm_rtl::method____ErasedTargetType::get_string 6.75 ns 6.75 ns 103685569 +bm_rtl::method____ErasedTargetAndReturnType::get_string 15.1 ns 15.1 ns 46352459 +----------------------------------- +[2026-01-19 22:17:39] >>> Run 3: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T22:17:39+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.81, 0.53, 0.22 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 0.614 ns 0.614 ns 1000000000 + +bm_call::via_function_ptr__Function::set_string 1.02 ns 1.02 ns 683812844 +bm_call::via_function_ptr____Method::set_string 1.22 ns 1.21 ns 577612805 + +bm_std::function_calls__Function::set_string 1.23 ns 1.23 ns 569775056 +bm_std::function_calls____Method::set_string 1.59 ns 1.59 ns 434079632 + +bm_rtl::function_calls__Function::set_string 1.02 ns 1.02 ns 683787447 +bm_rtl::method_calls______Method::set_string 1.42 ns 1.42 ns 488613617 + +bm_rtl::function__ErasedReturnType::set_string 7.37 ns 7.37 ns 95035791 +bm_rtl::method____ErasedReturnType::set_string 7.78 ns 7.78 ns 90042208 +bm_rtl::method____ErasedTargetType::set_string 3.90 ns 3.90 ns 180433649 +bm_rtl::method____ErasedTargetAndReturnType::set_string 8.60 ns 8.60 ns 81448564 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1.44 ns 1.44 ns 488585969 + +bm_call::via_function_ptr__Function::get_string 2.66 ns 2.66 ns 265152552 +bm_call::via_function_ptr____Method::get_string 2.46 ns 2.46 ns 284574733 + +bm_std::function_calls__Function::get_string 2.46 ns 2.46 ns 285006675 +bm_std::function_calls____Method::get_string 3.15 ns 3.15 ns 222331260 + +bm_rtl::function_calls__Function::get_string 2.26 ns 2.26 ns 310066005 +bm_rtl::method_calls______Method::get_string 2.67 ns 2.67 ns 253455004 + +bm_rtl::function__ErasedReturnType::get_string 13.7 ns 13.7 ns 50596278 +bm_rtl::method____ErasedReturnType::get_string 14.1 ns 14.1 ns 49241845 +bm_rtl::method____ErasedTargetType::get_string 6.76 ns 6.76 ns 103534631 +bm_rtl::method____ErasedTargetAndReturnType::get_string 15.2 ns 15.2 ns 46787119 +----------------------------------- +[2026-01-19 22:17:59] >>> Run 4: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T22:17:59+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.87, 0.56, 0.24 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 0.615 ns 0.614 ns 1000000000 + +bm_call::via_function_ptr__Function::set_string 1.02 ns 1.02 ns 682977689 +bm_call::via_function_ptr____Method::set_string 1.23 ns 1.23 ns 563075836 + +bm_std::function_calls__Function::set_string 1.23 ns 1.23 ns 569603803 +bm_std::function_calls____Method::set_string 1.54 ns 1.54 ns 460593978 + +bm_rtl::function_calls__Function::set_string 1.02 ns 1.02 ns 683892125 +bm_rtl::method_calls______Method::set_string 1.43 ns 1.43 ns 488236125 + +bm_rtl::function__ErasedReturnType::set_string 7.37 ns 7.37 ns 95016114 +bm_rtl::method____ErasedReturnType::set_string 7.78 ns 7.78 ns 90024009 +bm_rtl::method____ErasedTargetType::set_string 3.89 ns 3.89 ns 180054936 +bm_rtl::method____ErasedTargetAndReturnType::set_string 8.60 ns 8.60 ns 81331959 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1.43 ns 1.43 ns 488678219 + +bm_call::via_function_ptr__Function::get_string 2.66 ns 2.66 ns 264051337 +bm_call::via_function_ptr____Method::get_string 2.46 ns 2.46 ns 285120509 + +bm_std::function_calls__Function::get_string 2.46 ns 2.46 ns 285112848 +bm_std::function_calls____Method::get_string 3.23 ns 3.23 ns 226611386 + +bm_rtl::function_calls__Function::get_string 2.26 ns 2.26 ns 310198473 +bm_rtl::method_calls______Method::get_string 2.70 ns 2.70 ns 258499213 + +bm_rtl::function__ErasedReturnType::get_string 13.6 ns 13.6 ns 51481253 +bm_rtl::method____ErasedReturnType::get_string 14.1 ns 14.1 ns 50116508 +bm_rtl::method____ErasedTargetType::get_string 6.76 ns 6.76 ns 103642665 +bm_rtl::method____ErasedTargetAndReturnType::get_string 15.1 ns 15.1 ns 46654405 +----------------------------------- +[2026-01-19 22:18:18] >>> Run 5: workload scale = 0 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 0 iterations +============================================= + +2026-01-19T22:18:18+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.90, 0.59, 0.26 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 0.614 ns 0.614 ns 1000000000 + +bm_call::via_function_ptr__Function::set_string 1.02 ns 1.02 ns 680343092 +bm_call::via_function_ptr____Method::set_string 1.23 ns 1.23 ns 575099292 + +bm_std::function_calls__Function::set_string 1.23 ns 1.23 ns 569190838 +bm_std::function_calls____Method::set_string 1.49 ns 1.49 ns 452799580 + +bm_rtl::function_calls__Function::set_string 1.02 ns 1.02 ns 684190319 +bm_rtl::method_calls______Method::set_string 1.43 ns 1.43 ns 490962912 + +bm_rtl::function__ErasedReturnType::set_string 2.82 ns 2.82 ns 246594378 +bm_rtl::method____ErasedReturnType::set_string 3.33 ns 3.33 ns 211691857 +bm_rtl::method____ErasedTargetType::set_string 3.89 ns 3.89 ns 180435897 +bm_rtl::method____ErasedTargetAndReturnType::set_string 4.52 ns 4.52 ns 156477629 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1.43 ns 1.43 ns 487577300 + +bm_call::via_function_ptr__Function::get_string 2.66 ns 2.66 ns 263417306 +bm_call::via_function_ptr____Method::get_string 2.46 ns 2.46 ns 285094736 + +bm_std::function_calls__Function::get_string 2.46 ns 2.46 ns 285121796 +bm_std::function_calls____Method::get_string 3.16 ns 3.16 ns 215202059 + +bm_rtl::function_calls__Function::get_string 2.26 ns 2.26 ns 310197791 +bm_rtl::method_calls______Method::get_string 2.76 ns 2.76 ns 258111711 + +bm_rtl::function__ErasedReturnType::get_string 13.7 ns 13.7 ns 51303361 +bm_rtl::method____ErasedReturnType::get_string 14.1 ns 14.1 ns 50044327 +bm_rtl::method____ErasedTargetType::get_string 6.76 ns 6.76 ns 103673181 +bm_rtl::method____ErasedTargetAndReturnType::get_string 15.1 ns 15.1 ns 46222419 +----------------------------------- +[2026-01-19 22:18:39] >>> Run 1: workload scale = 1 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 1 iterations +============================================= + +2026-01-19T22:18:39+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.93, 0.62, 0.28 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 14.2 ns 14.2 ns 47602979 + +bm_call::via_function_ptr__Function::set_string 14.7 ns 14.7 ns 47551280 +bm_call::via_function_ptr____Method::set_string 14.5 ns 14.5 ns 48814713 + +bm_std::function_calls__Function::set_string 14.8 ns 14.8 ns 48125351 +bm_std::function_calls____Method::set_string 15.0 ns 15.0 ns 45842215 + +bm_rtl::function_calls__Function::set_string 14.6 ns 14.6 ns 47596122 +bm_rtl::method_calls______Method::set_string 14.8 ns 14.8 ns 47688533 + +bm_rtl::function__ErasedReturnType::set_string 16.3 ns 16.3 ns 43204263 +bm_rtl::method____ErasedReturnType::set_string 17.4 ns 17.4 ns 39803981 +bm_rtl::method____ErasedTargetType::set_string 17.4 ns 17.4 ns 40619050 +bm_rtl::method____ErasedTargetAndReturnType::set_string 17.5 ns 17.5 ns 39261182 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 19.8 ns 19.8 ns 35318159 + +bm_call::via_function_ptr__Function::get_string 19.9 ns 19.9 ns 34920150 +bm_call::via_function_ptr____Method::get_string 19.9 ns 19.9 ns 35041102 + +bm_std::function_calls__Function::get_string 20.3 ns 20.3 ns 34279465 +bm_std::function_calls____Method::get_string 20.7 ns 20.7 ns 33535205 + +bm_rtl::function_calls__Function::get_string 20.0 ns 20.0 ns 34773001 +bm_rtl::method_calls______Method::get_string 20.0 ns 20.0 ns 34838388 + +bm_rtl::function__ErasedReturnType::get_string 32.0 ns 32.0 ns 22025260 +bm_rtl::method____ErasedReturnType::get_string 32.3 ns 32.3 ns 21635178 +bm_rtl::method____ErasedTargetType::get_string 24.1 ns 24.1 ns 29030859 +bm_rtl::method____ErasedTargetAndReturnType::get_string 33.7 ns 33.6 ns 20685409 +----------------------------------- +[2026-01-19 22:18:59] >>> Run 2: workload scale = 1 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 1 iterations +============================================= + +2026-01-19T22:18:59+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.95, 0.65, 0.29 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 14.3 ns 14.3 ns 48584646 + +bm_call::via_function_ptr__Function::set_string 15.0 ns 15.0 ns 46029690 +bm_call::via_function_ptr____Method::set_string 14.9 ns 14.9 ns 46651918 + +bm_std::function_calls__Function::set_string 15.5 ns 15.5 ns 46957480 +bm_std::function_calls____Method::set_string 15.3 ns 15.3 ns 43780461 + +bm_rtl::function_calls__Function::set_string 15.0 ns 15.0 ns 47249334 +bm_rtl::method_calls______Method::set_string 14.8 ns 14.8 ns 47018811 + +bm_rtl::function__ErasedReturnType::set_string 16.6 ns 16.6 ns 41801460 +bm_rtl::method____ErasedReturnType::set_string 17.4 ns 17.4 ns 41245734 +bm_rtl::method____ErasedTargetType::set_string 17.4 ns 17.4 ns 40022891 +bm_rtl::method____ErasedTargetAndReturnType::set_string 17.9 ns 17.9 ns 39375751 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 25.0 ns 25.0 ns 27910450 + +bm_call::via_function_ptr__Function::get_string 25.0 ns 25.0 ns 27970128 +bm_call::via_function_ptr____Method::get_string 25.2 ns 25.1 ns 27845622 + +bm_std::function_calls__Function::get_string 25.2 ns 25.2 ns 27757309 +bm_std::function_calls____Method::get_string 25.3 ns 25.3 ns 27601367 + +bm_rtl::function_calls__Function::get_string 25.0 ns 25.0 ns 28025612 +bm_rtl::method_calls______Method::get_string 25.2 ns 25.2 ns 27785388 + +bm_rtl::function__ErasedReturnType::get_string 31.7 ns 31.7 ns 22028623 +bm_rtl::method____ErasedReturnType::get_string 32.3 ns 32.3 ns 21724774 +bm_rtl::method____ErasedTargetType::get_string 29.4 ns 29.4 ns 23749156 +bm_rtl::method____ErasedTargetAndReturnType::get_string 33.4 ns 33.4 ns 20507660 +----------------------------------- +[2026-01-19 22:19:19] >>> Run 3: workload scale = 1 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 1 iterations +============================================= + +2026-01-19T22:19:19+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.97, 0.67, 0.31 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 14.5 ns 14.5 ns 48240969 + +bm_call::via_function_ptr__Function::set_string 14.9 ns 14.9 ns 46922624 +bm_call::via_function_ptr____Method::set_string 14.9 ns 14.9 ns 46873657 + +bm_std::function_calls__Function::set_string 15.0 ns 15.0 ns 46979264 +bm_std::function_calls____Method::set_string 14.8 ns 14.8 ns 46821025 + +bm_rtl::function_calls__Function::set_string 14.9 ns 14.9 ns 47090225 +bm_rtl::method_calls______Method::set_string 14.9 ns 14.9 ns 47324383 + +bm_rtl::function__ErasedReturnType::set_string 16.5 ns 16.4 ns 42457769 +bm_rtl::method____ErasedReturnType::set_string 16.6 ns 16.6 ns 41747381 +bm_rtl::method____ErasedTargetType::set_string 17.3 ns 17.3 ns 40942180 +bm_rtl::method____ErasedTargetAndReturnType::set_string 19.2 ns 19.2 ns 36853482 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 20.2 ns 20.2 ns 34838734 + +bm_call::via_function_ptr__Function::get_string 20.1 ns 20.1 ns 34908842 +bm_call::via_function_ptr____Method::get_string 20.2 ns 20.2 ns 34891499 + +bm_std::function_calls__Function::get_string 20.3 ns 20.3 ns 34489947 +bm_std::function_calls____Method::get_string 20.5 ns 20.5 ns 34164828 + +bm_rtl::function_calls__Function::get_string 20.1 ns 20.1 ns 34860515 +bm_rtl::method_calls______Method::get_string 20.1 ns 20.1 ns 34509987 + +bm_rtl::function__ErasedReturnType::get_string 32.0 ns 32.0 ns 21715254 +bm_rtl::method____ErasedReturnType::get_string 32.5 ns 32.5 ns 21786883 +bm_rtl::method____ErasedTargetType::get_string 24.6 ns 24.6 ns 28372972 +bm_rtl::method____ErasedTargetAndReturnType::get_string 33.7 ns 33.7 ns 20781704 +----------------------------------- +[2026-01-19 22:19:40] >>> Run 1: workload scale = 5 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 5 iterations +============================================= + +2026-01-19T22:19:40+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 4865.77 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.98, 0.69, 0.32 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 105 ns 105 ns 6653489 + +bm_call::via_function_ptr__Function::set_string 107 ns 107 ns 6492983 +bm_call::via_function_ptr____Method::set_string 107 ns 107 ns 6535246 + +bm_std::function_calls__Function::set_string 107 ns 107 ns 6557447 +bm_std::function_calls____Method::set_string 108 ns 107 ns 6525899 + +bm_rtl::function_calls__Function::set_string 107 ns 107 ns 6529877 +bm_rtl::method_calls______Method::set_string 107 ns 107 ns 6500537 + +bm_rtl::function__ErasedReturnType::set_string 109 ns 109 ns 6433512 +bm_rtl::method____ErasedReturnType::set_string 109 ns 109 ns 6441045 +bm_rtl::method____ErasedTargetType::set_string 109 ns 109 ns 6430367 +bm_rtl::method____ErasedTargetAndReturnType::set_string 110 ns 110 ns 6367909 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 141 ns 141 ns 4992850 + +bm_call::via_function_ptr__Function::get_string 141 ns 141 ns 4947770 +bm_call::via_function_ptr____Method::get_string 140 ns 140 ns 5010278 + +bm_std::function_calls__Function::get_string 141 ns 141 ns 4978328 +bm_std::function_calls____Method::get_string 141 ns 141 ns 4892890 + +bm_rtl::function_calls__Function::get_string 141 ns 141 ns 4969715 +bm_rtl::method_calls______Method::get_string 140 ns 140 ns 4989739 + +bm_rtl::function__ErasedReturnType::get_string 150 ns 150 ns 4643950 +bm_rtl::method____ErasedReturnType::get_string 150 ns 150 ns 4635435 +bm_rtl::method____ErasedTargetType::get_string 143 ns 143 ns 4896326 +bm_rtl::method____ErasedTargetAndReturnType::get_string 151 ns 151 ns 4619363 +----------------------------------- +[2026-01-19 22:19:58] >>> Run 2: workload scale = 5 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 5 iterations +============================================= + +2026-01-19T22:19:58+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.98, 0.71, 0.34 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 103 ns 103 ns 6802745 + +bm_call::via_function_ptr__Function::set_string 105 ns 105 ns 6625968 +bm_call::via_function_ptr____Method::set_string 105 ns 105 ns 6695044 + +bm_std::function_calls__Function::set_string 105 ns 105 ns 6624223 +bm_std::function_calls____Method::set_string 105 ns 105 ns 6663752 + +bm_rtl::function_calls__Function::set_string 105 ns 105 ns 6681833 +bm_rtl::method_calls______Method::set_string 105 ns 105 ns 6668827 + +bm_rtl::function__ErasedReturnType::set_string 107 ns 107 ns 6536747 +bm_rtl::method____ErasedReturnType::set_string 107 ns 107 ns 6504031 +bm_rtl::method____ErasedTargetType::set_string 108 ns 108 ns 6469742 +bm_rtl::method____ErasedTargetAndReturnType::set_string 109 ns 109 ns 6479236 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 123 ns 123 ns 5698362 + +bm_call::via_function_ptr__Function::get_string 123 ns 123 ns 5718997 +bm_call::via_function_ptr____Method::get_string 122 ns 122 ns 5745089 + +bm_std::function_calls__Function::get_string 123 ns 123 ns 5703641 +bm_std::function_calls____Method::get_string 122 ns 122 ns 5715659 + +bm_rtl::function_calls__Function::get_string 123 ns 123 ns 5702709 +bm_rtl::method_calls______Method::get_string 123 ns 123 ns 5717900 + +bm_rtl::function__ErasedReturnType::get_string 131 ns 131 ns 5383228 +bm_rtl::method____ErasedReturnType::get_string 130 ns 130 ns 5398546 +bm_rtl::method____ErasedTargetType::get_string 125 ns 125 ns 5610784 +bm_rtl::method____ErasedTargetAndReturnType::get_string 132 ns 132 ns 5317235 +----------------------------------- +[2026-01-19 22:20:16] >>> Run 3: workload scale = 5 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 5 iterations +============================================= + +2026-01-19T22:20:16+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 1814.12 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.99, 0.73, 0.35 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 103 ns 103 ns 6759777 + +bm_call::via_function_ptr__Function::set_string 105 ns 105 ns 6599680 +bm_call::via_function_ptr____Method::set_string 105 ns 105 ns 6637960 + +bm_std::function_calls__Function::set_string 105 ns 105 ns 6634870 +bm_std::function_calls____Method::set_string 105 ns 105 ns 6629614 + +bm_rtl::function_calls__Function::set_string 105 ns 105 ns 6700534 +bm_rtl::method_calls______Method::set_string 105 ns 105 ns 6641565 + +bm_rtl::function__ErasedReturnType::set_string 107 ns 107 ns 6489816 +bm_rtl::method____ErasedReturnType::set_string 107 ns 107 ns 6457036 +bm_rtl::method____ErasedTargetType::set_string 108 ns 108 ns 6480403 +bm_rtl::method____ErasedTargetAndReturnType::set_string 109 ns 109 ns 6477196 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 123 ns 123 ns 5671951 + +bm_call::via_function_ptr__Function::get_string 123 ns 123 ns 5695007 +bm_call::via_function_ptr____Method::get_string 123 ns 123 ns 5701825 + +bm_std::function_calls__Function::get_string 123 ns 123 ns 5623063 +bm_std::function_calls____Method::get_string 122 ns 122 ns 5746720 + +bm_rtl::function_calls__Function::get_string 123 ns 123 ns 5685952 +bm_rtl::method_calls______Method::get_string 122 ns 122 ns 5737821 + +bm_rtl::function__ErasedReturnType::get_string 130 ns 130 ns 5363587 +bm_rtl::method____ErasedReturnType::get_string 130 ns 130 ns 5405976 +bm_rtl::method____ErasedTargetType::get_string 125 ns 125 ns 5623858 +bm_rtl::method____ErasedTargetAndReturnType::get_string 132 ns 132 ns 5294497 +----------------------------------- +[2026-01-19 22:20:35] >>> Run 1: workload scale = 10 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 10 iterations +============================================= + +2026-01-19T22:20:35+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 0.99, 0.75, 0.37 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 180 ns 180 ns 3892288 + +bm_call::via_function_ptr__Function::set_string 175 ns 175 ns 4013942 +bm_call::via_function_ptr____Method::set_string 175 ns 175 ns 4038326 + +bm_std::function_calls__Function::set_string 175 ns 175 ns 4011236 +bm_std::function_calls____Method::set_string 176 ns 176 ns 3969974 + +bm_rtl::function_calls__Function::set_string 175 ns 175 ns 4008955 +bm_rtl::method_calls______Method::set_string 175 ns 175 ns 4005545 + +bm_rtl::function__ErasedReturnType::set_string 178 ns 178 ns 3913334 +bm_rtl::method____ErasedReturnType::set_string 178 ns 178 ns 3957340 +bm_rtl::method____ErasedTargetType::set_string 178 ns 178 ns 3958988 +bm_rtl::method____ErasedTargetAndReturnType::set_string 179 ns 179 ns 3910029 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 236 ns 236 ns 2973260 + +bm_call::via_function_ptr__Function::get_string 236 ns 236 ns 2986989 +bm_call::via_function_ptr____Method::get_string 235 ns 235 ns 2980300 + +bm_std::function_calls__Function::get_string 236 ns 235 ns 2959537 +bm_std::function_calls____Method::get_string 236 ns 236 ns 2952611 + +bm_rtl::function_calls__Function::get_string 235 ns 235 ns 2982781 +bm_rtl::method_calls______Method::get_string 236 ns 236 ns 2962352 + +bm_rtl::function__ErasedReturnType::get_string 241 ns 241 ns 2897516 +bm_rtl::method____ErasedReturnType::get_string 242 ns 242 ns 2911112 +bm_rtl::method____ErasedTargetType::get_string 239 ns 240 ns 2930612 +bm_rtl::method____ErasedTargetAndReturnType::get_string 242 ns 242 ns 2885077 +----------------------------------- +[2026-01-19 22:20:55] >>> Run 2: workload scale = 10 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 10 iterations +============================================= + +2026-01-19T22:20:55+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.77, 0.38 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 165 ns 165 ns 4275197 + +bm_call::via_function_ptr__Function::set_string 168 ns 168 ns 4170135 +bm_call::via_function_ptr____Method::set_string 167 ns 167 ns 4163825 + +bm_std::function_calls__Function::set_string 169 ns 169 ns 4159852 +bm_std::function_calls____Method::set_string 170 ns 170 ns 4124142 + +bm_rtl::function_calls__Function::set_string 169 ns 169 ns 4126732 +bm_rtl::method_calls______Method::set_string 169 ns 169 ns 4134774 + +bm_rtl::function__ErasedReturnType::set_string 172 ns 172 ns 4038085 +bm_rtl::method____ErasedReturnType::set_string 171 ns 171 ns 4105946 +bm_rtl::method____ErasedTargetType::set_string 171 ns 171 ns 4105870 +bm_rtl::method____ErasedTargetAndReturnType::set_string 178 ns 178 ns 3951279 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 207 ns 207 ns 3403062 + +bm_call::via_function_ptr__Function::get_string 206 ns 206 ns 3379512 +bm_call::via_function_ptr____Method::get_string 206 ns 206 ns 3363220 + +bm_std::function_calls__Function::get_string 206 ns 206 ns 3434973 +bm_std::function_calls____Method::get_string 205 ns 205 ns 3398931 + +bm_rtl::function_calls__Function::get_string 206 ns 206 ns 3390234 +bm_rtl::method_calls______Method::get_string 205 ns 205 ns 3428973 + +bm_rtl::function__ErasedReturnType::get_string 212 ns 212 ns 3290226 +bm_rtl::method____ErasedReturnType::get_string 213 ns 213 ns 3308638 +bm_rtl::method____ErasedTargetType::get_string 213 ns 213 ns 3278298 +bm_rtl::method____ErasedTargetAndReturnType::get_string 213 ns 213 ns 3265716 +----------------------------------- +[2026-01-19 22:21:15] >>> Run 3: workload scale = 10 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 10 iterations +============================================= + +2026-01-19T22:21:15+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.78, 0.40 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 165 ns 165 ns 4267506 + +bm_call::via_function_ptr__Function::set_string 160 ns 160 ns 4395709 +bm_call::via_function_ptr____Method::set_string 159 ns 159 ns 4430252 + +bm_std::function_calls__Function::set_string 159 ns 159 ns 4404565 +bm_std::function_calls____Method::set_string 160 ns 160 ns 4313674 + +bm_rtl::function_calls__Function::set_string 160 ns 160 ns 4373147 +bm_rtl::method_calls______Method::set_string 159 ns 159 ns 4369703 + +bm_rtl::function__ErasedReturnType::set_string 161 ns 161 ns 4305630 +bm_rtl::method____ErasedReturnType::set_string 162 ns 162 ns 4292450 +bm_rtl::method____ErasedTargetType::set_string 161 ns 161 ns 4356887 +bm_rtl::method____ErasedTargetAndReturnType::set_string 168 ns 168 ns 4182174 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 204 ns 204 ns 3454724 + +bm_call::via_function_ptr__Function::get_string 204 ns 204 ns 3439998 +bm_call::via_function_ptr____Method::get_string 205 ns 205 ns 3428085 + +bm_std::function_calls__Function::get_string 204 ns 204 ns 3444872 +bm_std::function_calls____Method::get_string 205 ns 205 ns 3434997 + +bm_rtl::function_calls__Function::get_string 204 ns 204 ns 3420037 +bm_rtl::method_calls______Method::get_string 204 ns 204 ns 3419836 + +bm_rtl::function__ErasedReturnType::get_string 213 ns 213 ns 3283998 +bm_rtl::method____ErasedReturnType::get_string 213 ns 213 ns 3295983 +bm_rtl::method____ErasedTargetType::get_string 211 ns 211 ns 3308046 +bm_rtl::method____ErasedTargetAndReturnType::get_string 214 ns 214 ns 3280155 +----------------------------------- +[2026-01-19 22:21:35] >>> Run 1: workload scale = 15 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 15 iterations +============================================= + +2026-01-19T22:21:35+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.80, 0.41 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 213 ns 213 ns 3278456 + +bm_call::via_function_ptr__Function::set_string 209 ns 209 ns 3352560 +bm_call::via_function_ptr____Method::set_string 209 ns 209 ns 3360691 + +bm_std::function_calls__Function::set_string 209 ns 209 ns 3361073 +bm_std::function_calls____Method::set_string 210 ns 210 ns 3318972 + +bm_rtl::function_calls__Function::set_string 209 ns 209 ns 3369433 +bm_rtl::method_calls______Method::set_string 209 ns 209 ns 3354692 + +bm_rtl::function__ErasedReturnType::set_string 211 ns 211 ns 3314566 +bm_rtl::method____ErasedReturnType::set_string 217 ns 217 ns 3200487 +bm_rtl::method____ErasedTargetType::set_string 210 ns 210 ns 3339407 +bm_rtl::method____ErasedTargetAndReturnType::set_string 213 ns 213 ns 3272485 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 290 ns 290 ns 2399152 + +bm_call::via_function_ptr__Function::get_string 292 ns 292 ns 2391389 +bm_call::via_function_ptr____Method::get_string 294 ns 294 ns 2387165 + +bm_std::function_calls__Function::get_string 292 ns 292 ns 2385012 +bm_std::function_calls____Method::get_string 293 ns 293 ns 2370217 + +bm_rtl::function_calls__Function::get_string 290 ns 290 ns 2389109 +bm_rtl::method_calls______Method::get_string 291 ns 291 ns 2413141 + +bm_rtl::function__ErasedReturnType::get_string 293 ns 293 ns 2376124 +bm_rtl::method____ErasedReturnType::get_string 294 ns 294 ns 2372537 +bm_rtl::method____ErasedTargetType::get_string 296 ns 296 ns 2363057 +bm_rtl::method____ErasedTargetAndReturnType::get_string 295 ns 295 ns 2377778 +----------------------------------- +[2026-01-19 22:21:57] >>> Run 2: workload scale = 15 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 15 iterations +============================================= + +2026-01-19T22:21:57+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 801.32 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.81, 0.42 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 212 ns 212 ns 3309102 + +bm_call::via_function_ptr__Function::set_string 207 ns 207 ns 3394006 +bm_call::via_function_ptr____Method::set_string 207 ns 207 ns 3370944 + +bm_std::function_calls__Function::set_string 207 ns 207 ns 3376717 +bm_std::function_calls____Method::set_string 207 ns 207 ns 3373440 + +bm_rtl::function_calls__Function::set_string 207 ns 207 ns 3397337 +bm_rtl::method_calls______Method::set_string 207 ns 207 ns 3366295 + +bm_rtl::function__ErasedReturnType::set_string 209 ns 209 ns 3341976 +bm_rtl::method____ErasedReturnType::set_string 215 ns 215 ns 3250934 +bm_rtl::method____ErasedTargetType::set_string 209 ns 209 ns 3356043 +bm_rtl::method____ErasedTargetAndReturnType::set_string 213 ns 213 ns 3302810 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 290 ns 290 ns 2434486 + +bm_call::via_function_ptr__Function::get_string 290 ns 290 ns 2418544 +bm_call::via_function_ptr____Method::get_string 292 ns 292 ns 2391400 + +bm_std::function_calls__Function::get_string 290 ns 290 ns 2419226 +bm_std::function_calls____Method::get_string 292 ns 292 ns 2384728 + +bm_rtl::function_calls__Function::get_string 289 ns 289 ns 2421073 +bm_rtl::method_calls______Method::get_string 289 ns 289 ns 2407117 + +bm_rtl::function__ErasedReturnType::get_string 291 ns 291 ns 2407608 +bm_rtl::method____ErasedReturnType::get_string 292 ns 292 ns 2397277 +bm_rtl::method____ErasedTargetType::get_string 297 ns 297 ns 2375795 +bm_rtl::method____ErasedTargetAndReturnType::get_string 293 ns 293 ns 2389315 +----------------------------------- +[2026-01-19 22:22:18] >>> Run 3: workload scale = 15 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 15 iterations +============================================= + +2026-01-19T22:22:18+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.83, 0.44 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 213 ns 213 ns 3296227 + +bm_call::via_function_ptr__Function::set_string 214 ns 214 ns 3263923 +bm_call::via_function_ptr____Method::set_string 205 ns 205 ns 3257153 + +bm_std::function_calls__Function::set_string 197 ns 197 ns 3565329 +bm_std::function_calls____Method::set_string 196 ns 196 ns 3566944 + +bm_rtl::function_calls__Function::set_string 197 ns 197 ns 3533127 +bm_rtl::method_calls______Method::set_string 198 ns 198 ns 3543068 + +bm_rtl::function__ErasedReturnType::set_string 200 ns 200 ns 3486313 +bm_rtl::method____ErasedReturnType::set_string 199 ns 199 ns 3506394 +bm_rtl::method____ErasedTargetType::set_string 201 ns 201 ns 3461289 +bm_rtl::method____ErasedTargetAndReturnType::set_string 207 ns 207 ns 3387381 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 255 ns 255 ns 2755617 + +bm_call::via_function_ptr__Function::get_string 256 ns 256 ns 2766715 +bm_call::via_function_ptr____Method::get_string 255 ns 255 ns 2753165 + +bm_std::function_calls__Function::get_string 254 ns 254 ns 2746618 +bm_std::function_calls____Method::get_string 254 ns 254 ns 2759317 + +bm_rtl::function_calls__Function::get_string 254 ns 254 ns 2751392 +bm_rtl::method_calls______Method::get_string 255 ns 255 ns 2749046 + +bm_rtl::function__ErasedReturnType::get_string 259 ns 259 ns 2716598 +bm_rtl::method____ErasedReturnType::get_string 260 ns 260 ns 2686400 +bm_rtl::method____ErasedTargetType::get_string 260 ns 260 ns 2691016 +bm_rtl::method____ErasedTargetAndReturnType::get_string 261 ns 261 ns 2691710 +----------------------------------- +[2026-01-19 22:22:39] >>> Run 1: workload scale = 20 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 20 iterations +============================================= + +2026-01-19T22:22:39+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.84, 0.45 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 327 ns 327 ns 2130827 + +bm_call::via_function_ptr__Function::set_string 297 ns 297 ns 2358942 +bm_call::via_function_ptr____Method::set_string 297 ns 297 ns 2362573 + +bm_std::function_calls__Function::set_string 297 ns 297 ns 2350215 +bm_std::function_calls____Method::set_string 297 ns 297 ns 2358479 + +bm_rtl::function_calls__Function::set_string 297 ns 297 ns 2357670 +bm_rtl::method_calls______Method::set_string 298 ns 298 ns 2345741 + +bm_rtl::function__ErasedReturnType::set_string 302 ns 302 ns 2338843 +bm_rtl::method____ErasedReturnType::set_string 301 ns 301 ns 2320729 +bm_rtl::method____ErasedTargetType::set_string 302 ns 302 ns 2324269 +bm_rtl::method____ErasedTargetAndReturnType::set_string 303 ns 303 ns 2309848 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 423 ns 423 ns 1656887 + +bm_call::via_function_ptr__Function::get_string 421 ns 421 ns 1661981 +bm_call::via_function_ptr____Method::get_string 422 ns 422 ns 1656660 + +bm_std::function_calls__Function::get_string 422 ns 422 ns 1657954 +bm_std::function_calls____Method::get_string 423 ns 423 ns 1656490 + +bm_rtl::function_calls__Function::get_string 421 ns 420 ns 1661494 +bm_rtl::method_calls______Method::get_string 421 ns 421 ns 1661180 + +bm_rtl::function__ErasedReturnType::get_string 431 ns 431 ns 1619090 +bm_rtl::method____ErasedReturnType::get_string 431 ns 431 ns 1620223 +bm_rtl::method____ErasedTargetType::get_string 431 ns 431 ns 1619311 +bm_rtl::method____ErasedTargetAndReturnType::get_string 432 ns 432 ns 1616884 +----------------------------------- +[2026-01-19 22:23:03] >>> Run 2: workload scale = 20 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 20 iterations +============================================= + +2026-01-19T22:23:03+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.85, 0.47 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 328 ns 328 ns 2133046 + +bm_call::via_function_ptr__Function::set_string 297 ns 297 ns 2336742 +bm_call::via_function_ptr____Method::set_string 297 ns 297 ns 2330893 + +bm_std::function_calls__Function::set_string 299 ns 299 ns 2338388 +bm_std::function_calls____Method::set_string 299 ns 299 ns 2361470 + +bm_rtl::function_calls__Function::set_string 299 ns 299 ns 2355328 +bm_rtl::method_calls______Method::set_string 299 ns 299 ns 2354178 + +bm_rtl::function__ErasedReturnType::set_string 309 ns 309 ns 2248700 +bm_rtl::method____ErasedReturnType::set_string 307 ns 307 ns 2263835 +bm_rtl::method____ErasedTargetType::set_string 305 ns 305 ns 2290845 +bm_rtl::method____ErasedTargetAndReturnType::set_string 309 ns 309 ns 2270160 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 420 ns 420 ns 1667713 + +bm_call::via_function_ptr__Function::get_string 419 ns 419 ns 1665420 +bm_call::via_function_ptr____Method::get_string 420 ns 420 ns 1661441 + +bm_std::function_calls__Function::get_string 420 ns 420 ns 1665206 +bm_std::function_calls____Method::get_string 423 ns 423 ns 1659447 + +bm_rtl::function_calls__Function::get_string 419 ns 419 ns 1666035 +bm_rtl::method_calls______Method::get_string 419 ns 419 ns 1667963 + +bm_rtl::function__ErasedReturnType::get_string 431 ns 431 ns 1622118 +bm_rtl::method____ErasedReturnType::get_string 433 ns 432 ns 1624592 +bm_rtl::method____ErasedTargetType::get_string 431 ns 430 ns 1630012 +bm_rtl::method____ErasedTargetAndReturnType::get_string 433 ns 433 ns 1616972 +----------------------------------- +[2026-01-19 22:23:28] >>> Run 3: workload scale = 20 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 20 iterations +============================================= + +2026-01-19T22:23:28+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.87, 0.48 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 290 ns 290 ns 2424105 + +bm_call::via_function_ptr__Function::set_string 268 ns 268 ns 2627333 +bm_call::via_function_ptr____Method::set_string 266 ns 266 ns 2656460 + +bm_std::function_calls__Function::set_string 264 ns 264 ns 2608421 +bm_std::function_calls____Method::set_string 268 ns 268 ns 2624303 + +bm_rtl::function_calls__Function::set_string 264 ns 264 ns 2641920 +bm_rtl::method_calls______Method::set_string 264 ns 264 ns 2648786 + +bm_rtl::function__ErasedReturnType::set_string 270 ns 270 ns 2603193 +bm_rtl::method____ErasedReturnType::set_string 274 ns 274 ns 2555196 +bm_rtl::method____ErasedTargetType::set_string 270 ns 270 ns 2629662 +bm_rtl::method____ErasedTargetAndReturnType::set_string 275 ns 275 ns 2558749 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 365 ns 365 ns 1916083 + +bm_call::via_function_ptr__Function::get_string 365 ns 365 ns 1921180 +bm_call::via_function_ptr____Method::get_string 366 ns 366 ns 1904972 + +bm_std::function_calls__Function::get_string 365 ns 365 ns 1911332 +bm_std::function_calls____Method::get_string 368 ns 368 ns 1884370 + +bm_rtl::function_calls__Function::get_string 366 ns 366 ns 1923206 +bm_rtl::method_calls______Method::get_string 366 ns 366 ns 1908881 + +bm_rtl::function__ErasedReturnType::get_string 375 ns 375 ns 1863335 +bm_rtl::method____ErasedReturnType::get_string 375 ns 375 ns 1858239 +bm_rtl::method____ErasedTargetType::get_string 376 ns 376 ns 1870789 +bm_rtl::method____ErasedTargetAndReturnType::get_string 378 ns 378 ns 1847908 +----------------------------------- +[2026-01-19 22:23:51] >>> Run 1: workload scale = 25 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 25 iterations +============================================= + +2026-01-19T22:23:51+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.88, 0.50 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 329 ns 329 ns 2137193 + +bm_call::via_function_ptr__Function::set_string 314 ns 314 ns 2240187 +bm_call::via_function_ptr____Method::set_string 314 ns 314 ns 2262194 + +bm_std::function_calls__Function::set_string 309 ns 309 ns 2250921 +bm_std::function_calls____Method::set_string 306 ns 306 ns 2305127 + +bm_rtl::function_calls__Function::set_string 311 ns 311 ns 2239465 +bm_rtl::method_calls______Method::set_string 310 ns 310 ns 2237918 + +bm_rtl::function__ErasedReturnType::set_string 317 ns 317 ns 2168950 +bm_rtl::method____ErasedReturnType::set_string 305 ns 305 ns 2289661 +bm_rtl::method____ErasedTargetType::set_string 324 ns 324 ns 2180611 +bm_rtl::method____ErasedTargetAndReturnType::set_string 324 ns 324 ns 2167254 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 425 ns 425 ns 1646554 + +bm_call::via_function_ptr__Function::get_string 428 ns 428 ns 1646159 +bm_call::via_function_ptr____Method::get_string 425 ns 425 ns 1640333 + +bm_std::function_calls__Function::get_string 427 ns 427 ns 1644658 +bm_std::function_calls____Method::get_string 427 ns 427 ns 1645683 + +bm_rtl::function_calls__Function::get_string 426 ns 426 ns 1647963 +bm_rtl::method_calls______Method::get_string 435 ns 435 ns 1609578 + +bm_rtl::function__ErasedReturnType::get_string 436 ns 436 ns 1607688 +bm_rtl::method____ErasedReturnType::get_string 437 ns 437 ns 1609148 +bm_rtl::method____ErasedTargetType::get_string 438 ns 438 ns 1604011 +bm_rtl::method____ErasedTargetAndReturnType::get_string 438 ns 438 ns 1600233 +----------------------------------- +[2026-01-19 22:24:15] >>> Run 2: workload scale = 25 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 25 iterations +============================================= + +2026-01-19T22:24:16+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.89, 0.51 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 361 ns 361 ns 1941242 + +bm_call::via_function_ptr__Function::set_string 346 ns 346 ns 2027125 +bm_call::via_function_ptr____Method::set_string 346 ns 346 ns 2031783 + +bm_std::function_calls__Function::set_string 347 ns 347 ns 2034513 +bm_std::function_calls____Method::set_string 341 ns 341 ns 2049239 + +bm_rtl::function_calls__Function::set_string 347 ns 347 ns 2018577 +bm_rtl::method_calls______Method::set_string 346 ns 346 ns 2020807 + +bm_rtl::function__ErasedReturnType::set_string 357 ns 357 ns 1960365 +bm_rtl::method____ErasedReturnType::set_string 344 ns 344 ns 2030461 +bm_rtl::method____ErasedTargetType::set_string 359 ns 359 ns 1955218 +bm_rtl::method____ErasedTargetAndReturnType::set_string 358 ns 358 ns 1947898 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 484 ns 484 ns 1444771 + +bm_call::via_function_ptr__Function::get_string 486 ns 486 ns 1441287 +bm_call::via_function_ptr____Method::get_string 485 ns 485 ns 1446433 + +bm_std::function_calls__Function::get_string 487 ns 487 ns 1441524 +bm_std::function_calls____Method::get_string 487 ns 487 ns 1433549 + +bm_rtl::function_calls__Function::get_string 487 ns 487 ns 1436284 +bm_rtl::method_calls______Method::get_string 485 ns 485 ns 1444218 + +bm_rtl::function__ErasedReturnType::get_string 498 ns 498 ns 1405236 +bm_rtl::method____ErasedReturnType::get_string 501 ns 501 ns 1399059 +bm_rtl::method____ErasedTargetType::get_string 495 ns 495 ns 1394477 +bm_rtl::method____ErasedTargetAndReturnType::get_string 501 ns 501 ns 1394723 +----------------------------------- +[2026-01-19 22:24:40] >>> Run 3: workload scale = 25 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 25 iterations +============================================= + +2026-01-19T22:24:40+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.90, 0.52 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 317 ns 317 ns 2207040 + +bm_call::via_function_ptr__Function::set_string 326 ns 326 ns 2156299 +bm_call::via_function_ptr____Method::set_string 326 ns 326 ns 2165496 + +bm_std::function_calls__Function::set_string 326 ns 326 ns 2167831 +bm_std::function_calls____Method::set_string 326 ns 326 ns 2153224 + +bm_rtl::function_calls__Function::set_string 324 ns 324 ns 2151706 +bm_rtl::method_calls______Method::set_string 326 ns 326 ns 2121751 + +bm_rtl::function__ErasedReturnType::set_string 339 ns 339 ns 2052762 +bm_rtl::method____ErasedReturnType::set_string 325 ns 325 ns 2159375 +bm_rtl::method____ErasedTargetType::set_string 344 ns 344 ns 2023497 +bm_rtl::method____ErasedTargetAndReturnType::set_string 339 ns 339 ns 2051367 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 438 ns 438 ns 1606262 + +bm_call::via_function_ptr__Function::get_string 440 ns 440 ns 1578140 +bm_call::via_function_ptr____Method::get_string 439 ns 439 ns 1584218 + +bm_std::function_calls__Function::get_string 439 ns 439 ns 1581952 +bm_std::function_calls____Method::get_string 452 ns 452 ns 1551649 + +bm_rtl::function_calls__Function::get_string 442 ns 442 ns 1602573 +bm_rtl::method_calls______Method::get_string 440 ns 440 ns 1587330 + +bm_rtl::function__ErasedReturnType::get_string 458 ns 458 ns 1517252 +bm_rtl::method____ErasedReturnType::get_string 463 ns 463 ns 1508769 +bm_rtl::method____ErasedTargetType::get_string 455 ns 455 ns 1531543 +bm_rtl::method____ErasedTargetAndReturnType::get_string 460 ns 460 ns 1534110 +----------------------------------- +[2026-01-19 22:25:05] >>> Run 1: workload scale = 30 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 30 iterations +============================================= + +2026-01-19T22:25:05+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.91, 0.54 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 426 ns 426 ns 1642971 + +bm_call::via_function_ptr__Function::set_string 340 ns 340 ns 2060776 +bm_call::via_function_ptr____Method::set_string 340 ns 340 ns 2054856 + +bm_std::function_calls__Function::set_string 342 ns 342 ns 2047289 +bm_std::function_calls____Method::set_string 356 ns 356 ns 1968053 + +bm_rtl::function_calls__Function::set_string 340 ns 340 ns 2054394 +bm_rtl::method_calls______Method::set_string 342 ns 342 ns 2051463 + +bm_rtl::function__ErasedReturnType::set_string 351 ns 351 ns 1991950 +bm_rtl::method____ErasedReturnType::set_string 350 ns 350 ns 2009636 +bm_rtl::method____ErasedTargetType::set_string 353 ns 353 ns 1976671 +bm_rtl::method____ErasedTargetAndReturnType::set_string 358 ns 358 ns 1959273 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 493 ns 493 ns 1418974 + +bm_call::via_function_ptr__Function::get_string 495 ns 495 ns 1415006 +bm_call::via_function_ptr____Method::get_string 495 ns 495 ns 1417840 + +bm_std::function_calls__Function::get_string 495 ns 495 ns 1409827 +bm_std::function_calls____Method::get_string 498 ns 498 ns 1407422 + +bm_rtl::function_calls__Function::get_string 495 ns 495 ns 1419100 +bm_rtl::method_calls______Method::get_string 496 ns 496 ns 1409543 + +bm_rtl::function__ErasedReturnType::get_string 512 ns 512 ns 1364679 +bm_rtl::method____ErasedReturnType::get_string 510 ns 510 ns 1368522 +bm_rtl::method____ErasedTargetType::get_string 510 ns 510 ns 1372916 +bm_rtl::method____ErasedTargetAndReturnType::get_string 512 ns 512 ns 1365261 +----------------------------------- +[2026-01-19 22:25:28] >>> Run 2: workload scale = 30 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 30 iterations +============================================= + +2026-01-19T22:25:28+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 4445.26 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.92, 0.55 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 433 ns 433 ns 1616498 + +bm_call::via_function_ptr__Function::set_string 352 ns 352 ns 1985642 +bm_call::via_function_ptr____Method::set_string 353 ns 353 ns 1978449 + +bm_std::function_calls__Function::set_string 353 ns 353 ns 1991516 +bm_std::function_calls____Method::set_string 371 ns 371 ns 1867726 + +bm_rtl::function_calls__Function::set_string 353 ns 353 ns 1989083 +bm_rtl::method_calls______Method::set_string 354 ns 354 ns 1969449 + +bm_rtl::function__ErasedReturnType::set_string 352 ns 352 ns 1984958 +bm_rtl::method____ErasedReturnType::set_string 353 ns 353 ns 1986122 +bm_rtl::method____ErasedTargetType::set_string 354 ns 354 ns 1980813 +bm_rtl::method____ErasedTargetAndReturnType::set_string 362 ns 362 ns 1931931 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 510 ns 510 ns 1375075 + +bm_call::via_function_ptr__Function::get_string 511 ns 511 ns 1390317 +bm_call::via_function_ptr____Method::get_string 510 ns 510 ns 1360743 + +bm_std::function_calls__Function::get_string 511 ns 511 ns 1368314 +bm_std::function_calls____Method::get_string 518 ns 518 ns 1350815 + +bm_rtl::function_calls__Function::get_string 509 ns 509 ns 1380089 +bm_rtl::method_calls______Method::get_string 508 ns 508 ns 1383110 + +bm_rtl::function__ErasedReturnType::get_string 521 ns 521 ns 1350743 +bm_rtl::method____ErasedReturnType::get_string 523 ns 523 ns 1345324 +bm_rtl::method____ErasedTargetType::get_string 517 ns 517 ns 1363384 +bm_rtl::method____ErasedTargetAndReturnType::get_string 522 ns 522 ns 1343674 +----------------------------------- +[2026-01-19 22:25:49] >>> Run 3: workload scale = 30 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 30 iterations +============================================= + +2026-01-19T22:25:49+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.92, 0.56 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 414 ns 414 ns 1697314 + +bm_call::via_function_ptr__Function::set_string 345 ns 345 ns 2021772 +bm_call::via_function_ptr____Method::set_string 346 ns 346 ns 2022304 + +bm_std::function_calls__Function::set_string 346 ns 346 ns 2023585 +bm_std::function_calls____Method::set_string 347 ns 347 ns 2008508 + +bm_rtl::function_calls__Function::set_string 346 ns 346 ns 2014818 +bm_rtl::method_calls______Method::set_string 348 ns 348 ns 2017748 + +bm_rtl::function__ErasedReturnType::set_string 365 ns 365 ns 1925260 +bm_rtl::method____ErasedReturnType::set_string 374 ns 374 ns 1876867 +bm_rtl::method____ErasedTargetType::set_string 354 ns 354 ns 1985581 +bm_rtl::method____ErasedTargetAndReturnType::set_string 371 ns 371 ns 1878339 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 499 ns 499 ns 1407970 + +bm_call::via_function_ptr__Function::get_string 497 ns 497 ns 1405740 +bm_call::via_function_ptr____Method::get_string 497 ns 497 ns 1403761 + +bm_std::function_calls__Function::get_string 500 ns 500 ns 1000000 +bm_std::function_calls____Method::get_string 499 ns 499 ns 1391338 + +bm_rtl::function_calls__Function::get_string 497 ns 497 ns 1412667 +bm_rtl::method_calls______Method::get_string 497 ns 497 ns 1409384 + +bm_rtl::function__ErasedReturnType::get_string 515 ns 515 ns 1356884 +bm_rtl::method____ErasedReturnType::get_string 515 ns 515 ns 1353416 +bm_rtl::method____ErasedTargetType::get_string 511 ns 511 ns 1375675 +bm_rtl::method____ErasedTargetAndReturnType::get_string 517 ns 516 ns 1363123 +----------------------------------- +[2026-01-19 22:26:12] >>> Run 1: workload scale = 35 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 35 iterations +============================================= + +2026-01-19T22:26:12+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.93, 0.57 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 710 ns 710 ns 981145 + +bm_call::via_function_ptr__Function::set_string 692 ns 692 ns 1013095 +bm_call::via_function_ptr____Method::set_string 692 ns 692 ns 1011763 + +bm_std::function_calls__Function::set_string 691 ns 691 ns 1013638 +bm_std::function_calls____Method::set_string 714 ns 714 ns 972767 + +bm_rtl::function_calls__Function::set_string 691 ns 691 ns 1011286 +bm_rtl::method_calls______Method::set_string 693 ns 693 ns 1015686 + +bm_rtl::function__ErasedReturnType::set_string 706 ns 706 ns 990586 +bm_rtl::method____ErasedReturnType::set_string 707 ns 707 ns 990922 +bm_rtl::method____ErasedTargetType::set_string 711 ns 711 ns 985971 +bm_rtl::method____ErasedTargetAndReturnType::set_string 717 ns 717 ns 976150 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 922 ns 922 ns 759196 + +bm_call::via_function_ptr__Function::get_string 924 ns 924 ns 759281 +bm_call::via_function_ptr____Method::get_string 922 ns 922 ns 759827 + +bm_std::function_calls__Function::get_string 924 ns 924 ns 759626 +bm_std::function_calls____Method::get_string 927 ns 927 ns 752753 + +bm_rtl::function_calls__Function::get_string 925 ns 925 ns 756943 +bm_rtl::method_calls______Method::get_string 923 ns 923 ns 760058 + +bm_rtl::function__ErasedReturnType::get_string 960 ns 960 ns 730468 +bm_rtl::method____ErasedReturnType::get_string 961 ns 961 ns 728306 +bm_rtl::method____ErasedTargetType::get_string 950 ns 950 ns 737199 +bm_rtl::method____ErasedTargetAndReturnType::get_string 973 ns 973 ns 719799 +----------------------------------- +[2026-01-19 22:26:29] >>> Run 2: workload scale = 35 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 35 iterations +============================================= + +2026-01-19T22:26:29+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.93, 0.58 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 688 ns 688 ns 1012792 + +bm_call::via_function_ptr__Function::set_string 696 ns 696 ns 1003588 +bm_call::via_function_ptr____Method::set_string 696 ns 696 ns 1007834 + +bm_std::function_calls__Function::set_string 696 ns 696 ns 1006928 +bm_std::function_calls____Method::set_string 722 ns 722 ns 974459 + +bm_rtl::function_calls__Function::set_string 697 ns 697 ns 1004193 +bm_rtl::method_calls______Method::set_string 696 ns 696 ns 1007755 + +bm_rtl::function__ErasedReturnType::set_string 704 ns 704 ns 993190 +bm_rtl::method____ErasedReturnType::set_string 703 ns 703 ns 992625 +bm_rtl::method____ErasedTargetType::set_string 709 ns 709 ns 988352 +bm_rtl::method____ErasedTargetAndReturnType::set_string 707 ns 707 ns 992378 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 886 ns 886 ns 790128 + +bm_call::via_function_ptr__Function::get_string 887 ns 887 ns 790635 +bm_call::via_function_ptr____Method::get_string 886 ns 886 ns 790890 + +bm_std::function_calls__Function::get_string 886 ns 886 ns 790529 +bm_std::function_calls____Method::get_string 892 ns 892 ns 786318 + +bm_rtl::function_calls__Function::get_string 885 ns 885 ns 790710 +bm_rtl::method_calls______Method::get_string 887 ns 886 ns 789776 + +bm_rtl::function__ErasedReturnType::get_string 910 ns 909 ns 767868 +bm_rtl::method____ErasedReturnType::get_string 911 ns 910 ns 769923 +bm_rtl::method____ErasedTargetType::get_string 903 ns 903 ns 776352 +bm_rtl::method____ErasedTargetAndReturnType::get_string 910 ns 910 ns 767263 +----------------------------------- +[2026-01-19 22:26:46] >>> Run 3: workload scale = 35 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 35 iterations +============================================= + +2026-01-19T22:26:46+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 4826.63 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.94, 0.59 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 687 ns 687 ns 1012333 + +bm_call::via_function_ptr__Function::set_string 698 ns 698 ns 1001974 +bm_call::via_function_ptr____Method::set_string 699 ns 699 ns 1001002 + +bm_std::function_calls__Function::set_string 699 ns 699 ns 1003186 +bm_std::function_calls____Method::set_string 695 ns 695 ns 1008207 + +bm_rtl::function_calls__Function::set_string 698 ns 698 ns 1000755 +bm_rtl::method_calls______Method::set_string 700 ns 700 ns 1003123 + +bm_rtl::function__ErasedReturnType::set_string 713 ns 713 ns 983307 +bm_rtl::method____ErasedReturnType::set_string 705 ns 705 ns 986819 +bm_rtl::method____ErasedTargetType::set_string 721 ns 721 ns 973763 +bm_rtl::method____ErasedTargetAndReturnType::set_string 719 ns 718 ns 972130 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 868 ns 868 ns 808143 + +bm_call::via_function_ptr__Function::get_string 873 ns 873 ns 802283 +bm_call::via_function_ptr____Method::get_string 873 ns 873 ns 802368 + +bm_std::function_calls__Function::get_string 871 ns 871 ns 803251 +bm_std::function_calls____Method::get_string 875 ns 875 ns 800165 + +bm_rtl::function_calls__Function::get_string 875 ns 875 ns 799948 +bm_rtl::method_calls______Method::get_string 875 ns 875 ns 798701 + +bm_rtl::function__ErasedReturnType::get_string 906 ns 906 ns 772812 +bm_rtl::method____ErasedReturnType::get_string 905 ns 905 ns 773400 +bm_rtl::method____ErasedTargetType::get_string 896 ns 896 ns 779165 +bm_rtl::method____ErasedTargetAndReturnType::get_string 910 ns 910 ns 767525 +----------------------------------- +[2026-01-19 22:27:04] >>> Run 1: workload scale = 40 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 40 iterations +============================================= + +2026-01-19T22:27:04+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.94, 0.60 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 802 ns 802 ns 868548 + +bm_call::via_function_ptr__Function::set_string 807 ns 807 ns 867844 +bm_call::via_function_ptr____Method::set_string 812 ns 812 ns 863363 + +bm_std::function_calls__Function::set_string 807 ns 807 ns 867775 +bm_std::function_calls____Method::set_string 824 ns 824 ns 850370 + +bm_rtl::function_calls__Function::set_string 807 ns 807 ns 869726 +bm_rtl::method_calls______Method::set_string 812 ns 811 ns 861708 + +bm_rtl::function__ErasedReturnType::set_string 820 ns 820 ns 853781 +bm_rtl::method____ErasedReturnType::set_string 821 ns 821 ns 851633 +bm_rtl::method____ErasedTargetType::set_string 821 ns 821 ns 853270 +bm_rtl::method____ErasedTargetAndReturnType::set_string 821 ns 821 ns 852568 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1060 ns 1060 ns 658475 + +bm_call::via_function_ptr__Function::get_string 1065 ns 1064 ns 657487 +bm_call::via_function_ptr____Method::get_string 1064 ns 1063 ns 658536 + +bm_std::function_calls__Function::get_string 1065 ns 1065 ns 657326 +bm_std::function_calls____Method::get_string 1068 ns 1068 ns 654286 + +bm_rtl::function_calls__Function::get_string 1065 ns 1065 ns 656003 +bm_rtl::method_calls______Method::get_string 1064 ns 1064 ns 658205 + +bm_rtl::function__ErasedReturnType::get_string 1094 ns 1094 ns 640286 +bm_rtl::method____ErasedReturnType::get_string 1094 ns 1094 ns 640985 +bm_rtl::method____ErasedTargetType::get_string 1087 ns 1087 ns 644549 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1101 ns 1101 ns 636794 +----------------------------------- +[2026-01-19 22:27:21] >>> Run 2: workload scale = 40 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 40 iterations +============================================= + +2026-01-19T22:27:21+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.95, 0.61 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 786 ns 786 ns 883972 + +bm_call::via_function_ptr__Function::set_string 774 ns 774 ns 903846 +bm_call::via_function_ptr____Method::set_string 778 ns 778 ns 899190 + +bm_std::function_calls__Function::set_string 774 ns 774 ns 903053 +bm_std::function_calls____Method::set_string 774 ns 773 ns 907756 + +bm_rtl::function_calls__Function::set_string 773 ns 773 ns 906453 +bm_rtl::method_calls______Method::set_string 778 ns 778 ns 899327 + +bm_rtl::function__ErasedReturnType::set_string 780 ns 780 ns 897281 +bm_rtl::method____ErasedReturnType::set_string 782 ns 782 ns 895546 +bm_rtl::method____ErasedTargetType::set_string 785 ns 785 ns 890456 +bm_rtl::method____ErasedTargetAndReturnType::set_string 785 ns 785 ns 892386 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 988 ns 988 ns 709044 + +bm_call::via_function_ptr__Function::get_string 991 ns 991 ns 707835 +bm_call::via_function_ptr____Method::get_string 988 ns 988 ns 708817 + +bm_std::function_calls__Function::get_string 991 ns 991 ns 707988 +bm_std::function_calls____Method::get_string 993 ns 992 ns 705658 + +bm_rtl::function_calls__Function::get_string 989 ns 989 ns 706853 +bm_rtl::method_calls______Method::get_string 988 ns 988 ns 709751 + +bm_rtl::function__ErasedReturnType::get_string 1016 ns 1016 ns 690073 +bm_rtl::method____ErasedReturnType::get_string 1012 ns 1012 ns 692075 +bm_rtl::method____ErasedTargetType::get_string 1012 ns 1012 ns 694173 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1015 ns 1015 ns 690549 +----------------------------------- +[2026-01-19 22:27:39] >>> Run 3: workload scale = 40 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 40 iterations +============================================= + +2026-01-19T22:27:39+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.95, 0.61 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 771 ns 771 ns 885667 + +bm_call::via_function_ptr__Function::set_string 793 ns 793 ns 878508 +bm_call::via_function_ptr____Method::set_string 800 ns 800 ns 874309 + +bm_std::function_calls__Function::set_string 794 ns 794 ns 887848 +bm_std::function_calls____Method::set_string 779 ns 778 ns 901238 + +bm_rtl::function_calls__Function::set_string 793 ns 792 ns 880417 +bm_rtl::method_calls______Method::set_string 799 ns 799 ns 873660 + +bm_rtl::function__ErasedReturnType::set_string 786 ns 786 ns 894928 +bm_rtl::method____ErasedReturnType::set_string 801 ns 800 ns 877038 +bm_rtl::method____ErasedTargetType::set_string 788 ns 788 ns 887908 +bm_rtl::method____ErasedTargetAndReturnType::set_string 806 ns 806 ns 866137 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1016 ns 1016 ns 691784 + +bm_call::via_function_ptr__Function::get_string 1000 ns 1000 ns 697377 +bm_call::via_function_ptr____Method::get_string 1000 ns 1000 ns 698055 + +bm_std::function_calls__Function::get_string 1001 ns 1001 ns 700875 +bm_std::function_calls____Method::get_string 1003 ns 1003 ns 695781 + +bm_rtl::function_calls__Function::get_string 1001 ns 1000 ns 701247 +bm_rtl::method_calls______Method::get_string 999 ns 999 ns 700681 + +bm_rtl::function__ErasedReturnType::get_string 1023 ns 1023 ns 684652 +bm_rtl::method____ErasedReturnType::get_string 1022 ns 1022 ns 685580 +bm_rtl::method____ErasedTargetType::get_string 1016 ns 1016 ns 686936 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1031 ns 1031 ns 680324 +----------------------------------- +[2026-01-19 22:27:57] >>> Run 1: workload scale = 45 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 45 iterations +============================================= + +2026-01-19T22:27:57+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.95, 0.62 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 843 ns 842 ns 829422 + +bm_call::via_function_ptr__Function::set_string 826 ns 826 ns 847271 +bm_call::via_function_ptr____Method::set_string 830 ns 830 ns 841956 + +bm_std::function_calls__Function::set_string 828 ns 828 ns 845355 +bm_std::function_calls____Method::set_string 832 ns 832 ns 840493 + +bm_rtl::function_calls__Function::set_string 826 ns 826 ns 845523 +bm_rtl::method_calls______Method::set_string 831 ns 831 ns 842934 + +bm_rtl::function__ErasedReturnType::set_string 837 ns 837 ns 835998 +bm_rtl::method____ErasedReturnType::set_string 861 ns 861 ns 813815 +bm_rtl::method____ErasedTargetType::set_string 845 ns 845 ns 828408 +bm_rtl::method____ErasedTargetAndReturnType::set_string 845 ns 844 ns 829014 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1061 ns 1061 ns 659854 + +bm_call::via_function_ptr__Function::get_string 1059 ns 1059 ns 661004 +bm_call::via_function_ptr____Method::get_string 1059 ns 1058 ns 660856 + +bm_std::function_calls__Function::get_string 1059 ns 1059 ns 659554 +bm_std::function_calls____Method::get_string 1065 ns 1065 ns 657328 + +bm_rtl::function_calls__Function::get_string 1059 ns 1059 ns 660814 +bm_rtl::method_calls______Method::get_string 1058 ns 1058 ns 661209 + +bm_rtl::function__ErasedReturnType::get_string 1083 ns 1083 ns 645463 +bm_rtl::method____ErasedReturnType::get_string 1083 ns 1083 ns 645790 +bm_rtl::method____ErasedTargetType::get_string 1075 ns 1075 ns 649976 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1082 ns 1082 ns 645611 +----------------------------------- +[2026-01-19 22:28:14] >>> Run 2: workload scale = 45 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 45 iterations +============================================= + +2026-01-19T22:28:14+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.96, 0.63 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 873 ns 873 ns 798150 + +bm_call::via_function_ptr__Function::set_string 818 ns 818 ns 855496 +bm_call::via_function_ptr____Method::set_string 822 ns 822 ns 851194 + +bm_std::function_calls__Function::set_string 820 ns 820 ns 853680 +bm_std::function_calls____Method::set_string 826 ns 826 ns 848997 + +bm_rtl::function_calls__Function::set_string 820 ns 819 ns 855357 +bm_rtl::method_calls______Method::set_string 822 ns 822 ns 850380 + +bm_rtl::function__ErasedReturnType::set_string 829 ns 829 ns 843995 +bm_rtl::method____ErasedReturnType::set_string 833 ns 833 ns 841065 +bm_rtl::method____ErasedTargetType::set_string 835 ns 835 ns 836950 +bm_rtl::method____ErasedTargetAndReturnType::set_string 835 ns 835 ns 838849 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1106 ns 1106 ns 633211 + +bm_call::via_function_ptr__Function::get_string 1106 ns 1106 ns 632481 +bm_call::via_function_ptr____Method::get_string 1106 ns 1105 ns 633333 + +bm_std::function_calls__Function::get_string 1106 ns 1106 ns 632483 +bm_std::function_calls____Method::get_string 1114 ns 1114 ns 628515 + +bm_rtl::function_calls__Function::get_string 1106 ns 1106 ns 633284 +bm_rtl::method_calls______Method::get_string 1105 ns 1105 ns 633066 + +bm_rtl::function__ErasedReturnType::get_string 1136 ns 1136 ns 615606 +bm_rtl::method____ErasedReturnType::get_string 1134 ns 1134 ns 616323 +bm_rtl::method____ErasedTargetType::get_string 1129 ns 1129 ns 621462 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1140 ns 1139 ns 614829 +----------------------------------- +[2026-01-19 22:28:32] >>> Run 3: workload scale = 45 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 45 iterations +============================================= + +2026-01-19T22:28:32+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 2371.34 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.96, 0.64 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 848 ns 848 ns 821823 + +bm_call::via_function_ptr__Function::set_string 849 ns 849 ns 823432 +bm_call::via_function_ptr____Method::set_string 848 ns 848 ns 826357 + +bm_std::function_calls__Function::set_string 849 ns 849 ns 825248 +bm_std::function_calls____Method::set_string 834 ns 834 ns 840820 + +bm_rtl::function_calls__Function::set_string 847 ns 847 ns 826081 +bm_rtl::method_calls______Method::set_string 848 ns 848 ns 821829 + +bm_rtl::function__ErasedReturnType::set_string 868 ns 867 ns 806472 +bm_rtl::method____ErasedReturnType::set_string 848 ns 847 ns 823741 +bm_rtl::method____ErasedTargetType::set_string 872 ns 872 ns 802754 +bm_rtl::method____ErasedTargetAndReturnType::set_string 876 ns 876 ns 799331 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1064 ns 1064 ns 658715 + +bm_call::via_function_ptr__Function::get_string 1066 ns 1066 ns 655833 +bm_call::via_function_ptr____Method::get_string 1066 ns 1066 ns 656046 + +bm_std::function_calls__Function::get_string 1067 ns 1067 ns 655205 +bm_std::function_calls____Method::get_string 1069 ns 1068 ns 655293 + +bm_rtl::function_calls__Function::get_string 1066 ns 1065 ns 658227 +bm_rtl::method_calls______Method::get_string 1065 ns 1065 ns 657248 + +bm_rtl::function__ErasedReturnType::get_string 1088 ns 1088 ns 643258 +bm_rtl::method____ErasedReturnType::get_string 1087 ns 1087 ns 644904 +bm_rtl::method____ErasedTargetType::get_string 1078 ns 1078 ns 647611 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1078 ns 1078 ns 649254 +----------------------------------- +[2026-01-19 22:28:50] >>> Run 1: workload scale = 50 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 50 iterations +============================================= + +2026-01-19T22:28:50+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.96, 0.65 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 934 ns 934 ns 748128 + +bm_call::via_function_ptr__Function::set_string 903 ns 903 ns 774622 +bm_call::via_function_ptr____Method::set_string 901 ns 901 ns 775359 + +bm_std::function_calls__Function::set_string 904 ns 904 ns 774547 +bm_std::function_calls____Method::set_string 883 ns 883 ns 790621 + +bm_rtl::function_calls__Function::set_string 902 ns 902 ns 774979 +bm_rtl::method_calls______Method::set_string 901 ns 900 ns 777221 + +bm_rtl::function__ErasedReturnType::set_string 919 ns 919 ns 763272 +bm_rtl::method____ErasedReturnType::set_string 895 ns 895 ns 782345 +bm_rtl::method____ErasedTargetType::set_string 924 ns 923 ns 759790 +bm_rtl::method____ErasedTargetAndReturnType::set_string 927 ns 927 ns 754650 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1137 ns 1137 ns 617257 + +bm_call::via_function_ptr__Function::get_string 1139 ns 1139 ns 614025 +bm_call::via_function_ptr____Method::get_string 1137 ns 1137 ns 615042 + +bm_std::function_calls__Function::get_string 1134 ns 1134 ns 617301 +bm_std::function_calls____Method::get_string 1141 ns 1141 ns 614301 + +bm_rtl::function_calls__Function::get_string 1135 ns 1134 ns 617395 +bm_rtl::method_calls______Method::get_string 1137 ns 1137 ns 616732 + +bm_rtl::function__ErasedReturnType::get_string 1162 ns 1162 ns 601555 +bm_rtl::method____ErasedReturnType::get_string 1163 ns 1163 ns 602718 +bm_rtl::method____ErasedTargetType::get_string 1214 ns 1214 ns 577226 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1200 ns 1199 ns 572903 +----------------------------------- +[2026-01-19 22:29:08] >>> Run 2: workload scale = 50 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 50 iterations +============================================= + +2026-01-19T22:29:08+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 4884.6 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.97, 0.65 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 948 ns 948 ns 735867 + +bm_call::via_function_ptr__Function::set_string 874 ns 874 ns 801342 +bm_call::via_function_ptr____Method::set_string 876 ns 876 ns 799863 + +bm_std::function_calls__Function::set_string 875 ns 875 ns 798701 +bm_std::function_calls____Method::set_string 885 ns 885 ns 792333 + +bm_rtl::function_calls__Function::set_string 874 ns 874 ns 800998 +bm_rtl::method_calls______Method::set_string 876 ns 875 ns 798915 + +bm_rtl::function__ErasedReturnType::set_string 888 ns 888 ns 789682 +bm_rtl::method____ErasedReturnType::set_string 888 ns 888 ns 788441 +bm_rtl::method____ErasedTargetType::set_string 894 ns 894 ns 783465 +bm_rtl::method____ErasedTargetAndReturnType::set_string 898 ns 898 ns 779245 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1134 ns 1134 ns 618460 + +bm_call::via_function_ptr__Function::get_string 1135 ns 1135 ns 615819 +bm_call::via_function_ptr____Method::get_string 1133 ns 1132 ns 614053 + +bm_std::function_calls__Function::get_string 1133 ns 1133 ns 616594 +bm_std::function_calls____Method::get_string 1139 ns 1139 ns 614250 + +bm_rtl::function_calls__Function::get_string 1133 ns 1133 ns 616500 +bm_rtl::method_calls______Method::get_string 1134 ns 1134 ns 618471 + +bm_rtl::function__ErasedReturnType::get_string 1161 ns 1161 ns 603369 +bm_rtl::method____ErasedReturnType::get_string 1159 ns 1159 ns 603518 +bm_rtl::method____ErasedTargetType::get_string 1154 ns 1154 ns 607749 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1166 ns 1166 ns 598245 +----------------------------------- +[2026-01-19 22:29:26] >>> Run 3: workload scale = 50 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 50 iterations +============================================= + +2026-01-19T22:29:26+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.97, 0.66 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 939 ns 939 ns 742183 + +bm_call::via_function_ptr__Function::set_string 881 ns 881 ns 795159 +bm_call::via_function_ptr____Method::set_string 881 ns 881 ns 794504 + +bm_std::function_calls__Function::set_string 882 ns 882 ns 793816 +bm_std::function_calls____Method::set_string 882 ns 882 ns 794659 + +bm_rtl::function_calls__Function::set_string 881 ns 881 ns 795593 +bm_rtl::method_calls______Method::set_string 881 ns 881 ns 793528 + +bm_rtl::function__ErasedReturnType::set_string 891 ns 891 ns 785351 +bm_rtl::method____ErasedReturnType::set_string 911 ns 910 ns 770850 +bm_rtl::method____ErasedTargetType::set_string 895 ns 895 ns 780967 +bm_rtl::method____ErasedTargetAndReturnType::set_string 899 ns 899 ns 779662 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1198 ns 1198 ns 584557 + +bm_call::via_function_ptr__Function::get_string 1202 ns 1202 ns 583020 +bm_call::via_function_ptr____Method::get_string 1199 ns 1199 ns 583407 + +bm_std::function_calls__Function::get_string 1199 ns 1199 ns 583877 +bm_std::function_calls____Method::get_string 1197 ns 1197 ns 584932 + +bm_rtl::function_calls__Function::get_string 1199 ns 1199 ns 584180 +bm_rtl::method_calls______Method::get_string 1200 ns 1200 ns 583120 + +bm_rtl::function__ErasedReturnType::get_string 1217 ns 1217 ns 574509 +bm_rtl::method____ErasedReturnType::get_string 1218 ns 1218 ns 573906 +bm_rtl::method____ErasedTargetType::get_string 1210 ns 1210 ns 579508 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1219 ns 1219 ns 575157 +----------------------------------- +[2026-01-19 22:29:44] >>> Run 1: workload scale = 58 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 58 iterations +============================================= + +2026-01-19T22:29:44+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 0.97, 0.67 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1035 ns 1035 ns 674729 + +bm_call::via_function_ptr__Function::set_string 1008 ns 1008 ns 693696 +bm_call::via_function_ptr____Method::set_string 1006 ns 1006 ns 696133 + +bm_std::function_calls__Function::set_string 1008 ns 1008 ns 694435 +bm_std::function_calls____Method::set_string 1032 ns 1032 ns 677461 + +bm_rtl::function_calls__Function::set_string 1008 ns 1008 ns 695440 +bm_rtl::method_calls______Method::set_string 1006 ns 1006 ns 695446 + +bm_rtl::function__ErasedReturnType::set_string 1017 ns 1017 ns 688023 +bm_rtl::method____ErasedReturnType::set_string 1021 ns 1021 ns 684886 +bm_rtl::method____ErasedTargetType::set_string 1022 ns 1022 ns 685121 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1023 ns 1023 ns 685964 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1283 ns 1283 ns 545681 + +bm_call::via_function_ptr__Function::get_string 1289 ns 1289 ns 543451 +bm_call::via_function_ptr____Method::get_string 1289 ns 1289 ns 543536 + +bm_std::function_calls__Function::get_string 1289 ns 1289 ns 543144 +bm_std::function_calls____Method::get_string 1289 ns 1289 ns 542843 + +bm_rtl::function_calls__Function::get_string 1289 ns 1289 ns 543220 +bm_rtl::method_calls______Method::get_string 1288 ns 1288 ns 543490 + +bm_rtl::function__ErasedReturnType::get_string 1310 ns 1310 ns 534100 +bm_rtl::method____ErasedReturnType::get_string 1310 ns 1310 ns 534021 +bm_rtl::method____ErasedTargetType::get_string 1300 ns 1300 ns 537670 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1314 ns 1314 ns 532015 +----------------------------------- +[2026-01-19 22:30:02] >>> Run 2: workload scale = 58 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 58 iterations +============================================= + +2026-01-19T22:30:02+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.07, 0.99, 0.68 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1032 ns 1032 ns 678112 + +bm_call::via_function_ptr__Function::set_string 996 ns 995 ns 702900 +bm_call::via_function_ptr____Method::set_string 994 ns 994 ns 706621 + +bm_std::function_calls__Function::set_string 997 ns 997 ns 702773 +bm_std::function_calls____Method::set_string 1018 ns 1018 ns 687379 + +bm_rtl::function_calls__Function::set_string 996 ns 996 ns 704180 +bm_rtl::method_calls______Method::set_string 994 ns 994 ns 704523 + +bm_rtl::function__ErasedReturnType::set_string 1009 ns 1009 ns 694404 +bm_rtl::method____ErasedReturnType::set_string 1011 ns 1011 ns 692029 +bm_rtl::method____ErasedTargetType::set_string 1011 ns 1011 ns 691866 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1015 ns 1015 ns 689500 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1289 ns 1289 ns 542977 + +bm_call::via_function_ptr__Function::get_string 1293 ns 1293 ns 540961 +bm_call::via_function_ptr____Method::get_string 1292 ns 1292 ns 541764 + +bm_std::function_calls__Function::get_string 1294 ns 1294 ns 540441 +bm_std::function_calls____Method::get_string 1296 ns 1296 ns 540693 + +bm_rtl::function_calls__Function::get_string 1294 ns 1294 ns 540763 +bm_rtl::method_calls______Method::get_string 1293 ns 1293 ns 542121 + +bm_rtl::function__ErasedReturnType::get_string 1314 ns 1314 ns 532124 +bm_rtl::method____ErasedReturnType::get_string 1312 ns 1312 ns 533500 +bm_rtl::method____ErasedTargetType::get_string 1305 ns 1305 ns 536094 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1316 ns 1316 ns 531529 +----------------------------------- +[2026-01-19 22:30:20] >>> Run 3: workload scale = 58 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 58 iterations +============================================= + +2026-01-19T22:30:20+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.06, 0.99, 0.69 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1034 ns 1034 ns 675093 + +bm_call::via_function_ptr__Function::set_string 1003 ns 1003 ns 697584 +bm_call::via_function_ptr____Method::set_string 1002 ns 1002 ns 697925 + +bm_std::function_calls__Function::set_string 1004 ns 1004 ns 696678 +bm_std::function_calls____Method::set_string 1007 ns 1007 ns 693877 + +bm_rtl::function_calls__Function::set_string 1004 ns 1004 ns 697377 +bm_rtl::method_calls______Method::set_string 1003 ns 1003 ns 698516 + +bm_rtl::function__ErasedReturnType::set_string 1018 ns 1018 ns 687788 +bm_rtl::method____ErasedReturnType::set_string 1034 ns 1034 ns 677095 +bm_rtl::method____ErasedTargetType::set_string 1020 ns 1020 ns 686724 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1026 ns 1026 ns 681885 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1365 ns 1365 ns 512813 + +bm_call::via_function_ptr__Function::get_string 1366 ns 1366 ns 512341 +bm_call::via_function_ptr____Method::get_string 1365 ns 1365 ns 512596 + +bm_std::function_calls__Function::get_string 1366 ns 1366 ns 512693 +bm_std::function_calls____Method::get_string 1368 ns 1368 ns 511225 + +bm_rtl::function_calls__Function::get_string 1366 ns 1366 ns 512277 +bm_rtl::method_calls______Method::get_string 1364 ns 1364 ns 512854 + +bm_rtl::function__ErasedReturnType::get_string 1388 ns 1388 ns 504445 +bm_rtl::method____ErasedReturnType::get_string 1387 ns 1387 ns 505198 +bm_rtl::method____ErasedTargetType::get_string 1379 ns 1379 ns 507994 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1392 ns 1392 ns 502637 +----------------------------------- +[2026-01-19 22:30:38] >>> Run 1: workload scale = 66 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 66 iterations +============================================= + +2026-01-19T22:30:38+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.04, 0.99, 0.69 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1636 ns 1636 ns 427486 + +bm_call::via_function_ptr__Function::set_string 1628 ns 1628 ns 430101 +bm_call::via_function_ptr____Method::set_string 1629 ns 1629 ns 430065 + +bm_std::function_calls__Function::set_string 1628 ns 1628 ns 429723 +bm_std::function_calls____Method::set_string 1649 ns 1649 ns 424517 + +bm_rtl::function_calls__Function::set_string 1627 ns 1627 ns 430133 +bm_rtl::method_calls______Method::set_string 1628 ns 1628 ns 430349 + +bm_rtl::function__ErasedReturnType::set_string 1640 ns 1640 ns 427551 +bm_rtl::method____ErasedReturnType::set_string 1646 ns 1646 ns 425782 +bm_rtl::method____ErasedTargetType::set_string 1646 ns 1646 ns 425327 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1655 ns 1655 ns 423077 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1990 ns 1990 ns 351983 + +bm_call::via_function_ptr__Function::get_string 1992 ns 1992 ns 351406 +bm_call::via_function_ptr____Method::get_string 1992 ns 1992 ns 351688 + +bm_std::function_calls__Function::get_string 1993 ns 1993 ns 351092 +bm_std::function_calls____Method::get_string 1997 ns 1997 ns 350755 + +bm_rtl::function_calls__Function::get_string 1994 ns 1993 ns 350789 +bm_rtl::method_calls______Method::get_string 1991 ns 1990 ns 351526 + +bm_rtl::function__ErasedReturnType::get_string 2012 ns 2012 ns 348023 +bm_rtl::method____ErasedReturnType::get_string 2014 ns 2014 ns 347409 +bm_rtl::method____ErasedTargetType::get_string 2006 ns 2006 ns 349290 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2017 ns 2017 ns 347043 +----------------------------------- +[2026-01-19 22:30:58] >>> Run 2: workload scale = 66 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 66 iterations +============================================= + +2026-01-19T22:30:58+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.03, 1.00, 0.70 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1633 ns 1632 ns 428557 + +bm_call::via_function_ptr__Function::set_string 1638 ns 1638 ns 427508 +bm_call::via_function_ptr____Method::set_string 1637 ns 1637 ns 427652 + +bm_std::function_calls__Function::set_string 1639 ns 1639 ns 424126 +bm_std::function_calls____Method::set_string 1655 ns 1654 ns 423338 + +bm_rtl::function_calls__Function::set_string 1640 ns 1640 ns 427633 +bm_rtl::method_calls______Method::set_string 1637 ns 1637 ns 427542 + +bm_rtl::function__ErasedReturnType::set_string 1651 ns 1651 ns 424262 +bm_rtl::method____ErasedReturnType::set_string 1654 ns 1654 ns 423134 +bm_rtl::method____ErasedTargetType::set_string 1653 ns 1653 ns 424141 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1655 ns 1655 ns 423152 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1929 ns 1929 ns 363024 + +bm_call::via_function_ptr__Function::get_string 1930 ns 1930 ns 360634 +bm_call::via_function_ptr____Method::get_string 1928 ns 1927 ns 363245 + +bm_std::function_calls__Function::get_string 1934 ns 1934 ns 362508 +bm_std::function_calls____Method::get_string 1933 ns 1933 ns 362322 + +bm_rtl::function_calls__Function::get_string 1933 ns 1933 ns 362483 +bm_rtl::method_calls______Method::get_string 1927 ns 1927 ns 362975 + +bm_rtl::function__ErasedReturnType::get_string 1955 ns 1955 ns 358477 +bm_rtl::method____ErasedReturnType::get_string 1954 ns 1954 ns 358280 +bm_rtl::method____ErasedTargetType::get_string 1948 ns 1948 ns 359867 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1956 ns 1955 ns 357971 +----------------------------------- +[2026-01-19 22:31:18] >>> Run 3: workload scale = 66 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 66 iterations +============================================= + +2026-01-19T22:31:18+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.02, 1.00, 0.71 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1645 ns 1644 ns 425112 + +bm_call::via_function_ptr__Function::set_string 1637 ns 1637 ns 426452 +bm_call::via_function_ptr____Method::set_string 1634 ns 1634 ns 428366 + +bm_std::function_calls__Function::set_string 1638 ns 1638 ns 428140 +bm_std::function_calls____Method::set_string 1643 ns 1643 ns 426062 + +bm_rtl::function_calls__Function::set_string 1637 ns 1636 ns 427885 +bm_rtl::method_calls______Method::set_string 1627 ns 1627 ns 430136 + +bm_rtl::function__ErasedReturnType::set_string 1649 ns 1649 ns 424893 +bm_rtl::method____ErasedReturnType::set_string 1654 ns 1654 ns 420943 +bm_rtl::method____ErasedTargetType::set_string 1647 ns 1647 ns 424746 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1652 ns 1652 ns 424812 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 1924 ns 1924 ns 363906 + +bm_call::via_function_ptr__Function::get_string 1928 ns 1928 ns 363891 +bm_call::via_function_ptr____Method::get_string 1923 ns 1923 ns 364281 + +bm_std::function_calls__Function::get_string 1928 ns 1928 ns 363618 +bm_std::function_calls____Method::get_string 1927 ns 1927 ns 362893 + +bm_rtl::function_calls__Function::get_string 1928 ns 1928 ns 363817 +bm_rtl::method_calls______Method::get_string 1923 ns 1923 ns 363994 + +bm_rtl::function__ErasedReturnType::get_string 1949 ns 1948 ns 359235 +bm_rtl::method____ErasedReturnType::get_string 1949 ns 1949 ns 357588 +bm_rtl::method____ErasedTargetType::get_string 1942 ns 1942 ns 360625 +bm_rtl::method____ErasedTargetAndReturnType::get_string 1951 ns 1951 ns 359255 +----------------------------------- +[2026-01-19 22:31:38] >>> Run 1: workload scale = 74 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 74 iterations +============================================= + +2026-01-19T22:31:38+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.01, 1.00, 0.72 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1704 ns 1704 ns 410694 + +bm_call::via_function_ptr__Function::set_string 1719 ns 1718 ns 407996 +bm_call::via_function_ptr____Method::set_string 1716 ns 1716 ns 407893 + +bm_std::function_calls__Function::set_string 1719 ns 1719 ns 407912 +bm_std::function_calls____Method::set_string 1725 ns 1725 ns 405488 + +bm_rtl::function_calls__Function::set_string 1715 ns 1715 ns 407851 +bm_rtl::method_calls______Method::set_string 1717 ns 1716 ns 405912 + +bm_rtl::function__ErasedReturnType::set_string 1729 ns 1729 ns 405040 +bm_rtl::method____ErasedReturnType::set_string 1749 ns 1749 ns 400776 +bm_rtl::method____ErasedTargetType::set_string 1731 ns 1731 ns 404458 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1742 ns 1741 ns 402397 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2149 ns 2148 ns 325819 + +bm_call::via_function_ptr__Function::get_string 2155 ns 2155 ns 325341 +bm_call::via_function_ptr____Method::get_string 2152 ns 2151 ns 325266 + +bm_std::function_calls__Function::get_string 2155 ns 2155 ns 324846 +bm_std::function_calls____Method::get_string 2158 ns 2158 ns 324258 + +bm_rtl::function_calls__Function::get_string 2152 ns 2152 ns 325164 +bm_rtl::method_calls______Method::get_string 2151 ns 2151 ns 323536 + +bm_rtl::function__ErasedReturnType::get_string 2180 ns 2180 ns 321132 +bm_rtl::method____ErasedReturnType::get_string 2184 ns 2184 ns 320612 +bm_rtl::method____ErasedTargetType::get_string 2170 ns 2170 ns 322408 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2191 ns 2191 ns 320089 +----------------------------------- +[2026-01-19 22:31:58] >>> Run 2: workload scale = 74 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 74 iterations +============================================= + +2026-01-19T22:31:58+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.01, 1.00, 0.73 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1687 ns 1687 ns 414957 + +bm_call::via_function_ptr__Function::set_string 1692 ns 1692 ns 414692 +bm_call::via_function_ptr____Method::set_string 1690 ns 1690 ns 414379 + +bm_std::function_calls__Function::set_string 1692 ns 1692 ns 414244 +bm_std::function_calls____Method::set_string 1697 ns 1697 ns 412772 + +bm_rtl::function_calls__Function::set_string 1689 ns 1688 ns 414394 +bm_rtl::method_calls______Method::set_string 1691 ns 1690 ns 410590 + +bm_rtl::function__ErasedReturnType::set_string 1700 ns 1699 ns 412056 +bm_rtl::method____ErasedReturnType::set_string 1723 ns 1722 ns 406836 +bm_rtl::method____ErasedTargetType::set_string 1700 ns 1700 ns 411498 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1704 ns 1704 ns 411937 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2042 ns 2042 ns 342973 + +bm_call::via_function_ptr__Function::get_string 2047 ns 2046 ns 341626 +bm_call::via_function_ptr____Method::get_string 2048 ns 2048 ns 341905 + +bm_std::function_calls__Function::get_string 2047 ns 2047 ns 341688 +bm_std::function_calls____Method::get_string 2049 ns 2049 ns 341249 + +bm_rtl::function_calls__Function::get_string 2047 ns 2046 ns 342026 +bm_rtl::method_calls______Method::get_string 2047 ns 2047 ns 340194 + +bm_rtl::function__ErasedReturnType::get_string 2071 ns 2071 ns 338168 +bm_rtl::method____ErasedReturnType::get_string 2070 ns 2070 ns 338474 +bm_rtl::method____ErasedTargetType::get_string 2065 ns 2065 ns 339303 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2075 ns 2075 ns 337545 +----------------------------------- +[2026-01-19 22:32:18] >>> Run 3: workload scale = 74 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 74 iterations +============================================= + +2026-01-19T22:32:18+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.73 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1713 ns 1713 ns 408838 + +bm_call::via_function_ptr__Function::set_string 1737 ns 1737 ns 402892 +bm_call::via_function_ptr____Method::set_string 1736 ns 1736 ns 403689 + +bm_std::function_calls__Function::set_string 1738 ns 1738 ns 403157 +bm_std::function_calls____Method::set_string 1757 ns 1757 ns 394167 + +bm_rtl::function_calls__Function::set_string 1736 ns 1736 ns 403487 +bm_rtl::method_calls______Method::set_string 1738 ns 1738 ns 403093 + +bm_rtl::function__ErasedReturnType::set_string 1718 ns 1718 ns 407569 +bm_rtl::method____ErasedReturnType::set_string 1728 ns 1728 ns 405368 +bm_rtl::method____ErasedTargetType::set_string 1709 ns 1709 ns 409316 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1722 ns 1722 ns 406715 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2169 ns 2169 ns 322266 + +bm_call::via_function_ptr__Function::get_string 2173 ns 2173 ns 322587 +bm_call::via_function_ptr____Method::get_string 2174 ns 2173 ns 321966 + +bm_std::function_calls__Function::get_string 2174 ns 2174 ns 321859 +bm_std::function_calls____Method::get_string 2190 ns 2190 ns 319040 + +bm_rtl::function_calls__Function::get_string 2174 ns 2174 ns 321952 +bm_rtl::method_calls______Method::get_string 2174 ns 2174 ns 322166 + +bm_rtl::function__ErasedReturnType::get_string 2154 ns 2154 ns 324962 +bm_rtl::method____ErasedReturnType::get_string 2156 ns 2156 ns 324748 +bm_rtl::method____ErasedTargetType::get_string 2144 ns 2144 ns 326407 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2163 ns 2163 ns 323836 +----------------------------------- +[2026-01-19 22:32:38] >>> Run 1: workload scale = 82 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 82 iterations +============================================= + +2026-01-19T22:32:38+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.74 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1789 ns 1789 ns 391131 + +bm_call::via_function_ptr__Function::set_string 1763 ns 1763 ns 397562 +bm_call::via_function_ptr____Method::set_string 1761 ns 1760 ns 397612 + +bm_std::function_calls__Function::set_string 1761 ns 1761 ns 397459 +bm_std::function_calls____Method::set_string 1766 ns 1765 ns 395213 + +bm_rtl::function_calls__Function::set_string 1761 ns 1761 ns 397571 +bm_rtl::method_calls______Method::set_string 1765 ns 1764 ns 397363 + +bm_rtl::function__ErasedReturnType::set_string 1769 ns 1769 ns 395691 +bm_rtl::method____ErasedReturnType::set_string 1771 ns 1771 ns 395643 +bm_rtl::method____ErasedTargetType::set_string 1770 ns 1770 ns 395133 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1774 ns 1774 ns 395280 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2245 ns 2244 ns 311980 + +bm_call::via_function_ptr__Function::get_string 2248 ns 2248 ns 312148 +bm_call::via_function_ptr____Method::get_string 2246 ns 2246 ns 311894 + +bm_std::function_calls__Function::get_string 2246 ns 2246 ns 311496 +bm_std::function_calls____Method::get_string 2262 ns 2261 ns 309168 + +bm_rtl::function_calls__Function::get_string 2244 ns 2244 ns 311773 +bm_rtl::method_calls______Method::get_string 2248 ns 2248 ns 310230 + +bm_rtl::function__ErasedReturnType::get_string 2282 ns 2282 ns 306813 +bm_rtl::method____ErasedReturnType::get_string 2290 ns 2290 ns 305848 +bm_rtl::method____ErasedTargetType::get_string 2274 ns 2274 ns 307761 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2290 ns 2290 ns 305896 +----------------------------------- +[2026-01-19 22:32:59] >>> Run 2: workload scale = 82 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 82 iterations +============================================= + +2026-01-19T22:32:59+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.74 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1778 ns 1778 ns 393210 + +bm_call::via_function_ptr__Function::set_string 1748 ns 1748 ns 399918 +bm_call::via_function_ptr____Method::set_string 1747 ns 1747 ns 400516 + +bm_std::function_calls__Function::set_string 1750 ns 1750 ns 400672 +bm_std::function_calls____Method::set_string 1755 ns 1755 ns 398944 + +bm_rtl::function_calls__Function::set_string 1750 ns 1750 ns 400631 +bm_rtl::method_calls______Method::set_string 1749 ns 1749 ns 399395 + +bm_rtl::function__ErasedReturnType::set_string 1760 ns 1760 ns 397764 +bm_rtl::method____ErasedReturnType::set_string 1760 ns 1760 ns 397768 +bm_rtl::method____ErasedTargetType::set_string 1762 ns 1762 ns 397246 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1763 ns 1763 ns 397178 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2151 ns 2151 ns 325324 + +bm_call::via_function_ptr__Function::get_string 2149 ns 2148 ns 325850 +bm_call::via_function_ptr____Method::get_string 2148 ns 2148 ns 326230 + +bm_std::function_calls__Function::get_string 2149 ns 2149 ns 326263 +bm_std::function_calls____Method::get_string 2162 ns 2162 ns 323736 + +bm_rtl::function_calls__Function::get_string 2147 ns 2147 ns 325662 +bm_rtl::method_calls______Method::get_string 2147 ns 2147 ns 325369 + +bm_rtl::function__ErasedReturnType::get_string 2176 ns 2176 ns 322001 +bm_rtl::method____ErasedReturnType::get_string 2180 ns 2180 ns 320718 +bm_rtl::method____ErasedTargetType::get_string 2168 ns 2168 ns 322879 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2179 ns 2179 ns 321455 +----------------------------------- +[2026-01-19 22:33:19] >>> Run 3: workload scale = 82 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 82 iterations +============================================= + +2026-01-19T22:33:19+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.75 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1789 ns 1789 ns 391009 + +bm_call::via_function_ptr__Function::set_string 1774 ns 1773 ns 395022 +bm_call::via_function_ptr____Method::set_string 1773 ns 1773 ns 394648 + +bm_std::function_calls__Function::set_string 1774 ns 1774 ns 394608 +bm_std::function_calls____Method::set_string 1776 ns 1776 ns 394117 + +bm_rtl::function_calls__Function::set_string 1773 ns 1773 ns 394842 +bm_rtl::method_calls______Method::set_string 1773 ns 1773 ns 393793 + +bm_rtl::function__ErasedReturnType::set_string 1783 ns 1782 ns 392453 +bm_rtl::method____ErasedReturnType::set_string 1781 ns 1781 ns 393171 +bm_rtl::method____ErasedTargetType::set_string 1784 ns 1784 ns 392212 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1784 ns 1784 ns 392357 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2259 ns 2259 ns 309811 + +bm_call::via_function_ptr__Function::get_string 2262 ns 2262 ns 309475 +bm_call::via_function_ptr____Method::get_string 2261 ns 2261 ns 309595 + +bm_std::function_calls__Function::get_string 2263 ns 2263 ns 309747 +bm_std::function_calls____Method::get_string 2275 ns 2275 ns 307808 + +bm_rtl::function_calls__Function::get_string 2265 ns 2265 ns 309079 +bm_rtl::method_calls______Method::get_string 2262 ns 2262 ns 309463 + +bm_rtl::function__ErasedReturnType::get_string 2302 ns 2302 ns 304220 +bm_rtl::method____ErasedReturnType::get_string 2303 ns 2303 ns 303903 +bm_rtl::method____ErasedTargetType::get_string 2286 ns 2286 ns 306033 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2299 ns 2299 ns 303954 +----------------------------------- +[2026-01-19 22:33:39] >>> Run 1: workload scale = 90 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 90 iterations +============================================= + +2026-01-19T22:33:39+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.76 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1861 ns 1860 ns 375999 + +bm_call::via_function_ptr__Function::set_string 1835 ns 1835 ns 382030 +bm_call::via_function_ptr____Method::set_string 1834 ns 1834 ns 381859 + +bm_std::function_calls__Function::set_string 1836 ns 1836 ns 381565 +bm_std::function_calls____Method::set_string 1840 ns 1840 ns 380541 + +bm_rtl::function_calls__Function::set_string 1836 ns 1835 ns 381728 +bm_rtl::method_calls______Method::set_string 1834 ns 1834 ns 381897 + +bm_rtl::function__ErasedReturnType::set_string 1847 ns 1847 ns 379564 +bm_rtl::method____ErasedReturnType::set_string 1873 ns 1873 ns 373534 +bm_rtl::method____ErasedTargetType::set_string 1847 ns 1847 ns 379013 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1846 ns 1846 ns 377722 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2372 ns 2371 ns 295210 + +bm_call::via_function_ptr__Function::get_string 2375 ns 2374 ns 295181 +bm_call::via_function_ptr____Method::get_string 2371 ns 2371 ns 295161 + +bm_std::function_calls__Function::get_string 2373 ns 2373 ns 295444 +bm_std::function_calls____Method::get_string 2375 ns 2374 ns 294851 + +bm_rtl::function_calls__Function::get_string 2375 ns 2375 ns 295197 +bm_rtl::method_calls______Method::get_string 2371 ns 2370 ns 295144 + +bm_rtl::function__ErasedReturnType::get_string 2402 ns 2402 ns 291878 +bm_rtl::method____ErasedReturnType::get_string 2401 ns 2401 ns 291746 +bm_rtl::method____ErasedTargetType::get_string 2394 ns 2394 ns 292974 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2405 ns 2405 ns 291092 +----------------------------------- +[2026-01-19 22:34:00] >>> Run 2: workload scale = 90 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 90 iterations +============================================= + +2026-01-19T22:34:00+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.76 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1849 ns 1849 ns 378261 + +bm_call::via_function_ptr__Function::set_string 1823 ns 1823 ns 383390 +bm_call::via_function_ptr____Method::set_string 1826 ns 1826 ns 383423 + +bm_std::function_calls__Function::set_string 1826 ns 1826 ns 383591 +bm_std::function_calls____Method::set_string 1831 ns 1831 ns 381967 + +bm_rtl::function_calls__Function::set_string 1825 ns 1825 ns 383713 +bm_rtl::method_calls______Method::set_string 1827 ns 1826 ns 383181 + +bm_rtl::function__ErasedReturnType::set_string 1834 ns 1834 ns 381783 +bm_rtl::method____ErasedReturnType::set_string 1864 ns 1864 ns 375810 +bm_rtl::method____ErasedTargetType::set_string 1837 ns 1837 ns 380838 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1836 ns 1836 ns 381270 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2263 ns 2263 ns 309522 + +bm_call::via_function_ptr__Function::get_string 2263 ns 2263 ns 309279 +bm_call::via_function_ptr____Method::get_string 2264 ns 2263 ns 309468 + +bm_std::function_calls__Function::get_string 2264 ns 2264 ns 308991 +bm_std::function_calls____Method::get_string 2268 ns 2268 ns 308743 + +bm_rtl::function_calls__Function::get_string 2264 ns 2263 ns 309197 +bm_rtl::method_calls______Method::get_string 2263 ns 2263 ns 309007 + +bm_rtl::function__ErasedReturnType::get_string 2293 ns 2293 ns 305398 +bm_rtl::method____ErasedReturnType::get_string 2295 ns 2294 ns 305011 +bm_rtl::method____ErasedTargetType::get_string 2282 ns 2282 ns 306678 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2293 ns 2292 ns 305219 +----------------------------------- +[2026-01-19 22:34:20] >>> Run 3: workload scale = 90 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 90 iterations +============================================= + +2026-01-19T22:34:20+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.77 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1848 ns 1847 ns 379051 + +bm_call::via_function_ptr__Function::set_string 1834 ns 1834 ns 381757 +bm_call::via_function_ptr____Method::set_string 1840 ns 1840 ns 380947 + +bm_std::function_calls__Function::set_string 1836 ns 1835 ns 381485 +bm_std::function_calls____Method::set_string 1868 ns 1868 ns 375302 + +bm_rtl::function_calls__Function::set_string 1834 ns 1834 ns 381787 +bm_rtl::method_calls______Method::set_string 1837 ns 1836 ns 381079 + +bm_rtl::function__ErasedReturnType::set_string 1845 ns 1844 ns 379011 +bm_rtl::method____ErasedReturnType::set_string 1846 ns 1846 ns 379197 +bm_rtl::method____ErasedTargetType::set_string 1848 ns 1848 ns 379779 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1848 ns 1847 ns 379216 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2293 ns 2292 ns 305828 + +bm_call::via_function_ptr__Function::get_string 2290 ns 2290 ns 305261 +bm_call::via_function_ptr____Method::get_string 2296 ns 2296 ns 305268 + +bm_std::function_calls__Function::get_string 2293 ns 2293 ns 305575 +bm_std::function_calls____Method::get_string 2302 ns 2302 ns 304368 + +bm_rtl::function_calls__Function::get_string 2291 ns 2290 ns 305721 +bm_rtl::method_calls______Method::get_string 2295 ns 2295 ns 305440 + +bm_rtl::function__ErasedReturnType::get_string 2322 ns 2322 ns 301402 +bm_rtl::method____ErasedReturnType::get_string 2325 ns 2325 ns 300979 +bm_rtl::method____ErasedTargetType::get_string 2313 ns 2313 ns 301214 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2321 ns 2321 ns 301863 +----------------------------------- +[2026-01-19 22:34:41] >>> Run 1: workload scale = 100 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 100 iterations +============================================= + +2026-01-19T22:34:41+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.77 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1997 ns 1997 ns 348547 + +bm_call::via_function_ptr__Function::set_string 1990 ns 1990 ns 352058 +bm_call::via_function_ptr____Method::set_string 1990 ns 1990 ns 351866 + +bm_std::function_calls__Function::set_string 1989 ns 1989 ns 351920 +bm_std::function_calls____Method::set_string 1954 ns 1954 ns 358559 + +bm_rtl::function_calls__Function::set_string 1989 ns 1989 ns 352081 +bm_rtl::method_calls______Method::set_string 1992 ns 1992 ns 351760 + +bm_rtl::function__ErasedReturnType::set_string 1963 ns 1962 ns 357063 +bm_rtl::method____ErasedReturnType::set_string 1960 ns 1960 ns 357847 +bm_rtl::method____ErasedTargetType::set_string 1946 ns 1946 ns 359612 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1962 ns 1961 ns 356847 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2504 ns 2504 ns 278402 + +bm_call::via_function_ptr__Function::get_string 2501 ns 2501 ns 279911 +bm_call::via_function_ptr____Method::get_string 2502 ns 2502 ns 279036 + +bm_std::function_calls__Function::get_string 2500 ns 2499 ns 280151 +bm_std::function_calls____Method::get_string 2459 ns 2458 ns 283683 + +bm_rtl::function_calls__Function::get_string 2501 ns 2501 ns 279874 +bm_rtl::method_calls______Method::get_string 2504 ns 2504 ns 279888 + +bm_rtl::function__ErasedReturnType::get_string 2482 ns 2481 ns 282147 +bm_rtl::method____ErasedReturnType::get_string 2485 ns 2485 ns 282054 +bm_rtl::method____ErasedTargetType::get_string 2467 ns 2467 ns 283637 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2488 ns 2487 ns 281941 +----------------------------------- +[2026-01-19 22:35:01] >>> Run 2: workload scale = 100 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 100 iterations +============================================= + +2026-01-19T22:35:01+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.00, 1.00, 0.78 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1947 ns 1947 ns 359187 + +bm_call::via_function_ptr__Function::set_string 1938 ns 1938 ns 361868 +bm_call::via_function_ptr____Method::set_string 1935 ns 1935 ns 361960 + +bm_std::function_calls__Function::set_string 1937 ns 1936 ns 361911 +bm_std::function_calls____Method::set_string 1944 ns 1943 ns 360138 + +bm_rtl::function_calls__Function::set_string 1934 ns 1934 ns 361967 +bm_rtl::method_calls______Method::set_string 1935 ns 1935 ns 360915 + +bm_rtl::function__ErasedReturnType::set_string 1945 ns 1945 ns 360218 +bm_rtl::method____ErasedReturnType::set_string 1942 ns 1942 ns 358792 +bm_rtl::method____ErasedTargetType::set_string 1947 ns 1946 ns 359434 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1949 ns 1949 ns 359796 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2451 ns 2450 ns 285493 + +bm_call::via_function_ptr__Function::get_string 2453 ns 2453 ns 285744 +bm_call::via_function_ptr____Method::get_string 2451 ns 2451 ns 285759 + +bm_std::function_calls__Function::get_string 2456 ns 2455 ns 285718 +bm_std::function_calls____Method::get_string 2469 ns 2469 ns 283176 + +bm_rtl::function_calls__Function::get_string 2456 ns 2456 ns 285646 +bm_rtl::method_calls______Method::get_string 2451 ns 2451 ns 285771 + +bm_rtl::function__ErasedReturnType::get_string 2500 ns 2500 ns 281548 +bm_rtl::method____ErasedReturnType::get_string 2599 ns 2599 ns 274914 +bm_rtl::method____ErasedTargetType::get_string 2587 ns 2586 ns 270912 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2595 ns 2595 ns 269299 +----------------------------------- +[2026-01-19 22:35:22] >>> Run 3: workload scale = 100 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 100 iterations +============================================= + +2026-01-19T22:35:22+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 2685.67 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.08, 1.02, 0.79 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 1940 ns 1940 ns 359624 + +bm_call::via_function_ptr__Function::set_string 1944 ns 1944 ns 360107 +bm_call::via_function_ptr____Method::set_string 1942 ns 1942 ns 360542 + +bm_std::function_calls__Function::set_string 1942 ns 1942 ns 357815 +bm_std::function_calls____Method::set_string 1963 ns 1963 ns 356515 + +bm_rtl::function_calls__Function::set_string 1947 ns 1947 ns 360618 +bm_rtl::method_calls______Method::set_string 1943 ns 1943 ns 360619 + +bm_rtl::function__ErasedReturnType::set_string 1977 ns 1976 ns 358735 +bm_rtl::method____ErasedReturnType::set_string 1946 ns 1945 ns 358855 +bm_rtl::method____ErasedTargetType::set_string 1949 ns 1949 ns 359699 +bm_rtl::method____ErasedTargetAndReturnType::set_string 1949 ns 1949 ns 359356 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2458 ns 2458 ns 284033 + +bm_call::via_function_ptr__Function::get_string 2457 ns 2457 ns 285086 +bm_call::via_function_ptr____Method::get_string 2458 ns 2458 ns 285013 + +bm_std::function_calls__Function::get_string 2455 ns 2455 ns 285133 +bm_std::function_calls____Method::get_string 2462 ns 2462 ns 284508 + +bm_rtl::function_calls__Function::get_string 2457 ns 2457 ns 285057 +bm_rtl::method_calls______Method::get_string 2456 ns 2456 ns 285020 + +bm_rtl::function__ErasedReturnType::get_string 2486 ns 2486 ns 281798 +bm_rtl::method____ErasedReturnType::get_string 2487 ns 2486 ns 281683 +bm_rtl::method____ErasedTargetType::get_string 2470 ns 2470 ns 283091 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2492 ns 2492 ns 280955 +----------------------------------- +[2026-01-19 22:35:43] >>> Run 1: workload scale = 120 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 120 iterations +============================================= + +2026-01-19T22:35:43+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.06, 1.01, 0.80 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 2137 ns 2137 ns 326829 + +bm_call::via_function_ptr__Function::set_string 2125 ns 2124 ns 329605 +bm_call::via_function_ptr____Method::set_string 2125 ns 2125 ns 329665 + +bm_std::function_calls__Function::set_string 2124 ns 2124 ns 329576 +bm_std::function_calls____Method::set_string 2157 ns 2157 ns 324516 + +bm_rtl::function_calls__Function::set_string 2123 ns 2123 ns 329881 +bm_rtl::method_calls______Method::set_string 2125 ns 2124 ns 329448 + +bm_rtl::function__ErasedReturnType::set_string 2129 ns 2129 ns 328759 +bm_rtl::method____ErasedReturnType::set_string 2131 ns 2130 ns 305340 +bm_rtl::method____ErasedTargetType::set_string 2131 ns 2131 ns 328500 +bm_rtl::method____ErasedTargetAndReturnType::set_string 2132 ns 2132 ns 328066 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 3007 ns 3007 ns 232978 + +bm_call::via_function_ptr__Function::get_string 3011 ns 3010 ns 232634 +bm_call::via_function_ptr____Method::get_string 3012 ns 3011 ns 232464 + +bm_std::function_calls__Function::get_string 3014 ns 3013 ns 232339 +bm_std::function_calls____Method::get_string 3019 ns 3019 ns 231831 + +bm_rtl::function_calls__Function::get_string 3014 ns 3013 ns 232535 +bm_rtl::method_calls______Method::get_string 3008 ns 3008 ns 232654 + +bm_rtl::function__ErasedReturnType::get_string 3051 ns 3051 ns 229522 +bm_rtl::method____ErasedReturnType::get_string 3040 ns 3040 ns 230285 +bm_rtl::method____ErasedTargetType::get_string 3040 ns 3040 ns 230408 +bm_rtl::method____ErasedTargetAndReturnType::get_string 3042 ns 3041 ns 230091 +----------------------------------- +[2026-01-19 22:36:05] >>> Run 2: workload scale = 120 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 120 iterations +============================================= + +2026-01-19T22:36:05+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.04, 1.01, 0.80 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 2128 ns 2128 ns 329355 + +bm_call::via_function_ptr__Function::set_string 2125 ns 2125 ns 329104 +bm_call::via_function_ptr____Method::set_string 2128 ns 2128 ns 329260 + +bm_std::function_calls__Function::set_string 2126 ns 2126 ns 329537 +bm_std::function_calls____Method::set_string 2159 ns 2158 ns 325160 + +bm_rtl::function_calls__Function::set_string 2126 ns 2126 ns 329470 +bm_rtl::method_calls______Method::set_string 2125 ns 2125 ns 329217 + +bm_rtl::function__ErasedReturnType::set_string 2134 ns 2134 ns 326337 +bm_rtl::method____ErasedReturnType::set_string 2140 ns 2140 ns 327348 +bm_rtl::method____ErasedTargetType::set_string 2137 ns 2137 ns 327992 +bm_rtl::method____ErasedTargetAndReturnType::set_string 2150 ns 2150 ns 325220 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2895 ns 2894 ns 242080 + +bm_call::via_function_ptr__Function::get_string 2892 ns 2892 ns 242012 +bm_call::via_function_ptr____Method::get_string 2897 ns 2897 ns 241915 + +bm_std::function_calls__Function::get_string 2894 ns 2894 ns 242013 +bm_std::function_calls____Method::get_string 2897 ns 2897 ns 241621 + +bm_rtl::function_calls__Function::get_string 2891 ns 2891 ns 242113 +bm_rtl::method_calls______Method::get_string 2970 ns 2939 ns 241649 + +bm_rtl::function__ErasedReturnType::get_string 2922 ns 2922 ns 239779 +bm_rtl::method____ErasedReturnType::get_string 2924 ns 2924 ns 238642 +bm_rtl::method____ErasedTargetType::get_string 2911 ns 2911 ns 240434 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2937 ns 2937 ns 237304 +----------------------------------- +[2026-01-19 22:36:26] >>> Run 3: workload scale = 120 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 120 iterations +============================================= + +2026-01-19T22:36:26+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.02, 1.01, 0.81 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 2123 ns 2123 ns 330104 + +bm_call::via_function_ptr__Function::set_string 2119 ns 2118 ns 331108 +bm_call::via_function_ptr____Method::set_string 2143 ns 2142 ns 327007 + +bm_std::function_calls__Function::set_string 2117 ns 2117 ns 330772 +bm_std::function_calls____Method::set_string 2123 ns 2123 ns 329985 + +bm_rtl::function_calls__Function::set_string 2118 ns 2118 ns 331201 +bm_rtl::method_calls______Method::set_string 2123 ns 2123 ns 330834 + +bm_rtl::function__ErasedReturnType::set_string 2132 ns 2131 ns 328810 +bm_rtl::method____ErasedReturnType::set_string 2157 ns 2156 ns 324121 +bm_rtl::method____ErasedTargetType::set_string 2135 ns 2134 ns 321782 +bm_rtl::method____ErasedTargetAndReturnType::set_string 2130 ns 2130 ns 328678 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 2890 ns 2890 ns 242683 + +bm_call::via_function_ptr__Function::get_string 2892 ns 2891 ns 237467 +bm_call::via_function_ptr____Method::get_string 2891 ns 2891 ns 242306 + +bm_std::function_calls__Function::get_string 2891 ns 2891 ns 242434 +bm_std::function_calls____Method::get_string 2893 ns 2892 ns 242299 + +bm_rtl::function_calls__Function::get_string 2888 ns 2887 ns 242305 +bm_rtl::method_calls______Method::get_string 2897 ns 2897 ns 242416 + +bm_rtl::function__ErasedReturnType::get_string 2918 ns 2918 ns 239887 +bm_rtl::method____ErasedReturnType::get_string 3088 ns 3087 ns 238252 +bm_rtl::method____ErasedTargetType::get_string 2907 ns 2907 ns 236594 +bm_rtl::method____ErasedTargetAndReturnType::get_string 2929 ns 2928 ns 239651 +----------------------------------- +[2026-01-19 22:36:48] >>> Run 1: workload scale = 150 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 150 iterations +============================================= + +2026-01-19T22:36:48+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.10, 1.03, 0.82 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 3502 ns 3502 ns 200154 + +bm_call::via_function_ptr__Function::set_string 3514 ns 3514 ns 199717 +bm_call::via_function_ptr____Method::set_string 3511 ns 3511 ns 198567 + +bm_std::function_calls__Function::set_string 3515 ns 3515 ns 199394 +bm_std::function_calls____Method::set_string 3485 ns 3485 ns 200801 + +bm_rtl::function_calls__Function::set_string 3511 ns 3510 ns 199483 +bm_rtl::method_calls______Method::set_string 3515 ns 3514 ns 199409 + +bm_rtl::function__ErasedReturnType::set_string 3524 ns 3524 ns 196051 +bm_rtl::method____ErasedReturnType::set_string 3496 ns 3495 ns 200018 +bm_rtl::method____ErasedTargetType::set_string 3531 ns 3531 ns 197723 +bm_rtl::method____ErasedTargetAndReturnType::set_string 3534 ns 3533 ns 198440 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 4399 ns 4399 ns 159236 + +bm_call::via_function_ptr__Function::get_string 4399 ns 4398 ns 159393 +bm_call::via_function_ptr____Method::get_string 4393 ns 4392 ns 159311 + +bm_std::function_calls__Function::get_string 4393 ns 4393 ns 158980 +bm_std::function_calls____Method::get_string 4394 ns 4394 ns 159365 + +bm_rtl::function_calls__Function::get_string 4391 ns 4391 ns 159379 +bm_rtl::method_calls______Method::get_string 4400 ns 4399 ns 159263 + +bm_rtl::function__ErasedReturnType::get_string 4437 ns 4436 ns 157746 +bm_rtl::method____ErasedReturnType::get_string 4434 ns 4434 ns 157288 +bm_rtl::method____ErasedTargetType::get_string 4426 ns 4425 ns 158114 +bm_rtl::method____ErasedTargetAndReturnType::get_string 4434 ns 4434 ns 157500 +----------------------------------- +[2026-01-19 22:37:13] >>> Run 2: workload scale = 150 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 150 iterations +============================================= + +2026-01-19T22:37:13+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.06, 1.02, 0.83 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 3527 ns 3526 ns 198689 + +bm_call::via_function_ptr__Function::set_string 3483 ns 3483 ns 200998 +bm_call::via_function_ptr____Method::set_string 3488 ns 3487 ns 201053 + +bm_std::function_calls__Function::set_string 3485 ns 3484 ns 200867 +bm_std::function_calls____Method::set_string 3490 ns 3489 ns 200690 + +bm_rtl::function_calls__Function::set_string 3483 ns 3482 ns 200910 +bm_rtl::method_calls______Method::set_string 3487 ns 3487 ns 200961 + +bm_rtl::function__ErasedReturnType::set_string 3493 ns 3493 ns 200445 +bm_rtl::method____ErasedReturnType::set_string 3491 ns 3491 ns 199857 +bm_rtl::method____ErasedTargetType::set_string 3495 ns 3495 ns 200225 +bm_rtl::method____ErasedTargetAndReturnType::set_string 3495 ns 3494 ns 199782 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 4404 ns 4404 ns 159253 + +bm_call::via_function_ptr__Function::get_string 4394 ns 4394 ns 159252 +bm_call::via_function_ptr____Method::get_string 4504 ns 4504 ns 159232 + +bm_std::function_calls__Function::get_string 4571 ns 4570 ns 153180 +bm_std::function_calls____Method::get_string 4586 ns 4585 ns 152353 + +bm_rtl::function_calls__Function::get_string 4578 ns 4578 ns 153148 +bm_rtl::method_calls______Method::get_string 4571 ns 4571 ns 153119 + +bm_rtl::function__ErasedReturnType::get_string 4602 ns 4601 ns 152206 +bm_rtl::method____ErasedReturnType::get_string 4607 ns 4606 ns 151999 +bm_rtl::method____ErasedTargetType::get_string 4589 ns 4588 ns 152669 +bm_rtl::method____ErasedTargetAndReturnType::get_string 4600 ns 4600 ns 152200 +----------------------------------- +[2026-01-19 22:37:38] >>> Run 3: workload scale = 150 + +======== RTL Benchmark Configuration ======== +Workload: concatenate string of length 500 +Scale : 150 iterations +============================================= + +2026-01-19T22:37:38+05:30 +Running ./bin/RTLBenchmarkApp +Run on (16 X 800 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 20480 KiB (x1) +Load Average: 1.04, 1.02, 0.83 +-------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::set_string 3547 ns 3547 ns 197337 + +bm_call::via_function_ptr__Function::set_string 3484 ns 3484 ns 200911 +bm_call::via_function_ptr____Method::set_string 3484 ns 3484 ns 200978 + +bm_std::function_calls__Function::set_string 3484 ns 3484 ns 200913 +bm_std::function_calls____Method::set_string 3485 ns 3485 ns 200887 + +bm_rtl::function_calls__Function::set_string 3482 ns 3482 ns 201096 +bm_rtl::method_calls______Method::set_string 3485 ns 3484 ns 200963 + +bm_rtl::function__ErasedReturnType::set_string 3490 ns 3490 ns 200491 +bm_rtl::method____ErasedReturnType::set_string 3491 ns 3491 ns 200589 +bm_rtl::method____ErasedTargetType::set_string 3496 ns 3495 ns 200278 +bm_rtl::method____ErasedTargetAndReturnType::set_string 3496 ns 3496 ns 200227 +-------------------------------------------------------------------------------------------------- +bm_call::direct__Function::get_string 4561 ns 4560 ns 153507 + +bm_call::via_function_ptr__Function::get_string 4560 ns 4559 ns 153553 +bm_call::via_function_ptr____Method::get_string 4559 ns 4559 ns 153622 + +bm_std::function_calls__Function::get_string 4559 ns 4559 ns 153581 +bm_std::function_calls____Method::get_string 4578 ns 4578 ns 152921 + +bm_rtl::function_calls__Function::get_string 4627 ns 4627 ns 153630 +bm_rtl::method_calls______Method::get_string 4486 ns 4484 ns 158892 + +bm_rtl::function__ErasedReturnType::get_string 4433 ns 4433 ns 156084 +bm_rtl::method____ErasedReturnType::get_string 4433 ns 4432 ns 157643 +bm_rtl::method____ErasedTargetType::get_string 4403 ns 4403 ns 158980 +bm_rtl::method____ErasedTargetAndReturnType::get_string 4422 ns 4421 ns 157853 +----------------------------------- +All benchmarks completed. diff --git a/docs/benchmark_summary.md b/docs/benchmark_summary.md new file mode 100644 index 00000000..a74cda08 --- /dev/null +++ b/docs/benchmark_summary.md @@ -0,0 +1,104 @@ +# ⚡ RTL Performance Summary + +This document provides a concise, evidence-backed overview of the runtime performance characteristics of **RTL**, derived from systematic microbenchmarking across multiple workload scales, CPU frequencies, and typical real-world C++ usage patterns. + +## Benchmark Overview + +The benchmark measures the cost of calling functions that perform simple but realistic `string` work. Two variants are evaluated using the types `std::string_view` and `std::string`. + +### Lightweight Workflow + +The `set`/`get` functions are called via reflection and, RTL’s dispatch layer perfect-forwards the provided arguments to the target call site. + +* The input string of length 500 is passed by value as `std::string_view`. +* The function `set(std::string_view)` copies the argument. This copy is very lightweight, as it only contains a pointer and a size. +* The actual work performed is concatenating the passed string into a global `std::string` for a given number of iterations (the workload scale). +* The getter, `std::string_view get(std::string_view)`, follows the same flow, including the argument copy, and returns a `std::string_view` pointing to the globally stored string, which is again a lightweight object. + +### Heavy Workflow + +The dispatch setup of the heavy workflow is the same, except it uses `std::string` instead of `std::string_view`, which means: + +* The input string is passed by value as `std::string` and is copied on every call. Both `set` and `get` perform this copy operation for a 500-character string, typically involving heap allocation. +* Each workload iteration concatenates this 500-character string into the global storage. +* The getter `std::string get(std::string)`, returns a full `std::string` copy of the accumulated global string, which grows in size with the workload and requires heap allocation. + +In both cases, the real work is dominated by string concatenation, allocation, and copying. +The benchmarks therefore highlight how different call paths – direct calls, `std::function`, and reflected(`rtl::function`/`rtl::method`) calls behave when meaningful work is present, rather than measuring dispatch overhead in isolation. + +Workload scales tested: *0, 1, 5, 10, 15, 20, 25 … up to 150.* + +## 🚀 Results with `std::string_view` Workflow + +### Dispatch Overhead + + + +***RTL (standard)** refers to typed calls where the target and return types are known at compile time.* + +### Scaling Workloads (0 to 150) + + + +### Observations + +* `rtl::function` matches or outperforms `std::function`. +* Non-erased RTL calls are effectively zero-overhead. +* Erased return types introduce measurable but bounded overhead. +* Dispatch cost is quickly amortized once real work is present. + +## 🧱 Results with `std::string` Workflow + +### Dispatch Overhead + + + +### Scaling Workloads (0 to 150) + + + +### Observations + +* Getter cost is significantly higher due to return-by-value. +* Memory allocation and copying dominate runtime. +* Reflection overhead becomes negligible in comparison. +* Even fully erased RTL calls remain within ~3–5% of direct calls. + +## 📌 Key Insights + +* `rtl::function` consistently matches or outperforms `std::function` across all workloads. +* Non-erased RTL calls behave like near-zero-overhead abstractions, comparable to raw function pointers. +* Type erasure introduces overhead, but the cost is bounded and predictable. +* Return-type erasure is more expensive than target-type erasure, especially for `std::string` return values. +* As workload size increases, real work dominates dispatch overhead. +* Memory allocation and string copying become the primary performance costs. +* Reflection does not distort scaling behavior or introduce nonlinear slowdowns. +* The value vs view semantics have a larger performance impact than reflection itself. + +## 🖥️ Test Bed + +The benchmarks were executed on a Linux x86_64 system in a typical release-style configuration. The details below capture the essential factors needed for reproducibility. + +* **OS:** Linux (Kernel `6.12.38+kali-amd64`) +* **Compiler:** Clang++ **21.1.8** +* **C++ Standard:** GNU++20 (`-std=gnu++20`) +* **Optimization:** `-O3 -DNDEBUG` +* **LTO:** disabled (no `-flto`) +* **RTTI / Exceptions:** enabled (defaults) +* **CPU tuning:** generic x86-64 (no `-march=native`) +* **Standard library:** `libstdc++` (system default) + +**Hardware (observed):** + +* 16 logical cores +* Dynamic frequency scaling (~800 MHz – ~4.8 GHz) + +Benchmarks were run multiple times under **low system load** (load average consistently < 1.0, as recorded in logs) to ensure stable and comparable performance trends across workloads. + +## 📂 Raw Benchmark Logs + +[benchmark_runs_string.log](benchmark_runs_string.log) + +[benchmark_runs_string_view.log](benchmark_runs_string_view.log) + +These logs contain the full per-scale measurements for all dispatch paths, including multiple runs at different CPU frequencies to validate consistency. diff --git a/docs/images/string_micro_bm.png b/docs/images/string_micro_bm.png new file mode 100644 index 00000000..cce074d1 Binary files /dev/null and b/docs/images/string_micro_bm.png differ diff --git a/docs/images/string_view_micro_bm.png b/docs/images/string_view_micro_bm.png new file mode 100644 index 00000000..dc74fbb9 Binary files /dev/null and b/docs/images/string_view_micro_bm.png differ diff --git a/docs/images/string_view_workload_bm.png b/docs/images/string_view_workload_bm.png new file mode 100644 index 00000000..c522823d Binary files /dev/null and b/docs/images/string_view_workload_bm.png differ diff --git a/docs/images/string_workload_bm.png b/docs/images/string_workload_bm.png new file mode 100644 index 00000000..6e7bcb1f Binary files /dev/null and b/docs/images/string_workload_bm.png differ diff --git a/run_benchmarks.sh b/run_benchmarks.sh new file mode 100755 index 00000000..e6d42d56 --- /dev/null +++ b/run_benchmarks.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# =========================== +# RTL Benchmark Runner Script +# =========================== + +BINARY="./bin/RTLBenchmarkApp" +LOGFILE="./benchmark_runs.log" + +# Clear old log file +: > "$LOGFILE" + +echo "Starting benchmark runs..." | tee -a "$LOGFILE" +echo "Binary: $BINARY" | tee -a "$LOGFILE" +echo "Log: $LOGFILE" | tee -a "$LOGFILE" +echo "===================================" | tee -a "$LOGFILE" + +# Helper: run workload N times +run_benchmark() { + local scale=$1 + local reps=$2 + for i in $(seq 1 "$reps"); do + echo "[$(date '+%Y-%m-%d %H:%M:%S')] >>> Run $i: workload scale = $scale" | tee -a "$LOGFILE" + if ! "$BINARY" "$scale" >> "$LOGFILE" 2>&1; then + echo "[ERROR] Binary failed at scale=$scale (run $i)" | tee -a "$LOGFILE" + fi + echo "-----------------------------------" | tee -a "$LOGFILE" + done +} + +# --------------------------- +# Phase 1: Baseline runs (scale 0, 10 reps) +# --------------------------- +run_benchmark 0 5 + +# --------------------------- +# Phase 2: Scales 1 → 50 +# --------------------------- +SCALES_PHASE2=(1 5 10 15 20 25 30 35 40 45 50) +for SCALE in "${SCALES_PHASE2[@]}"; do + run_benchmark "$SCALE" 3 +done + +# --------------------------- +# Phase 3: Scales 58 → 90 (step 8) +# --------------------------- +for SCALE in $(seq 58 8 90); do + run_benchmark "$SCALE" 3 +done + +# --------------------------- +# Phase 4: Final higher scales +# --------------------------- +for SCALE in 100 120 150; do + run_benchmark "$SCALE" 3 +done + +echo "All benchmarks completed." | tee -a "$LOGFILE"