├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── CMakeSettings.json ├── README.md ├── benchmark ├── CMakeLists.txt └── benchmark.cpp ├── cmake └── FindPriori.cmake ├── include └── priori │ ├── export.h │ └── priori.h ├── license.txt ├── src └── priori.cpp └── test ├── CMakeLists.txt └── test.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | build/ 11 | *.tmp 12 | *.bak 13 | *.swp 14 | *~.nib 15 | local.properties 16 | .classpath 17 | .settings/ 18 | .loadpath 19 | 20 | # External tool builders 21 | .externalToolBuilders/ 22 | 23 | # Locally stored "Eclipse launch configurations" 24 | *.launch 25 | 26 | # CDT-specific 27 | .cproject 28 | 29 | # PDT-specific 30 | .buildpath 31 | 32 | 33 | ################# 34 | ## Visual Studio 35 | ################# 36 | 37 | ## Ignore Visual Studio temporary files, build results, and 38 | ## files generated by popular Visual Studio add-ons. 39 | 40 | # User-specific files 41 | *.suo 42 | *.user 43 | *.sln.docstates 44 | 45 | # Build results 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | *_i.c 49 | *_p.c 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.vspscc 64 | .builds 65 | *.dotCover 66 | 67 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 68 | #packages/ 69 | 70 | # Visual C++ cache files 71 | ipch/ 72 | *.aps 73 | *.ncb 74 | *.opensdf 75 | *.sdf 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | 81 | # ReSharper is a .NET coding add-in 82 | _ReSharper* 83 | 84 | # Installshield output folder 85 | [Ee]xpress 86 | 87 | # DocProject is a documentation generator add-in 88 | DocProject/buildhelp/ 89 | DocProject/Help/*.HxT 90 | DocProject/Help/*.HxC 91 | DocProject/Help/*.hhc 92 | DocProject/Help/*.hhk 93 | DocProject/Help/*.hhp 94 | DocProject/Help/Html2 95 | DocProject/Help/html 96 | 97 | # Click-Once directory 98 | publish 99 | 100 | # Others 101 | [Bb]in 102 | [Oo]bj 103 | sql 104 | TestResults 105 | *.Cache 106 | ClientBin 107 | stylecop.* 108 | ~$* 109 | *.dbmdl 110 | Generated_Code #added for RIA/Silverlight projects 111 | 112 | # Backup & report files from converting an old project file to a newer 113 | # Visual Studio version. Backup files are not needed, because we have git ;-) 114 | _UpgradeReport_Files/ 115 | Backup*/ 116 | UpgradeLog*.XML 117 | 118 | 119 | 120 | ############ 121 | ## Windows 122 | ############ 123 | 124 | # Windows image file caches 125 | Thumbs.db 126 | 127 | # Folder config file 128 | Desktop.ini 129 | 130 | 131 | ############# 132 | ## Python 133 | ############# 134 | 135 | *.py[co] 136 | 137 | # Packages 138 | *.egg 139 | *.egg-info 140 | dist 141 | build 142 | eggs 143 | parts 144 | bin 145 | var 146 | sdist 147 | develop-eggs 148 | .installed.cfg 149 | 150 | # Installer logs 151 | pip-log.txt 152 | 153 | # Unit test / coverage reports 154 | .coverage 155 | .tox 156 | 157 | #Translations 158 | *.mo 159 | 160 | #Mr Developer 161 | .mr.developer.cfg 162 | 163 | # Mac crap 164 | .DS_Store 165 | 166 | ################# 167 | ## Custom 168 | ################# 169 | 170 | *.jpg 171 | *.png 172 | *.xcf 173 | [Bb]uild 174 | 175 | ############# 176 | ## CMake 177 | ############# 178 | CMakeCache.txt 179 | CMakeFiles/ 180 | Makefile 181 | cmake_install.cmake 182 | 183 | ############# 184 | # PRODUCTS 185 | ############# 186 | prioriBenchmark.exe 187 | prioriTest.exe 188 | lib*.a 189 | lib*.so 190 | 191 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Top level makefile for Priori 3 | # 4 | # John Farrier 5 | # 6 | 7 | # 8 | # Cmake Configuration 9 | # 10 | 11 | CMAKE_MINIMUM_REQUIRED(VERSION 3.1) 12 | 13 | include(CheckFunctionExists) 14 | include(CheckCXXSourceCompiles) 15 | include(CheckIncludeFile) 16 | 17 | # 18 | # User Options 19 | # 20 | 21 | option(PRIORI_COMPILE_DYNAMIC_LIBRARIES "Set to ON to build Priori for dynamic linking. Use OFF for static." ON) 22 | option(PRIORI_USE_FOLDERS "Enable to put Priori in its own solution folder under Visual Studio" OFF) 23 | option(PRIORI_THREAD_SAFE "Enable to compile Priori for thread safety. Disable for very slight speed advantage." ON) 24 | 25 | if(PRIORI_COMPILE_DYNAMIC_LIBRARIES) 26 | SET(PRIORI_USER_DEFINED_SHARED_OR_STATIC "SHARED") 27 | else() 28 | SET(PRIORI_USER_DEFINED_SHARED_OR_STATIC "STATIC") 29 | endif() 30 | 31 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 32 | 33 | macro(PrioriSetDefaultCompilerOptions) 34 | set_target_properties(${PROJECT_NAME} PROPERTIES 35 | POSITION_INDEPENDENT_CODE "${PRIORI_COMPILE_PIC}" 36 | ) 37 | if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) 38 | target_compile_options(${PROJECT_NAME} PRIVATE /D_VARIADIC_MAX=10 ) 39 | target_compile_options(${PROJECT_NAME} PRIVATE /D_CRT_SECURE_NO_WARNINGS) 40 | target_compile_options(${PROJECT_NAME} PRIVATE /wd4251) 41 | target_compile_options(${PROJECT_NAME} PRIVATE /MP) 42 | target_compile_options(${PROJECT_NAME} PRIVATE /D_SCL_SECURE_NO_WARNINGS) 43 | target_compile_options(${PROJECT_NAME} PRIVATE /permissive-) 44 | 45 | if(PRIORI_TREAT_WARNINGS_AS_ERRORS) 46 | target_compile_options(${PROJECT_NAME} PRIVATE /WX) 47 | endif() 48 | 49 | set_target_properties(${PROJECT_NAME} PROPERTIES 50 | ARCHIVE_OUTPUT_NAME "${PROJECT_NAME}.dll") 51 | 52 | elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU) 53 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall) 54 | 55 | elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang) 56 | if(${CMAKE_SYSTEM_NAME} STREQUAL Windows) 57 | target_compile_options(${PROJECT_NAME} PRIVATE -Xclang) 58 | target_compile_options(${PROJECT_NAME} PRIVATE -Wno-c++98-compat) 59 | target_compile_options(${PROJECT_NAME} PRIVATE -Wno-c++98-compat-pedantic) 60 | target_compile_options(${PROJECT_NAME} PRIVATE -Wno-reserved-id-macro) 61 | if(PRIORI_TREAT_WARNINGS_AS_ERRORS) 62 | target_compile_options(${PROJECT_NAME} PRIVATE -Werror) 63 | endif() 64 | else() 65 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall) 66 | if(PRIORI_TREAT_WARNINGS_AS_ERRORS) 67 | target_compile_options(${PROJECT_NAME} PRIVATE -Werror) 68 | endif() 69 | endif() 70 | 71 | elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL AppleClang) 72 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall) 73 | 74 | if(PRIORI_TREAT_WARNINGS_AS_ERRORS) 75 | target_compile_options(${PROJECT_NAME} PRIVATE -Werror) 76 | endif() 77 | endif() 78 | endmacro() 79 | 80 | # 81 | # Compiler Settings 82 | # 83 | 84 | 85 | # Project Name 86 | set(PROJECT_NAME priori) 87 | PROJECT(${PROJECT_NAME}) 88 | 89 | include(CheckFunctionExists) 90 | include(CheckCXXSourceCompiles) 91 | include(CheckIncludeFile) 92 | 93 | # 94 | # Build and Install Settings 95 | # 96 | 97 | set(CMAKE_CXX_STANDARD 14) 98 | set(CMAKE_CXX_EXTENSIONS OFF) 99 | 100 | set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually d on windows") 101 | set(CMAKE_RELEASE_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows") 102 | set(CMAKE_RELWITHDEBINFO_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows") 103 | set(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows") 104 | 105 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 106 | 107 | 108 | # --------------------------------------------------------------------------- # 109 | # --------------------------------------------------------------------------- # 110 | 111 | # 112 | # Install Locations 113 | # 114 | 115 | # 116 | # include path to be used by all projects 117 | # 118 | 119 | SET(HEADER_PATH ${priori_SOURCE_DIR}/include) 120 | 121 | if(PRIORI_COMPILE_DYNAMIC_LIBRARIES) 122 | add_definitions(-DPRIORI_EXPORTS) 123 | else() 124 | add_definitions(-DPRIORI_STATIC) 125 | endif() 126 | 127 | if(PRIORI_THREAD_SAFE) 128 | add_definitions(-DPRIORI_THREAD_SAFE) 129 | endif() 130 | 131 | # 132 | # Define header and sources 133 | # 134 | 135 | set(TARGET_H 136 | include/priori/export.h 137 | include/priori/priori.h 138 | ) 139 | 140 | set(TARGET_SRC 141 | src/priori.cpp 142 | ) 143 | 144 | set(TARGET_LIBRARIES ${SYSLIBS}) 145 | add_library(${PROJECT_NAME} ${PRIORI_USER_DEFINED_SHARED_OR_STATIC} ${TARGET_SRC} ${TARGET_H}) 146 | PrioriSetDefaultCompilerOptions() 147 | 148 | include_directories(${HEADER_PATH}) 149 | 150 | # --------------------------------------------------------------------------- 151 | # Install and exports 152 | # --------------------------------------------------------------------------- 153 | 154 | install(TARGETS ${PROJECT_NAME} 155 | EXPORT ${PROJECT_NAME}-target 156 | RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin 157 | LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib 158 | ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib 159 | ) 160 | 161 | install(DIRECTORY include DESTINATION ${CMAKE_INSTALL_PREFIX}) 162 | 163 | # export to be used from install location 164 | install(EXPORT ${PROJECT_NAME}-target 165 | DESTINATION ${CMAKE_INSTALL_PREFIX}/share 166 | ) 167 | 168 | # export to be used from build directory 169 | export(EXPORT ${PROJECT_NAME}-target 170 | FILE ${PROJECT_NAME}-target.cmake 171 | ) 172 | 173 | # --------------------------------------------------------------------------- # 174 | # --------------------------------------------------------------------------- # 175 | 176 | # --------------------------------------------------------------------------- # 177 | # GTest Unit Tests 178 | # --------------------------------------------------------------------------- # 179 | 180 | option(PRIORI_GTEST "Set to ON to enable Google tests Priori." ON) 181 | 182 | if(PRIORI_GTEST) 183 | add_subdirectory(test) 184 | endif() 185 | 186 | # --------------------------------------------------------------------------- # 187 | # Priori Celero Benchmarks 188 | # --------------------------------------------------------------------------- # 189 | 190 | option(PRIORI_PRIORI "Set to ON to enable Priori benchmarks Priori." ON) 191 | 192 | if(PRIORI_PRIORI) 193 | add_subdirectory(benchmark) 194 | endif() 195 | 196 | # 197 | # Optional 198 | # 199 | 200 | if(PRIORI_USE_FOLDERS) 201 | set_property(TARGET priori PROPERTY FOLDER "Priori") 202 | endif() -------------------------------------------------------------------------------- /CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64-Debug", 5 | "generator": "Ninja", 6 | "configurationType": "Debug", 7 | "inheritEnvironments": [ "msvc_x64_x64" ], 8 | "buildRoot": "${projectDir}\\out\\build\\${name}", 9 | "installRoot": "${projectDir}\\out\\install\\${name}", 10 | "cmakeCommandArgs": "", 11 | "buildCommandArgs": "-v", 12 | "ctestCommandArgs": "", 13 | "variables": [] 14 | }, 15 | { 16 | "name": "x64-Release", 17 | "generator": "Ninja", 18 | "configurationType": "RelWithDebInfo", 19 | "buildRoot": "${projectDir}\\out\\build\\${name}", 20 | "installRoot": "${projectDir}\\out\\install\\${name}", 21 | "cmakeCommandArgs": "", 22 | "buildCommandArgs": "-v", 23 | "ctestCommandArgs": "", 24 | "inheritEnvironments": [ "msvc_x64_x64" ], 25 | "variables": [ 26 | { 27 | "name": "CELERO_ENABLE_TESTS", 28 | "value": "True", 29 | "type": "BOOL" 30 | }, 31 | { 32 | "name": "CELERO_ENABLE_EXPERIMENTS", 33 | "value": "True", 34 | "type": "BOOL" 35 | } 36 | ] 37 | }, 38 | { 39 | "name": "x64-Clang-Debug", 40 | "generator": "Ninja", 41 | "configurationType": "Debug", 42 | "buildRoot": "${projectDir}\\out\\build\\${name}", 43 | "installRoot": "${projectDir}\\out\\install\\${name}", 44 | "cmakeCommandArgs": "", 45 | "buildCommandArgs": "-v", 46 | "ctestCommandArgs": "", 47 | "inheritEnvironments": [ "clang_cl_x64" ], 48 | "variables": [] 49 | }, 50 | { 51 | "name": "x64-Clang-Release", 52 | "generator": "Ninja", 53 | "configurationType": "RelWithDebInfo", 54 | "buildRoot": "${projectDir}\\out\\build\\${name}", 55 | "installRoot": "${projectDir}\\out\\install\\${name}", 56 | "cmakeCommandArgs": "", 57 | "buildCommandArgs": "-v", 58 | "ctestCommandArgs": "", 59 | "inheritEnvironments": [ "clang_cl_x64" ], 60 | "variables": [ 61 | { 62 | "name": "CELERO_ENABLE_EXPERIMENTS", 63 | "value": "True", 64 | "type": "BOOL" 65 | }, 66 | { 67 | "name": "CELERO_ENABLE_TESTS", 68 | "value": "True", 69 | "type": "BOOL" 70 | } 71 | ] 72 | } 73 | ] 74 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Priori 2 | 3 | ## C++ Fast dynamic_cast<> Alternative 4 | 5 | Copyright 2013-2021 John Farrier 6 | Apache 2.0 License 7 | 8 | ## Overview 9 | 10 | Priori is a special base class which facilitates a very fast `dynamic_cast<>` alternative when `dynamic_cast<>` itself has shown to be a bottleneck. Specifically in the case where `dynamic_cast<>` from a base class to a derived class is impacting performance. 11 | 12 | Priori is interesting, but not a wholesale replacement for `dynamic_cast`. There are very specific use cases when Priori should be considered to relieve a quantified bottle-neck. Benchmarking shows that the following scenarios show measurable improvements for non-threaded applications. Review the benchmark tables below to see if there is a measurable performance improvement for your specific use case. (There are several use cases which are slower than `dynamic_cast`, so consider this a highly-specialized micro-optimization.) 13 | 14 | Priori uses [CMake](https://github.com/Kitware/CMake) to provide cross-platform builds. It does require a modern compiler due to its use of C++11. 15 | 16 | ## Benchmark 17 | 18 | Given 10 levels of inheritance and benchmarked using [Celero](https://github.com/DigitalInBlue/Celero). (Start by looking at the "Baseline" number. Lower is better.) 19 | 20 | For the non-thread-safe implementation: 21 | 22 | ``` 23 | Celero 24 | Timer resolution: 0.100000 us 25 | | Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec | 26 | |:--------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:| 27 | |priori_deep_fro | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.01781 | 56143502.79 | 28 | |priori_wide_fro | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.01614 | 61973227.57 | 29 | |priori_deep_toB | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.00464 | 215331610.68 | 30 | |priori_wide_toB | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.00458 | 218150087.26 | 31 | |priori_deep_toS | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.00498 | 200702458.61 | 32 | |priori_wide_toS | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.00492 | 203417412.53 | 33 | |rttiCosts | typeinfo | Null | 128 | 2000000 | 1.00000 | 0.00459 | 217983651.23 | 34 | |priori_deep_fro | priori_cast | Null | 128 | 2000000 | 0.78115 | 0.01391 | 71872641.68 | 35 | |priori_wide_fro | priori_cast | Null | 128 | 2000000 | 1.05311 | 0.01699 | 58847760.84 | 36 | |priori_deep_toB | priori_cast | Null | 128 | 2000000 | 0.97782 | 0.00454 | 220215811.50 | 37 | |priori_wide_toB | priori_cast | Null | 128 | 2000000 | 0.99247 | 0.00455 | 219804374.11 | 38 | |priori_deep_toS | priori_cast | Null | 128 | 2000000 | 0.91159 | 0.00454 | 220167327.17 | 39 | |priori_wide_toS | priori_cast | Null | 128 | 2000000 | 0.88314 | 0.00434 | 230335137.63 | 40 | |rttiCosts | typeinfoHash | Null | 128 | 2000000 | 2.48262 | 0.01139 | 87804021.42 | 41 | |rttiCosts | typeinfoName | Null | 128 | 2000000 | 1.39401 | 0.00639 | 156372165.75 | 42 | ``` 43 | 44 | For the thread-safe implementation: 45 | 46 | ``` 47 | Celero 48 | Timer resolution: 0.100000 us 49 | | Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec | 50 | |:--------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:| 51 | |priori_deep_fro | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.01781 | 56154537.29 | 52 | |priori_wide_fro | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.01612 | 62034739.45 | 53 | |priori_deep_toB | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.00455 | 219973603.17 | 54 | |priori_wide_toB | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.00457 | 219034059.80 | 55 | |priori_deep_toS | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.00503 | 198925800.68 | 56 | |priori_wide_toS | dynamic_cast | Null | 128 | 2000000 | 1.00000 | 0.00488 | 204918032.79 | 57 | |rttiCosts | typeinfo | Null | 128 | 2000000 | 1.00000 | 0.00454 | 220312844.24 | 58 | |priori_deep_fro | priori_cast | Null | 128 | 2000000 | 1.46114 | 0.02602 | 38431975.40 | 59 | |priori_wide_fro | priori_cast | Null | 128 | 2000000 | 1.94498 | 0.03135 | 31894874.49 | 60 | |priori_deep_toB | priori_cast | Null | 128 | 2000000 | 0.99890 | 0.00454 | 220215811.50 | 61 | |priori_wide_toB | priori_cast | Null | 128 | 2000000 | 0.99660 | 0.00455 | 219780219.78 | 62 | |priori_deep_toS | priori_cast | Null | 128 | 2000000 | 0.90302 | 0.00454 | 220288578.04 | 63 | |priori_wide_toS | priori_cast | Null | 128 | 2000000 | 0.88648 | 0.00433 | 231160425.34 | 64 | |rttiCosts | typeinfoHash | Null | 128 | 2000000 | 2.49251 | 0.01131 | 88389976.58 | 65 | |rttiCosts | typeinfoName | Null | 128 | 2000000 | 1.41683 | 0.00643 | 155496812.32 | 66 | ``` 67 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Priori Bemchmark 3 | # 4 | # Copyright 2014-2021 John Farrier 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | project(priori-benchmark) 20 | 21 | add_executable(${PROJECT_NAME}) 22 | 23 | find_package(celero CONFIG REQUIRED) 24 | 25 | target_sources(${PROJECT_NAME} PRIVATE 26 | benchmark.cpp 27 | ) 28 | 29 | PrioriSetDefaultCompilerOptions() 30 | 31 | target_link_libraries(${PROJECT_NAME} 32 | celero 33 | priori 34 | ) 35 | 36 | target_include_directories(${PROJECT_NAME} PUBLIC 37 | $ 38 | $ 39 | ${CMAKE_SOURCE_DIR}/include 40 | ) 41 | 42 | if(PRIORI_ENABLE_FOLDERS) 43 | set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "priori") 44 | endif() 45 | -------------------------------------------------------------------------------- /benchmark/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | CELERO_MAIN; 5 | 6 | #define INHERIT_ME(baseClass, newClass) class newClass : public baseClass { public: newClass() : baseClass() { priori(this); } }; 7 | 8 | using namespace priori; 9 | 10 | INHERIT_ME(Base, Wide0); 11 | INHERIT_ME(Wide0, Wide1); 12 | INHERIT_ME(Wide1, Wide2); 13 | INHERIT_ME(Wide2, Wide3); 14 | INHERIT_ME(Wide3, Wide4); 15 | INHERIT_ME(Wide4, Wide5); 16 | INHERIT_ME(Wide5, Wide6); 17 | INHERIT_ME(Wide6, Wide7); 18 | INHERIT_ME(Wide7, Wide8); 19 | INHERIT_ME(Wide8, Wide9); 20 | INHERIT_ME(Wide9, WideFinal); 21 | 22 | INHERIT_ME(Base, Deep0); 23 | INHERIT_ME(Deep0, Deep1); 24 | INHERIT_ME(Deep1, Deep2); 25 | INHERIT_ME(Deep2, Deep3); 26 | INHERIT_ME(Deep3, Deep4); 27 | INHERIT_ME(Deep4, Deep5); 28 | INHERIT_ME(Deep5, Deep6); 29 | INHERIT_ME(Deep6, Deep7); 30 | INHERIT_ME(Deep7, Deep8); 31 | INHERIT_ME(Deep8, Deep9); 32 | INHERIT_ME(Deep9, DeepFinal); 33 | 34 | 35 | class InheritanceFixture : public celero::TestFixture 36 | { 37 | public: 38 | /// Before each run, build a vector of random integers. 39 | void setUp(const celero::TestFixture::ExperimentValue&) override 40 | { 41 | this->deep = new DeepFinal; 42 | this->deepBase = this->deep; 43 | 44 | this->wide = new WideFinal; 45 | this->wideBase = this->wide; 46 | } 47 | 48 | /// After each run, clear the vector of random integers. 49 | void tearDown() override 50 | { 51 | if (this->deep != nullptr) 52 | { 53 | delete this->deep; 54 | } 55 | 56 | if (this->wide != nullptr) 57 | { 58 | delete this->wide; 59 | } 60 | } 61 | 62 | DeepFinal* deep{ nullptr }; 63 | Base* deepBase{ nullptr }; 64 | 65 | WideFinal* wide{ nullptr }; 66 | Base* wideBase{ nullptr }; 67 | }; 68 | 69 | // ---------------------------------------------------------------------------- 70 | // Cast from a base to the derrived type. 71 | // ---------------------------------------------------------------------------- 72 | BASELINE_F(priori_deep_fromBase, dynamic_cast, InheritanceFixture, 128, 2000000) 73 | { 74 | celero::DoNotOptimizeAway(dynamic_cast(this->deepBase)); 75 | } 76 | 77 | BENCHMARK_F(priori_deep_fromBase, priori_cast, InheritanceFixture, 128, 2000000) 78 | { 79 | celero::DoNotOptimizeAway(priori_cast(this->deepBase)); 80 | } 81 | 82 | // ---------------------------------------------------------------------------- 83 | // Cast from a base to the derrived type. 84 | // ---------------------------------------------------------------------------- 85 | BASELINE_F(priori_wide_fromBase, dynamic_cast, InheritanceFixture, 128, 2000000) 86 | { 87 | celero::DoNotOptimizeAway(dynamic_cast(this->wideBase)); 88 | } 89 | 90 | BENCHMARK_F(priori_wide_fromBase, priori_cast, InheritanceFixture, 128, 2000000) 91 | { 92 | celero::DoNotOptimizeAway(priori_cast(this->wideBase)); 93 | } 94 | 95 | // ---------------------------------------------------------------------------- 96 | // Cast from a derrived type to the base type. 97 | // ---------------------------------------------------------------------------- 98 | BASELINE_F(priori_deep_toBase, dynamic_cast, InheritanceFixture, 128, 2000000) 99 | { 100 | celero::DoNotOptimizeAway(dynamic_cast(this->deep)); 101 | } 102 | 103 | BENCHMARK_F(priori_deep_toBase, priori_cast, InheritanceFixture, 128, 2000000) 104 | { 105 | celero::DoNotOptimizeAway(priori_cast(this->deep)); 106 | } 107 | 108 | // ---------------------------------------------------------------------------- 109 | // Cast from a derrived type to the base type. 110 | // ---------------------------------------------------------------------------- 111 | BASELINE_F(priori_wide_toBase, dynamic_cast, InheritanceFixture, 128, 2000000) 112 | { 113 | celero::DoNotOptimizeAway(dynamic_cast(this->wide)); 114 | } 115 | 116 | BENCHMARK_F(priori_wide_toBase, priori_cast, InheritanceFixture, 128, 2000000) 117 | { 118 | celero::DoNotOptimizeAway(priori_cast(this->wide)); 119 | } 120 | 121 | // ---------------------------------------------------------------------------- 122 | // Cast from a derrived type to the same derrived type. 123 | // ---------------------------------------------------------------------------- 124 | BASELINE_F(priori_deep_toSelf, dynamic_cast, InheritanceFixture, 128, 2000000) 125 | { 126 | celero::DoNotOptimizeAway(dynamic_cast(this->deep)); 127 | } 128 | 129 | BENCHMARK_F(priori_deep_toSelf, priori_cast, InheritanceFixture, 128, 2000000) 130 | { 131 | celero::DoNotOptimizeAway(priori_cast(this->deep)); 132 | } 133 | 134 | // ---------------------------------------------------------------------------- 135 | // Cast from a derrived type to the same derrived type. 136 | // ---------------------------------------------------------------------------- 137 | BASELINE_F(priori_wide_toSelf, dynamic_cast, InheritanceFixture, 128, 2000000) 138 | { 139 | celero::DoNotOptimizeAway(dynamic_cast(this->wide)); 140 | } 141 | 142 | BENCHMARK_F(priori_wide_toSelf, priori_cast, InheritanceFixture, 128, 2000000) 143 | { 144 | celero::DoNotOptimizeAway(priori_cast(this->wide)); 145 | } 146 | 147 | // ---------------------------------------------------------------------------- 148 | // Experiments for rtti operations costs. 149 | // ---------------------------------------------------------------------------- 150 | BASELINE(rttiCosts, typeinfo, 128, 2000000) 151 | { 152 | celero::DoNotOptimizeAway(typeid(WideFinal)); 153 | } 154 | 155 | BENCHMARK(rttiCosts, typeinfoHash, 128, 2000000) 156 | { 157 | celero::DoNotOptimizeAway(typeid(WideFinal).hash_code()); 158 | } 159 | 160 | BENCHMARK(rttiCosts, typeinfoName, 128, 2000000) 161 | { 162 | celero::DoNotOptimizeAway(typeid(WideFinal).name()); 163 | } 164 | 165 | -------------------------------------------------------------------------------- /cmake/FindPriori.cmake: -------------------------------------------------------------------------------- 1 | # Try to find Priori headers and libraries. 2 | # 3 | # Usage of this module as follows: 4 | # 5 | # find_package(Priori) 6 | # 7 | # Variables used by this module, they can change the default behaviour and need 8 | # to be set before calling find_package: 9 | # 10 | # PRIORI_PREFIX Set this variable to the root installation of 11 | # priori if the module has problems finding the 12 | # proper installation path. 13 | # 14 | # Note that you can set the PRIORI_PREFIX variable as environment variable. 15 | # 16 | # Variables defined by this module: 17 | # 18 | # PRIORI_FOUND System has the Priori library and headers 19 | # PRIORI_LIBRARIES The Priori library 20 | # PRIORI_INCLUDE_DIRS The location of Priori headers 21 | 22 | if(NOT PRIORI_PREFIX) 23 | set(PRIORI_PREFIX $ENV{PRIORI_PREFIX}) 24 | endif() 25 | 26 | set(PRIORI_HINTS ${PRIORI_PREFIX} $ENV{PRIORI_PREFIX}) 27 | find_path(PRIORI_ROOT 28 | NAMES include/priori/Priori.h 29 | HINTS "${PRIORI_HINTS}" 30 | ) 31 | 32 | find_library(PRIORI_LIBRARIES 33 | NAMES libpriori.so 34 | HINTS ${PRIORI_ROOT}/lib ${PRIORI_ROOT}/lib64 35 | ) 36 | 37 | find_path(PRIORI_INCLUDE_DIRS 38 | NAMES priori/Priori.h 39 | HINTS ${PRIORI_ROOT}/include 40 | ) 41 | 42 | include(FindPackageHandleStandardArgs) 43 | find_package_handle_standard_args(PRIORI DEFAULT_MSG 44 | PRIORI_LIBRARIES 45 | PRIORI_INCLUDE_DIRS 46 | ) 47 | 48 | mark_as_advanced( 49 | PRIORI_LIBRARIES 50 | PRIORI_INCLUDE_DIRS 51 | PRIORI_ROOT 52 | ) 53 | -------------------------------------------------------------------------------- /include/priori/export.h: -------------------------------------------------------------------------------- 1 | #ifndef H_PRIORI_EXPORT_H 2 | #define H_PRIORI_EXPORT_H 3 | 4 | // www.helleboreconsulting.com 5 | 6 | /// 7 | /// \author John Farrier 8 | /// 9 | 10 | #ifdef PRIORI_STATIC 11 | #define PRIORI_EXPORT 12 | #define PRIORI_EXPORT_C 13 | #else 14 | #ifdef WIN32 15 | #if defined PRIORI_EXPORTS 16 | #define PRIORI_EXPORT _declspec(dllexport) 17 | #define PRIORI_EXPORT_C extern "C" _declspec(dllexport) 18 | #else 19 | #define PRIORI_EXPORT _declspec(dllimport) 20 | #define PRIORI_EXPORT_C extern "C" _declspec(dllimport) 21 | #endif 22 | #else 23 | #define PRIORI_EXPORT 24 | #define PRIORI_EXPORT_C extern "C" 25 | #endif 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/priori/priori.h: -------------------------------------------------------------------------------- 1 | #ifndef H_PRIORI_H 2 | #define H_PRIORI_H 3 | 4 | // www.helleboreconsulting.com 5 | 6 | /// 7 | /// \namespace priori 8 | /// 9 | /// \author John Farrier 10 | /// 11 | /// \copyright Copyright 2013 John Farrier 12 | /// 13 | /// Licensed under the Apache License, Version 2.0 (the "License"); 14 | /// you may not use this file except in compliance with the License. 15 | /// You may obtain a copy of the License at 16 | /// 17 | /// http://www.apache.org/licenses/LICENSE-2.0 18 | /// 19 | /// Unless required by applicable law or agreed to in writing, software 20 | /// distributed under the License is distributed on an "AS IS" BASIS, 21 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | /// See the License for the specific language governing permissions and 23 | /// limitations under the License. 24 | /// 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace priori 32 | { 33 | /// 34 | /// \class Base 35 | /// 36 | /// \author John Farrier 37 | /// 38 | /// A base class required to inherit from to use priori_cast<> 39 | /// 40 | class PRIORI_EXPORT Base 41 | { 42 | public: 43 | /// 44 | /// Default constructor. 45 | /// 46 | Base(); 47 | 48 | /// 49 | /// Copy constructor. 50 | /// 51 | Base(Base& other); 52 | 53 | /// 54 | /// Move constructor 55 | /// 56 | Base(Base&& other); 57 | 58 | /// 59 | /// Trivial destructor 60 | /// 61 | virtual ~Base() throw(); 62 | 63 | /// 64 | /// Test to determine if this class can cast to the type passed in. 65 | /// 66 | /// \param x The priorifactor to test for inheritance. 67 | /// 68 | /// \return True if this class can cast to the type passed in. 69 | /// 70 | bool priori(const uint64_t x) const; 71 | 72 | protected: 73 | /// 74 | /// Convert a Base pointer 75 | /// 76 | void priori(const Base* const x); 77 | 78 | private: 79 | /// The secret sauce which stores our type information. 80 | uint64_t prioriFactor{ 0 }; 81 | }; 82 | 83 | PRIORI_EXPORT extern uint64_t get(const priori::Base* const x); 84 | PRIORI_EXPORT extern uint64_t get(const std::type_info& x); 85 | } 86 | 87 | /// 88 | /// \brief priori_cast 89 | /// 90 | /// Built a template that looks like standard c++ casts (static_cast, const_cast, etc.) 91 | /// 92 | template T priori_cast(V base) 93 | { 94 | if (base == nullptr) 95 | { 96 | return nullptr; 97 | } 98 | 99 | // If it is convertable to the base class or to itself, return 100 | if (std::is_convertible::type, typename std::remove_pointer::type>::value == true) 101 | { 102 | return reinterpret_cast(base); 103 | } 104 | 105 | const auto factor = priori::get(typeid(typename std::remove_pointer::type)); 106 | 107 | if ((factor != 0) && (base->priori(factor) == true)) 108 | { 109 | return reinterpret_cast(base); 110 | } 111 | 112 | return nullptr; 113 | } 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Priori 2 | 3 | Fast Dynamic-Cast Alternative for C++ 4 | 5 | Copyright 2013,2014 John Farrier, Hellebore Consulting LLC 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | 19 | Apache License 20 | Version 2.0, January 2004 21 | http://www.apache.org/licenses/ 22 | 23 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 24 | 25 | 1. Definitions. 26 | 27 | "License" shall mean the terms and conditions for use, reproduction, 28 | and distribution as defined by Sections 1 through 9 of this document. 29 | 30 | "Licensor" shall mean the copyright owner or entity authorized by 31 | the copyright owner that is granting the License. 32 | 33 | "Legal Entity" shall mean the union of the acting entity and all 34 | other entities that control, are controlled by, or are under common 35 | control with that entity. For the purposes of this definition, 36 | "control" means (i) the power, direct or indirect, to cause the 37 | direction or management of such entity, whether by contract or 38 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 39 | outstanding shares, or (iii) beneficial ownership of such entity. 40 | 41 | "You" (or "Your") shall mean an individual or Legal Entity 42 | exercising permissions granted by this License. 43 | 44 | "Source" form shall mean the preferred form for making modifications, 45 | including but not limited to software source code, documentation 46 | source, and configuration files. 47 | 48 | "Object" form shall mean any form resulting from mechanical 49 | transformation or translation of a Source form, including but 50 | not limited to compiled object code, generated documentation, 51 | and conversions to other media types. 52 | 53 | "Work" shall mean the work of authorship, whether in Source or 54 | Object form, made available under the License, as indicated by a 55 | copyright notice that is included in or attached to the work 56 | (an example is provided in the Appendix below). 57 | 58 | "Derivative Works" shall mean any work, whether in Source or Object 59 | form, that is based on (or derived from) the Work and for which the 60 | editorial revisions, annotations, elaborations, or other modifications 61 | represent, as a whole, an original work of authorship. For the purposes 62 | of this License, Derivative Works shall not include works that remain 63 | separable from, or merely link (or bind by name) to the interfaces of, 64 | the Work and Derivative Works thereof. 65 | 66 | "Contribution" shall mean any work of authorship, including 67 | the original version of the Work and any modifications or additions 68 | to that Work or Derivative Works thereof, that is intentionally 69 | submitted to Licensor for inclusion in the Work by the copyright owner 70 | or by an individual or Legal Entity authorized to submit on behalf of 71 | the copyright owner. For the purposes of this definition, "submitted" 72 | means any form of electronic, verbal, or written communication sent 73 | to the Licensor or its representatives, including but not limited to 74 | communication on electronic mailing lists, source code control systems, 75 | and issue tracking systems that are managed by, or on behalf of, the 76 | Licensor for the purpose of discussing and improving the Work, but 77 | excluding communication that is conspicuously marked or otherwise 78 | designated in writing by the copyright owner as "Not a Contribution." 79 | 80 | "Contributor" shall mean Licensor and any individual or Legal Entity 81 | on behalf of whom a Contribution has been received by Licensor and 82 | subsequently incorporated within the Work. 83 | 84 | 2. Grant of Copyright License. Subject to the terms and conditions of 85 | this License, each Contributor hereby grants to You a perpetual, 86 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 87 | copyright license to reproduce, prepare Derivative Works of, 88 | publicly display, publicly perform, sublicense, and distribute the 89 | Work and such Derivative Works in Source or Object form. 90 | 91 | 3. Grant of Patent License. Subject to the terms and conditions of 92 | this License, each Contributor hereby grants to You a perpetual, 93 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 94 | (except as stated in this section) patent license to make, have made, 95 | use, offer to sell, sell, import, and otherwise transfer the Work, 96 | where such license applies only to those patent claims licensable 97 | by such Contributor that are necessarily infringed by their 98 | Contribution(s) alone or by combination of their Contribution(s) 99 | with the Work to which such Contribution(s) was submitted. If You 100 | institute patent litigation against any entity (including a 101 | cross-claim or counterclaim in a lawsuit) alleging that the Work 102 | or a Contribution incorporated within the Work constitutes direct 103 | or contributory patent infringement, then any patent licenses 104 | granted to You under this License for that Work shall terminate 105 | as of the date such litigation is filed. 106 | 107 | 4. Redistribution. You may reproduce and distribute copies of the 108 | Work or Derivative Works thereof in any medium, with or without 109 | modifications, and in Source or Object form, provided that You 110 | meet the following conditions: 111 | 112 | (a) You must give any other recipients of the Work or 113 | Derivative Works a copy of this License; and 114 | 115 | (b) You must cause any modified files to carry prominent notices 116 | stating that You changed the files; and 117 | 118 | (c) You must retain, in the Source form of any Derivative Works 119 | that You distribute, all copyright, patent, trademark, and 120 | attribution notices from the Source form of the Work, 121 | excluding those notices that do not pertain to any part of 122 | the Derivative Works; and 123 | 124 | (d) If the Work includes a "NOTICE" text file as part of its 125 | distribution, then any Derivative Works that You distribute must 126 | include a readable copy of the attribution notices contained 127 | within such NOTICE file, excluding those notices that do not 128 | pertain to any part of the Derivative Works, in at least one 129 | of the following places: within a NOTICE text file distributed 130 | as part of the Derivative Works; within the Source form or 131 | documentation, if provided along with the Derivative Works; or, 132 | within a display generated by the Derivative Works, if and 133 | wherever such third-party notices normally appear. The contents 134 | of the NOTICE file are for informational purposes only and 135 | do not modify the License. You may add Your own attribution 136 | notices within Derivative Works that You distribute, alongside 137 | or as an addendum to the NOTICE text from the Work, provided 138 | that such additional attribution notices cannot be construed 139 | as modifying the License. 140 | 141 | You may add Your own copyright statement to Your modifications and 142 | may provide additional or different license terms and conditions 143 | for use, reproduction, or distribution of Your modifications, or 144 | for any such Derivative Works as a whole, provided Your use, 145 | reproduction, and distribution of the Work otherwise complies with 146 | the conditions stated in this License. 147 | 148 | 5. Submission of Contributions. Unless You explicitly state otherwise, 149 | any Contribution intentionally submitted for inclusion in the Work 150 | by You to the Licensor shall be under the terms and conditions of 151 | this License, without any additional terms or conditions. 152 | Notwithstanding the above, nothing herein shall supersede or modify 153 | the terms of any separate license agreement you may have executed 154 | with Licensor regarding such Contributions. 155 | 156 | 6. Trademarks. This License does not grant permission to use the trade 157 | names, trademarks, service marks, or product names of the Licensor, 158 | except as required for reasonable and customary use in describing the 159 | origin of the Work and reproducing the content of the NOTICE file. 160 | 161 | 7. Disclaimer of Warranty. Unless required by applicable law or 162 | agreed to in writing, Licensor provides the Work (and each 163 | Contributor provides its Contributions) on an "AS IS" BASIS, 164 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 165 | implied, including, without limitation, any warranties or conditions 166 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 167 | PARTICULAR PURPOSE. You are solely responsible for determining the 168 | appropriateness of using or redistributing the Work and assume any 169 | risks associated with Your exercise of permissions under this License. 170 | 171 | 8. Limitation of Liability. In no event and under no legal theory, 172 | whether in tort (including negligence), contract, or otherwise, 173 | unless required by applicable law (such as deliberate and grossly 174 | negligent acts) or agreed to in writing, shall any Contributor be 175 | liable to You for damages, including any direct, indirect, special, 176 | incidental, or consequential damages of any character arising as a 177 | result of this License or out of the use or inability to use the 178 | Work (including but not limited to damages for loss of goodwill, 179 | work stoppage, computer failure or malfunction, or any and all 180 | other commercial damages or losses), even if such Contributor 181 | has been advised of the possibility of such damages. 182 | 183 | 9. Accepting Warranty or Additional Liability. While redistributing 184 | the Work or Derivative Works thereof, You may choose to offer, 185 | and charge a fee for, acceptance of support, warranty, indemnity, 186 | or other liability obligations and/or rights consistent with this 187 | License. However, in accepting such obligations, You may act only 188 | on Your own behalf and on Your sole responsibility, not on behalf 189 | of any other Contributor, and only if You agree to indemnify, 190 | defend, and hold each Contributor harmless for any liability 191 | incurred by, or claims asserted against, such Contributor by reason 192 | of your accepting any such warranty or additional liability. 193 | 194 | -------------------------------------------------------------------------------- /src/priori.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace priori 9 | { 10 | namespace impl 11 | { 12 | #ifdef PRIORI_THREAD_SAFE 13 | std::mutex Lock; 14 | #endif 15 | 16 | // std::map was found to perform better here than a std::unordered_map, due to key distribution? 17 | static std::map CastMap; 18 | static uint64_t Idx{ 0 }; 19 | 20 | /// The table of primes was generated by http://ww2.valdosta.edu/~ckicey/primes.html 21 | /// This table is fixed to 1254 total primes. 22 | /// This could easily be replaced by a function which generated primes numbers on demand for a 23 | /// more dynamic solution when more than 512 total classes would exist in the same inheritance tree. 24 | 25 | constexpr uint64_t primeSize{ 1254 }; 26 | 27 | static const std::array primes = { 28 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 29 | 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 30 | 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 31 | 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 32 | 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 33 | 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 34 | 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 35 | 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 36 | 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 37 | 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 38 | 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 39 | 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 40 | 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 41 | 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 42 | 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 43 | 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 44 | 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 45 | 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 46 | 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 47 | 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 48 | 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 49 | 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 50 | 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 51 | 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 52 | 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 53 | 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 54 | 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 55 | 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 56 | 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 57 | 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 58 | 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 59 | 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 60 | 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 61 | 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 62 | 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 63 | 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 64 | 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 65 | 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 66 | 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 67 | 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 68 | 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 69 | 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 70 | 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 71 | 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 72 | 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 73 | 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 74 | 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 75 | 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 76 | 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 77 | 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 78 | 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 79 | 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 80 | 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 81 | 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 82 | 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 83 | 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 84 | 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 85 | 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 86 | 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 87 | 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 88 | 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 89 | 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 90 | 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 91 | 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 92 | 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 93 | 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 94 | 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 95 | 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 96 | 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, 9749, 97 | 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 98 | 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069, 99 | 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 100 | 10193, 10211, 10223 101 | }; 102 | } 103 | 104 | uint64_t get(const priori::Base* const x) 105 | { 106 | return priori::get(typeid(*x)); 107 | } 108 | 109 | uint64_t get(const std::type_info& ti) 110 | { 111 | // Critical Section 112 | #ifdef PRIORI_THREAD_SAFE 113 | std::unique_lock uniqueLock(priori::impl::Lock); 114 | #endif 115 | 116 | auto it = std::find_if(priori::impl::CastMap.begin(), priori::impl::CastMap.end(), 117 | [&ti](std::pair entry) -> bool 118 | { 119 | return entry.first->operator==(ti); 120 | }); 121 | 122 | if (it != priori::impl::CastMap.end()) 123 | { 124 | return it->second; 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | Base::Base() : prioriFactor(1) 131 | { 132 | this->priori(this); 133 | } 134 | 135 | Base::Base(Base& other) : prioriFactor(other.prioriFactor) 136 | { 137 | } 138 | 139 | Base::Base(Base&& other) : prioriFactor(other.prioriFactor) 140 | { 141 | other.prioriFactor = 0; 142 | } 143 | 144 | Base::~Base() 145 | { 146 | this->prioriFactor = 0; 147 | } 148 | 149 | void Base::priori(const Base* const x) 150 | { 151 | auto prioriNumber = priori::get(x); 152 | 153 | if (prioriNumber == 0) 154 | { 155 | assert(priori::impl::Idx < priori::impl::primeSize); 156 | 157 | prioriNumber = priori::impl::primes[priori::impl::Idx]; 158 | 159 | // Critical Section 160 | { 161 | #ifdef PRIORI_THREAD_SAFE 162 | std::unique_lock uniqueLock(priori::impl::Lock); 163 | #endif 164 | 165 | priori::impl::CastMap.insert(std::make_pair(&typeid(*x), prioriNumber)); 166 | } 167 | 168 | priori::impl::Idx++; 169 | } 170 | 171 | this->prioriFactor *= prioriNumber; 172 | } 173 | 174 | bool Base::priori(const uint64_t x) const 175 | { 176 | return ((this->prioriFactor % x) == 0); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Top level makefile for Priori 3 | # 4 | # Copyright 2014-2021 John Farrier 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | project(priori-test) 20 | 21 | add_executable(${PROJECT_NAME}) 22 | 23 | find_package(GTest CONFIG REQUIRED) 24 | 25 | target_sources(${PROJECT_NAME} PRIVATE 26 | test.cpp 27 | ) 28 | 29 | if(MSVC) 30 | set(SYSLIBS 31 | PowrProf.lib 32 | ) 33 | else() 34 | #pthread is required for std::thread to work. 35 | set(SYSLIBS 36 | pthread 37 | ) 38 | endif() 39 | 40 | PrioriSetDefaultCompilerOptions() 41 | 42 | target_link_libraries(${PROJECT_NAME} 43 | ${SYSLIBS} 44 | GTest::gtest 45 | GTest::gtest_main 46 | priori 47 | ) 48 | 49 | target_include_directories(${PROJECT_NAME} PUBLIC 50 | $ 51 | $ 52 | ${CMAKE_SOURCE_DIR}/include 53 | ${GTEST_INCLUDE_DIR} 54 | ) 55 | 56 | if(PRIORI_ENABLE_FOLDERS) 57 | set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "priori") 58 | endif() 59 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Alpha : public priori::Base 5 | { 6 | public: 7 | Alpha() 8 | { 9 | this->priori(this); 10 | }; 11 | }; 12 | 13 | class Beta : public Alpha 14 | { 15 | public: 16 | Beta() 17 | { 18 | this->priori(this); 19 | }; 20 | }; 21 | 22 | class Beta2 : public Alpha 23 | { 24 | public: 25 | Beta2() 26 | { 27 | this->priori(this); 28 | } 29 | }; 30 | 31 | class Gamma : public Beta 32 | { 33 | public: 34 | Gamma() 35 | { 36 | this->priori(this); 37 | }; 38 | }; 39 | 40 | class Delta : public Gamma 41 | { 42 | public: 43 | Delta() 44 | { 45 | this->priori(this); 46 | }; 47 | }; 48 | 49 | class Epsilon : public Delta 50 | { 51 | public: 52 | Epsilon() 53 | { 54 | this->priori(this); 55 | }; 56 | }; 57 | 58 | class Zeta : public Epsilon 59 | { 60 | public: 61 | Zeta() 62 | { 63 | this->priori(this); 64 | }; 65 | }; 66 | 67 | class Eta : public Zeta 68 | { 69 | public: 70 | Eta() 71 | { 72 | this->priori(this); 73 | }; 74 | }; 75 | 76 | class Theta : public Eta 77 | { 78 | public: 79 | Theta() 80 | { 81 | this->priori(this); 82 | }; 83 | }; 84 | 85 | /// Test the old fashioned dynamic_cast 86 | TEST(priori, dynamicCast) 87 | { 88 | Alpha a; 89 | Beta b; 90 | Beta2 c; 91 | Alpha* aPrime = &b; 92 | 93 | // Ensure both a and b derrive from priori::Base 94 | EXPECT_TRUE(dynamic_cast(&a) != nullptr); 95 | EXPECT_TRUE(dynamic_cast(&b) != nullptr); 96 | 97 | EXPECT_TRUE(dynamic_cast(&b) != nullptr); 98 | EXPECT_TRUE(dynamic_cast(&b) != nullptr); 99 | 100 | EXPECT_TRUE(dynamic_cast(aPrime) != nullptr); 101 | EXPECT_TRUE(dynamic_cast(aPrime) != nullptr); 102 | EXPECT_TRUE(dynamic_cast(aPrime) != nullptr); 103 | 104 | EXPECT_TRUE(dynamic_cast(&c) != nullptr); 105 | EXPECT_TRUE(dynamic_cast(&c) != nullptr); 106 | EXPECT_TRUE(dynamic_cast(&c) == nullptr); 107 | EXPECT_TRUE(dynamic_cast(&c) != nullptr); 108 | } 109 | 110 | /// Test the quick/dirty priori_cast 111 | TEST(priori, prioriCast) 112 | { 113 | priori::Base x; 114 | Alpha a; 115 | Beta b; 116 | Beta2 c; 117 | Alpha* aPrime = &b; 118 | 119 | // Ensure both a and b derrive from priori::Base 120 | EXPECT_TRUE(priori_cast(&a) != nullptr); 121 | EXPECT_TRUE(priori_cast(&b) != nullptr); 122 | 123 | EXPECT_TRUE(priori_cast(&b) != nullptr); 124 | EXPECT_TRUE(priori_cast(&b) != nullptr); 125 | 126 | EXPECT_TRUE(priori_cast(aPrime) != nullptr); 127 | EXPECT_TRUE(priori_cast(aPrime) != nullptr); 128 | EXPECT_TRUE(priori_cast(aPrime) != nullptr); 129 | 130 | EXPECT_TRUE(priori_cast(&c) != nullptr); 131 | EXPECT_TRUE(priori_cast(&c) != nullptr); 132 | EXPECT_TRUE(priori_cast(&c) == nullptr); 133 | EXPECT_TRUE(priori_cast(&c) != nullptr); 134 | } --------------------------------------------------------------------------------