From 9676da8861675581e91cb4d5411a7d01e8165b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB?= <119668441+Jiga228@users.noreply.github.com> Date: Mon, 28 Jul 2025 20:09:18 +0700 Subject: [PATCH] Add tests --- CMakeLists.txt | 8 ++++ README.md | 11 +++++ RTTI/CMakeLists.txt | 26 +++++++++++ RTTI/RTTI_Meta.h | 2 +- Tests/CMakeLists.txt | 55 ++++++++++++++++++++++ Tests/ClassesDefault/ClassA.cpp | 8 ++++ Tests/ClassesDefault/ClassA.h | 6 +++ Tests/ClassesDefault/ClassB.cpp | 5 ++ Tests/ClassesDefault/ClassB.h | 8 ++++ Tests/ClassesDefault/ClassC.cpp | 6 +++ Tests/ClassesDefault/ClassC.h | 8 ++++ Tests/ClassesDefault/ClassD.cpp | 6 +++ Tests/ClassesDefault/ClassD.h | 8 ++++ Tests/ClassesDefault/ClassE.cpp | 6 +++ Tests/ClassesDefault/ClassE.h | 9 ++++ Tests/ClassesFast/ClassA.cpp | 8 ++++ Tests/ClassesFast/ClassA.h | 9 ++++ Tests/ClassesFast/ClassB.cpp | 5 ++ Tests/ClassesFast/ClassB.h | 9 ++++ Tests/ClassesFast/ClassC.cpp | 6 +++ Tests/ClassesFast/ClassC.h | 9 ++++ Tests/ClassesFast/ClassD.cpp | 6 +++ Tests/ClassesFast/ClassD.h | 9 ++++ Tests/ClassesFast/ClassE.cpp | 6 +++ Tests/ClassesFast/ClassE.h | 10 ++++ Tests/test_default_rtti.cpp | 82 +++++++++++++++++++++++++++++++++ Tests/test_fast_rtti.cpp | 78 +++++++++++++++++++++++++++++++ 27 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt create mode 100644 RTTI/CMakeLists.txt create mode 100644 Tests/CMakeLists.txt create mode 100644 Tests/ClassesDefault/ClassA.cpp create mode 100644 Tests/ClassesDefault/ClassA.h create mode 100644 Tests/ClassesDefault/ClassB.cpp create mode 100644 Tests/ClassesDefault/ClassB.h create mode 100644 Tests/ClassesDefault/ClassC.cpp create mode 100644 Tests/ClassesDefault/ClassC.h create mode 100644 Tests/ClassesDefault/ClassD.cpp create mode 100644 Tests/ClassesDefault/ClassD.h create mode 100644 Tests/ClassesDefault/ClassE.cpp create mode 100644 Tests/ClassesDefault/ClassE.h create mode 100644 Tests/ClassesFast/ClassA.cpp create mode 100644 Tests/ClassesFast/ClassA.h create mode 100644 Tests/ClassesFast/ClassB.cpp create mode 100644 Tests/ClassesFast/ClassB.h create mode 100644 Tests/ClassesFast/ClassC.cpp create mode 100644 Tests/ClassesFast/ClassC.h create mode 100644 Tests/ClassesFast/ClassD.cpp create mode 100644 Tests/ClassesFast/ClassD.h create mode 100644 Tests/ClassesFast/ClassE.cpp create mode 100644 Tests/ClassesFast/ClassE.h create mode 100644 Tests/test_default_rtti.cpp create mode 100644 Tests/test_fast_rtti.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..057ecb5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.5) + +project(FastRTTI VERSION 1.0.0) + +file(GLOB_RECURSE SRC "*.cpp" "*.h") + +add_subdirectory(RTTI) +add_subdirectory(Tests) \ No newline at end of file diff --git a/README.md b/README.md index 5e44557..b327733 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ # Fast-RTTI This library implements fast RTTI for C++. + +Tests: +[Direct type casting] +dynami_cast: 202ms +RTTI::dyn_cast: 54ms +[Possible type casting] +dynami_cast: 193ms +RTTI::dyn_cast: 41ms +[Not possible type casting] +dynami_cast: 489ms +RTTI::dyn_cast: 43ms diff --git a/RTTI/CMakeLists.txt b/RTTI/CMakeLists.txt new file mode 100644 index 0000000..924e89a --- /dev/null +++ b/RTTI/CMakeLists.txt @@ -0,0 +1,26 @@ +file(GLOB SRC "*.cpp" "*.h") + +add_library(${CMAKE_PROJECT_NAME} STATIC ${SRC}) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + message(STATUS "Release mode: enabling optimizations") + + if(MSVC) + # /O2 - высокая оптимизация + # /GL - link-time optimization + # /DNDEBUG - отключить assert() + # /GR- - отключить RTTI + target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE /O2 /GL /DNDEBUG /GR-) + target_link_options(${CMAKE_PROJECT_NAME} PRIVATE /LTCG) + else() + # GCC / Clang + target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE + -O3 + -march=native + -flto + -fno-rtti + -DNDEBUG + ) + target_link_options(${CMAKE_PROJECT_NAME} PRIVATE -flto) + endif() +endif() \ No newline at end of file diff --git a/RTTI/RTTI_Meta.h b/RTTI/RTTI_Meta.h index e77121a..03f0000 100644 --- a/RTTI/RTTI_Meta.h +++ b/RTTI/RTTI_Meta.h @@ -13,5 +13,5 @@ template struct Meta; // Enum type classes enum class Classes { - IRTTI + IRTTI, ClassA, ClassB, ClassC, ClassD, ClassE }; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt new file mode 100644 index 0000000..830a56b --- /dev/null +++ b/Tests/CMakeLists.txt @@ -0,0 +1,55 @@ +file(GLOB test_default_src "test_default_rtti.cpp" "ClassesDefault/*.cpp" "ClassesDefault/*.h") + +add_executable(test_defalt_rtti ${test_default_src}) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + message(STATUS "Release mode: enabling optimizations") + + if(MSVC) + # /O2 - высокая оптимизация + # /GL - link-time optimization + # /DNDEBUG - отключить assert() + target_compile_options(test_defalt_rtti PRIVATE /O2 /GL /DNDEBUG) + target_link_options(test_defalt_rtti PRIVATE /LTCG) + else() + # GCC / Clang + target_compile_options(test_defalt_rtti PRIVATE + -O3 + -march=native + -flto + -DNDEBUG + ) + target_link_options(Tests PRIVATE -flto) + endif() +endif() + + + +file(GLOB test_fast_src "test_fast_rtti.cpp" "ClassesFast/*.cpp" "ClassesFast/*.h") + +add_executable(test_fast_rtti ${test_fast_src}) +target_link_libraries(test_fast_rtti PRIVATE FastRTTI) +target_include_directories(test_fast_rtti PRIVATE ${PROJECT_SOURCE_DIR}/RTTI) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + message(STATUS "Release mode: enabling optimizations") + + if(MSVC) + # /O2 - высокая оптимизация + # /GL - link-time optimization + # /DNDEBUG - отключить assert() + # /GR- - отключить RTTI + target_compile_options(test_fast_rtti PRIVATE /O2 /GL /DNDEBUG /GR-) + target_link_options(test_fast_rtti PRIVATE /LTCG) + else() + # GCC / Clang + target_compile_options(test_fast_rtti PRIVATE + -O3 + -march=native + -flto + -fno-rtti + -DNDEBUG + ) + target_link_options(test_fast_rtti PRIVATE -flto) + endif() +endif() \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassA.cpp b/Tests/ClassesDefault/ClassA.cpp new file mode 100644 index 0000000..1fffeeb --- /dev/null +++ b/Tests/ClassesDefault/ClassA.cpp @@ -0,0 +1,8 @@ +#include "ClassA.h" + +#include + +int ClassA::foo() +{ + return 0; +} diff --git a/Tests/ClassesDefault/ClassA.h b/Tests/ClassesDefault/ClassA.h new file mode 100644 index 0000000..ed0f8bb --- /dev/null +++ b/Tests/ClassesDefault/ClassA.h @@ -0,0 +1,6 @@ +#pragma once + +class ClassA { +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassB.cpp b/Tests/ClassesDefault/ClassB.cpp new file mode 100644 index 0000000..62d615c --- /dev/null +++ b/Tests/ClassesDefault/ClassB.cpp @@ -0,0 +1,5 @@ +#include "ClassB.h" + +int ClassB::foo() { + return 1; +} \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassB.h b/Tests/ClassesDefault/ClassB.h new file mode 100644 index 0000000..b42cc7e --- /dev/null +++ b/Tests/ClassesDefault/ClassB.h @@ -0,0 +1,8 @@ +#pragma once + +#include "ClassA.h" + +class ClassB : public ClassA{ +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassC.cpp b/Tests/ClassesDefault/ClassC.cpp new file mode 100644 index 0000000..f5138a7 --- /dev/null +++ b/Tests/ClassesDefault/ClassC.cpp @@ -0,0 +1,6 @@ +#include "ClassC.h" + +int ClassC::foo() +{ + return 2; +} \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassC.h b/Tests/ClassesDefault/ClassC.h new file mode 100644 index 0000000..f3012e4 --- /dev/null +++ b/Tests/ClassesDefault/ClassC.h @@ -0,0 +1,8 @@ +#pragma once + +#include "ClassB.h" + +class ClassC : public ClassB { +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassD.cpp b/Tests/ClassesDefault/ClassD.cpp new file mode 100644 index 0000000..4170a49 --- /dev/null +++ b/Tests/ClassesDefault/ClassD.cpp @@ -0,0 +1,6 @@ +#include "ClassD.h" + +int ClassD::foo() +{ + return 3; +} \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassD.h b/Tests/ClassesDefault/ClassD.h new file mode 100644 index 0000000..820429e --- /dev/null +++ b/Tests/ClassesDefault/ClassD.h @@ -0,0 +1,8 @@ +#pragma once + +#include "ClassC.h" + +class ClassD : public ClassC { +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassE.cpp b/Tests/ClassesDefault/ClassE.cpp new file mode 100644 index 0000000..4b88e12 --- /dev/null +++ b/Tests/ClassesDefault/ClassE.cpp @@ -0,0 +1,6 @@ +#include "ClassE.h" + +int ClassE::foo() +{ + return 4; +} \ No newline at end of file diff --git a/Tests/ClassesDefault/ClassE.h b/Tests/ClassesDefault/ClassE.h new file mode 100644 index 0000000..7f20ebc --- /dev/null +++ b/Tests/ClassesDefault/ClassE.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ClassD.h" + +class ClassE : public ClassD +{ +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesFast/ClassA.cpp b/Tests/ClassesFast/ClassA.cpp new file mode 100644 index 0000000..1fffeeb --- /dev/null +++ b/Tests/ClassesFast/ClassA.cpp @@ -0,0 +1,8 @@ +#include "ClassA.h" + +#include + +int ClassA::foo() +{ + return 0; +} diff --git a/Tests/ClassesFast/ClassA.h b/Tests/ClassesFast/ClassA.h new file mode 100644 index 0000000..0f2a3a1 --- /dev/null +++ b/Tests/ClassesFast/ClassA.h @@ -0,0 +1,9 @@ +#pragma once + +#include "RTTI.h" + +GENERATE_META(ClassA) +class ClassA : public IRTTI { +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesFast/ClassB.cpp b/Tests/ClassesFast/ClassB.cpp new file mode 100644 index 0000000..62d615c --- /dev/null +++ b/Tests/ClassesFast/ClassB.cpp @@ -0,0 +1,5 @@ +#include "ClassB.h" + +int ClassB::foo() { + return 1; +} \ No newline at end of file diff --git a/Tests/ClassesFast/ClassB.h b/Tests/ClassesFast/ClassB.h new file mode 100644 index 0000000..5abeee1 --- /dev/null +++ b/Tests/ClassesFast/ClassB.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ClassA.h" + +GENERATE_META(ClassB) +class ClassB : public ClassA{ +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesFast/ClassC.cpp b/Tests/ClassesFast/ClassC.cpp new file mode 100644 index 0000000..f5138a7 --- /dev/null +++ b/Tests/ClassesFast/ClassC.cpp @@ -0,0 +1,6 @@ +#include "ClassC.h" + +int ClassC::foo() +{ + return 2; +} \ No newline at end of file diff --git a/Tests/ClassesFast/ClassC.h b/Tests/ClassesFast/ClassC.h new file mode 100644 index 0000000..a9d5390 --- /dev/null +++ b/Tests/ClassesFast/ClassC.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ClassB.h" + +GENERATE_META(ClassC) +class ClassC : public ClassB { +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesFast/ClassD.cpp b/Tests/ClassesFast/ClassD.cpp new file mode 100644 index 0000000..4170a49 --- /dev/null +++ b/Tests/ClassesFast/ClassD.cpp @@ -0,0 +1,6 @@ +#include "ClassD.h" + +int ClassD::foo() +{ + return 3; +} \ No newline at end of file diff --git a/Tests/ClassesFast/ClassD.h b/Tests/ClassesFast/ClassD.h new file mode 100644 index 0000000..3e4095b --- /dev/null +++ b/Tests/ClassesFast/ClassD.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ClassC.h" + +GENERATE_META(ClassD) +class ClassD : public ClassC { +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/ClassesFast/ClassE.cpp b/Tests/ClassesFast/ClassE.cpp new file mode 100644 index 0000000..4b88e12 --- /dev/null +++ b/Tests/ClassesFast/ClassE.cpp @@ -0,0 +1,6 @@ +#include "ClassE.h" + +int ClassE::foo() +{ + return 4; +} \ No newline at end of file diff --git a/Tests/ClassesFast/ClassE.h b/Tests/ClassesFast/ClassE.h new file mode 100644 index 0000000..b6f4f71 --- /dev/null +++ b/Tests/ClassesFast/ClassE.h @@ -0,0 +1,10 @@ +#pragma once + +#include "ClassD.h" + +GENERATE_META(ClassE) +class ClassE : public ClassD +{ +public: + virtual int foo(); +}; \ No newline at end of file diff --git a/Tests/test_default_rtti.cpp b/Tests/test_default_rtti.cpp new file mode 100644 index 0000000..a33f0ad --- /dev/null +++ b/Tests/test_default_rtti.cpp @@ -0,0 +1,82 @@ +#include + +#include "ClassesDefault/ClassA.h" +#include "ClassesDefault/ClassB.h" +#include "ClassesDefault/ClassC.h" +#include "ClassesDefault/ClassD.h" +#include "ClassesDefault/ClassE.h" + +int main() +{ + ClassA* a = new ClassD(); + + { + std::cout << "[Direct type casting]\n"; + + ClassD* d1; + clock_t first, second; + clock_t realTime = 0; + + for (int i = 0; i < 100; ++i) + { + first = clock(); + for (unsigned long long i = 0; i < 10000000; ++i) + d1 = dynamic_cast(a); + second = clock(); + realTime += second - first; + } + std::cout << "dynami_cast: " << realTime / 100 << "ms\n"; + realTime = 0; + + if (d1 != nullptr) + d1->foo(); + } + + + + { + std::cout << "[Possible type casting]\n"; + + ClassC* d1; + clock_t first, second; + clock_t realTime = 0; + + for (int i = 0; i < 100; ++i) + { + first = clock(); + for (unsigned long long i = 0; i < 10000000; ++i) + d1 = dynamic_cast(a); + second = clock(); + realTime += second - first; + } + std::cout << "dynami_cast: " << realTime / 100 << "ms\n"; + realTime = 0; + + if (d1 != nullptr) + d1->foo(); + } + + + + { + std::cout << "[Not possible type casting]\n"; + + ClassE* d1; + clock_t first, second; + clock_t realTime = 0; + + for (int i = 0; i < 100; ++i) + { + first = clock(); + for (unsigned long long i = 0; i < 10000000; ++i) + d1 = dynamic_cast(a); + second = clock(); + realTime += second - first; + } + std::cout << "dynami_cast: " << realTime / 100 << "ms\n"; + realTime = 0; + + if (d1 != nullptr) + d1->foo(); + } +} diff --git a/Tests/test_fast_rtti.cpp b/Tests/test_fast_rtti.cpp new file mode 100644 index 0000000..5a3ca27 --- /dev/null +++ b/Tests/test_fast_rtti.cpp @@ -0,0 +1,78 @@ +#include + +#include "ClassesFast/ClassA.h" +#include "ClassesFast/ClassB.h" +#include "ClassesFast/ClassC.h" +#include "ClassesFast/ClassD.h" +#include "ClassesFast/ClassE.h" + +int main() +{ + ClassA* a = new ClassD(); + + { + std::cout << "[Direct type casting]\n"; + + ClassD* d1; + clock_t first, second; + clock_t realTime = 0; + + for (int i = 0; i < 100; ++i) + { + first = clock(); + for (unsigned long long i = 0; i < 10000000; ++i) + d1 = RTTI::dyn_cast(a); + second = clock(); + realTime += second - first; + } + std::cout << "RTTI::dyn_cast: " << realTime / 100 << "ms\n"; + + if (d1 != nullptr) + d1->foo(); + } + + + + { + std::cout << "[Possible type casting]\n"; + + ClassC* d1; + clock_t first, second; + clock_t realTime = 0; + + for (int i = 0; i < 100; ++i) + { + first = clock(); + for (unsigned long long i = 0; i < 10000000; ++i) + d1 = RTTI::dyn_cast(a); + second = clock(); + realTime += second - first; + } + std::cout << "RTTI::dyn_cast: " << realTime / 100 << "ms\n"; + + if (d1 != nullptr) + d1->foo(); + } + + + { + std::cout << "[Not possible type casting]\n"; + + ClassE* d1; + clock_t first, second; + clock_t realTime = 0; + + for (int i = 0; i < 100; ++i) + { + first = clock(); + for (unsigned long long i = 0; i < 10000000; ++i) + d1 = RTTI::dyn_cast(a); + second = clock(); + realTime += second - first; + } + std::cout << "RTTI::dyn_cast: " << realTime / 100 << "ms\n"; + + if (d1 != nullptr) + d1->foo(); + } +}