├── .buckconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── BUCK ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── buckaroo.json ├── cmake └── vs_source_groups.cmake ├── conanfile.py ├── examples ├── BUCK ├── CMakeLists.txt └── main.cpp ├── inception.py ├── include └── ctti │ ├── detail │ ├── algorithm.hpp │ ├── cstring.hpp │ ├── entity_name.hpp │ ├── hash.hpp │ ├── language_features.hpp │ ├── meta.hpp │ ├── name_filters.hpp │ ├── nlohmann_json.hpp │ ├── preprocessor.hpp │ └── pretty_function.hpp │ ├── detailed_nameof.hpp │ ├── hash_literal.hpp │ ├── map.hpp │ ├── model.hpp │ ├── name.hpp │ ├── nameof.hpp │ ├── serialization.hpp │ ├── static_value.hpp │ ├── symbol.hpp │ ├── symbol_from_hash.hpp │ ├── tie.hpp │ ├── type_id.hpp │ └── type_tag.hpp ├── test_package ├── BUCK ├── CMakeLists.txt ├── conanfile.py └── main.cpp └── tests ├── CMakeLists.txt ├── catch.hpp ├── cstring.cpp ├── detailed_nameof.cpp ├── hash.cpp ├── main.cpp ├── map.cpp ├── model.cpp ├── name_filters.cpp ├── nameof.cpp ├── serialization.cpp ├── static ├── CMakeLists.txt ├── algorithm.cpp ├── cstring.cpp ├── hash.cpp ├── model.cpp ├── name.cpp ├── static_test.hpp ├── static_value.cpp └── symbol.cpp ├── symbol.cpp └── tie.cpp /.buckconfig: -------------------------------------------------------------------------------- 1 | [project] 2 | ignore = .git 3 | 4 | [cxx] 5 | cxxflags = -std=c++14 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.idea 3 | *.vcxproj* 4 | Debug/ 5 | Release/ 6 | *.exe 7 | *.s 8 | 9 | # More VS stuff 10 | *.sln 11 | *.sdf 12 | *.opensdf 13 | *.vs* 14 | 15 | # conan.io stuff 16 | conanbuildinfo.txt 17 | conaninfo.txt 18 | conanfile.pyc 19 | 20 | # Buck / Buckaroo 21 | /buck-out/ 22 | /.buckd/ 23 | /buckaroo/ 24 | .buckconfig.local 25 | BUCKAROO_DEPS 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: 3 | - gcc 4 | - clang 5 | 6 | addons: 7 | apt: 8 | packages: 9 | - clang-3.7 10 | - g++-5 11 | - gcc-5 12 | sources: 13 | - ubuntu-toolchain-r-test 14 | - llvm-toolchain-precise-3.7 15 | 16 | install: 17 | - if [ "$CC" == "clang" ]; then export CXX=clang++-3.7 CC=clang-3.7; fi 18 | - if [ "$CC" == "gcc" ]; then export CXX=g++-5 CC=gcc-5; fi 19 | 20 | - pip install --user conan && export PATH=$PATH:$HOME/.local/bin 21 | - conan --version 22 | 23 | - DEPS_DIR="${HOME}/deps" 24 | - mkdir ${DEPS_DIR} && cd ${DEPS_DIR} 25 | - CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz" 26 | - mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake 27 | - export PATH=${DEPS_DIR}/cmake/bin:${PATH} 28 | - cd ${TRAVIS_BUILD_DIR} 29 | 30 | - cmake --version 31 | 32 | - mkdir build && cd build 33 | - cmake .. -DCTTI_BUILD_TESTS=ON 34 | - cmake --build . 35 | - ctest -V 36 | 37 | script: 38 | - cd ${TRAVIS_BUILD_DIR} 39 | - conan test_package --build=outdated 40 | -------------------------------------------------------------------------------- /BUCK: -------------------------------------------------------------------------------- 1 | prebuilt_cxx_library( 2 | name = 'ctti', 3 | header_namespace = 'ctti', 4 | header_only = True, 5 | exported_headers = subdir_glob([ 6 | ('include/ctti', '**/*.hpp'), 7 | ]), 8 | visibility = [ 9 | 'PUBLIC', 10 | ], 11 | ) 12 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(ctti) 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | option(CTTI_BUILD_TESTS "Build ctti feature tests" OFF) 5 | option(CTTI_BUILD_EXAMPLES "Build ctti examples" OFF) 6 | 7 | include(cmake/vs_source_groups.cmake) 8 | 9 | set(CTTI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) 10 | 11 | set(CMAKE_CXX_STANDARD 14) 12 | if(NOT MSVC) 13 | set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wall -Werror") 14 | endif() 15 | 16 | add_library(ctti INTERFACE) 17 | target_include_directories(ctti INTERFACE ${CTTI_SOURCE_DIR}/include) 18 | 19 | if(CTTI_BUILD_TESTS) 20 | enable_testing() 21 | add_subdirectory(tests) 22 | endif() 23 | 24 | if(CTTI_BUILD_EXAMPLES) 25 | add_subdirectory(examples) 26 | endif() 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 Manuel Sánchez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CTTI [![badge](https://img.shields.io/badge/conan.io-ctti%2F0.0.1-green.svg?logo=data:image/png;base64%2CiVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAA1VBMVEUAAABhlctjlstkl8tlmMtlmMxlmcxmmcxnmsxpnMxpnM1qnc1sn85voM91oM11oc1xotB2oc56pNF6pNJ2ptJ8ptJ8ptN9ptN8p9N5qNJ9p9N9p9R8qtOBqdSAqtOAqtR%2BrNSCrNJ/rdWDrNWCsNWCsNaJs9eLs9iRvNuVvdyVv9yXwd2Zwt6axN6dxt%2Bfx%2BChyeGiyuGjyuCjyuGly%2BGlzOKmzOGozuKoz%2BKqz%2BOq0OOv1OWw1OWw1eWx1eWy1uay1%2Baz1%2Baz1%2Bez2Oe02Oe12ee22ujUGwH3AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgBQkREyOxFIh/AAAAiklEQVQI12NgAAMbOwY4sLZ2NtQ1coVKWNvoc/Eq8XDr2wB5Ig62ekza9vaOqpK2TpoMzOxaFtwqZua2Bm4makIM7OzMAjoaCqYuxooSUqJALjs7o4yVpbowvzSUy87KqSwmxQfnsrPISyFzWeWAXCkpMaBVIC4bmCsOdgiUKwh3JojLgAQ4ZCE0AMm2D29tZwe6AAAAAElFTkSuQmCC)](http://www.conan.io/source/ctti/0.0.1/Manu343726/testing) [![Build Status](https://travis-ci.org/Manu343726/ctti.svg?branch=master)](https://travis-ci.org/Manu343726/ctti) [![Join the chat at https://gitter.im/Manu343726/ctti](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Manu343726/ctti?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | Compile Time Type Information for the C++ programming language. 4 | 5 | ## Background 6 | 7 | We know C++ is a statically typed compiled language, but it's disappointing that we cannot even get 8 | the name of a C++ type at compile time, having to use RTTI (Run Time Type Information) which introduces 9 | a lot of overhead. In fact, that's one of the most feared features of C++, usually disabled in performance dependent 10 | scenarios such as videogames programming. 11 | 12 | This library aims to provide features similar to RTTI `std::type_info` at compile-time, currently `constexpr` type name and 13 | a `constexpr` replacement of `std::type_index` for indexing maps with types. 14 | 15 | ``` cpp 16 | #include "ctti/type_id.hpp" 17 | 18 | int main() 19 | { 20 | static_assert(ctti::type_id() != ctti::type_id("hello"), "compile-time type-id comparison"); 21 | 22 | std::unordered_map sizeof_map; 23 | 24 | sizeof_map[ctti::type_id()] = sizeof(int); 25 | } 26 | ``` 27 | 28 | ## Support and current status 29 | 30 | This was tested on Visual Studio 2015, GCC 5.2.0, MinGW GCC 5.1, Clang >3.6.2, and cygwin Clang 3.5.2. 31 | ctti does no use of generalized `constexpr` and must work on C++11 mode, but it needs support of `constexpr` `__func__`-like variables in the compiler. 32 | All major compilers except GCC before 5.1 support this. 33 | 34 | ## Features 35 | 36 | - **`ctti::nameof()`**: `constexpr` demangled full qualified type names. 37 | - **`ctti::nameof()`**: `constexpr` demangled value strings. 38 | - **`ctti::static_calue`**: `std::integral_constant` on steroids, to pass values as template parameters. 39 | - **`CTTI_STATIC_VALUE(Value)`**: Handy macro to instance a `ctti::static_value` from the given value. 40 | - **`ctti::detailed_nameof<>()`**: Alternatives to nameof with detailed name info, supporting non-qualified names, getting qualifiers, etc. See `ctti::name_t` for details. 41 | - **`ctti::nameof_v<>` and `ctti::detailed_nameof_v<>`**: C++14 variable template alternatives to the nameof family of functions. Thanks C++ Bruja for this suggestion. 42 | - **`ctti::type_id()`**: `constexpr` `std::type_info`-like type identifier. See `ctti::type_id_t` bellow for details. 43 | - **`ctti::id_from_name(name)`**: Get the type id corresponding to the given typename. 44 | - **`ctti::unnamed_type_id()`**: `constexpr` `std::type_info`-like hash-only type identifier. See `ctti::unnamed_type_id_t` bellow for details. 45 | - **Symbol based introspection**: Automatic serialization (wip), object conversion, etc. See symbolic introspection bellow. 46 | 47 | ### Name customization 48 | 49 | The names ctti return for a given static value or typename can be overrided with the `ctti_nameof()` function. This can be achieved in two ways: 50 | 51 | - **Intrusive override**: The user defined class defines a `ctti_nameof()` function as part of its static public API: 52 | ``` cpp 53 | struct Foo 54 | { 55 | static constexpr const char* ctti_nameof() 56 | { 57 | return "foo"; 58 | } 59 | }; 60 | ``` 61 | - **Non-intrusive override**: A `ctti_nameof(type/value tag)` customization point is defined in the type/value namespace: 62 | ``` cpp 63 | #include 64 | 65 | namespace std 66 | { 67 | constexpr const char* ctti_nameof(ctti::type_tag) 68 | { 69 | return "std::string"; // instead of "std::__foobar::basic_string" 70 | } 71 | } 72 | ``` 73 | 74 | ### `ctti::detail::cstring` 75 | 76 | `cstring` is a `constexpr` implementation of an string view and the core of ctti. All strings returned by the ctti API are represented by this type. 77 | It supports slicing via `operator()(begin index, end index)`, subscript, hashing, string padding, comparison operators, print to `std::ostream`, etc. 78 | 79 | ``` cpp 80 | constexpr ctti::detail::cstring str{"hello world"}; 81 | constexpr ctti::detail::cstring str2{" hello world "}; 82 | 83 | static_assert(str(0, 5) == "hello"); 84 | static_assert(str2.pad(2, 2) == str); 85 | 86 | constexpr std::uint64_t hash = str.hash(); // fnv1a hash or "hello world" 87 | ``` 88 | 89 | ### `ctti::name_t` 90 | 91 | `name_t` contains methods to extract information of a name. Given a full qualified name (like those returned by `ctti::nameof()`) a `name_t` can be constructed and 92 | queried: 93 | 94 | ``` cpp 95 | struct Foo 96 | { 97 | int i; 98 | }; 99 | 100 | constexpr ctti::name_t FooName = ctti::detailed_nameof(); 101 | 102 | int main() 103 | { 104 | std::cout << FooName.name(); // prints "i" 105 | std::cout << FooName.full_name(); // prints "&Foo::i" 106 | std::cout << FooName.full_homogeneous_name(); // prints "Foo::i" 107 | std::cout << FooName.qualifier(0); // prints "Foo" 108 | } 109 | ``` 110 | 111 | All methods in `name_t` are `constexpr` and return `cstring`s. 112 | 113 | ### `ctti::type_id_t` 114 | 115 | A `constexpr` class representing an object identifier. It has the minimal `constexpr` comparable interface to be used as a key type. The id is based on 116 | a fnv1a hash of the type name, which can be obtained by calling `type_id_t::hash()`. `std::hash` is specialized for this type. 117 | 118 | ``` cpp 119 | std::unordered_map factories; 120 | 121 | factories[ctti::type_id()] = []() -> void* { return new int{}; }; 122 | factories[ctti::type_id()] = []() -> void* { return new std::string{}; }; 123 | 124 | void* int_var = factories[ctti::id_from_name("int")](); 125 | ``` 126 | 127 | ### `ctti::unnamed_type_id_t` 128 | 129 | A lightweight version of `type_id_t` which only stores the type hash (`ctti::type_id_t` stores the name string, which takes one pointer and a `size_t`, and 130 | computes hash on demand. `unnamed_type_id_t` stores the `std::uint64_t` hash only). 131 | 132 | ``` cpp 133 | struct object 134 | { 135 | ctti::unnamed_type_id_t type_id; 136 | void* data; 137 | }; 138 | ``` 139 | 140 | ### Symbolic introspection 141 | 142 | ctti implements object introspection by working with abstract "symbols" defined by the user: 143 | 144 | ``` cpp 145 | #include 146 | 147 | CTTI_DEFINE_SYMBOL(foo); 148 | ``` 149 | 150 | the `CTTI_DEFINE_SYMBOL` macro defines an abstract identifier, a symbol, in the current namespace. After its definition, 151 | classes can be asked for members through that symbo: 152 | 153 | ``` cpp 154 | CTTI_DEFINE_SYMBOL(i); 155 | 156 | struct my_struct 157 | { 158 | int i; 159 | }; 160 | 161 | static_assert(i::is_member_of(), "Has my_struct a member named 'i'?"); 162 | ``` 163 | 164 | with symbols as non-intrusive generic member identifiers, objects can be manipulated in a generic way: 165 | 166 | ``` cpp 167 | #include 168 | #include 169 | 170 | CTTI_DEFINE_SYMBOL(a); 171 | CTTI_DEFINE_SYMBOL(b); 172 | CTTI_DEFINE_SYMBOL(c); 173 | 174 | struct foo 175 | { 176 | int a, b, c; 177 | }; 178 | 179 | 180 | int var_a, var_b; 181 | foo my_foo{1, 2, 3}; 182 | 183 | ctti::tie(var_a, var_b) = my_foo; 184 | 185 | assert(var_a == 1); 186 | assert(var_a == 2); 187 | ``` 188 | 189 | ``` cpp 190 | struct bar 191 | { 192 | int a, b; 193 | }; 194 | 195 | bar my_bar; 196 | 197 | // Copy my_foo.a to my_bar.a and my_foo.b to my_bar.b: 198 | ctti::map(my_foo, my_bar, ctti::mapping(), ctti::mapping()); 199 | ``` 200 | 201 | ### Conditional features 202 | 203 | ctti has a set of conditional features that depend on non-C++11 language features. This ctti features can be controlled by different macros: 204 | 205 | - `ctti::nameof_v/detailed_nameof_v` are declared only if `CTTI_HAS_VARIABLE_TEMPLATES` is defined. Enabled by default if the compiler supports variable templates. 206 | - `ctti::nameof/detailed_nameof` could work with enum values if the compiler prints those values as part of their `PRETTY_FUNCTION` variables. ctti controls this 207 | by defining the `CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION`. If this macro is not defined ctti gives no guarantee you will get the right string from an enum value. 208 | 209 | ## Acknowledgments 210 | 211 | Thanks a lot to Jonathan "foonathan" Müller, both for the `constexpr` hash and the idea for the `__PRETTY_FUNCTION__` trick. 212 | 213 | ## License 214 | 215 | This project is licensed under the MIT license. See LICENSE.md for more details. 216 | -------------------------------------------------------------------------------- /buckaroo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ctti" 3 | } -------------------------------------------------------------------------------- /cmake/vs_source_groups.cmake: -------------------------------------------------------------------------------- 1 | 2 | function(_generate_vs_source_groups GROUP_NAME TOP_DIRECTORY CURRENT_SUBDIRECTORY RESULT_FILES) 3 | 4 | file(GLOB headers 5 | ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*.h 6 | ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*.hpp 7 | ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*.hh 8 | ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*.hxx 9 | ) 10 | 11 | file(GLOB sources 12 | ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*.c 13 | ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*.cpp 14 | ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*.cc 15 | ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*.cxx 16 | ) 17 | 18 | string(REPLACE "/" "\\" subgroups "${CURRENT_SUBDIRECTORY}") 19 | 20 | source_group("${GROUP_NAME}\\${subgroups}" FILES ${headers} ${sources}) 21 | 22 | list(APPEND result_files ${headers} ${sources}) 23 | 24 | file(GLOB childs RELATIVE ${TOP_DIRECTORY} ${TOP_DIRECTORY}/${CURRENT_SUBDIRECTORY}/*) 25 | 26 | foreach(child ${childs}) 27 | if(IS_DIRECTORY ${TOP_DIRECTORY}/${child}) 28 | _generate_vs_source_groups("${GROUP_NAME}" "${TOP_DIRECTORY}" "${child}" res) 29 | list(APPEND result_files ${res}) 30 | endif() 31 | endforeach() 32 | 33 | set(${RESULT_FILES} ${result_files} PARENT_SCOPE) 34 | endfunction() 35 | 36 | function(generate_vs_source_groups GROUP_NAME TOP_DIRECTORY RESULT_FILES) 37 | _generate_vs_source_groups("${GROUP_NAME}" "${TOP_DIRECTORY}" "" ${RESULT_FILES}) 38 | set(${RESULT_FILES} "${${RESULT_FILES}}" PARENT_SCOPE) 39 | endfunction() -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | from conans import ConanFile 2 | 3 | class Ctti(ConanFile): 4 | name = "ctti" 5 | url = "https::/github.com/Manu343726/ctti" 6 | license = "MIT" 7 | version = "0.0.2" 8 | exports = "*.hpp" 9 | build_policy = "missing" 10 | 11 | def package(self): 12 | self.copy("*.hpp", src="include", dst="include") 13 | -------------------------------------------------------------------------------- /examples/BUCK: -------------------------------------------------------------------------------- 1 | cxx_binary( 2 | name = 'examples', 3 | srcs = [ 4 | 'main.cpp', 5 | ], 6 | deps = [ 7 | '//:ctti', 8 | ], 9 | ) 10 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(ctti-example main.cpp) 2 | target_link_libraries(ctti-example PRIVATE ctti) 3 | -------------------------------------------------------------------------------- /examples/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct foo 6 | { 7 | int i = 0; 8 | }; 9 | 10 | int f(const std::string&, int) 11 | { 12 | return 42; 13 | } 14 | 15 | enum class bar_enum 16 | { 17 | FOO, 18 | BAR, 19 | QUUX 20 | }; 21 | 22 | int main() 23 | { 24 | static_assert(ctti::type_id() != ctti::type_id(), "what?"); 25 | 26 | std::cout << ctti::nameof() << std::endl; 27 | std::cout << ctti::nameof() << std::endl; 28 | std::cout << ctti::nameof() << std::endl; 29 | std::cout << ctti::pretty_function::value() << " -> " << ctti::nameof() << std::endl; 30 | std::cout << ctti::pretty_function::value() << " -> " << ctti::nameof() << std::endl; 31 | std::cout << ctti::nameof() << std::endl; 32 | std::cout << ctti::nameof() << std::endl; 33 | std::cout << ctti::type_id(std::cout).hash() << std::endl; 34 | std::cout << ctti::unnamed_type_id(std::cin).hash() << std::endl; 35 | std::cout << "sizeof(ctti::type_id_t) = " << sizeof(ctti::type_id()) << std::endl; 36 | std::cout << "sizeof(ctti::unnamed_type_id_t) = " << sizeof(ctti::unnamed_type_id()) << std::endl; 37 | std::cin.get(); 38 | } 39 | -------------------------------------------------------------------------------- /inception.py: -------------------------------------------------------------------------------- 1 | """ 2 | Invoke as follows: 3 | 4 | python inception.py path/to/project/sources [libclang.so full path] 5 | """ 6 | 7 | 8 | from clang.cindex import Index, Cursor, CursorKind, Config 9 | import os, sys, re, fnmatch 10 | 11 | def align_doc(doc): 12 | processed_lines = [] 13 | 14 | for line in doc.split('\n'): 15 | stripped = line.strip() 16 | aligned = '{}{}'.format(' '*(0 if stripped.startswith('/') else 5), stripped) 17 | 18 | processed_lines.append(aligned) 19 | 20 | return '\n'.join(processed_lines) 21 | 22 | def parse_cursor(c): 23 | element = {} 24 | element['file'] = c.location.file 25 | element['line'] = c.location.line 26 | element['spelling'] = c.spelling 27 | element['kind'] = '{}'.format(c.kind) 28 | element['cursor'] = c 29 | 30 | return element; 31 | 32 | def generate_symbols(elements): 33 | with open('symbols.hpp', mode='w+') as file: 34 | file.write(""" 35 | /* 36 | * Generated from sources 37 | * Symbolic introspection the lazy way 38 | */ 39 | 40 | #ifndef CTTI_SYMBOLS_HPP 41 | #define CTTI_SYMBOLS_HPP 42 | """) 43 | 44 | for element in elements.values(): 45 | file.write(""" 46 | #ifndef CTTI_SYMBOLS_{0}_DEFINED 47 | #define CTTI_SYMBOLS_{0}_DEFINED 48 | CTTI_DEFINE_SYMBOL({0}); // from {1}:{2} ({3}) 49 | #endif // CTTI_SYMBOLS_{0}_DEFINED 50 | 51 | """.format(element['spelling'], element['file'], element['line'], element['kind'])); 52 | 53 | file.write(""" 54 | #endif // CTTI_DEFINE_SYMBOLS_HPP"""); 55 | 56 | def parse(project_includedir, libclang_lib): 57 | if libclang_lib != "": 58 | Config.set_library_file(libclang_lib) 59 | 60 | index = Index.create() 61 | values = {}; 62 | processed_files = []; 63 | abs_project_includedir = os.path.abspath(project_includedir) 64 | 65 | valid_kinds = [ 66 | CursorKind.NAMESPACE, 67 | CursorKind.CLASS_DECL, 68 | CursorKind.STRUCT_DECL, 69 | CursorKind.UNION_DECL, 70 | CursorKind.ENUM_DECL, 71 | CursorKind.FIELD_DECL, 72 | CursorKind.TYPE_ALIAS_DECL, 73 | CursorKind.NAMESPACE_ALIAS, 74 | CursorKind.CLASS_TEMPLATE, 75 | CursorKind.CXX_METHOD, 76 | CursorKind.ENUM_CONSTANT_DECL 77 | ]; 78 | 79 | invalid_names = [ 80 | "", 81 | "static_assert", # An static assert expression is parsed as a CXX METHOD, lol 82 | "std", 83 | "hash", 84 | "get_member", 85 | "value_type", 86 | "member_type", 87 | "MOCK_METHOD0", 88 | "MOCK_METHOD1", 89 | "MOCK_METHOD2", 90 | "MOCK_METHOD3", 91 | "MOCK_METHOD4", 92 | "MOCK_METHOD5", 93 | "MOCK_METHOD6", 94 | "MOCK_METHOD7", 95 | "MOCK_METHOD8", 96 | "MOCK_METHOD9", 97 | "MOCK_METHOD10", 98 | "MOCK_CONST_METHOD0", 99 | "MOCK_CONST_METHOD1", 100 | "MOCK_CONST_METHOD2", 101 | "MOCK_CONST_METHOD3", 102 | "MOCK_CONST_METHOD4", 103 | "MOCK_CONST_METHOD5", 104 | "MOCK_CONST_METHOD6", 105 | "MOCK_CONST_METHOD7", 106 | "MOCK_CONST_METHOD8", 107 | "MOCK_CONST_METHOD9", 108 | "MOCK_CONST_METHOD10", 109 | "operator()", 110 | "operator+", 111 | "operator++", 112 | "operator+=", 113 | "operator-", 114 | "operator--", 115 | "operator-=", 116 | "operator<", 117 | "operator<=", 118 | "operator<<", 119 | "operator<<=", 120 | "operator>", 121 | "operator>=", 122 | "operator>>", 123 | "operator>>=", 124 | "operator=", 125 | "operator*=", 126 | "operator->", 127 | "operator*", 128 | "operator==", 129 | "operator!=", 130 | "operator~", 131 | "operator^", 132 | "operator^=", 133 | "operator%", 134 | "operator%=", 135 | "operator|", 136 | "operator|=", 137 | "operator||", 138 | "operator&", 139 | "operator&=", 140 | "operator&&", 141 | "operator[]", 142 | "operator/", 143 | "operator/=", 144 | "operator!", 145 | "operator!=" 146 | ]; 147 | 148 | print 'project include dir: ' + abs_project_includedir 149 | 150 | def visitor(cursor): 151 | if cursor.kind == CursorKind.TRANSLATION_UNIT: 152 | abs_file = os.path.abspath(str(cursor.spelling)) 153 | else: 154 | if cursor.location.file is not None: 155 | abs_file = os.path.abspath(str(cursor.location.file)) 156 | else: 157 | abs_file = "" 158 | 159 | common_path = os.path.commonprefix([abs_file, abs_project_includedir]) 160 | 161 | if common_path == abs_project_includedir and cursor.spelling not in invalid_names and \ 162 | cursor.kind in valid_kinds and \ 163 | cursor.spelling not in values: 164 | print '{}# {}:{}: {} (Kind={})'.format(len(values), cursor.location.file, cursor.location.line, cursor.spelling, cursor.kind) 165 | values[cursor.spelling] = parse_cursor(cursor) 166 | 167 | if common_path == abs_project_includedir and ((cursor.kind == CursorKind.TRANSLATION_UNIT and (not cursor.location.file in processed_files)) or \ 168 | cursor.kind != CursorKind.TRANSLATION_UNIT): 169 | for c in cursor.get_children(): 170 | visitor(c) 171 | 172 | for root, dirnames, filenames in os.walk(project_includedir): 173 | for filename in \ 174 | fnmatch.filter(filenames, '*.pb.h') + \ 175 | fnmatch.filter(filenames, '*.pb.cc') + \ 176 | fnmatch.filter(filenames, '*.h') + \ 177 | fnmatch.filter(filenames, '*.hpp') + \ 178 | fnmatch.filter(filenames, '*.c') + \ 179 | fnmatch.filter(filenames, '*.cpp'): 180 | file = os.path.join(root, filename) 181 | tu = index.parse(file) 182 | visitor(tu.cursor) 183 | 184 | generate_symbols(values) 185 | 186 | def main(): 187 | project_includedir = sys.argv[1] 188 | libclang_lib = ""; 189 | 190 | if len(sys.argv) > 2: 191 | libclang_lib = sys.argv[2] 192 | 193 | parse(project_includedir, libclang_lib) 194 | 195 | if __name__ == '__main__': 196 | main() 197 | -------------------------------------------------------------------------------- /include/ctti/detail/algorithm.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_DETAIL_ALGORITHM_HPP 2 | #define CTTI_DETAIL_ALGORITHM_HPP 3 | 4 | #include 5 | 6 | namespace ctti 7 | { 8 | 9 | namespace detail 10 | { 11 | 12 | template 13 | constexpr const T* begin(const T(&array)[N]) 14 | { 15 | return &array[0]; 16 | } 17 | 18 | template 19 | constexpr const T* end(const T(&array)[N]) 20 | { 21 | return &array[N]; 22 | } 23 | 24 | template 25 | constexpr bool equal_range(LhsIt lhsBegin, LhsIt lhsEnd, RhsIt rhsBegin, RhsIt rhsEnd) 26 | { 27 | return (lhsBegin != lhsEnd && rhsBegin != rhsEnd) ? *lhsBegin == *rhsBegin && 28 | equal_range(lhsBegin + 1, lhsEnd, rhsBegin + 1, rhsEnd) : (lhsBegin == lhsEnd && rhsBegin == rhsEnd); 29 | } 30 | 31 | template 32 | constexpr const T& max(const T& lhs, const T& rhs) 33 | { 34 | return (lhs >= rhs) ? lhs : rhs; 35 | } 36 | 37 | template 38 | constexpr const T& min(const T& lhs, const T& rhs) 39 | { 40 | return (lhs <= rhs) ? lhs : rhs; 41 | } 42 | 43 | } 44 | 45 | } 46 | 47 | #endif // CTTI_DETAIL_ALGORITHM_HPP 48 | -------------------------------------------------------------------------------- /include/ctti/detail/cstring.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_DETAIL_CSTRING_HPP 2 | #define CTTI_DETAIL_CSTRING_HPP 3 | 4 | #include "hash.hpp" 5 | #include "algorithm.hpp" 6 | #include 7 | #include 8 | 9 | namespace ctti 10 | { 11 | 12 | namespace detail 13 | { 14 | 15 | class cstring 16 | { 17 | public: 18 | template 19 | constexpr cstring(const char (&str)[N]) : 20 | cstring{&str[0], N - 1} 21 | {} 22 | 23 | constexpr cstring(const char* begin, std::size_t length) : 24 | _str{begin}, 25 | _length{length} 26 | {} 27 | 28 | constexpr cstring(const char* begin, const char* end) : 29 | cstring{begin, static_cast(end - begin)} 30 | {} 31 | 32 | constexpr cstring(const char* begin) : 33 | cstring{begin, length(begin)} 34 | {} 35 | 36 | static constexpr std::size_t length(const char* str) 37 | { 38 | return *str ? 1 + length(str + 1) : 0; 39 | } 40 | 41 | constexpr std::size_t length() const 42 | { 43 | return _length; 44 | } 45 | 46 | constexpr std::size_t size() const 47 | { 48 | return length(); 49 | } 50 | 51 | constexpr hash_t hash() const 52 | { 53 | return fnv1a_hash(length(), begin()); 54 | } 55 | 56 | std::string cppstring() const 57 | { 58 | return {begin(), end()}; 59 | } 60 | 61 | std::string str() const 62 | { 63 | return cppstring(); 64 | } 65 | 66 | constexpr const char* begin() const 67 | { 68 | return _str; 69 | } 70 | 71 | constexpr const char* end() const 72 | { 73 | return _str + _length; 74 | } 75 | 76 | constexpr char operator[](std::size_t i) const 77 | { 78 | return _str[i]; 79 | } 80 | 81 | constexpr const char* operator()(std::size_t i) const 82 | { 83 | return _str + i; 84 | } 85 | 86 | constexpr cstring operator()(std::size_t begin, std::size_t end) const 87 | { 88 | return {_str + begin, _str + end}; 89 | } 90 | 91 | constexpr cstring pad(std::size_t begin_offset, std::size_t end_offset) const 92 | { 93 | return operator()(begin_offset, size() - end_offset); 94 | } 95 | 96 | friend std::ostream& operator<<(std::ostream& os, const cstring& str) 97 | { 98 | for(const char c : str) 99 | { 100 | os << c; 101 | } 102 | 103 | return os; 104 | } 105 | 106 | private: 107 | const char* _str; 108 | std::size_t _length; 109 | }; 110 | 111 | constexpr bool operator==(const cstring& lhs, const cstring& rhs) 112 | { 113 | return ctti::detail::equal_range(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); 114 | } 115 | 116 | constexpr bool operator!=(const cstring& lhs, const cstring& rhs) 117 | { 118 | return !(lhs == rhs); 119 | } 120 | 121 | } 122 | 123 | } 124 | 125 | #endif // CTTI_DETAIL_CSTRING_HPP 126 | -------------------------------------------------------------------------------- /include/ctti/detail/entity_name.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_DETAIL_ENTITY_NAME_HPP 2 | #define CTTI_DETAIL_ENTITY_NAME_HPP 3 | 4 | #include "cstring.hpp" 5 | 6 | namespace ctti 7 | { 8 | 9 | namespace detail 10 | { 11 | 12 | class entity_name 13 | { 14 | public: 15 | constexpr entity_name(const ctti::detail::cstring& str) : 16 | _str{str} 17 | {} 18 | 19 | constexpr ctti::detail::cstring str() const 20 | { 21 | return _str; 22 | } 23 | 24 | constexpr ctti::detail::cstring operator[](std::size_t i) const 25 | { 26 | return colon_scan(_str.begin(), _str.end(), i); 27 | } 28 | 29 | private: 30 | ctti::detail::cstring _str; 31 | 32 | constexpr ctti::detail::cstring colon_scan(const char* begin, const char* end, std::size_t i) const 33 | { 34 | return (begin == end) ? {begin, end} : 35 | (i == 0) ? {begin, end} 36 | (colon_count == 0 && *begin == ':') ? colon_scan(++begin, end, i, ++colon_count) : 37 | (colon_count == 1 && *begin == ':') ? colon_scan(++begin, end, i - 1, 0) 38 | ( 39 | } 40 | }; 41 | 42 | } 43 | 44 | } 45 | 46 | #endif // CTTI_DETAIL_ENTITY_NAME_HPP 47 | -------------------------------------------------------------------------------- /include/ctti/detail/hash.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_DETAIL_HASH_HPP 2 | #define CTTI_DETAIL_HASH_HPP 3 | 4 | #include 5 | 6 | namespace ctti 7 | { 8 | namespace detail 9 | { 10 | // From https://github.com/foonathan/string_id. As usually, thanks Jonathan. 11 | 12 | using hash_t = std::uint64_t; 13 | 14 | // See http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param 15 | constexpr hash_t fnv_basis = 14695981039346656037ull; 16 | constexpr hash_t fnv_prime = 1099511628211ull; 17 | 18 | // FNV-1a 64 bit hash 19 | constexpr hash_t fnv1a_hash(std::size_t n, const char *str, hash_t hash = fnv_basis) 20 | { 21 | return n > 0 ? fnv1a_hash(n - 1, str + 1, (hash ^ *str) * fnv_prime) : hash; 22 | } 23 | 24 | template 25 | constexpr hash_t fnv1a_hash(const char (&array)[N]) 26 | { 27 | return fnv1a_hash(N - 1, &array[0]); 28 | } 29 | } 30 | } 31 | 32 | #endif /* CTTI_DETAIL_HASH_HPP */ 33 | -------------------------------------------------------------------------------- /include/ctti/detail/language_features.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_LANGUAGE_FEATURES_HPP 2 | #define CTTI_LANGUAGE_FEATURES_HPP 3 | 4 | #ifdef __cpp_variable_templates 5 | #define CTTI_HAS_VARIABLE_TEMPLATES 6 | #endif // __cpp_variable_templates 7 | 8 | #define CTTI_HAS_CONSTEXPR_PRETTY_FUNCTION 9 | 10 | #if defined(__GCC__) && __GCC__ < 5 11 | #undef CTTI_HAS_CONSTEXPR_PRETTY_FUNCTION 12 | #endif // GCC 4.x 13 | 14 | #ifdef __clang__ 15 | #define CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 16 | #endif // __clang__ 17 | 18 | #endif // CTTI_LANGUAGE_FEATURES_HPP 19 | -------------------------------------------------------------------------------- /include/ctti/detail/meta.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_UTILITY_META_H 2 | #define CTTI_UTILITY_META_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ctti 9 | { 10 | 11 | namespace meta 12 | { 13 | template 14 | using decay_t = typename std::decay::type; 15 | 16 | template 17 | struct assert; 18 | 19 | template 20 | struct assert : assert 21 | { 22 | static_assert(B::value, "Assertion failed"); 23 | }; 24 | 25 | template<> 26 | struct assert<> {}; 27 | 28 | template 29 | using void_t = typename std::conditional= 0, void, T>::type; 30 | 31 | template 32 | struct identity 33 | { 34 | using type = T; 35 | }; 36 | 37 | template 38 | using type_t = typename Metafunction::type; 39 | 40 | template 41 | using enable_if_t = typename std::enable_if::type; 42 | 43 | template 44 | using apply_t = type_t>; 45 | 46 | template 47 | struct sequence_apply; 48 | 49 | template class Seq, typename... Ts> 51 | struct sequence_apply> 52 | { 53 | using type = apply_t; 54 | }; 55 | 56 | template 57 | using sequence_apply_t = type_t>; 58 | 59 | template 60 | using uint8_t = std::integral_constant; 61 | template 62 | using uint16_t = std::integral_constant; 63 | template 64 | using uint32_t = std::integral_constant; 65 | template 66 | using uint64_t = std::integral_constant; 67 | 68 | template 69 | using int8_t = std::integral_constant; 70 | template 71 | using int16_t = std::integral_constant; 72 | template 73 | using int32_t = std::integral_constant; 74 | template 75 | using int64_t = std::integral_constant; 76 | 77 | template 78 | using size_t = std::integral_constant; 79 | 80 | template 81 | using bool_ = std::integral_constant; 82 | using true_ = bool_; 83 | using false_ = bool_; 84 | 85 | template 86 | using char_ = std::integral_constant; 87 | 88 | template 89 | struct is_integral : false_ {}; 90 | template 91 | struct is_integral> : 92 | true_ 93 | {}; 94 | 95 | template>> 96 | constexpr decltype(T::value) value() 97 | { 98 | return T::value; 99 | } 100 | 101 | template class Function> 102 | struct defer 103 | { 104 | template 105 | struct apply 106 | { 107 | template::value> 108 | struct result 109 | { 110 | using type = Instance; 111 | }; 112 | 113 | template 114 | struct result 115 | { 116 | using type = type_t; 117 | }; 118 | 119 | using type = type_t>>; 120 | }; 121 | }; 122 | 123 | struct and_ 124 | { 125 | template 126 | struct apply : assert< 127 | is_integral, 128 | is_integral 129 | > 130 | { 131 | using type = bool_; 132 | }; 133 | }; 134 | 135 | template 136 | using and_t = apply_t; 137 | 138 | struct or_ 139 | { 140 | template 141 | struct apply : assert< 142 | is_integral, 143 | is_integral 144 | > 145 | { 146 | using type = bool_; 147 | }; 148 | }; 149 | 150 | template 151 | using or_t = apply_t; 152 | 153 | struct add_ 154 | { 155 | template 156 | struct apply : assert< 157 | is_integral, 158 | is_integral 159 | > 160 | { 161 | using type = std::integral_constant; 162 | }; 163 | }; 164 | 165 | struct div_ 166 | { 167 | template 168 | struct apply : assert< 169 | is_integral, 170 | is_integral 171 | > 172 | { 173 | using type = std::integral_constant; 174 | }; 175 | }; 176 | 177 | template 178 | using add_t = apply_t; 179 | 180 | template 181 | using div_t = apply_t; 182 | 183 | struct greater 184 | { 185 | template 186 | struct apply : assert< 187 | is_integral, 188 | is_integral 189 | > 190 | { 191 | using type = bool_<(Lhs::value > Rhs::value)>; 192 | }; 193 | }; 194 | struct greater_or_equal 195 | { 196 | template 197 | struct apply : assert< 198 | is_integral, 199 | is_integral 200 | > 201 | { 202 | using type = bool_<(Lhs::value >= Rhs::value)>; 203 | }; 204 | }; 205 | struct less 206 | { 207 | template 208 | struct apply : assert< 209 | is_integral, 210 | is_integral 211 | > 212 | { 213 | using type = bool_<(Lhs::value < Rhs::value)>; 214 | }; 215 | }; 216 | struct less_or_equal 217 | { 218 | template 219 | struct apply : assert< 220 | is_integral, 221 | is_integral 222 | > 223 | { 224 | using type = bool_<(Lhs::value <= Rhs::value)>; 225 | }; 226 | }; 227 | 228 | template 229 | struct list 230 | { 231 | static constexpr std::size_t size = sizeof...(Ts); 232 | }; 233 | 234 | template 235 | constexpr std::size_t list::size; 236 | 237 | template 238 | struct list_size; 239 | 240 | template class Sequence, typename... Ts> 241 | struct list_size> : public size_t 242 | {}; 243 | 244 | template 245 | using string = list...>; 246 | 247 | 248 | template 249 | struct functor 250 | { 251 | static_assert(sizeof(Seq) != sizeof(Seq), "Type is not a sequence"); 252 | }; 253 | 254 | template class Seq, typename... Ts> 255 | struct functor> 256 | { 257 | template 258 | struct apply 259 | { 260 | using type = Seq; 261 | }; 262 | 263 | template class Seq2, typename... Us> 264 | struct apply> 265 | { 266 | using type = Seq; 267 | }; 268 | }; 269 | 270 | template 271 | using apply_functor = apply_t, Ts...>; 272 | 273 | template 274 | using functor_t = apply_functor; 275 | 276 | template 277 | struct cat; 278 | 279 | template class Seq, 280 | typename... Lhs, typename... Rhs> 281 | struct cat, Seq> 282 | { 283 | using type = Seq; 284 | }; 285 | 286 | template 287 | using cat_t = type_t>; 288 | 289 | template 290 | using index_t = std::integral_constant; 291 | 292 | template 293 | using integer_sequence = list...>; 294 | 295 | template 296 | using index_sequence = list...>; 297 | 298 | namespace detail 299 | { 300 | template 301 | struct split; 302 | 303 | template class Seq, std::size_t Index, 304 | typename... Left, typename Head, typename... Tail> 305 | struct split, Index, Seq> 306 | { 307 | using next = split, Index - 1, Seq>; 308 | 309 | using before = typename next::before; 310 | using left = typename next::left; 311 | using head = typename next::head; 312 | using right = typename next::right; 313 | using after = typename next::after; 314 | }; 315 | 316 | template class Seq, 317 | typename... Left, typename Head, typename... Tail> 318 | struct split, 0, Seq> 319 | { 320 | using before = Seq; 321 | using left = Seq; 322 | using head = Head; 323 | using right = Seq; 324 | using after = Seq; 325 | }; 326 | 327 | template class Seq, 328 | typename Head> 329 | struct split, 0, Seq<>> 330 | { 331 | using before = Seq<>; 332 | using left = Seq; 333 | using head = Head; 334 | using right = Seq; 335 | using after = Seq<>; 336 | }; 337 | } 338 | 339 | template 340 | using pack_split = detail::split, Index, list>; 341 | template 342 | using pack_split_left_t = typename pack_split::left; 343 | template 344 | using pack_get_t = typename pack_split::head; 345 | template 346 | using pack_split_right_t = typename pack_split::right; 347 | template 348 | using pack_split_before_t = typename pack_split::before; 349 | template 350 | using pack_split_after_t = typename pack_split::after; 351 | template 352 | using pack_head_t = pack_get_t<0, Ts...>; 353 | template 354 | using pack_tail_t = pack_split_after_t<0, Ts...>; 355 | 356 | template 357 | struct split; 358 | template class Seq, typename... Ts> 359 | struct split> 360 | { 361 | using splitter = detail::split, Index, Seq>; 362 | 363 | using before = typename splitter::before; 364 | using left = typename splitter::left; 365 | using head = typename splitter::head; 366 | using right = typename splitter::right; 367 | using after = typename splitter::after; 368 | }; 369 | template 370 | using split_left_t = typename split::left; 371 | template 372 | using get_t = typename split::head; 373 | template 374 | using split_right_t = typename split::right; 375 | template 376 | using split_before_t = typename split::before; 377 | template 378 | using split_after_t = typename split::after; 379 | template 380 | using head_t = get_t<0, Seq>; 381 | template 382 | using tail_t = split_after_t<0, Seq>; 383 | 384 | 385 | template 386 | using pack_prepend_t = list; 387 | template 388 | using pack_append_t = list; 389 | template 390 | using pack_insert_t = cat_t, T>, pack_split_right_t>; 391 | template 392 | using pack_remove_t = cat_t, pack_split_after_t>; 393 | 394 | template 395 | struct prepend; 396 | template class Seq, typename... Ts> 397 | struct prepend> 398 | { 399 | using type = Seq; 400 | }; 401 | template 402 | struct append; 403 | template class Seq, typename... Ts> 404 | struct append> 405 | { 406 | using type = Seq; 407 | }; 408 | 409 | template 410 | using prepend_t = type_t>; 411 | template 412 | using append_t = type_t>; 413 | template 414 | using insert_t = cat_t, T>, split_right_t>; 415 | template 416 | using remove_t = cat_t, split_after_t>; 417 | 418 | namespace detail 419 | { 420 | template 421 | struct merge; 422 | 423 | template class Sequence, typename... Ts, typename LhsHead, typename... LhsTail, typename RhsHead, typename... RhsTail, typename Compare> 424 | struct merge, Sequence, Sequence, Compare> 425 | { 426 | using next_result = typename std::conditional< 427 | apply_t::value, 428 | Sequence, 429 | Sequence 430 | >::type; 431 | using next_lhs = typename std::conditional< 432 | apply_t::value, 433 | Sequence, 434 | Sequence 435 | >::type; 436 | using next_rhs = typename std::conditional< 437 | apply_t::value, 438 | Sequence, 439 | Sequence 440 | >::type; 441 | 442 | using type = type_t< 443 | merge< 444 | next_result, 445 | next_lhs, 446 | next_rhs, 447 | Compare 448 | > 449 | >; 450 | }; 451 | 452 | template class Sequence, typename... Ts, typename LhsHead, typename... LhsTail, typename Compare> 453 | struct merge, Sequence, Sequence<>, Compare> 454 | { 455 | using type = Sequence; 456 | }; 457 | 458 | template class Sequence, typename... Ts, typename RhsHead, typename... RhsTail, typename Compare> 459 | struct merge, Sequence<>, Sequence, Compare> 460 | { 461 | using type = Sequence; 462 | }; 463 | 464 | template class Sequence, typename... Ts, typename Compare> 465 | struct merge, Sequence<>, Sequence<>, Compare> 466 | { 467 | using type = Sequence; 468 | }; 469 | } 470 | 471 | template 472 | using merge = detail::merge, Lhs, Rhs, Compare>; 473 | 474 | template 475 | using merge_t = type_t>; 476 | 477 | namespace detail 478 | { 479 | namespace mergesort 480 | { 481 | template 482 | struct mergesort 483 | { 484 | using left = split_left_t< div_t, int32_t<2>>::value, List>; 485 | using right = split_after_t, int32_t<2>>::value, List>; 486 | 487 | using left_sorted = type_t>; 488 | using right_sorted = type_t>; 489 | 490 | using type = merge_t; 491 | }; 492 | 493 | template class Sequence, typename Compare> 494 | struct mergesort, Compare> 495 | { 496 | using type = Sequence<>; 497 | }; 498 | 499 | template class Sequence, typename T, typename Compare> 500 | struct mergesort, Compare> 501 | { 502 | using type = Sequence; 503 | }; 504 | 505 | template class Sequence, typename T, typename U, typename Compare> 506 | struct mergesort, Compare> 507 | { 508 | template::value> 509 | struct apply 510 | { 511 | using type = Sequence; 512 | }; 513 | 514 | template 515 | struct apply 516 | { 517 | using type = Sequence; 518 | }; 519 | 520 | using type = type_t>; 521 | }; 522 | } 523 | } 524 | 525 | template 526 | using sort = detail::mergesort::mergesort; 527 | 528 | template 529 | using sort_t = type_t>; 530 | 531 | template 532 | struct pair 533 | { 534 | using key = Key; 535 | using value = Value; 536 | }; 537 | 538 | template 539 | using key_t = typename Pair::key; 540 | template 541 | using value_t = typename Pair::value; 542 | 543 | template 544 | struct inherit : Ts... {}; 545 | 546 | template 547 | struct inherit> : Ts... {}; 548 | 549 | namespace detail 550 | { 551 | template 552 | struct aggregate; 553 | 554 | template class Seq, typename T, typename... Ts> 555 | struct aggregate> : public 556 | aggregate> 557 | { 558 | aggregate() = delete; 559 | aggregate(const aggregate&) = delete; 560 | aggregate(aggregate&&) = delete; 561 | aggregate& operator=(const aggregate&) = delete; 562 | aggregate& operator=(aggregate&&) = delete; 563 | 564 | T member; 565 | }; 566 | 567 | template class Seq> 568 | struct aggregate> 569 | { 570 | aggregate() = delete; 571 | aggregate(const aggregate&) = delete; 572 | aggregate(aggregate&&) = delete; 573 | aggregate& operator=(const aggregate&) = delete; 574 | aggregate& operator=(aggregate&&) = delete; 575 | }; 576 | } 577 | 578 | template 579 | using aggregate = ::ctti::meta::detail::aggregate<::ctti::meta::list>; 580 | 581 | template 582 | struct map; 583 | 584 | template 585 | struct map...> 586 | { 587 | using keys = list; 588 | using values = list; 589 | using pairs = list...>; 590 | 591 | struct key_not_found {}; 592 | 593 | template 594 | using at_key = type_t*)nullptr))>; 595 | private: 596 | template 597 | static identity lookup(pair*); 598 | 599 | template 600 | static identity lookup(...); 601 | }; 602 | 603 | template 604 | using keys_t = typename Map::keys; 605 | template 606 | using values_t = typename Map::values; 607 | template 608 | using pairs_t = typename Map::pairs; 609 | template 610 | using at_key = typename Map::template at_key; 611 | 612 | template 613 | struct pack_fmap 614 | { 615 | using type = list...>; 616 | }; 617 | 618 | template 619 | struct fmap; 620 | 621 | template class Seq, typename... Ts> 622 | struct fmap> 623 | { 624 | using type = Seq...>; 625 | }; 626 | 627 | namespace detail 628 | { 629 | template 630 | struct filter; 631 | 632 | template class Seq, typename... Filtered, typename Head, typename... Tail> 634 | struct filter, Seq> 635 | { 636 | template>()> 637 | struct next 638 | { 639 | using type = Seq; 640 | }; 641 | 642 | template 643 | struct next<_Head, false> 644 | { 645 | using type = Seq; 646 | }; 647 | 648 | using type = type_t>, Seq>>; 649 | }; 650 | 651 | template class Seq, typename... Filtered> 653 | struct filter, Seq<>> 654 | { 655 | using type = Seq; 656 | }; 657 | } 658 | 659 | template 660 | struct foldl; 661 | 662 | template class Seq, typename Head, typename... Tail> 664 | struct foldl> 665 | { 666 | using type = type_t< 667 | foldl, 669 | Seq 670 | > 671 | >; 672 | }; 673 | 674 | template class Seq> 676 | struct foldl> 677 | { 678 | using type = Seed; 679 | }; 680 | 681 | template 682 | struct foldr; 683 | 684 | template class Seq, typename Head, typename... Tail> 686 | struct foldr> 687 | { 688 | using type = apply_t< 689 | Function, Head, 690 | type_t>> 691 | >; 692 | }; 693 | 694 | template class Seq> 696 | struct foldr> 697 | { 698 | using type = Seed; 699 | }; 700 | 701 | template 702 | using pack_fmap_t = type_t>; 703 | template 704 | using fmap_t = type_t>; 705 | 706 | template 707 | using pack_foldl = foldl>; 708 | template 709 | using pack_foldl_t = type_t>; 710 | template 711 | using foldl_t = type_t>; 712 | 713 | template 714 | using pack_foldr = foldr>; 715 | template 716 | using pack_foldr_t = type_t>; 717 | template 718 | using foldr_t = type_t>; 719 | 720 | template 721 | using filter = detail::filter, Seq>; 722 | template 723 | using filter_t = type_t>; 724 | template 725 | using pack_filter = detail::filter, list>; 726 | template 727 | using pack_filter_t = type_t>; 728 | 729 | template 730 | using any_of = foldl; 731 | template 732 | using any_of_t = foldl_t; 733 | template 734 | using pack_any_of = pack_foldl; 735 | template 736 | using pack_any_of_t = pack_foldl_t; 737 | 738 | template 739 | using any_of = foldl; 740 | template 741 | using any_of_t = foldl_t; 742 | template 743 | using pack_any_of = pack_foldl; 744 | template 745 | using pack_any_of_t = pack_foldl_t; 746 | 747 | template 748 | using join = foldl, apply_functor>, apply_functor, Seqs...>>; 749 | template 750 | using join_t = type_t>; 751 | 752 | namespace detail 753 | { 754 | template class Seq, std::size_t N> 755 | struct make_index_sequence 756 | { 757 | static constexpr std::size_t n = (N % 2) ? ((N - 1) / 2) : (N / 2); 758 | static constexpr std::size_t m = N - n; 759 | 760 | struct adder 761 | { 762 | template 763 | struct apply 764 | { 765 | using type = apply_t, T>; 766 | }; 767 | }; 768 | 769 | using type = cat_t< 770 | type_t>, 771 | fmap_t>> 772 | >; 773 | }; 774 | 775 | template class Seq> 776 | struct make_index_sequence 777 | { 778 | using type = Seq>; 779 | }; 780 | 781 | template class Seq> 782 | struct make_index_sequence 783 | { 784 | using type = Seq<>; 785 | }; 786 | } 787 | 788 | template class Seq = list> 789 | using make_index_sequence = type_t>; 790 | template 791 | using make_index_sequence_for = make_index_sequence; 792 | template 793 | struct to_index_sequence; 794 | template class Seq, typename... Ts> 795 | struct to_index_sequence> 796 | { 797 | using type = make_index_sequence; 798 | }; 799 | template 800 | using to_index_sequence_t = type_t>; 801 | 802 | template 803 | using make_index_sequence_from_sequence = ctti::meta::functor_t, ctti::meta::to_index_sequence_t>; 804 | 805 | namespace detail 806 | { 807 | template 808 | void foreach(ctti::meta::list, ctti::meta::index_sequence, Function function) 809 | { 810 | (void)function; 811 | [](...){}(std::array{{(function(ctti::meta::identity(), ctti::meta::size_t()), 0)..., 0}}); 812 | } 813 | } 814 | 815 | template 816 | void foreach(Function function) 817 | { 818 | ctti::meta::detail::foreach(ctti::meta::apply_functor, Sequence>(), ctti::meta::make_index_sequence_from_sequence(), function); 819 | } 820 | } 821 | 822 | } 823 | 824 | #endif // CTTI_UTILITY_META_H 825 | -------------------------------------------------------------------------------- /include/ctti/detail/name_filters.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_DETAIL_NAMEFILTERS_HPP 2 | #define CTTI_DETAIL_NAMEFILTERS_HPP 3 | 4 | #include "cstring.hpp" 5 | 6 | namespace ctti 7 | { 8 | 9 | namespace detail 10 | { 11 | 12 | constexpr ctti::detail::cstring filter_prefix(const ctti::detail::cstring& str, const ctti::detail::cstring& prefix) 13 | { 14 | return str.size() >= prefix.size() ? (str(0, prefix.size()) == prefix ? str(prefix.size(), str.size()) : str) : str; 15 | } 16 | 17 | constexpr ctti::detail::cstring leftpad(const ctti::detail::cstring& str) 18 | { 19 | return (str.size() > 0 && str[0] == ' ') ? leftpad(str(1, str.size())) : str; 20 | } 21 | 22 | constexpr ctti::detail::cstring filter_class(const ctti::detail::cstring& type_name) 23 | { 24 | return leftpad(filter_prefix(leftpad(type_name), "class")); 25 | } 26 | 27 | constexpr ctti::detail::cstring filter_struct(const ctti::detail::cstring& type_name) 28 | { 29 | return leftpad(filter_prefix(leftpad(type_name), "struct")); 30 | } 31 | 32 | constexpr ctti::detail::cstring filter_typename_prefix(const ctti::detail::cstring& type_name) 33 | { 34 | return filter_struct(filter_class(type_name)); 35 | } 36 | 37 | namespace 38 | { 39 | 40 | constexpr const char* find_ith_impl(const ctti::detail::cstring& name, const ctti::detail::cstring& substring, const char* res, std::size_t i, bool infinite = false) 41 | { 42 | return (name.length() >= substring.length()) ? 43 | ((name(0, substring.length()) == substring) ? 44 | ((i == 0) ? 45 | name.begin() 46 | : 47 | find_ith_impl(name(substring.length(), name.length()), substring, name.begin(), i - 1, infinite)) 48 | : 49 | find_ith_impl(name(1, name.length()), substring, res, i, infinite)) 50 | : 51 | (!infinite) ? name.end() : res; 52 | } 53 | 54 | } 55 | 56 | constexpr const char* find_ith(const ctti::detail::cstring& name, const ctti::detail::cstring& substring, std::size_t i) 57 | { 58 | return find_ith_impl(name, substring, name.end(), i); 59 | } 60 | 61 | constexpr const char* find_last(const ctti::detail::cstring& name, const ctti::detail::cstring& substring) 62 | { 63 | return find_ith_impl(name, substring, name.end(), -1, true); 64 | } 65 | 66 | constexpr const char* find(const ctti::detail::cstring& name, const ctti::detail::cstring& substring) 67 | { 68 | return find_ith(name, substring, 0); 69 | } 70 | 71 | 72 | 73 | } 74 | 75 | } 76 | 77 | #endif // CTTI_DETAIL_NAMEFILTERS_HPP 78 | -------------------------------------------------------------------------------- /include/ctti/detail/preprocessor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_DETAIL_PREPROCESSOR_HPP 2 | #define CTTI_DETAIL_PREPROCESSOR_HPP 3 | 4 | #define CTTI_PP_STR_IMPL(x) #x 5 | #define CTTI_PP_STR(x) CTTI_PP_STR_IMPL(x) 6 | 7 | #endif // CTTI_DETAIL_PREPROCESSOR_HPP 8 | -------------------------------------------------------------------------------- /include/ctti/detail/pretty_function.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by manu343726 on 4/08/15. 3 | // 4 | 5 | #ifndef CTTI_PRETTY_FUNCTION_HPP 6 | #define CTTI_PRETTY_FUNCTION_HPP 7 | 8 | #include "cstring.hpp" 9 | 10 | #if defined(__clang__) 11 | #define CTTI_PRETTY_FUNCTION __PRETTY_FUNCTION__ 12 | #elif defined(__GNUC__) && !defined(__clang__) 13 | #define CTTI_PRETTY_FUNCTION __PRETTY_FUNCTION__ 14 | #elif defined(_MSC_VER) 15 | #define CTTI_PRETTY_FUNCTION __FUNCSIG__ 16 | #else 17 | #error "No support for this compiler." 18 | #endif 19 | 20 | namespace ctti 21 | { 22 | 23 | namespace pretty_function 24 | { 25 | 26 | template 27 | constexpr ctti::detail::cstring type() 28 | { 29 | return {CTTI_PRETTY_FUNCTION}; 30 | } 31 | 32 | template 33 | constexpr ctti::detail::cstring value() 34 | { 35 | return {CTTI_PRETTY_FUNCTION}; 36 | } 37 | 38 | } 39 | 40 | } 41 | 42 | #if defined(__clang__) 43 | #define CTTI_TYPE_PRETTY_FUNCTION_PREFIX "ctti::detail::cstring ctti::pretty_function::type() [T = " 44 | #define CTTI_TYPE_PRETTY_FUNCTION_SUFFIX "]" 45 | #elif defined(__GNUC__) && !defined(__clang__) 46 | #define CTTI_TYPE_PRETTY_FUNCTION_PREFIX "constexpr ctti::detail::cstring ctti::pretty_function::type() [with T = " 47 | #define CTTI_TYPE_PRETTY_FUNCTION_SUFFIX "]" 48 | #elif defined(_MSC_VER) 49 | #define CTTI_TYPE_PRETTY_FUNCTION_PREFIX "struct ctti::detail::cstring __cdecl ctti::pretty_function::type<" 50 | #define CTTI_TYPE_PRETTY_FUNCTION_SUFFIX ">(void)" 51 | #else 52 | #error "No support for this compiler." 53 | #endif 54 | 55 | #define CTTI_TYPE_PRETTY_FUNCTION_LEFT (sizeof(CTTI_TYPE_PRETTY_FUNCTION_PREFIX) - 1) 56 | #define CTTI_TYPE_PRETTY_FUNCTION_RIGHT (sizeof(CTTI_TYPE_PRETTY_FUNCTION_SUFFIX) - 1) 57 | 58 | #if defined(__clang__) 59 | #define CTTI_VALUE_PRETTY_FUNCTION_PREFIX "ctti::detail::cstring ctti::pretty_function::value() [T = " 60 | #define CTTI_VALUE_PRETTY_FUNCTION_SEPARATOR "; Value = " 61 | #define CTTI_VALUE_PRETTY_FUNCTION_SUFFIX "]" 62 | #elif defined(__GNUC__) && !defined(__clang__) 63 | #define CTTI_VALUE_PRETTY_FUNCTION_PREFIX "constexpr ctti::detail::cstring ctti::pretty_function::value() [with T = " 64 | #define CTTI_VALUE_PRETTY_FUNCTION_SEPARATOR "; T Value = " 65 | #define CTTI_VALUE_PRETTY_FUNCTION_SUFFIX "]" 66 | #elif defined(_MSC_VER) 67 | #define CTTI_VALUE_PRETTY_FUNCTION_PREFIX "struct ctti::detail::cstring __cdecl ctti::pretty_function::value<" 68 | #define CTTI_VALUE_PRETTY_FUNCTION_SEPARATOR "; T Value = " 69 | #define CTTI_VALUE_PRETTY_FUNCTION_SUFFIX ">(void)" 70 | #else 71 | #error "No support for this compiler." 72 | #endif 73 | 74 | #define CTTI_VALUE_PRETTY_FUNCTION_LEFT (sizeof(CTTI_VALUE_PRETTY_FUNCTION_PREFIX) - 1) 75 | #define CTTI_VALUE_PRETTY_FUNCTION_SEPARATION (sizeof(CTTI_VALUE_PRETTY_FUNCTION_SEPARATOR) - 1) 76 | #define CTTI_VALUE_PRETTY_FUNCTION_RIGHT (sizeof(CTTI_VALUE_PRETTY_FUNCTION_SUFFIX) - 1) 77 | 78 | #endif //CTTI_PRETTY_FUNCTION_HPP 79 | -------------------------------------------------------------------------------- /include/ctti/detailed_nameof.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_DETAILED_NAMEOF_HPP 2 | #define CTTI_DETAILED_NAMEOF_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ctti 9 | { 10 | 11 | 12 | template 13 | constexpr name_t detailed_nameof() 14 | { 15 | return {ctti::nameof()}; 16 | } 17 | 18 | template 19 | constexpr name_t detailed_nameof() 20 | { 21 | return {ctti::nameof()}; 22 | } 23 | 24 | #ifdef CTTI_HAS_VARIABLE_TEMPLATES 25 | template 26 | constexpr ctti::name_t detailed_nameof_v = ctti::detailed_nameof(); 27 | 28 | // CONSIDER USING detailed_nameof_v INSTEAD 29 | template 30 | constexpr ctti::name_t detailed_nameof_value_v = ctti::detailed_nameof(); 31 | #endif // CTTI_HAS_VARIABLE_TEMPLATES 32 | 33 | } 34 | 35 | #endif // CTTI_DETAILED_NAMEOF_HPP 36 | -------------------------------------------------------------------------------- /include/ctti/hash_literal.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_HASH_LITERAL_HPP 2 | #define CTTI_HASH_LITERAL_HPP 3 | 4 | #include 5 | 6 | #ifdef CTI_HASH_LITERAL_NAMESPACE 7 | namespace CTTI_HASH_LITERAL_NAMESPACE 8 | { 9 | #endif // CTTI_HASH_LITERAL_NAMESPACE 10 | 11 | constexpr std::uint64_t operator"" _sh(const char* str, std::size_t length) 12 | { 13 | return ctti::detail::cstring{str, length}.hash(); 14 | } 15 | 16 | #ifdef CTTI_HASH_LITERAL_NAMESPACE 17 | } 18 | #endif // CTTI_HASH_LITERAL_NAMESPACE 19 | 20 | #endif // CTTI_HASH_LITERAL_HPP 21 | -------------------------------------------------------------------------------- /include/ctti/map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_MAP_HPP 2 | #define CTTI_MAP_HPP 3 | 4 | #include 5 | 6 | namespace ctti 7 | { 8 | 9 | struct default_symbol_mapping_function 10 | { 11 | constexpr default_symbol_mapping_function() = default; 12 | 13 | template 14 | void operator()(const Source& source, SourceSymbol, Sink& sink, SinkSymbol) const 15 | { 16 | ctti::set_member_value(sink, ctti::get_member_value(source)); 17 | } 18 | }; 19 | 20 | template 21 | void map(const Source& source, Sink& sink, const Function& function) 22 | { 23 | function(source, SourceSymbol(), sink, SinkSymbol()); 24 | } 25 | 26 | template 27 | void map(const Source& source, Sink& sink) 28 | { 29 | ctti::map(source, sink, ctti::default_symbol_mapping_function()); 30 | } 31 | 32 | template 33 | struct symbol_mapping 34 | { 35 | constexpr symbol_mapping(Function function) : 36 | function{function} 37 | {} 38 | 39 | Function function; 40 | 41 | template 42 | auto operator()(const Source& source, SourceSymbol, Sink& sink, SinkSymbol) const -> 43 | ctti::meta::void_t()(source, SourceSymbol(), sink, SinkSymbol()))> 44 | { 45 | function(source, SourceSymbol(), sink, SinkSymbol()); 46 | } 47 | 48 | template 49 | auto operator()(const Source& source, SourceSymbol, Sink& sink, SinkSymbol) const -> 50 | ctti::meta::void_t()(ctti::get_member_value(source), ctti::type_tag>()))> 51 | { 52 | ctti::set_member_value(sink, function( 53 | ctti::get_member_value(source), 54 | ctti::type_tag>() 55 | )); 56 | } 57 | }; 58 | 59 | template 60 | constexpr ctti::symbol_mapping> mapping(const Function& function) 61 | { 62 | return {function}; 63 | } 64 | 65 | template 66 | constexpr ctti::symbol_mapping mapping() 67 | { 68 | return {ctti::default_symbol_mapping_function()}; 69 | } 70 | 71 | template 72 | void map(const Source& source, Sink& sink, const ctti::symbol_mapping&... mapping) 73 | { 74 | [](...){}((map(source, sink, mapping), 0)...); 75 | } 76 | 77 | } 78 | 79 | #endif // CTTI_MAP_HPP 80 | -------------------------------------------------------------------------------- /include/ctti/model.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_MODEL_HPP 2 | #define CTTI_MODEL_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ctti 9 | { 10 | 11 | template 12 | struct model 13 | { 14 | using symbols = ctti::meta::list; 15 | }; 16 | 17 | template 18 | ctti::model<> ctti_model(ctti::type_tag); 19 | 20 | namespace detail 21 | { 22 | template 23 | struct get_model 24 | { 25 | using type = decltype(ctti_model(ctti::type_tag())); 26 | }; 27 | 28 | template 29 | struct get_model> 30 | { 31 | using type = typename T::ctti_model; 32 | }; 33 | } 34 | 35 | template 36 | using get_model = typename ctti::detail::get_model::type; 37 | 38 | template 39 | struct has_model : public ctti::meta::bool_< 40 | (ctti::meta::list_size>() > 0) 41 | > {}; 42 | 43 | } 44 | 45 | #endif // CTTI_MODEL_HPP 46 | -------------------------------------------------------------------------------- /include/ctti/name.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_NAME_HPP 2 | #define CTTI_NAME_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace ctti 8 | { 9 | 10 | struct name_t 11 | { 12 | constexpr name_t(const ctti::detail::cstring& full_name) : 13 | _full_name{full_name} 14 | {} 15 | 16 | constexpr ctti::detail::cstring name() const 17 | { 18 | return ctti::detail::find_last(_full_name, "::") == _full_name.end() ? 19 | _full_name : ctti::detail::cstring{ctti::detail::find_last(_full_name, "::") + 2, _full_name.end()}; 20 | } 21 | 22 | constexpr ctti::detail::cstring full_name() const 23 | { 24 | return _full_name; 25 | } 26 | 27 | constexpr ctti::detail::cstring full_homogeneous_name() const 28 | { 29 | return ctti::detail::filter_prefix(full_name(), "&"); 30 | } 31 | 32 | constexpr ctti::detail::cstring qualifier(std::size_t i) const 33 | { 34 | return (i > 0) ? get_qualifier( 35 | ctti::detail::find_ith(_full_name, "::", i - 1) + 2, 36 | ctti::detail::find_ith(_full_name, "::", i) 37 | ) : (ctti::detail::find_ith(_full_name, "::", i) != _full_name.end()) ? 38 | ctti::detail::cstring{_full_name.begin(), ctti::detail::find_ith(_full_name, "::", i)} : 39 | ctti::detail::cstring{""}; 40 | } 41 | 42 | private: 43 | ctti::detail::cstring _full_name; 44 | 45 | constexpr ctti::detail::cstring right(const ctti::detail::cstring& str) const 46 | { 47 | return {ctti::detail::min(_full_name.end(), str.begin()), _full_name.end()}; 48 | } 49 | 50 | constexpr ctti::detail::cstring left(const char* end) const 51 | { 52 | return (end < _full_name.end()) ? 53 | ctti::detail::cstring{_full_name.begin(), end} 54 | : 55 | ctti::detail::cstring{""}; 56 | } 57 | 58 | constexpr ctti::detail::cstring get_name(const ctti::detail::cstring& name) const 59 | { 60 | return (name != "") ? name : _full_name; 61 | } 62 | 63 | constexpr ctti::detail::cstring get_qualifier(const char* begin, const char* end) const 64 | { 65 | return get_qualifier_impl(begin, end); 66 | } 67 | 68 | constexpr ctti::detail::cstring get_qualifier_impl(const char* begin, const char* end) const 69 | { 70 | return (end == _full_name.end()) ? ctti::detail::cstring{""} : ctti::detail::cstring{begin, end}; 71 | } 72 | }; 73 | 74 | constexpr bool operator==(const name_t& lhs, const name_t rhs) 75 | { 76 | return lhs.full_name() == rhs.full_name(); 77 | } 78 | 79 | constexpr bool operator!=(const name_t& lhs, const name_t rhs) 80 | { 81 | return !(lhs == rhs); 82 | } 83 | 84 | } 85 | 86 | #endif // CTTI_NAME_HPP 87 | -------------------------------------------------------------------------------- /include/ctti/nameof.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_NAMEOF_HPP 2 | #define CTTI_NAMEOF_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace ctti 14 | { 15 | 16 | template 17 | constexpr ctti::detail::cstring nameof(); 18 | 19 | template 20 | constexpr ctti::detail::cstring nameof(); 21 | 22 | namespace detail 23 | { 24 | 25 | template 26 | struct TypeNameLength : 27 | std::integral_constant< 28 | std::size_t, 29 | ctti::nameof().length() 30 | > 31 | {}; 32 | 33 | template 34 | struct TypeNameLength : 35 | std::integral_constant< 36 | std::size_t, 37 | ctti::nameof().length() 38 | > 39 | {}; 40 | 41 | template 42 | struct TypeNameLength::value>::type> : 43 | std::integral_constant< 44 | std::size_t, 45 | ctti::nameof().length() 46 | > 47 | {}; 48 | 49 | } 50 | 51 | template 52 | constexpr ctti::detail::cstring nameof(); 53 | 54 | namespace detail 55 | { 56 | 57 | template 58 | struct another_level_of_indirection {}; 59 | 60 | template 61 | struct nameof_impl 62 | { 63 | static constexpr ctti::detail::cstring apply() 64 | { 65 | return ctti::detail::filter_typename_prefix(ctti::pretty_function::type().pad( 66 | CTTI_TYPE_PRETTY_FUNCTION_LEFT, 67 | CTTI_TYPE_PRETTY_FUNCTION_RIGHT 68 | )); 69 | } 70 | }; 71 | 72 | template 73 | struct nameof_impl> 74 | { 75 | static constexpr ctti::detail::cstring apply() 76 | { 77 | return T::ctti_nameof(); 78 | } 79 | }; 80 | 81 | template 82 | struct nameof_impl>, void> 83 | { 84 | static constexpr ctti::detail::cstring apply() 85 | { 86 | return ctti::pretty_function::value().pad( 87 | CTTI_VALUE_PRETTY_FUNCTION_LEFT + ctti::detail::TypeNameLength::value + CTTI_VALUE_PRETTY_FUNCTION_SEPARATION, 88 | CTTI_VALUE_PRETTY_FUNCTION_RIGHT 89 | ); 90 | } 91 | }; 92 | 93 | template 94 | struct nameof_impl, void> 95 | { 96 | static constexpr ctti::detail::cstring apply() 97 | { 98 | return ctti::nameof(); 99 | } 100 | }; 101 | 102 | } 103 | 104 | template 105 | constexpr ctti::detail::cstring ctti_nameof(ctti::type_tag) 106 | { 107 | return ctti::detail::nameof_impl::apply(); 108 | } 109 | 110 | template 111 | constexpr ctti::detail::cstring ctti_nameof(ctti::static_value) 112 | { 113 | return ctti::detail::nameof_impl>>::apply(); 114 | } 115 | 116 | template 117 | constexpr ctti::detail::cstring nameof() 118 | { 119 | using namespace ctti; 120 | return ctti_nameof(ctti::type_tag()); 121 | } 122 | 123 | template 124 | constexpr ctti::detail::cstring nameof() 125 | { 126 | using namespace ctti; 127 | return ctti_nameof(ctti::static_value()); 128 | } 129 | 130 | #ifdef CTTI_HAS_VARIABLE_TEMPLATES 131 | template 132 | constexpr ctti::detail::cstring nameof_v = ctti::nameof(); 133 | 134 | // CONSIDER USING nameof_v INSTEAD 135 | template 136 | constexpr ctti::detail::cstring nameof_value_v = ctti::nameof(); 137 | #endif // CTTI_HAS_VARIABLE_TEMPLATES 138 | 139 | } 140 | 141 | namespace std 142 | { 143 | constexpr ctti::detail::cstring ctti_nameof(ctti::type_tag) 144 | { 145 | return "std::string"; 146 | } 147 | } 148 | 149 | #endif // CTTI_NAMEOF_HPP 150 | -------------------------------------------------------------------------------- /include/ctti/serialization.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_SERIALIZATION_HPP 2 | #define CTTI_SERIALIZATION_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace ctti 13 | { 14 | 15 | namespace serialization 16 | { 17 | 18 | template 19 | void serialize(Formatter formatter, Output& output, const T& value); 20 | 21 | template 22 | void serialize(Writer writer, const T& value); 23 | 24 | template 25 | void deserialize(Reader reader, T& value); 26 | 27 | namespace detail 28 | { 29 | template(), bool EmptyModel = ctti::meta::list_size>() == 0> 30 | struct serialize 31 | { 32 | using Model = ctti::get_model; 33 | 34 | template 35 | struct loop_body 36 | { 37 | Writer* writer; 38 | const T* value; 39 | 40 | template 41 | void operator()(SymbolIdentity, Index) 42 | { 43 | using Symbol = ctti::meta::type_t; 44 | constexpr std::size_t index = Index(); 45 | 46 | writer->value(Symbol::symbol().str(), ctti::get_member_value(*value)); 47 | 48 | if(index + 1 < ctti::meta::list_size()) 49 | { 50 | writer->value_separator(); 51 | } 52 | } 53 | }; 54 | 55 | template 56 | static void apply(Writer& writer, const T& value) 57 | { 58 | loop_body loop_body{&writer, &value}; 59 | 60 | writer.begin_object(value); 61 | ctti::meta::foreach(loop_body); 62 | writer.end_object(value); 63 | } 64 | }; 65 | 66 | template 67 | struct serialize 68 | { 69 | using Model = ctti::get_model; 70 | 71 | template 72 | struct loop_body 73 | { 74 | Writer* writer; 75 | const T* value; 76 | 77 | template 78 | void operator()(SymbolIdentity, Index) 79 | { 80 | using Symbol = ctti::meta::type_t; 81 | 82 | if(Symbol::template get_member() == *value) 83 | { 84 | // Found the enumeration value with this value 85 | writer->raw_value(Symbol::symbol().str()); 86 | } 87 | } 88 | }; 89 | 90 | template 91 | static void apply(Writer& writer, const T& value) 92 | { 93 | loop_body loop_body{&writer, &value}; 94 | ctti::meta::foreach(loop_body); 95 | } 96 | }; 97 | 98 | template 99 | struct serialize 100 | { 101 | template 102 | static void apply(Writer& writer, const T& value) 103 | { 104 | writer.value(value); 105 | } 106 | }; 107 | 108 | template::value, bool HasModel = ctti::has_model::value> 109 | struct deserialize 110 | { 111 | using Model = ctti::get_model; 112 | 113 | template 114 | struct loop_body 115 | { 116 | Reader* reader; 117 | T* value; 118 | 119 | template 120 | void operator()(SymbolIdentity, Index) 121 | { 122 | using Symbol = ctti::meta::type_t; 123 | reader->value(Symbol::symbol().str(), ctti::get_member_value(*value)); 124 | } 125 | }; 126 | 127 | template 128 | static void apply(Reader& reader, T& value) 129 | { 130 | loop_body loop_body{&reader, &value}; 131 | ctti::meta::foreach(loop_body); 132 | } 133 | }; 134 | 135 | template 136 | struct deserialize 137 | { 138 | using Model = ctti::get_model; 139 | 140 | template 141 | struct loop_body 142 | { 143 | T* value; 144 | InputValue input_value; 145 | 146 | template 147 | void operator()(SymbolIdentity, Index) 148 | { 149 | using Symbol = ctti::meta::type_t; 150 | 151 | if(static_cast::type>(Symbol::template get_member()) == 152 | static_cast::type>(input_value)) 153 | { 154 | *value = Symbol::template get_member(); 155 | } 156 | } 157 | }; 158 | 159 | template 160 | struct loop_body 161 | { 162 | T* value; 163 | std::string input_value; 164 | 165 | template 166 | void operator()(SymbolIdentity, Index) 167 | { 168 | using Symbol = ctti::meta::type_t; 169 | 170 | if(Symbol::symbol().str() == input_value) 171 | { 172 | *value = Symbol::template get_member(); 173 | } 174 | } 175 | }; 176 | 177 | struct callback 178 | { 179 | template 180 | T operator()(const InputValue& input_value) 181 | { 182 | T output_value{}; 183 | ctti::meta::foreach(loop_body{&output_value, input_value}); 184 | return output_value; 185 | } 186 | }; 187 | 188 | template 189 | static void apply(Reader& reader, T& value) 190 | { 191 | reader.enum_value(value, callback()); 192 | } 193 | }; 194 | 195 | template 196 | struct deserialize 197 | { 198 | template 199 | static void apply(Reader& reader, T& value) 200 | { 201 | reader.value(value); 202 | } 203 | }; 204 | } 205 | 206 | template 207 | struct Writer 208 | { 209 | Writer(Formatter formatter, Output& output) : 210 | _formatter{formatter}, 211 | _output{&output} 212 | {} 213 | 214 | void value_separator() 215 | { 216 | _formatter.value_separator(*_output); 217 | } 218 | 219 | template 220 | void raw_value(const T& value) 221 | { 222 | _formatter.raw_value(*_output, value); 223 | } 224 | 225 | template 226 | void value(const T& value) 227 | { 228 | _formatter.value(*_output, value); 229 | } 230 | 231 | template 232 | void value(const std::string& name, const T& value) 233 | { 234 | _formatter.value(*_output, name, value); 235 | } 236 | 237 | template 238 | void begin_object(const T& object) 239 | { 240 | _formatter.begin_object(*_output, object); 241 | } 242 | 243 | template 244 | void end_object(const T& object) 245 | { 246 | _formatter.end_object(*_output, object); 247 | } 248 | 249 | private: 250 | Formatter _formatter; 251 | Output* _output; 252 | }; 253 | 254 | template 255 | Writer make_writer(Formatter formatter, Output& output) 256 | { 257 | return {formatter, output}; 258 | } 259 | 260 | struct ostream_otuput 261 | { 262 | ostream_otuput(std::ostream& os) : 263 | os(&os) 264 | {} 265 | 266 | template 267 | void write(const T& value) 268 | { 269 | (*os) << value; 270 | } 271 | 272 | private: 273 | std::ostream* os; 274 | }; 275 | 276 | struct json_formatter 277 | { 278 | template 279 | void raw_value(Output& output, const T& value) 280 | { 281 | output.write(value); 282 | } 283 | 284 | template 285 | void value_separator(Output& out) 286 | { 287 | out.write(", "); 288 | } 289 | 290 | template 291 | void begin_object(Output& out, const T&) 292 | { 293 | out.write("{"); 294 | } 295 | 296 | template 297 | void end_object(Output& out, const T&) 298 | { 299 | out.write("}"); 300 | } 301 | 302 | template 303 | void value(Output& out, const std::string& name, const T& value) 304 | { 305 | out.write("\""); out.write(name); out.write("\": "); this->value(out, value); 306 | } 307 | 308 | template 309 | void value(Output& out, const T& value) 310 | { 311 | write_value(out, value, ctti::meta::bool_>() == 0>()); 312 | } 313 | 314 | template 315 | void value(Output& out, const std::string& value) 316 | { 317 | out.write("\""); out.write(value); out.write("\""); 318 | } 319 | 320 | template 321 | void value(Output& out, const std::vector& vector) 322 | { 323 | out.write("["); 324 | 325 | for(std::size_t i = 0; i < vector.size(); ++i) 326 | { 327 | ctti::serialization::serialize(*this, out, vector[i]); 328 | 329 | if(i + 1 < vector.size()) 330 | { 331 | out.write(", "); 332 | } 333 | } 334 | 335 | out.write("]"); 336 | } 337 | 338 | template 339 | void value(Output& out, const std::array& array) 340 | { 341 | out.write("["); 342 | 343 | for(std::size_t i = 0; i < array.size(); ++i) 344 | { 345 | ctti::serialization::serialize(*this, out, array[i]); 346 | 347 | if(i + 1 < array.size()) 348 | { 349 | out.write(", "); 350 | } 351 | } 352 | 353 | out.write("]"); 354 | } 355 | 356 | template 357 | void value(Output& out, const std::unordered_map& map) 358 | { 359 | out.write("["); 360 | std::size_t i = 0; 361 | 362 | for(const auto& keyValue : map) 363 | { 364 | out.write("{"); 365 | ctti::serialization::serialize(*this, out, keyValue.first); 366 | out.write(": "); 367 | ctti::serialization::serialize(*this, out, keyValue.second); 368 | out.write("}"); 369 | 370 | if(i + 1 < map.size()) 371 | { 372 | out.write(", "); 373 | } 374 | 375 | ++i; 376 | } 377 | 378 | out.write("]"); 379 | } 380 | 381 | template 382 | void value(Output& out, const std::tuple& tuple) 383 | { 384 | out.write("("); 385 | ctti::meta::foreach>(tuple_loop_body_t{&tuple, this, &out}); 386 | out.write(")"); 387 | } 388 | 389 | private: 390 | template 391 | struct tuple_loop_body_t 392 | { 393 | const std::tuple* tuple; 394 | json_formatter* self; 395 | Output* out; 396 | 397 | template 398 | void operator()(ctti::meta::identity, ctti::meta::size_t) const 399 | { 400 | ctti::serialization::serialize(*self, *out, std::get(*tuple)); 401 | 402 | if(Index + 1 < sizeof...(Ts)) 403 | { 404 | out->write(", "); 405 | } 406 | } 407 | }; 408 | 409 | template 410 | void write_value(Output& out, const T& value, ctti::meta::true_) 411 | { 412 | out.write(value); 413 | } 414 | 415 | template 416 | void write_value(Output& out, const T& value, ctti::meta::false_) 417 | { 418 | ctti::serialization::serialize(*this, out, value); 419 | } 420 | }; 421 | 422 | struct json_writer 423 | { 424 | json_writer(nlohmann::json& current_object) : 425 | _current_object{¤t_object} 426 | {} 427 | 428 | template 429 | ctti::meta::enable_if_t::value> value(const std::string& name, const T& value) 430 | { 431 | ctti::serialization::serialize(json_writer((*_current_object)[name]), value); 432 | } 433 | 434 | template 435 | ctti::meta::enable_if_t::value> value(const std::string& name, const T& value) 436 | { 437 | (*_current_object)[name] = nlohmann::json(value); 438 | } 439 | 440 | template 441 | void raw_value(const T& value) 442 | { 443 | *_current_object = nlohmann::json(value); 444 | } 445 | 446 | template 447 | ctti::meta::enable_if_t::value> value(const T& value) 448 | { 449 | ctti::serialization::serialize(json_writer(*_current_object), value); 450 | } 451 | 452 | template 453 | ctti::meta::enable_if_t::value> value(const T& value) 454 | { 455 | raw_value(value); 456 | } 457 | 458 | template 459 | void begin_object(const T&) 460 | { 461 | } 462 | 463 | template 464 | void end_object(const T&) 465 | { 466 | } 467 | 468 | void value_separator() {} 469 | 470 | private: 471 | nlohmann::json* _current_object; 472 | }; 473 | 474 | struct json_reader 475 | { 476 | json_reader(const nlohmann::json& json) : 477 | _current_object{&json} 478 | {} 479 | 480 | template 481 | ctti::meta::enable_if_t::value> value(T& value) 482 | { 483 | ctti::serialization::deserialize(json_reader(*_current_object), value); 484 | } 485 | 486 | template 487 | ctti::meta::enable_if_t::value> value(T& value) 488 | { 489 | value = _current_object->get(); 490 | } 491 | 492 | template 493 | void enum_value(T& value, Function callback) 494 | { 495 | if(_current_object->is_number()) 496 | { 497 | value = callback(_current_object->get::type>()); 498 | } 499 | else if(_current_object->is_string()) 500 | { 501 | value = callback(_current_object->get()); 502 | } 503 | } 504 | 505 | template 506 | ctti::meta::enable_if_t::value> value(const std::string& name, T& value) 507 | { 508 | ctti::serialization::deserialize(json_reader((*_current_object)[name]), value); 509 | } 510 | 511 | template 512 | ctti::meta::enable_if_t::value> value(const std::string& name, T& value) 513 | { 514 | auto subobject = (*_current_object)[name]; 515 | value = subobject.get(); 516 | } 517 | 518 | template 519 | void value(const std::string& name, std::unordered_map& map) 520 | { 521 | value((*_current_object)[name], map); 522 | } 523 | 524 | template 525 | void value(std::unordered_map& map) 526 | { 527 | value(*_current_object, map); 528 | } 529 | 530 | private: 531 | const nlohmann::json* _current_object; 532 | 533 | template 534 | void value(const nlohmann::json& json, std::unordered_map& map) 535 | { 536 | assert(json.is_array()); 537 | 538 | for(const auto& key_value_object : json) 539 | { 540 | // maps are serialized as key, value arrays, where key value pairs are arrays too 541 | assert(key_value_object.is_array()); 542 | assert(key_value_object.size() == 2); 543 | 544 | const auto& key = key_value_object[0]; 545 | const auto& value = key_value_object[1]; 546 | 547 | Key deserialized_key; 548 | Value deserialized_value; 549 | ctti::serialization::deserialize(json_reader(key), deserialized_key); 550 | ctti::serialization::deserialize(json_reader(value), deserialized_value); 551 | 552 | map[std::move(deserialized_key)] = std::move(deserialized_value); 553 | } 554 | } 555 | }; 556 | 557 | struct enum_from_string_reader 558 | { 559 | enum_from_string_reader(const std::string& input) : 560 | _input{input} 561 | {} 562 | 563 | template 564 | void enum_value(T& value, Callback callback) 565 | { 566 | value = callback(_input); 567 | } 568 | 569 | private: 570 | std::string _input; 571 | }; 572 | 573 | struct enum_to_string_writer 574 | { 575 | enum_to_string_writer(std::string& output) : 576 | _output{&output} 577 | {} 578 | 579 | void raw_value(const std::string& enum_value) 580 | { 581 | *_output = enum_value; 582 | } 583 | 584 | private: 585 | std::string* _output; 586 | }; 587 | 588 | template 589 | ctti::meta::enable_if_t::value && std::is_enum::value, std::string> enum_to_string(const Enum value) 590 | { 591 | std::string output; 592 | ctti::serialization::serialize(ctti::serialization::enum_to_string_writer(output), value); 593 | return output; 594 | } 595 | 596 | template 597 | ctti::meta::enable_if_t::value && std::is_enum::value, Enum> enum_from_string(const std::string& enum_string) 598 | { 599 | Enum enum_value{}; 600 | ctti::serialization::deserialize(ctti::serialization::enum_from_string_reader(enum_string), enum_value); 601 | return enum_value; 602 | } 603 | 604 | template 605 | void serialize(Writer writer, const T& value) 606 | { 607 | ctti::serialization::detail::serialize::apply(writer, value); 608 | } 609 | 610 | template 611 | void serialize(Formatter formatter, Output& output, const T& value) 612 | { 613 | auto writer = ctti::serialization::make_writer(formatter, output); 614 | ctti::serialization::serialize(writer, value); 615 | } 616 | 617 | template 618 | void serialize(Formatter formatter, Output output, const T& value) 619 | { 620 | auto writer = ctti::serialization::make_writer(formatter, output); 621 | ctti::serialization::serialize(writer, value); 622 | } 623 | 624 | template 625 | void deserialize(Reader reader, T& value) 626 | { 627 | ctti::serialization::detail::deserialize::apply(reader, value); 628 | } 629 | 630 | namespace detail 631 | { 632 | template>() == 0, typename = void> 633 | struct is_default_ostream_serializable : public ctti::meta::false_ {}; 634 | 635 | template 636 | struct is_default_ostream_serializable> : public ctti::meta::true_ {}; 637 | 638 | template 639 | struct is_default_ostream_serializable().ctti_ostream_print())>> : public ctti::meta::true_ {}; 640 | 641 | template 642 | struct is_default_ostream_serializable>()))>> : public ctti::meta::true_ {}; 643 | } 644 | 645 | } 646 | 647 | } 648 | 649 | template 650 | ctti::meta::enable_if_t::value, std::ostream&> operator<<(std::ostream& os, const T& value) 651 | { 652 | ctti::serialization::serialize(ctti::serialization::json_formatter(), ctti::serialization::ostream_otuput(os), value); 653 | return os; 654 | } 655 | 656 | #endif // CTTI_SERIALIZATION_HPP 657 | -------------------------------------------------------------------------------- /include/ctti/static_value.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_DETAIL_STATIC_VALUE_HPP 2 | #define CTTI_DETAIL_STATIC_VALUE_HPP 3 | 4 | namespace ctti 5 | { 6 | 7 | template 8 | struct static_value 9 | { 10 | constexpr static_value() = default; 11 | using value_type = T; 12 | static constexpr value_type value = Value; 13 | 14 | constexpr operator value_type() const 15 | { 16 | return Value; 17 | } 18 | 19 | constexpr value_type get() const 20 | { 21 | return Value; 22 | } 23 | 24 | friend constexpr bool operator==(const static_value& lhs, const value_type rhs) 25 | { 26 | return lhs.get() == rhs; 27 | } 28 | 29 | friend constexpr bool operator==(const value_type lhs, const static_value& rhs) 30 | { 31 | return rhs == lhs; 32 | } 33 | 34 | friend constexpr bool operator!=(const static_value& lhs, const value_type rhs) 35 | { 36 | return !(lhs == rhs); 37 | } 38 | 39 | friend constexpr bool operator!=(const value_type lhs, const static_value& rhs) 40 | { 41 | return !(lhs == rhs); 42 | } 43 | }; 44 | 45 | template 46 | constexpr T static_value::value; 47 | 48 | } 49 | 50 | #define CTTI_STATIC_VALUE(x) ::ctti::static_value 51 | 52 | #endif // CTTI_DETAIL_STATIC_VALUE_HPP 53 | -------------------------------------------------------------------------------- /include/ctti/symbol.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_SYMBOL_HPP 2 | #define CTTI_SYMBOL_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define CTTI_DEFINE_SYMBOL(name) \ 11 | struct name { \ 12 | constexpr name() {} \ 13 | \ 14 | static constexpr ctti::detail::cstring symbol() { \ 15 | return CTTI_PP_STR(name); \ 16 | } \ 17 | \ 18 | static constexpr std::uint64_t hash() { \ 19 | return symbol().hash(); \ 20 | } \ 21 | \ 22 | template::value, typename = void> \ 23 | struct impl \ 24 | { \ 25 | static constexpr bool is_member_of() { \ 26 | return false; \ 27 | } \ 28 | \ 29 | using member_type = std::nullptr_t; \ 30 | \ 31 | static constexpr member_type get_member() { \ 32 | return nullptr; \ 33 | } \ 34 | \ 35 | static constexpr ctti::detail::cstring member_name() { \ 36 | return CTTI_PP_STR(name); \ 37 | } \ 38 | }; \ 39 | \ 40 | template \ 41 | struct impl> { \ 42 | static constexpr bool is_member_of() { \ 43 | return true; \ 44 | } \ 45 | \ 46 | using member_type = decltype(&T::name); \ 47 | \ 48 | static constexpr member_type get_member() { \ 49 | return &T::name; \ 50 | } \ 51 | \ 52 | static constexpr ctti::detail::cstring member_name() { \ 53 | return ctti::nameof(); \ 54 | } \ 55 | }; \ 56 | \ 57 | template \ 58 | struct impl> { \ 59 | static constexpr bool is_member_of() { \ 60 | return true; \ 61 | } \ 62 | \ 63 | using member_type = decltype(T::name); \ 64 | \ 65 | static constexpr member_type get_member() { \ 66 | return T::name; \ 67 | } \ 68 | \ 69 | static constexpr ctti::detail::cstring member_name() { \ 70 | return CTTI_PP_STR(name); \ 71 | } \ 72 | }; \ 73 | \ 74 | template \ 75 | using member_type = typename impl::member_type; \ 76 | \ 77 | template \ 78 | static constexpr bool is_member_of() { \ 79 | return impl::is_member_of(); \ 80 | } \ 81 | \ 82 | template \ 83 | static constexpr member_type get_member() { \ 84 | return impl::get_member(); \ 85 | } \ 86 | \ 87 | template \ 88 | static constexpr ctti::name_t detailed_name() { \ 89 | return ctti::detailed_nameof())>(); \ 90 | } \ 91 | \ 92 | template \ 93 | static constexpr ctti::detail::cstring member_name() { \ 94 | return impl::member_name(); \ 95 | } \ 96 | \ 97 | template \ 98 | using value_type = typename ::ctti::detail::member_traits>::value_type; \ 99 | }; \ 100 | \ 101 | name ctti_symbol_from_hash(::ctti::meta::uint64_t) 102 | 103 | 104 | namespace ctti 105 | { 106 | 107 | namespace detail 108 | { 109 | 110 | template 111 | struct member_traits; 112 | 113 | template 114 | struct member_traits 115 | { 116 | using value_type = T; 117 | using pointer_type = T Class::*; 118 | 119 | template 120 | static constexpr const value_type& get(const Obj& object, pointer_type member) 121 | { 122 | return object.*member; 123 | } 124 | 125 | template 126 | static constexpr value_type& get(Obj& object, pointer_type member) 127 | { 128 | return object.*member; 129 | } 130 | 131 | template 132 | static void set(Obj& object, pointer_type member, Value&& value) 133 | { 134 | get(object, member) = std::forward(value); 135 | } 136 | }; 137 | 138 | template 139 | struct member_traits 140 | { 141 | using value_type = T; 142 | using pointer_type = T (Class::*)(Args...); 143 | 144 | template 145 | static constexpr value_type get(const Obj& object, pointer_type member, _Args&&... args) 146 | { 147 | return (object.*member)(std::forward<_Args>(args)...); 148 | } 149 | 150 | template 151 | static void set(Obj& object, pointer_type member, _Args&&... args) 152 | { 153 | get(object, member, std::forward<_Args>(args)...); 154 | } 155 | }; 156 | 157 | template 158 | struct member_traits 159 | { 160 | using pointer_type = void (Class::*)(Arg); 161 | using value_type = ctti::meta::decay_t; 162 | 163 | template 164 | static void set(Obj& object, pointer_type member, _Arg&& arg) 165 | { 166 | (object.*member)(std::forward<_Arg>(arg)); 167 | } 168 | }; 169 | 170 | template 171 | struct member_traits 172 | { 173 | using value_type = T; 174 | using pointer_type = T (Class::*)(Args...) const; 175 | 176 | template 177 | static constexpr value_type get(const Obj& object, pointer_type member, _Args&&... args) 178 | { 179 | return (object.*member)(std::forward<_Args>(args)...); 180 | } 181 | }; 182 | 183 | template 184 | constexpr auto member_traits_get(const T& object, Member member, Args&&... args) 185 | -> const typename member_traits::value_type& 186 | { 187 | return member_traits::get(object, member, std::forward(args)...); 188 | } 189 | 190 | template 191 | constexpr auto member_traits_get(T& object, Member member, Args&&... args) 192 | -> typename member_traits::value_type& 193 | { 194 | return member_traits::get(object, member, std::forward(args)...); 195 | } 196 | 197 | template 198 | void member_traits_set(T& object, Member member, Args&&... args) 199 | { 200 | member_traits::set(object, member, std::forward(args)...); 201 | } 202 | 203 | template 204 | struct no_symbol_for_hash {}; 205 | 206 | } 207 | 208 | template 209 | constexpr const typename Symbol::template value_type& get_member_value(const T& object, Args&&... args) 210 | { 211 | static_assert(Symbol::template is_member_of(), "not a member of the class"); 212 | return ctti::detail::member_traits_get(object, Symbol::template get_member(), std::forward(args)...); 213 | } 214 | 215 | template 216 | typename Symbol::template value_type& 217 | get_member_value(T& object, Args&&... args) 218 | { 219 | static_assert(Symbol::template is_member_of(), "not a member of the class"); 220 | return ctti::detail::member_traits_get(object, Symbol::template get_member(), std::forward(args)...); 221 | } 222 | 223 | template 224 | void set_member_value(const T& object, Args&&... args) 225 | { 226 | static_assert(Symbol::template is_member_of(), "not a member of the class"); 227 | ctti::detail::member_traits_set(object, Symbol::template get_member(), std::forward(args)...); 228 | } 229 | 230 | template 231 | void set_member_value(T& object, Args&&... args) 232 | { 233 | static_assert(Symbol::template is_member_of(), "not a member of the class"); 234 | ctti::detail::member_traits_set(object, Symbol::template get_member(), std::forward(args)...); 235 | } 236 | 237 | } 238 | 239 | template 240 | ctti::detail::no_symbol_for_hash ctti_symbol_from_hash(Hash); 241 | 242 | #endif // CTTI_SYMBOL_HPP 243 | -------------------------------------------------------------------------------- /include/ctti/symbol_from_hash.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_SYMBOL_FROM_HASH_HPP 2 | #define CTTI_SYMBOL_FROM_HASH_HPP 3 | 4 | #include 5 | 6 | namespace ctti 7 | { 8 | 9 | template 10 | using symbol_from_hash = decltype(ctti_symbol_from_hash(ctti::meta::uint64_t())); 11 | 12 | } 13 | 14 | 15 | #endif // CTTI_SYMBOL_FROM_HASH_HPP 16 | -------------------------------------------------------------------------------- /include/ctti/tie.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_TIE_HPP 2 | #define CTTI_TIE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ctti 9 | { 10 | 11 | namespace detail 12 | { 13 | 14 | template 15 | struct tie_t; 16 | 17 | template 18 | struct tie_t, ctti::meta::list> 19 | { 20 | constexpr tie_t(Refs&... refs) : 21 | _refs{refs...} 22 | {} 23 | 24 | template 25 | void operator=(const T& object) 26 | { 27 | assign(object, ctti::meta::make_index_sequence_for()); 28 | } 29 | 30 | private: 31 | template 32 | using Symbol = ctti::meta::pack_get_t; 33 | 34 | 35 | template::template is_member_of() 37 | >::type> 38 | void assign_member(const T& object) 39 | { 40 | std::get(_refs) = ctti::get_member_value>(object); 41 | } 42 | 43 | template::template is_member_of() 45 | >::type> 46 | void assign_member(const T& object) 47 | {} 48 | 49 | template 50 | void assign(const T& object, ctti::meta::index_sequence) 51 | { 52 | [](...){}((tie_t::assign_member(object), 42)...); 53 | } 54 | 55 | std::tuple _refs; 56 | }; 57 | 58 | } 59 | 60 | template 61 | constexpr ctti::detail::tie_t< 62 | ctti::meta::list, ctti::meta::list 63 | > tie(Refs&... refs) 64 | { 65 | return {refs...}; 66 | } 67 | 68 | } 69 | 70 | #endif // CTTI_TIE_HPP 71 | -------------------------------------------------------------------------------- /include/ctti/type_id.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by manu343726 on 4/08/15. 3 | // 4 | 5 | #ifndef CTTI_HASH_HPP 6 | #define CTTI_HASH_HPP 7 | 8 | #include 9 | #include "detail/hash.hpp" 10 | #include "detail/cstring.hpp" 11 | #include "nameof.hpp" 12 | 13 | #ifdef CTTI_DEBUG_ID_FUNCTIONS 14 | #include 15 | #include 16 | 17 | #ifndef CTTI_CONSTEXPR_ID 18 | #define CTTI_CONSTEXPR_ID 19 | #endif 20 | #else 21 | #ifndef CTTI_CONSTEXPR_ID 22 | #define CTTI_CONSTEXPR_ID constexpr 23 | #endif 24 | #endif 25 | namespace ctti 26 | { 27 | struct type_id_t 28 | { 29 | constexpr type_id_t(const detail::cstring& name) : 30 | name_{name} 31 | {} 32 | 33 | constexpr type_id_t() : 34 | type_id_t{"void"} 35 | {} 36 | 37 | type_id_t& operator=(const type_id_t&) = default; 38 | 39 | constexpr detail::hash_t hash() const 40 | { 41 | return name_.hash(); 42 | } 43 | 44 | constexpr const detail::cstring& name() const 45 | { 46 | return name_; 47 | } 48 | 49 | friend constexpr bool operator==(const type_id_t& lhs, const type_id_t& rhs) 50 | { 51 | return lhs.hash() == rhs.hash(); 52 | } 53 | 54 | friend constexpr bool operator!=(const type_id_t& lhs, const type_id_t& rhs) 55 | { 56 | return !(lhs == rhs); 57 | } 58 | 59 | private: 60 | detail::cstring name_; 61 | }; 62 | 63 | struct unnamed_type_id_t 64 | { 65 | constexpr unnamed_type_id_t(const detail::hash_t hash) : 66 | _hash{hash} 67 | {} 68 | 69 | constexpr unnamed_type_id_t(const type_id_t& id) : 70 | _hash{id.hash()} 71 | {} 72 | 73 | unnamed_type_id_t& operator=(const unnamed_type_id_t&) = default; 74 | 75 | constexpr detail::hash_t hash() const 76 | { 77 | return _hash; 78 | } 79 | 80 | friend constexpr bool operator==(const unnamed_type_id_t& lhs, const unnamed_type_id_t& rhs) 81 | { 82 | return lhs.hash() == rhs.hash(); 83 | } 84 | 85 | friend constexpr bool operator!=(const unnamed_type_id_t& lhs, const unnamed_type_id_t& rhs) 86 | { 87 | return !(lhs == rhs); 88 | } 89 | 90 | private: 91 | detail::hash_t _hash; 92 | }; 93 | 94 | using type_index = unnamed_type_id_t; // To mimic std::type_index when using maps 95 | 96 | 97 | template 98 | constexpr ctti::unnamed_type_id_t id_from_name(const char (&typeName)[N]) 99 | { 100 | return detail::fnv1a_hash(typeName); 101 | } 102 | 103 | constexpr ctti::unnamed_type_id_t id_from_name(const char* typeName, std::size_t length) 104 | { 105 | return detail::fnv1a_hash(length, typeName); 106 | } 107 | 108 | constexpr ctti::unnamed_type_id_t id_from_name(const ctti::detail::cstring& name) 109 | { 110 | return detail::fnv1a_hash(name.size(), name.begin()); 111 | } 112 | 113 | // Inline to prevent ODR violation 114 | inline ctti::unnamed_type_id_t id_from_name(const std::string& typeName) 115 | { 116 | return detail::fnv1a_hash(typeName.size(), typeName.data()); 117 | } 118 | 119 | namespace detail 120 | { 121 | template 122 | CTTI_CONSTEXPR_ID ctti::type_id_t type_id() 123 | { 124 | return { ctti::nameof() }; 125 | } 126 | 127 | template 128 | CTTI_CONSTEXPR_ID ctti::unnamed_type_id_t unnamed_type_id() 129 | { 130 | return { id_from_name(ctti::nameof()) }; 131 | } 132 | } 133 | 134 | /** 135 | * Returns type information at compile-time for a value 136 | * of type T. Decay is applied to argument type first, use 137 | * ctti::type_id() to preserve references and cv qualifiers. 138 | */ 139 | template 140 | constexpr type_id_t type_id(T&&) 141 | { 142 | return detail::type_id::type>(); 143 | } 144 | 145 | /** 146 | * Returns type information at compile-time for type T. 147 | */ 148 | template 149 | constexpr type_id_t type_id() 150 | { 151 | return detail::type_id(); 152 | } 153 | 154 | /** 155 | * Returns unnamed type information at compile-time for a value 156 | * of type T. Decay is applied to argument type first, use 157 | * ctti::type_id() to preserve references and cv qualifiers. 158 | */ 159 | template 160 | constexpr unnamed_type_id_t unnamed_type_id(T&&) 161 | { 162 | return detail::unnamed_type_id::type>(); 163 | } 164 | 165 | /** 166 | * Returns unnamed type information at compile-time for type T. 167 | */ 168 | template 169 | constexpr unnamed_type_id_t unnamed_type_id() 170 | { 171 | return detail::unnamed_type_id(); 172 | } 173 | 174 | //assert commented out, GCC 5.2.0 ICE here. 175 | //static_assert(type_id() == type_id(), "ctti::type_id_t instances must be constant expressions"); 176 | } 177 | 178 | namespace std 179 | { 180 | template<> 181 | struct hash 182 | { 183 | constexpr std::size_t operator()(const ctti::type_id_t& id) const 184 | { 185 | // quiet warning about possible loss of data 186 | return std::size_t(id.hash()); 187 | } 188 | }; 189 | 190 | template<> 191 | struct hash 192 | { 193 | constexpr std::size_t operator()(const ctti::unnamed_type_id_t& id) const 194 | { 195 | // quiet warning about possible loss of data 196 | return std::size_t(id.hash()); 197 | } 198 | }; 199 | } 200 | 201 | #endif //CTTI_HASH_HPP 202 | -------------------------------------------------------------------------------- /include/ctti/type_tag.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_TYPE_TAG_HPP 2 | #define CTTI_TYPE_TAG_HPP 3 | 4 | namespace ctti 5 | { 6 | 7 | template 8 | struct type_tag 9 | { 10 | constexpr type_tag() = default; 11 | using type = T; 12 | }; 13 | 14 | } 15 | 16 | #endif // CTTI_TYPE_TAG_HPP 17 | -------------------------------------------------------------------------------- /test_package/BUCK: -------------------------------------------------------------------------------- 1 | cxx_binary( 2 | name = 'test_package', 3 | srcs = [ 4 | 'main.cpp', 5 | ], 6 | deps = [ 7 | '//:ctti', 8 | ], 9 | ) 10 | -------------------------------------------------------------------------------- /test_package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(ctti_test_package) 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) 5 | conan_basic_setup(TARGETS) 6 | 7 | add_executable(example main.cpp) 8 | if(NOT MSVC) 9 | target_compile_options(example PRIVATE -std=c++11) 10 | endif() 11 | target_link_libraries(example PRIVATE CONAN_PKG::ctti) 12 | -------------------------------------------------------------------------------- /test_package/conanfile.py: -------------------------------------------------------------------------------- 1 | from conans import ConanFile, CMake 2 | import os 3 | 4 | version = os.getenv('CONAN_CTTI_VERSION', '0.0.1') 5 | user = os.getenv('CONAN_CTTI_USER', 'Manu343726') 6 | channel = os.getenv('CONAN_CTTI_CHANNEL', 'testing') 7 | 8 | class TestCtti(ConanFile): 9 | settings = 'os', 'compiler', 'build_type', 'arch' 10 | requires = ( 11 | 'ctti/{}@{}/{}'.format(version, user, channel) 12 | ) 13 | generators = 'cmake' 14 | 15 | def build(self): 16 | cmake = CMake(self) 17 | cmake.configure() 18 | cmake.build() 19 | 20 | def test(self): 21 | self.run(os.path.join('.', 'bin', 'example')) 22 | -------------------------------------------------------------------------------- /test_package/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::cout << ctti::type_id().name() << std::endl; 7 | } 8 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(static) 2 | 3 | add_executable(ctti-test 4 | main.cpp 5 | cstring.cpp 6 | hash.cpp 7 | nameof.cpp 8 | name_filters.cpp 9 | detailed_nameof.cpp 10 | tie.cpp 11 | map.cpp 12 | model.cpp 13 | symbol.cpp 14 | serialization.cpp 15 | ) 16 | 17 | target_link_libraries(ctti-test PRIVATE ctti) 18 | 19 | if(NOT MSVC) 20 | target_compile_options(ctti-test PRIVATE -ftemplate-backtrace-limit=0 -DCATCH_CONFIG_NO_POSIX_SIGNALS) 21 | endif() 22 | 23 | add_test(ctti-test ctti-test) 24 | -------------------------------------------------------------------------------- /tests/cstring.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "catch.hpp" 3 | 4 | using namespace ctti::detail; 5 | 6 | TEST_CASE("cstring") 7 | { 8 | 9 | SECTION("initialization") 10 | { 11 | SECTION("initialization from string literal") 12 | { 13 | constexpr cstring hello{"hello"}; 14 | constexpr cstring hello_world{"hello, world"}; 15 | constexpr const char* hello_buff = hello.begin(); 16 | 17 | REQUIRE(hello.str() == "hello"); 18 | REQUIRE(hello.length() == 5); 19 | REQUIRE(hello.end() == hello.begin() + 5); 20 | } 21 | 22 | SECTION("initialization from const char*") 23 | { 24 | constexpr const char* str = "hello"; 25 | constexpr cstring hello{str}; 26 | 27 | REQUIRE(hello.length() == 5); 28 | REQUIRE(hello.str() == "hello"); 29 | REQUIRE(hello.end() == hello.begin() + 5); 30 | } 31 | 32 | SECTION("initialization from const char* and length") 33 | { 34 | constexpr const char* str = "hello world"; 35 | constexpr cstring hello{str, 5}; 36 | 37 | REQUIRE(hello.length() == 5); 38 | REQUIRE(hello.str() == "hello"); 39 | REQUIRE(hello.end() == hello.begin() + 5); 40 | } 41 | } 42 | 43 | SECTION("comparison") 44 | { 45 | constexpr cstring hello{"hello"}; 46 | 47 | REQUIRE(hello == hello); 48 | REQUIRE(hello != "world"); 49 | } 50 | 51 | SECTION("slices") 52 | { 53 | SECTION("slice") 54 | { 55 | constexpr cstring hello_world{"hello world"}; 56 | constexpr auto hello = hello_world(0, 5); 57 | constexpr auto world = hello_world(6, 11); 58 | 59 | REQUIRE(hello.begin() == hello_world.begin()); 60 | REQUIRE(world.begin() == hello_world.begin() + 6); 61 | REQUIRE(hello.length() == 5); 62 | REQUIRE(world.length() == 5); 63 | 64 | REQUIRE(hello == "hello"); 65 | REQUIRE(world == "world"); 66 | REQUIRE(hello.str() == "hello"); 67 | REQUIRE(world.str() == "world"); 68 | } 69 | 70 | SECTION("pad") 71 | { 72 | constexpr cstring hello_world{" hello world "}; 73 | constexpr auto padded = hello_world.pad(3, 3); 74 | 75 | REQUIRE(padded == "hello world"); 76 | REQUIRE(padded.length() == hello_world.length() - 6); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /tests/detailed_nameof.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "catch.hpp" 3 | 4 | using namespace ctti; 5 | 6 | struct Struct 7 | { 8 | int member; 9 | }; 10 | 11 | enum class Enum 12 | { 13 | Value 14 | }; 15 | 16 | namespace Namespace 17 | { 18 | struct Struct 19 | { 20 | int member; 21 | enum class Enum 22 | { 23 | Value 24 | }; 25 | }; 26 | }; 27 | 28 | constexpr ctti::detail::cstring ctti_nameof(CTTI_STATIC_VALUE(Enum::Value)) 29 | { 30 | return "Enum::Value"; 31 | } 32 | 33 | constexpr ctti::detail::cstring ctti_nameof(CTTI_STATIC_VALUE(Namespace::Struct::Enum::Value)) 34 | { 35 | return "Namespace::Struct::Enum::Value"; 36 | } 37 | 38 | TEST_CASE("detailed_nameof") 39 | { 40 | SECTION("full_name") 41 | { 42 | REQUIRE(detailed_nameof().full_name() == "Struct"); 43 | REQUIRE(detailed_nameof().full_name() == "Enum"); 44 | REQUIRE(detailed_nameof().full_name() == "Namespace::Struct"); 45 | REQUIRE(detailed_nameof().full_name() == "&Struct::member"); 46 | REQUIRE(detailed_nameof().full_name() == "&Namespace::Struct::member"); 47 | REQUIRE(detailed_nameof().full_name() == "Enum::Value"); 48 | 49 | #ifdef CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 50 | REQUIRE(detailed_nameof().full_name() == "Namespace::Struct::Enum::Value"); 51 | #else 52 | REQUIRE(detailed_nameof().full_name() == "(Namespace::Struct::Enum)0"); 53 | #endif // CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 54 | } 55 | 56 | SECTION("full_homogeneous_name") 57 | { 58 | REQUIRE(detailed_nameof().full_homogeneous_name() == "Struct"); 59 | REQUIRE(detailed_nameof().full_homogeneous_name() == "Enum"); 60 | REQUIRE(detailed_nameof().full_homogeneous_name() == "Namespace::Struct"); 61 | REQUIRE(detailed_nameof().full_homogeneous_name() == "Namespace::Struct::Enum"); 62 | REQUIRE(detailed_nameof().full_homogeneous_name() == "Struct::member"); 63 | REQUIRE(detailed_nameof().full_homogeneous_name() == "Namespace::Struct::member"); 64 | REQUIRE(detailed_nameof().full_homogeneous_name() == "Enum::Value"); 65 | 66 | #ifdef CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 67 | REQUIRE(detailed_nameof().full_homogeneous_name() == "Namespace::Struct::Enum::Value"); 68 | #else 69 | REQUIRE(detailed_nameof().full_homogeneous_name() == "(Namespace::Struct::Enum)0"); 70 | #endif // CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 71 | } 72 | 73 | SECTION("name") 74 | { 75 | REQUIRE(detailed_nameof().name() == "Struct"); 76 | REQUIRE(detailed_nameof().name() == "Enum"); 77 | REQUIRE(detailed_nameof().name() == "Struct"); 78 | REQUIRE(detailed_nameof().name() == "Enum"); 79 | REQUIRE(detailed_nameof().name() == "member"); 80 | REQUIRE(detailed_nameof().name() == "Value"); 81 | REQUIRE(detailed_nameof().name() == "member"); 82 | REQUIRE(detailed_nameof().name() == "Value"); 83 | 84 | #ifdef CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 85 | REQUIRE(detailed_nameof().name() == "Value"); 86 | #else 87 | REQUIRE(detailed_nameof().name() == "Enum)0"); 88 | #endif // CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 89 | } 90 | 91 | SECTION("qualifiers") 92 | { 93 | REQUIRE(detailed_nameof().qualifier(0) == ""); 94 | REQUIRE(detailed_nameof().qualifier(1) == ""); 95 | REQUIRE(detailed_nameof().qualifier(2) == ""); 96 | REQUIRE(detailed_nameof().qualifier(0) == ""); 97 | REQUIRE(detailed_nameof().qualifier(1) == ""); 98 | REQUIRE(detailed_nameof().qualifier(2) == ""); 99 | REQUIRE(detailed_nameof().qualifier(0) == "Namespace"); 100 | REQUIRE(detailed_nameof().qualifier(1) == ""); 101 | REQUIRE(detailed_nameof().qualifier(2) == ""); 102 | REQUIRE(detailed_nameof().qualifier(0) == "Namespace"); 103 | REQUIRE(detailed_nameof().qualifier(1) == "Struct"); 104 | REQUIRE(detailed_nameof().qualifier(2) == ""); 105 | REQUIRE(detailed_nameof().qualifier(0) == "Enum"); 106 | 107 | #ifdef CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 108 | REQUIRE(detailed_nameof().qualifier(0) == "Namespace"); 109 | #else 110 | REQUIRE(detailed_nameof().qualifier(0) == "(Namespace"); 111 | #endif // CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 112 | } 113 | 114 | #ifdef CTTI_HAS_VARIABLE_TEMPLATES 115 | SECTION("variable templates") 116 | { 117 | REQUIRE(detailed_nameof_v == detailed_nameof()); 118 | REQUIRE(detailed_nameof_value_v == detailed_nameof()); 119 | } 120 | #endif // CTTI_HAS_VARIABLE_TEMPLATES 121 | } 122 | -------------------------------------------------------------------------------- /tests/hash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "catch.hpp" 3 | 4 | using namespace ctti::detail; 5 | 6 | TEST_CASE("fnv1a_hash") 7 | { 8 | // http://www.isthe.com/chongo/tech/comp/fnv/ 9 | // challenge 56 "strings yielding 64 bit fnv1 zero hash" 10 | SECTION("64 bit FNV1 zero hash") 11 | { 12 | REQUIRE(fnv1a_hash("!0IC=VloaY") == 0); 13 | REQUIRE(fnv1a_hash("=. hx\"iX<;") == 0); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | -------------------------------------------------------------------------------- /tests/map.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "catch.hpp" 4 | 5 | struct Foo 6 | { 7 | int i; 8 | std::string str; 9 | int get_i() const 10 | { 11 | return i; 12 | } 13 | }; 14 | 15 | struct Bar 16 | { 17 | int j; 18 | std::string anotherString; 19 | 20 | void set_anotherString(const std::string& str) 21 | { 22 | anotherString = str; 23 | } 24 | }; 25 | 26 | CTTI_DEFINE_SYMBOL(i); 27 | CTTI_DEFINE_SYMBOL(get_i); 28 | CTTI_DEFINE_SYMBOL(str); 29 | CTTI_DEFINE_SYMBOL(j); 30 | CTTI_DEFINE_SYMBOL(anotherString); 31 | CTTI_DEFINE_SYMBOL(set_anotherString); 32 | 33 | template 34 | std::string lexical_cast(const T& value) 35 | { 36 | std::ostringstream ss; 37 | ss << value; 38 | return ss.str(); 39 | } 40 | 41 | template 42 | T lexical_cast(const std::string& str) 43 | { 44 | std::istringstream ss{str}; 45 | T value; 46 | ss >> value; 47 | return value; 48 | } 49 | 50 | struct string_to_value 51 | { 52 | template 53 | void operator()(const Source& source, SourceSymbol, Sink& sink, SinkSymbol) const 54 | { 55 | ctti::get_member_value(sink) = lexical_cast>(ctti::get_member_value(source)); 56 | } 57 | }; 58 | 59 | struct value_to_string 60 | { 61 | template 62 | void operator()(const Source& source, SourceSymbol, Sink& sink, SinkSymbol) const 63 | { 64 | ctti::get_member_value(sink) = lexical_cast(ctti::get_member_value(source)); 65 | } 66 | }; 67 | 68 | struct lexical_cast_t 69 | { 70 | template 71 | std::string operator()(const T& value, ctti::type_tag) const 72 | { 73 | return lexical_cast(value); 74 | } 75 | 76 | template 77 | T operator()(const std::string& value, ctti::type_tag) const 78 | { 79 | return lexical_cast(value); 80 | } 81 | }; 82 | 83 | TEST_CASE("map") 84 | { 85 | Foo foo{42, "foo"}; 86 | Bar bar; 87 | 88 | SECTION("member to member mapping") 89 | { 90 | ctti::map(foo, bar, ctti::mapping(), ctti::mapping()); 91 | 92 | REQUIRE(bar.j == 42); 93 | REQUIRE(bar.anotherString == "foo"); 94 | } 95 | 96 | SECTION("custom member to member specific mapping") 97 | { 98 | foo.str = "42"; 99 | foo.i = 0; 100 | bar.anotherString = ""; 101 | bar.j = -1; 102 | 103 | ctti::map(foo, bar, ctti::mapping(value_to_string()), ctti::mapping(string_to_value())); 104 | REQUIRE(bar.anotherString == "0"); 105 | REQUIRE(bar.j == 42); 106 | } 107 | 108 | SECTION("generic member-agnostic user defined mapping") 109 | { 110 | Foo foo{0, "42"}; 111 | Bar bar{-1, ""}; 112 | 113 | ctti::map(foo, bar, ctti::mapping(lexical_cast_t()), ctti::mapping(lexical_cast_t())); 114 | REQUIRE(bar.anotherString == "0"); 115 | REQUIRE(bar.j == 42); 116 | 117 | foo.i = 42; 118 | 119 | ctti::map(foo, bar, ctti::mapping(lexical_cast_t())); 120 | REQUIRE(bar.anotherString == "42"); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /tests/model.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "catch.hpp" 4 | 5 | CTTI_DEFINE_SYMBOL(i); 6 | CTTI_DEFINE_SYMBOL(b); 7 | 8 | struct Foo 9 | { 10 | int i; bool b; 11 | 12 | using ctti_model = ctti::model<::i, ::b>; 13 | }; 14 | 15 | struct Bar 16 | { 17 | int i; bool b; 18 | }; 19 | 20 | ctti::model ctti_model(ctti::type_tag); 21 | 22 | TEST_CASE("model") 23 | { 24 | REQUIRE(ctti::nameof>() == ctti::nameof>()); 25 | REQUIRE(ctti::nameof>() == ctti::nameof>()); 26 | } 27 | -------------------------------------------------------------------------------- /tests/name_filters.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "catch.hpp" 3 | 4 | using namespace ctti::detail; 5 | 6 | TEST_CASE("name_filters") 7 | { 8 | constexpr cstring foo_full{"foo::foo::foo::foo"}; 9 | constexpr cstring foobar{"foo::bar"}; 10 | 11 | SECTION("find_ith") 12 | { 13 | REQUIRE(find_ith(foo_full, "foo", 0) == foo_full.begin()); 14 | REQUIRE(find_ith(foo_full, "foo", 1) == foo_full.begin() + cstring("foo::").length()); 15 | REQUIRE(find_ith(foo_full, "foo", 2) == foo_full.begin() + cstring("foo::foo::").length()); 16 | 17 | REQUIRE(find_ith(foo_full, "::", 0) == foo_full.begin() + cstring{"foo"}.length()); 18 | REQUIRE(find_ith(foo_full, "::", 1) == foo_full.begin() + cstring("foo::foo").length()); 19 | REQUIRE(find_ith(foo_full, "::", 2) == foo_full.begin() + cstring("foo::foo::foo").length()); 20 | 21 | REQUIRE(find_ith(foobar, "foo", 1) == foobar.end()); 22 | REQUIRE(find_ith(foobar, "foo", 2) == foobar.end()); 23 | REQUIRE(find_ith(foobar, "foo", 3) == foobar.end()); 24 | 25 | REQUIRE(find_ith(foobar, "::", 1) == foobar.end()); 26 | } 27 | 28 | SECTION("find") 29 | { 30 | REQUIRE(find(foo_full, "foo") == foo_full.begin()); 31 | REQUIRE(find(foo_full, "::") == foo_full.begin() + cstring{"foo"}.length()); 32 | } 33 | 34 | SECTION("find_last") 35 | { 36 | REQUIRE(find_last(foo_full, "foo") == foo_full.begin() + cstring("foo::foo::foo::").length()); 37 | REQUIRE(find_last(foo_full, "::") == foo_full.begin() + cstring("foo::foo::foo").length()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/nameof.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "catch.hpp" 3 | 4 | using namespace ctti; 5 | 6 | namespace foo 7 | { 8 | struct Foo {}; 9 | 10 | namespace bar 11 | { 12 | struct Bar {}; 13 | } 14 | 15 | inline namespace inline_quux 16 | { 17 | struct Quux {}; 18 | } 19 | } 20 | 21 | namespace bar 22 | { 23 | struct Bar {}; 24 | 25 | constexpr ctti::detail::cstring ctti_nameof(ctti::type_tag) 26 | { 27 | return "Bar"; // without namespace 28 | } 29 | 30 | enum class Enum 31 | { 32 | A, B, C 33 | }; 34 | 35 | constexpr ctti::detail::cstring ctti_nameof(CTTI_STATIC_VALUE(Enum::C)) 36 | { 37 | return "Enum::Si"; 38 | } 39 | } 40 | 41 | class MyClass 42 | { 43 | public: 44 | class InnerClass {}; 45 | }; 46 | 47 | struct MyStruct 48 | { 49 | struct InnerStruct {}; 50 | }; 51 | 52 | enum ClassicEnum { A, B, C }; 53 | enum class EnumClass { A, B, C }; 54 | 55 | TEST_CASE("nameof") 56 | { 57 | SECTION("basic types") 58 | { 59 | REQUIRE(nameof() == "int"); 60 | REQUIRE(nameof() == "bool"); 61 | REQUIRE(nameof() == "char"); 62 | REQUIRE(nameof() == "void"); 63 | } 64 | 65 | SECTION("class types") 66 | { 67 | REQUIRE(nameof() == "MyClass"); 68 | REQUIRE(nameof() == "MyClass::InnerClass"); 69 | } 70 | 71 | SECTION("struct types") 72 | { 73 | 74 | REQUIRE(nameof() == "MyStruct"); 75 | REQUIRE(nameof() == "MyStruct::InnerStruct"); 76 | } 77 | 78 | SECTION("enum types") 79 | { 80 | REQUIRE(nameof() == "ClassicEnum"); 81 | REQUIRE(nameof() == "EnumClass"); 82 | } 83 | 84 | SECTION("with namespaces") 85 | { 86 | REQUIRE(nameof() == "foo::Foo"); 87 | REQUIRE(nameof() == "foo::bar::Bar"); 88 | 89 | SECTION("inline namespaces") 90 | { 91 | REQUIRE(nameof() == "foo::inline_quux::Quux"); 92 | REQUIRE(nameof() == "foo::inline_quux::Quux"); 93 | } 94 | 95 | SECTION("std") 96 | { 97 | REQUIRE(nameof() == "std::string"); 98 | } 99 | } 100 | 101 | SECTION("with custom ctti_nameof()") 102 | { 103 | SECTION("intrusive customize") 104 | { 105 | struct Foo 106 | { 107 | static constexpr const char* ctti_nameof() 108 | { 109 | return "Foobar"; 110 | } 111 | }; 112 | 113 | 114 | REQUIRE(nameof() == "Foobar"); 115 | } 116 | 117 | SECTION("non-intrusive customize") 118 | { 119 | REQUIRE(nameof() == "Bar"); 120 | REQUIRE(nameof() == "Enum::Si"); 121 | } 122 | } 123 | 124 | #ifdef CTTI_HAS_VARIABLE_TEMPLATES 125 | SECTION("variable templates") 126 | { 127 | REQUIRE(ctti::nameof_v == nameof()); 128 | REQUIRE(ctti::nameof_value_v == nameof()); 129 | } 130 | #endif // CTTI_HAS_VARIABLE_TEMPLATES 131 | } 132 | 133 | TEST_CASE("nameof.enums", "[!mayfail]") 134 | { 135 | #ifdef CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION 136 | SECTION("enum values") 137 | { 138 | REQUIRE(nameof() == "ClassicEnum::A"); 139 | REQUIRE(nameof() == "EnumClass::A"); 140 | REQUIRE(nameof() == "ClassicEnum::A"); 141 | } 142 | #else 143 | SECTION("enum values") 144 | { 145 | WARN("Thie section may fail in GCC due to 'u' suffix in integer literals. " 146 | "It seems that some GCC versions use unsigned int as default enum underlying type"); 147 | 148 | REQUIRE(nameof() == "(ClassicEnum)0"); 149 | REQUIRE(nameof() == "(EnumClass)0"); 150 | REQUIRE(nameof() == "(ClassicEnum)0"); 151 | } 152 | #endif 153 | } 154 | -------------------------------------------------------------------------------- /tests/serialization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "catch.hpp" 4 | 5 | namespace symbols 6 | { 7 | CTTI_DEFINE_SYMBOL(A); 8 | CTTI_DEFINE_SYMBOL(B); 9 | CTTI_DEFINE_SYMBOL(a); 10 | CTTI_DEFINE_SYMBOL(b); 11 | CTTI_DEFINE_SYMBOL(c); 12 | CTTI_DEFINE_SYMBOL(d); 13 | } 14 | 15 | struct Foo 16 | { 17 | enum class Enum 18 | { 19 | A, B 20 | }; 21 | 22 | int a; 23 | std::string b; 24 | Enum c; 25 | 26 | struct Bar 27 | { 28 | struct enum_hash 29 | { 30 | std::size_t operator()(Foo::Enum value) const 31 | { 32 | return std::hash>>()( 33 | static_cast>>(value) 34 | ); 35 | } 36 | }; 37 | 38 | std::vector a{1, 2, 3, 4}; 39 | std::unordered_map b{ {Enum::A, "A"}, {Enum::B, "B"} }; 40 | std::array, 2> c{{std::make_tuple(1, 2), std::make_tuple(3, 4)}}; 41 | 42 | using ctti_model = ctti::model; 43 | }; 44 | 45 | Bar d; 46 | 47 | using ctti_model = ctti::model; 48 | void ctti_ostream_print(); 49 | }; 50 | 51 | ctti::model ctti_model(ctti::type_tag); 52 | void ctti_ostream_print(ctti::type_tag); 53 | 54 | TEST_CASE("serialization") 55 | { 56 | Foo foo{42, "42", Foo::Enum::A, Foo::Bar{}}; 57 | std::ostringstream ss; 58 | 59 | SECTION("enum to string") 60 | { 61 | REQUIRE(ctti::serialization::enum_to_string(Foo::Enum::A) == "A"); 62 | REQUIRE(ctti::serialization::enum_to_string(Foo::Enum::B) == "B"); 63 | } 64 | 65 | SECTION("enum from string") 66 | { 67 | REQUIRE(ctti::serialization::enum_from_string("A") == Foo::Enum::A); 68 | REQUIRE(ctti::serialization::enum_from_string("B") == Foo::Enum::B); 69 | } 70 | 71 | SECTION("json formatter") 72 | { 73 | ctti::serialization::serialize(ctti::serialization::json_formatter(), ctti::serialization::ostream_otuput(ss), foo); 74 | REQUIRE(ss.str() == R"({"a": 42, "b": "42", "c": A, "d": {"a": [1, 2, 3, 4], "b": [{B: "B"}, {A: "A"}], "c": [(1, 2), (3, 4)]}})"); 75 | ss.str(""); 76 | } 77 | 78 | SECTION("default ostream print") 79 | { 80 | std::ostringstream ss; 81 | ss << foo; 82 | REQUIRE(ss.str() == R"({"a": 42, "b": "42", "c": A, "d": {"a": [1, 2, 3, 4], "b": [{B: "B"}, {A: "A"}], "c": [(1, 2), (3, 4)]}})"); 83 | ss.str(""); 84 | 85 | ss << Foo::Enum::A; 86 | REQUIRE(ss.str() == "A"); 87 | } 88 | 89 | SECTION("json writer") 90 | { 91 | nlohmann::json json; 92 | ctti::serialization::serialize(ctti::serialization::json_writer(json), foo); 93 | REQUIRE(json.dump() == R"({"a":42,"b":"42","c":"A","d":{"a":[1,2,3,4],"b":[[1,"B"],[0,"A"]],"c":[[1,2],[3,4]]}})"); 94 | } 95 | 96 | SECTION("json reader enum as int") 97 | { 98 | auto json = nlohmann::json::parse(R"({"a":42,"b":"42","c":"A","d":{"a":[1,2,3,4],"b":[[1,"B"],[0,"A"]],"c":[[1,2],[3,4]]}})"); 99 | Foo foo2; 100 | ctti::serialization::deserialize(ctti::serialization::json_reader(json), foo2); 101 | REQUIRE(foo2.a == 42); 102 | REQUIRE(foo2.b == "42"); 103 | REQUIRE(foo2.c == Foo::Enum::A); 104 | REQUIRE(foo2.d.a == std::vector{1, 2, 3, 4}); 105 | REQUIRE(foo2.d.b.size() == 2); 106 | REQUIRE(foo2.d.b.at(Foo::Enum::A) == "A"); 107 | REQUIRE(foo2.d.b.at(Foo::Enum::B) == "B"); 108 | REQUIRE(foo2.d.c == std::array, 2>{ std::make_tuple(1, 2), std::make_tuple(3, 4)}); 109 | } 110 | 111 | SECTION("json reader enum as string") 112 | { 113 | auto json = nlohmann::json::parse(R"({"a":42,"b":"42","c":"A","d":{"a":[1,2,3,4],"b":[["B","B"],["A","A"]],"c":[[1,2],[3,4]]}})"); 114 | Foo foo2; 115 | ctti::serialization::deserialize(ctti::serialization::json_reader(json), foo2); 116 | REQUIRE(foo2.a == 42); 117 | REQUIRE(foo2.b == "42"); 118 | REQUIRE(foo2.c == Foo::Enum::A); 119 | REQUIRE(foo2.d.a == std::vector{1, 2, 3, 4}); 120 | REQUIRE(foo2.d.b.size() == 2); 121 | REQUIRE(foo2.d.b.at(Foo::Enum::A) == "A"); 122 | REQUIRE(foo2.d.b.at(Foo::Enum::B) == "B"); 123 | REQUIRE(foo2.d.c == std::array, 2>{ std::make_tuple(1, 2), std::make_tuple(3, 4)}); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /tests/static/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(ctti-static-tests 2 | algorithm.cpp 3 | cstring.cpp 4 | hash.cpp 5 | symbol.cpp 6 | name.cpp 7 | static_value.cpp 8 | ) 9 | 10 | target_link_libraries(ctti-static-tests PRIVATE ctti) 11 | -------------------------------------------------------------------------------- /tests/static/algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "static_test.hpp" 3 | 4 | using namespace ctti::detail; 5 | 6 | constexpr int array_a[] = {1, 2, 3, 4}; 7 | constexpr int array_b[] = {1, 2, 3, 42}; 8 | constexpr int array_c[] = {1, 2}; 9 | constexpr int array_d[] = {1}; 10 | constexpr const char* hello_world = "hello world"; 11 | constexpr const char* world = "world"; 12 | 13 | EXPECT_EQ(begin(array_a), &array_a[0]); 14 | EXPECT_EQ(end(array_a), &array_a[sizeof(array_a) / sizeof(int)]); 15 | 16 | EXPECT_TRUE( 17 | ctti::detail::equal_range( 18 | begin(array_a), end(array_a), 19 | begin(array_a), end(array_a) 20 | ) 21 | ); 22 | 23 | EXPECT_FALSE( 24 | ctti::detail::equal_range( 25 | begin(array_a), end(array_a), 26 | begin(array_b), end(array_b) 27 | ) 28 | ); 29 | 30 | EXPECT_TRUE( 31 | ctti::detail::equal_range( 32 | &world[0], &world[5], 33 | &hello_world[6], &hello_world[11] 34 | ) 35 | ); 36 | -------------------------------------------------------------------------------- /tests/static/cstring.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "static_test.hpp" 3 | 4 | using namespace ctti::detail; 5 | 6 | constexpr cstring hello{"hello"}; 7 | constexpr cstring world{"world"}; 8 | 9 | EXPECT_EQ(hello.length(), 5); 10 | EXPECT_EQ((cstring{"hello", 5}.length()), 5); 11 | EXPECT_EQ(hello.begin() + hello.size(), hello.end()); 12 | EXPECT_EQ(hello, hello); 13 | EXPECT_NE(hello, world); 14 | 15 | template 16 | constexpr ctti::detail::cstring get_string() 17 | { 18 | return "default string"; 19 | } 20 | 21 | template<> 22 | constexpr ctti::detail::cstring get_string() 23 | { 24 | return "foobar"; 25 | } 26 | 27 | EXPECT_EQ(get_string(), "foobar"); 28 | -------------------------------------------------------------------------------- /tests/static/hash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "static_test.hpp" 3 | 4 | using namespace ctti::detail; 5 | /* 6 | EXPECT_EQ(fnv1a_hash("Mt5Kexny31n"), 0); 7 | EXPECT_EQ(fnv1a_hash("OjSHjikPNYV"), 0); 8 | */ 9 | -------------------------------------------------------------------------------- /tests/static/model.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "static_test.hpp" 3 | 4 | CTTI_DEFINE_SYMBOL(i); 5 | CTTI_DEFINE_SYMBOL(b); 6 | 7 | struct Foo 8 | { 9 | int i; bool b; 10 | 11 | using ctti_model = ctti::model<::i, ::b>; 12 | }; 13 | 14 | EXPECT_TRUE(std::is_same, ctti::model>()); 15 | -------------------------------------------------------------------------------- /tests/static/name.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "static_test.hpp" 3 | 4 | EXPECT_EQ(ctti::name_t{"hello::world"}.name(), "world"); 5 | EXPECT_EQ(ctti::name_t{"hello::world"}.full_name(), "hello::world"); 6 | EXPECT_EQ(ctti::name_t{"::hello::world"}.name(), "world"); 7 | EXPECT_EQ(ctti::name_t{"::hello::world"}.full_name(), "::hello::world"); 8 | EXPECT_EQ(ctti::name_t{"world"}.name(), "world"); 9 | 10 | EXPECT_EQ(ctti::name_t{"hello::world"}.qualifier(0), "hello"); 11 | EXPECT_EQ(ctti::name_t{"foo::bar::quux::foobar::foobarquux"}.qualifier(0), "foo"); 12 | EXPECT_EQ(ctti::name_t{"foo::bar::quux::foobar::foobarquux"}.qualifier(1), "bar"); 13 | EXPECT_EQ(ctti::name_t{"foo::bar::quux::foobar::foobarquux"}.qualifier(2), "quux"); 14 | EXPECT_EQ(ctti::name_t{"foo::bar::quux::foobar::foobarquux"}.qualifier(3), "foobar"); 15 | EXPECT_EQ(ctti::name_t{"foo::bar::quux::foobar::foobarquux"}.name(), "foobarquux"); 16 | EXPECT_EQ(ctti::name_t{"::foo::bar::quux::foobar::foobarquux"}.qualifier(0), ""); 17 | EXPECT_EQ(ctti::name_t{"::foo::bar::quux::foobar::foobarquux"}.qualifier(1), "foo"); 18 | EXPECT_EQ(ctti::name_t{"::foo::bar::quux::foobar::foobarquux"}.qualifier(2), "bar"); 19 | EXPECT_EQ(ctti::name_t{"::foo::bar::quux::foobar::foobarquux"}.qualifier(3), "quux"); 20 | EXPECT_EQ(ctti::name_t{"::foo::bar::quux::foobar::foobarquux"}.qualifier(4), "foobar"); 21 | EXPECT_EQ(ctti::name_t{"::foo::bar::quux::foobar::foobarquux"}.name(), "foobarquux"); 22 | -------------------------------------------------------------------------------- /tests/static/static_test.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTTI_TESTS_STATIC_TEST_HPP 2 | #define CTTI_TESTS_STATIC_TEST_HPP 3 | 4 | #define PP_STR_IMPL(x) #x 5 | #define PP_STR(...) PP_STR_IMPL((__VA_ARGS__)) 6 | 7 | #define EXPECT_TRUE(...) \ 8 | static_assert((__VA_ARGS__), "Expected '" PP_STR(__VA_ARGS__) "' to be true") 9 | 10 | #define EXPECT_FALSE(...) \ 11 | static_assert(!(__VA_ARGS__), "Expected '" PP_STR(__VA_ARGS__) "' to be false") 12 | 13 | #define EXPECT_EQ(x, y) \ 14 | static_assert(x == y, "Expected '" PP_STR(x) "' to be equal to '" PP_STR(y) "'") 15 | 16 | #define EXPECT_NE(x, y) \ 17 | static_assert(x != y, "Expected '" PP_STR(x) "' to be not equal to '" PP_STR(y) "'") 18 | 19 | #endif // CTTI_TESTS_STATIC_TEST_HPP 20 | -------------------------------------------------------------------------------- /tests/static/static_value.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "static_test.hpp" 3 | 4 | EXPECT_EQ(CTTI_STATIC_VALUE(42)::value, 42); 5 | EXPECT_EQ(CTTI_STATIC_VALUE(42){}.get(), 42); 6 | EXPECT_EQ(CTTI_STATIC_VALUE(42){}, 42); 7 | EXPECT_NE(CTTI_STATIC_VALUE(43){}, 42); 8 | EXPECT_EQ(42, CTTI_STATIC_VALUE(42){}); 9 | EXPECT_NE(42, CTTI_STATIC_VALUE(43){}); 10 | EXPECT_EQ(static_cast(CTTI_STATIC_VALUE(42){}), 42); 11 | -------------------------------------------------------------------------------- /tests/static/symbol.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "static_test.hpp" 4 | 5 | struct Foo 6 | { 7 | int foobar; 8 | int getter() const; 9 | void setter(int i); 10 | }; 11 | 12 | enum class Enum 13 | { 14 | Value 15 | }; 16 | 17 | CTTI_DEFINE_SYMBOL(foobar); 18 | CTTI_DEFINE_SYMBOL(Value); 19 | CTTI_DEFINE_SYMBOL(getter); 20 | CTTI_DEFINE_SYMBOL(setter); 21 | 22 | #include 23 | 24 | EXPECT_TRUE(foobar::is_member_of()); 25 | EXPECT_FALSE(foobar::is_member_of()); 26 | EXPECT_FALSE(Value::is_member_of()); 27 | EXPECT_TRUE(Value::is_member_of()); 28 | EXPECT_TRUE(getter::is_member_of()); 29 | EXPECT_TRUE(setter::is_member_of()); 30 | 31 | EXPECT_EQ(foobar::get_member(), &Foo::foobar); 32 | EXPECT_EQ(foobar::get_member(), nullptr); 33 | EXPECT_EQ(Value::get_member(), Enum::Value); 34 | EXPECT_EQ(Value::get_member(), nullptr); 35 | 36 | EXPECT_EQ(foobar::symbol(), "foobar"); 37 | EXPECT_EQ(Value::symbol(), "Value"); 38 | 39 | EXPECT_TRUE(std::is_same>()); 40 | -------------------------------------------------------------------------------- /tests/symbol.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "catch.hpp" 5 | 6 | CTTI_DEFINE_SYMBOL(foo); 7 | 8 | #include 9 | 10 | TEST_CASE("symbol") 11 | { 12 | REQUIRE(ctti::nameof() == ctti::nameof>()); 13 | } 14 | -------------------------------------------------------------------------------- /tests/tie.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "catch.hpp" 3 | 4 | CTTI_DEFINE_SYMBOL(a); 5 | CTTI_DEFINE_SYMBOL(b); 6 | CTTI_DEFINE_SYMBOL(c); 7 | 8 | struct Struct 9 | { 10 | int a; 11 | std::string b; 12 | bool c; 13 | }; 14 | 15 | TEST_CASE("tie") 16 | { 17 | int var_a; 18 | std::string var_b; 19 | bool var_c; 20 | Struct object{42, "foo", true}; 21 | 22 | ctti::tie(var_a, var_b, var_c) = object; 23 | 24 | REQUIRE(var_a == 42); 25 | REQUIRE(var_b == "foo"); 26 | REQUIRE(var_c == true); 27 | } 28 | --------------------------------------------------------------------------------