├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── README.zh.md ├── docs ├── assets │ ├── cover.png │ ├── full_std_string.png │ ├── noutf_nocolor_full_std_string.png │ ├── sample_ptr.png │ ├── std_function.png │ └── std_string.png └── enum.md ├── generate.py ├── include └── magic │ ├── customization.h │ ├── enum.h │ ├── field_count.h │ ├── function_traits.h │ ├── generate │ ├── struct_bind_of_field_access.code │ ├── struct_bind_of_field_types.code │ └── template.code │ ├── macro.h │ ├── raw_name.h │ ├── struct.h │ ├── template_traits.h │ ├── type_traits.h │ ├── type_tree.h │ └── visualize.h ├── script ├── struct_bind.py └── template.py ├── test ├── field_count_test.cpp ├── function_traits_test.cpp ├── raw_name_test.cpp └── template_traits_test.cpp └── xmake.lua /.clang-format: -------------------------------------------------------------------------------- 1 | # .clang-format example configuration 2 | IndentWidth: 4 3 | UseTab: Never 4 | AlignAfterOpenBracket: true 5 | AlignTrailingComments: 6 | Kind: Always 7 | 8 | AlwaysBreakTemplateDeclarations: Yes 9 | RequiresClausePosition: WithPreceding 10 | ColumnLimit: 140 11 | NamespaceIndentation: All 12 | AllowShortBlocksOnASingleLine: Always 13 | AllowShortFunctionsOnASingleLine: All 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortCaseLabelsOnASingleLine: true 16 | AllowShortEnumsOnASingleLine: true 17 | AllowShortLoopsOnASingleLine: true 18 | AllowShortIfStatementsOnASingleLine: false 19 | AlignArrayOfStructures: Left 20 | PointerAlignment: Left 21 | IncludeBlocks: Preserve 22 | SpacesBeforeTrailingComments: 1 23 | BreakBeforeBraces: Custom 24 | 25 | BraceWrapping: 26 | AfterClass: true 27 | AfterControlStatement: Always 28 | AfterEnum: true 29 | AfterFunction: true 30 | AfterNamespace: true 31 | AfterStruct: true 32 | AfterUnion: true 33 | AfterExternBlock: true 34 | BeforeCatch: true 35 | BeforeElse: true 36 | BeforeLambdaBody: true 37 | IndentBraces: false 38 | SplitEmptyFunction: true 39 | SplitEmptyRecord: true 40 | SplitEmptyNamespace: true 41 | BeforeWhile: true 42 | 43 | AllowAllArgumentsOnNextLine: false 44 | BinPackArguments: false 45 | LambdaBodyIndentation: Signature -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | .vscode/ 35 | .xmake/ 36 | build/ 37 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.22) 2 | project(magic-cpp CXX) 3 | 4 | add_library(MAGIC_CPP INTERFACE) 5 | target_include_directories(MAGIC_CPP INTERFACE include) 6 | 7 | option(MAGIC_CPP_INCLUDE_TESTS "Include tests" ON) 8 | if(NOT MAGIC_CPP_INCLUDE_TESTS) 9 | return() 10 | endif() 11 | 12 | # 检查编译器版本支持 13 | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 14 | execute_process( 15 | COMMAND ${CMAKE_CXX_COMPILER} -dumpfullversion -std=c++20 16 | OUTPUT_VARIABLE GCC_VERSION 17 | ) 18 | string(REGEX MATCH "[0-9]+\\.[0-9]+" GCC_VERSION ${GCC_VERSION}) 19 | if(GCC_VERSION VERSION_LESS 10.0) 20 | message(FATAL_ERROR "Minimum required version of g++ is 10.0") 21 | endif() 22 | message(STATUS "Using g++ version ${GCC_VERSION}") 23 | endif() 24 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 25 | execute_process( 26 | COMMAND ${CMAKE_CXX_COMPILER} --version 27 | OUTPUT_VARIABLE CLANG_VERSION_OUTPUT 28 | ) 29 | string(REGEX MATCH "clang version ([0-9]+\\.[0-9]+)" CLANG_VERSION ${CLANG_VERSION_OUTPUT}) 30 | string(REGEX REPLACE "clang version ([0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION ${CLANG_VERSION}) 31 | if(CLANG_VERSION VERSION_LESS 10.0) 32 | message(FATAL_ERROR "Minimum required version of clang is 10.0") 33 | endif() 34 | message(STATUS "Using clang version ${CLANG_VERSION}") 35 | endif() 36 | if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 37 | if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.28) 38 | message(FATAL_ERROR "Minimum required version of MSVC is 19.28 (Visual Studio 2019 version 16.10)") 39 | endif() 40 | message(STATUS "Using MSVC version ${CMAKE_CXX_COMPILER_VERSION}") 41 | endif() 42 | 43 | # 检查C++的版本 44 | include(CheckCXXCompilerFlag) 45 | check_cxx_compiler_flag(-std=c++20 HAS_CXX23_FLAG) 46 | check_cxx_compiler_flag(-std=c++20 HAS_CXX20_FLAG) 47 | if (HAS_CXX23_FLAG) 48 | set(CMAKE_CXX_STANDARD 23) 49 | elseif (HAS_CXX20_FLAG) 50 | set(CMAKE_CXX_STANDARD 20) 51 | else() 52 | message(FATAL_ERROR "C++20 standard is required!") 53 | endif() 54 | 55 | if(NOT MSVC) 56 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") 57 | endif() 58 | 59 | # 优先寻找本地的GTest 60 | find_package(GTest QUIET) 61 | 62 | if(NOT GTest_FOUND) 63 | message(STATUS "GoogleTest not found locally, downloading with FetchContent...") 64 | include(FetchContent) 65 | FetchContent_Declare( 66 | googletest 67 | URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip 68 | DOWNLOAD_EXTRACT_TIMESTAMP TRUE 69 | ) 70 | # For Windows: Prevent overriding the parent project's compiler/linker settings 71 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 72 | FetchContent_MakeAvailable(googletest) 73 | else() 74 | message(STATUS "GoogleTest found locally.") 75 | endif() 76 | 77 | enable_testing() 78 | 79 | include_directories(include) 80 | 81 | # 使用通配符一次性添加多个测试文件 82 | file(GLOB TEST_SOURCES "test/*.cpp") 83 | 84 | # 创建一个包含所有测试文件的可执行文件 85 | add_executable(all_tests ${TEST_SOURCES}) 86 | 87 | target_link_libraries(all_tests GTest::gtest_main) 88 | # 链接Google Test库到测试可执行文件 89 | 90 | # 使用Google Test自动发现所有测试并将其添加到测试套件中 91 | include(GoogleTest) 92 | gtest_discover_tests(all_tests) 93 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 ykiko 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![cover](docs/assets/cover.png) 2 | 3 | magic-cpp is a header-only C++ library. It aims to make it easier for you to use C++, including a series of functions such as visualizing type names, reflection of structs and enumerations, etc. It can help you get rid of the compiler's error messages which are difficult to read 4 | 5 | [English](README.md) | [简体中文](README.zh.md) 6 | 7 | - [Visualizing type](#visualizing-type) 8 | - [Basic usage](#basic-usage) 9 | - [Custom type name](#custom-type-name) 10 | - [Configurability](#configurability) 11 | - [Other features](#other-features) 12 | 13 | 14 | # Visualizing type 15 | `#include `to use features below, `C++17` is minimum required 16 | 17 | ## Basic usage 18 | when using template programming, you often encounter the dilemma of type mismatch, especially when using libraries like `ranges`, templates are often deeply nested and difficult to read. Do not worry, `magic-cpp` can help you visualize the type, making it easier for human to understand the type. Consider the following example 19 | ```cpp 20 | using T = int (*(*(*)(int*))[4])(int*); // hard to understand 21 | std::cout << magic::visualize() << std::endl; 22 | ``` 23 | Output: 24 | 25 | ![visualize](docs/assets/sample_ptr.png) 26 | 27 | Or you may encounter this when writing code 28 | ```cpp 29 | using T = std::function&, std::tuple)>; // hard to understand 30 | std::cout << magic::visualize() << std::endl; 31 | ``` 32 | Output: 33 | 34 | ![visualize](docs/assets/std_function.png) 35 | 36 | Almost all commonly used templates can be converted into such a tree representation, which is clear at a glance. Of course, the full expansion of some types is very long and not what you expected, for example, the output effect of `std::string` on `gcc` is like this 37 | 38 | ![visualize](docs/assets/full_std_string.png) 39 | 40 | ## Custom type name 41 | As you can see, there is a lot of information we don't want to see. It doesn't matter! Provide a custom type name through explicit specialization 42 | ```cpp 43 | template<> 44 | struct magic::type_info 45 | { 46 | inline static std::string name = "std::string"; 47 | }; 48 | ``` 49 | In this way, when encountering `std::string`, only the following will be displayed 50 | 51 | ![visualize](docs/assets/std_string.png) 52 | 53 | It's the custom name, isn't it convenient? I have pre-defined some commonly used type aliases such as `std::size_t`, `std::string`, `std::vector` in `customization.h`. If you need it, you can try to modify or add it yourself 54 | 55 | ## Configurability 56 | Considering that some terminals do not support color, or do not support `utf` characters, the display will appear garbled, so we provide options to turn off these functions 57 | ```cpp 58 | magic::VisualizeOption option; 59 | option.utf_support = false; // do not use utf8 characters 60 | option.color_support = false; // turn off color support 61 | option.full_name = true; // use full name instead of custom alias 62 | std::cout << magic::visualize(option) << std::endl; 63 | ``` 64 | Output: 65 | 66 | ![visualize](docs/assets/noutf_nocolor_full_std_string.png) 67 | 68 | if you want to customize the color scheme, you can use the `HighlightConfig` structure 69 | ```cpp 70 | struct HighlightConfig 71 | { 72 | std::uint32_t type; // type: int, double, ... 73 | std::uint32_t nttp; // non type template parameter: 1, 2, ... 74 | std::uint32_t tmpl; // template: std::vector, ... 75 | std::uint32_t builtin; // built-in compound type: ptr, ref... 76 | std::uint32_t modifier; // modifier: const, volatile, ... 77 | std::uint32_t tag; // tag: R: , M: , ... 78 | }; 79 | 80 | // default color scheme is Dark 81 | constexpr static inline HighlightConfig Dark = { 82 | .type = 0xE5C07B, // yellow 83 | .nttp = 0xD19A66, // orange 84 | .tmpl = 0x0087CE, // blue 85 | .builtin = 0xC678DD, // purple 86 | .modifier = 0x98C379, // green 87 | .tag = 0x5C6370, // gray 88 | }; 89 | 90 | // there is also a built-in Light style color scheme 91 | ``` 92 | You can also customize the color scheme yourself, and then pass it to the `visualize` function 93 | ```cpp 94 | magic::VisualizeOption option; // default option 95 | std::cout << magic::visualize(option, magic::Light) << std::endl; 96 | ``` 97 | ## Other features 98 | Besides visualizing types, we also support some other operations 99 | 100 | retrieving a type's `display_name` 101 | ```cpp 102 | 103 | 104 | ``` 105 | 106 | retrieving `raw_name` in compile time 107 | ```cpp 108 | template 109 | struct Point 110 | { 111 | T start; 112 | T end; 113 | }; 114 | 115 | // retrieving a type's raw_name 116 | constexpr auto name = magic::raw_name_of>(); 117 | // name => "Point" 118 | 119 | // retrieving a non-type template parameter's raw_name 120 | constexpr auto name2 = magic::raw_name_of<1>(); 121 | // name2 => "1" 122 | 123 | // retrieving a template's raw_name 124 | constexpr auto name3 = magic::raw_name_of_template>(); 125 | // name3 => "Point" 126 | 127 | // retrieving a member's raw_name, C++20 or higher is required 128 | Point point; 129 | constexpr auto name4 = magic::raw_name_of_member<&point.start>(); 130 | // name4 => "start" 131 | 132 | constexpr auto name5 = magic::raw_name_of_member<&point.end>(); 133 | // name5 => "end" 134 | 135 | 136 | enum class Color 137 | { 138 | RED, 139 | GREEN, 140 | BLUE, 141 | }; 142 | 143 | // retrieving an enumeration's raw_name 144 | constexpr auto name6 = magic::raw_name_of(); 145 | // name6 => "RED" 146 | ``` 147 | Please note that the content obtained by these methods may be different on different compilers, please do not use them to build the core part of the code. -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | ![cover](docs/assets/cover.png) 2 | 3 | `magic-cpp`是一个 `header-only`的库,它旨在让您更加方便的使用`C++`,包括了可视化类型名,对结构体枚举的反射等一些列功能,它能帮摆脱那难以阅读的编译器报错信息 4 | 5 | [English](README.md) | [简体中文](README.zh.md) 6 | 7 | - [可视化类型](#可视化类型) 8 | - [基本使用](#基本使用) 9 | - [自定义类型名](#自定义类型名) 10 | - [可配置性](#可配置性) 11 | - [其他功能](#其他功能) 12 | 13 | # 可视化类型 14 | `#include `即可使用本小节的内容,最低版本要求`C++17` 15 | 16 | ## 基本使用 17 | 在使用模板编程的时候常常遇到类型不匹配的困境,尤其是使用像`ranges`这样的库的时候,模板常常深层嵌套难以阅读。没关系,`magic-cpp`可以帮助你可视化类型,让你更加方便的理解类型,考虑下面这个示例 18 | ```cpp 19 | using T = int (*(*(*)(int*))[4])(int*); // 非常难以理解 20 | std::cout << magic::visualize() << std::endl; 21 | ``` 22 | 输出效果: 23 | 24 | ![visualize](docs/assets/sample_ptr.png) 25 | 26 | 或者在平常写代码的时候也可能遇到的 27 | ```cpp 28 | using T = std::function&, std::tuple)>; // 非常难以理解 29 | std::cout << magic::visualize() << std::endl; 30 | ``` 31 | 输出效果: 32 | 33 | ![visualize](docs/assets/std_function.png) 34 | 35 | 几乎常用的所有模板都可以转换这样的树状表示,一目了然有没有。当然有有些类型的完全展开是很冗长,并且不是你期待的样子的,例如`std::string`在`gcc`上的输出效果是这样的 36 | 37 | ![visualize](docs/assets/full_std_string.png) 38 | 39 | ## 自定义类型名 40 | 可以看到,有很多我们不希望看见的信息,没关系!通过显式特化提供自定义的类型名即可 41 | ```cpp 42 | template<> 43 | struct magic::type_info 44 | { 45 | inline static std::string name = "std::string"; 46 | }; 47 | ``` 48 | 这样的话遇到`std::string`就只会显示 49 | 50 | ![visualize](docs/assets/std_string.png) 51 | 52 | 它自定义的名字了,是不是很方便呢?我已经预先在`customization.h`预先定义好了一些`std::size_t`,`std::string`,`std::vector`等常用类型的别名,如果有需要你可以自己尝试修改或者添加 53 | 54 | ## 可配置性 55 | 考虑到有的终端并不支持彩色,或者不支持`utf`字符,这样的话显示就出出现乱码,所以我们提供选项来关闭这些功能 56 | ```cpp 57 | magic::VisualizeOption option; 58 | option.utf_support = false; // 不使用utf8字符 59 | option.color_support = false; // 关闭彩色支持 60 | option.full_name = true; // 使用全名而不是自定义的别名 61 | std::cout << magic::visualize(option) << std::endl; 62 | ``` 63 | 64 | ![visualize](docs/assets/noutf_nocolor_full_std_string.png) 65 | 66 | 如果你的终端是支持彩色的,那么也可以自定义高亮,而不是选择我们默认的配色方案 67 | ```cpp 68 | struct HighlightConfig 69 | { 70 | std::uint32_t type; // 类型: int, double, ... 71 | std::uint32_t nttp; // 非类型模板参数: 1, 2, ... 72 | std::uint32_t tmpl; // 模板: std::vector, ... 73 | std::uint32_t builtin; // 内置复合类型: ptr, ... 74 | std::uint32_t modifier; // 修饰符: const, volatile, ... 75 | std::uint32_t tag; // 标记: R: , M: , ... 76 | }; 77 | 78 | // 默认采用的配色方案是 Dark 79 | constexpr static inline HighlightConfig Dark = { 80 | .type = 0xE5C07B, // 黄色 81 | .nttp = 0xD19A66, // 橙色 82 | .tmpl = 0x0087CE, // 蓝色 83 | .builtin = 0xC678DD, // 紫色 84 | .modifier = 0x98C379, // 绿色 85 | .tag = 0x5C6370, // 灰色 86 | }; 87 | 88 | // 还有一套内置的 Light 风格的配色方案选择 89 | ``` 90 | 直接将其作为第二个函数参数传入即可 91 | ```cpp 92 | magic::VisualizeOption option; // 默认选项 93 | std::cout << magic::visualize(option, magic::Light) << std::endl; 94 | ``` 95 | ## 其他功能 96 | 除了可视化类型以外,我们还支持其它的一些操作 97 | 98 | 获取类型的`display_name` 99 | ```cpp 100 | 101 | 102 | ``` 103 | 104 | 编译期获取类型,非类型模板参数,模板,枚举,成员的`raw_name` 105 | ```cpp 106 | template 107 | struct Point 108 | { 109 | T start; 110 | T end; 111 | }; 112 | 113 | // 获取类型的raw_name 114 | constexpr auto name = magic::raw_name_of>(); 115 | // name => "Point" 116 | 117 | // 获取非类型模板参数的raw_name 118 | constexpr auto name2 = magic::raw_name_of<1>(); 119 | // name2 => "1" 120 | 121 | // 获取模板的raw_name 122 | constexpr auto name3 = magic::raw_name_of_template>(); 123 | // name3 => "Point" 124 | 125 | // 获取成员的raw_name,需要 C++20 或者更高版本 126 | Point point; 127 | constexpr auto name4 = magic::raw_name_of_member<&point.start>(); 128 | // name4 => "start" 129 | 130 | constexpr auto name5 = magic::raw_name_of_member<&point.end>(); 131 | // name5 => "end" 132 | 133 | 134 | enum class Color 135 | { 136 | RED, 137 | GREEN, 138 | BLUE, 139 | }; 140 | 141 | // 获取枚举的raw_name 142 | constexpr auto name6 = magic::raw_name_of(); 143 | // name6 => "RED" 144 | ``` 145 | 请注意,这些方式获取到的内容在不同编译器上可能不同,请不要用它们构建核心部分的代码。 146 | 147 | 148 | -------------------------------------------------------------------------------- /docs/assets/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/16bit-ykiko/magic-cpp/3a2c23c5daf300872b2c5b8777efaca1ea217259/docs/assets/cover.png -------------------------------------------------------------------------------- /docs/assets/full_std_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/16bit-ykiko/magic-cpp/3a2c23c5daf300872b2c5b8777efaca1ea217259/docs/assets/full_std_string.png -------------------------------------------------------------------------------- /docs/assets/noutf_nocolor_full_std_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/16bit-ykiko/magic-cpp/3a2c23c5daf300872b2c5b8777efaca1ea217259/docs/assets/noutf_nocolor_full_std_string.png -------------------------------------------------------------------------------- /docs/assets/sample_ptr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/16bit-ykiko/magic-cpp/3a2c23c5daf300872b2c5b8777efaca1ea217259/docs/assets/sample_ptr.png -------------------------------------------------------------------------------- /docs/assets/std_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/16bit-ykiko/magic-cpp/3a2c23c5daf300872b2c5b8777efaca1ea217259/docs/assets/std_function.png -------------------------------------------------------------------------------- /docs/assets/std_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/16bit-ykiko/magic-cpp/3a2c23c5daf300872b2c5b8777efaca1ea217259/docs/assets/std_string.png -------------------------------------------------------------------------------- /docs/enum.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /generate.py: -------------------------------------------------------------------------------- 1 | import os.path as path 2 | import argparse 3 | 4 | from script.struct_bind import * 5 | from script.template import * 6 | 7 | parser = argparse.ArgumentParser(description='Description of your script.') 8 | parser.add_argument('--fields', '-f', type=int, default=32, 9 | help="the max of supported fields") 10 | parser.add_argument('--templates', '-t', type=int, default=4, 11 | help="the max of supported template parameters") 12 | 13 | args = parser.parse_args() 14 | src = path.join(path.dirname(__file__), "include/magic/generate") 15 | 16 | 17 | def main(): 18 | with open(path.join(src, "struct_bind_of_field_types.code"), "w") as f: 19 | f.write(generate_struct_bind_of_field_types(args.fields)) 20 | 21 | with open(path.join(src, "struct_bind_of_field_access.code"), "w") as f: 22 | f.write(generate_struct_bind_of_field_access(args.fields)) 23 | 24 | with open(path.join(src, "template.code"), "w") as f: 25 | f.write(generate_template_traits(args.templates)) 26 | 27 | 28 | if __name__ == "__main__": 29 | main() 30 | -------------------------------------------------------------------------------- /include/magic/customization.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_customization_H 2 | #define MAGIC_CPP_customization_H 3 | #include "type_tree.h" 4 | 5 | template <> 6 | struct magic::type_info 7 | { 8 | constexpr static const char* name = "std::size_t"; 9 | }; 10 | 11 | template <> 12 | struct magic::type_info 13 | { 14 | constexpr static const char* name = "std::string"; 15 | }; 16 | 17 | template <> 18 | struct magic::type_info 19 | { 20 | constexpr static const char* name = "std::string_view"; 21 | }; 22 | 23 | #endif -------------------------------------------------------------------------------- /include/magic/enum.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_ENUM_H 2 | #define MAGIC_CPP_ENUM_H 3 | 4 | #include "macro.h" 5 | 6 | #ifdef MAGIC_CPP_20_SUPPORT 7 | #include "raw_name.h" 8 | #include 9 | 10 | #define ENUM_SEARCH_RANGE 32 11 | namespace magic 12 | { 13 | template 14 | struct type_info; 15 | } // namespace magic 16 | 17 | namespace magic::details 18 | { 19 | template 20 | consteval std::ptrdiff_t search_possible_enum_start() 21 | { 22 | if constexpr (raw_name_of_enum(N)>() != "") 23 | { 24 | return N; 25 | } 26 | else if constexpr (std::is_signed_v>) 27 | { 28 | if constexpr (raw_name_of_enum(-N)>() != "") 29 | { 30 | return -N; 31 | } 32 | else 33 | { 34 | return search_possible_enum_start(); 35 | } 36 | } 37 | else 38 | { 39 | return search_possible_enum_start(); 40 | } 41 | } 42 | 43 | template ()> 44 | consteval std::ptrdiff_t search_possible_continuous_enum_max() 45 | { 46 | constexpr auto is_end = [](std::index_sequence) 47 | { return (raw_name_of_enum(N + Is)>().empty() && ...); }(std::make_index_sequence<8>{}); 48 | 49 | if constexpr (is_end) 50 | { 51 | return N - 1; 52 | } 53 | else 54 | { 55 | return search_possible_continuous_enum_max(); 56 | } 57 | } 58 | } // namespace magic::details 59 | namespace magic 60 | { 61 | template 62 | requires std::is_enum_v 63 | consteval std::ptrdiff_t enum_start() 64 | { 65 | if constexpr (requires { magic::type_info::start; }) 66 | { 67 | return magic::type_info::start; 68 | } 69 | else 70 | { 71 | return details::search_possible_enum_start(); 72 | } 73 | } 74 | 75 | template 76 | requires std::is_enum_v 77 | consteval std::ptrdiff_t enum_max() 78 | { 79 | if constexpr (requires { magic::type_info::max; }) 80 | { 81 | return magic::type_info::max; 82 | } 83 | else 84 | { 85 | return details::search_possible_continuous_enum_max(); 86 | } 87 | } 88 | 89 | template 90 | consteval bool is_bit_field_enum() 91 | { 92 | if constexpr (requires { magic::type_info::bit; }) 93 | { 94 | return magic::type_info::bit; 95 | } 96 | else 97 | { 98 | return false; 99 | } 100 | } 101 | 102 | } // namespace magic 103 | namespace magic::details 104 | { 105 | template 106 | consteval auto search_possible_bit_field_enum_length() 107 | { 108 | constexpr auto max = sizeof(T) * 8; 109 | std::size_t result = raw_name_of_enum(0)>() != ""; 110 | [&](std::index_sequence) 111 | { ((raw_name_of_enum(1 << Is)>() != "" ? result++ : result), ...); }(std::make_index_sequence{}); 112 | return result; 113 | } 114 | 115 | template 116 | constexpr auto split_initialize(auto&& f) 117 | { 118 | constexpr auto group_num = length / 64; 119 | constexpr auto rest = length % 64; 120 | 121 | [](std::index_sequence, auto&& f, auto&&... args) 122 | { 123 | ( 124 | [](std::index_sequence, auto&& f) { 125 | (f.template operator()(), ...); 126 | }.template operator()(std::make_index_sequence<64>{}, f, args...), 127 | ...); 128 | }(std::make_index_sequence{}, f); 129 | 130 | [](std::index_sequence, auto&& f) 131 | { (f.template operator()(), ...); }(std::make_index_sequence{}, f); 132 | } 133 | 134 | template 135 | constexpr auto enum_names_of_impl() 136 | { 137 | if constexpr (!is_bit_field_enum()) 138 | { 139 | constexpr auto start = enum_start(); 140 | constexpr auto max = enum_max(); 141 | constexpr auto length = max - start + 1; 142 | std::array names{}; 143 | split_initialize([&]() { names[I] = raw_name_of_enum(start + I)>(); }); 144 | return names; 145 | } 146 | else 147 | { 148 | constexpr auto length = search_possible_bit_field_enum_length(); 149 | std::array names{}; 150 | constexpr auto has_zero = raw_name_of_enum(0)>() != ""; 151 | if constexpr (has_zero) 152 | { 153 | names[0] = raw_name_of_enum(0)>(); 154 | split_initialize([&]() { names[I + 1] = raw_name_of_enum(1 << I)>(); }); 155 | } 156 | else 157 | { 158 | split_initialize([&]() { names[I] = raw_name_of_enum(1 << I)>(); }); 159 | } 160 | return names; 161 | } 162 | } 163 | 164 | template 165 | struct enum_names_storage 166 | { 167 | constexpr static auto storage = enum_names_of_impl(); 168 | constexpr static auto& names = storage; 169 | }; 170 | 171 | template 172 | requires std::is_enum_v 173 | struct Field 174 | { 175 | constexpr static std::string_view name() { return raw_name_of_enum(N)>(); } 176 | 177 | using type = T; 178 | 179 | constexpr static std::ptrdiff_t value() { return N; } 180 | 181 | constexpr static std::string_view type_name() { return raw_name_of_enum(); } 182 | }; 183 | 184 | template 185 | requires std::is_enum_v 186 | constexpr void foreach (auto&& f) 187 | { 188 | if constexpr (!is_bit_field_enum()) 189 | { 190 | constexpr auto start = search_possible_enum_start(); 191 | constexpr auto max = search_possible_continuous_enum_max(); 192 | constexpr auto length = max - start + 1; 193 | 194 | split_initialize([&]() { f(Field{}); }); 195 | } 196 | else 197 | { 198 | constexpr auto length = search_possible_bit_field_enum_length(); 199 | constexpr auto has_zero = raw_name_of_enum(0)>() != ""; 200 | if constexpr (has_zero) 201 | { 202 | f(Field{}); 203 | split_initialize([&]() { f(Field{}); }); 204 | } 205 | else 206 | { 207 | split_initialize([&]() { f(Field{}); }); 208 | } 209 | } 210 | } 211 | 212 | } // namespace magic::details 213 | 214 | namespace magic 215 | { 216 | using details::foreach; 217 | 218 | template 219 | requires std::is_enum_v 220 | constexpr auto& enum_names_of() 221 | { 222 | return details::enum_names_storage::names; 223 | } 224 | 225 | template 226 | requires std::is_enum_v 227 | constexpr auto& raw_name_of_enum(T value) 228 | { 229 | constexpr auto start = enum_start(); 230 | return details::enum_names_storage::names[static_cast(value + start)]; 231 | } 232 | } // namespace magic 233 | #endif 234 | #endif // MAGIC_CPP_ENUM_H -------------------------------------------------------------------------------- /include/magic/field_count.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_FIELD_COUNT_H 2 | #define MAGIC_CPP_FIELD_COUNT_H 3 | 4 | #define MAGIC_CPP_C_ARRAY_SUPPORT 1 5 | 6 | #include 7 | namespace magic::details 8 | { 9 | struct Any; 10 | 11 | struct Any 12 | { 13 | constexpr Any(int) {} 14 | 15 | template 16 | requires std::is_copy_constructible_v 17 | operator T&(); 18 | 19 | template 20 | requires std::is_move_constructible_v 21 | operator T&&(); 22 | 23 | struct Empty 24 | { 25 | }; 26 | 27 | template 28 | requires(!std::is_copy_constructible_v && !std::is_move_constructible_v && !std::is_constructible_v) 29 | operator T(); 30 | }; 31 | 32 | template 33 | consteval std::size_t try_initialize_with_n() 34 | { 35 | return [](std::index_sequence) { return requires { T{Any(Is)...}; }; }(std::make_index_sequence{}); 36 | } 37 | 38 | template 39 | consteval std::size_t total_count_of_fields() 40 | { 41 | if constexpr (try_initialize_with_n() && !try_initialize_with_n()) 42 | { 43 | return N; 44 | } 45 | else 46 | { 47 | return total_count_of_fields(); 48 | } 49 | } 50 | } // namespace magic::details 51 | 52 | #if MAGIC_CPP_C_ARRAY_SUPPORT 53 | namespace magic::details 54 | { 55 | 56 | template 57 | consteval std::size_t try_initialize_with_three_parts() 58 | { 59 | return [](std::index_sequence, 60 | std::index_sequence, 61 | std::index_sequence) { 62 | return requires { T{Any(I1)..., {Any(I2)...}, Any(I3)...}; }; 63 | }(std::make_index_sequence{}, std::make_index_sequence{}, std::make_index_sequence{}); 64 | } 65 | 66 | template 67 | constexpr bool try_place_n_in_pos() 68 | { 69 | constexpr auto Total = total_count_of_fields(); 70 | if constexpr (N == 0) 71 | { 72 | return true; 73 | } 74 | else if constexpr (position + N <= Total) 75 | { 76 | return try_initialize_with_three_parts(); 77 | } 78 | else 79 | { 80 | return false; 81 | } 82 | } 83 | 84 | template 85 | constexpr bool has_extra_elements() 86 | { 87 | constexpr auto Total = total_count_of_fields(); 88 | if constexpr (try_initialize_with_three_parts()) 89 | { 90 | return false; 91 | } 92 | else if constexpr (N + 1 <= Max) 93 | { 94 | return has_extra_elements(); 95 | } 96 | else 97 | { 98 | return true; 99 | } 100 | } 101 | 102 | template 103 | constexpr std::size_t search_max_in_pos() 104 | { 105 | constexpr auto Total = total_count_of_fields(); 106 | if constexpr (!has_extra_elements()) 107 | { 108 | return 1; 109 | } 110 | else 111 | { 112 | std::size_t result = 0; 113 | [&](std::index_sequence) 114 | { ((try_place_n_in_pos() ? result = Is : 0), ...); }(std::make_index_sequence()); 115 | return result; 116 | } 117 | } 118 | 119 | template 120 | constexpr auto search_all_extra_index(auto&& array) 121 | { 122 | constexpr auto total = total_count_of_fields(); 123 | constexpr auto value = std::max(search_max_in_pos(), 1); 124 | array[N] = value; 125 | if constexpr (N + value < total) 126 | { 127 | search_all_extra_index(array); 128 | } 129 | } 130 | 131 | template 132 | constexpr auto true_count_of_fields() 133 | { 134 | constexpr auto max = total_count_of_fields(); 135 | if constexpr (max == 0) 136 | { 137 | return 0; 138 | } 139 | else 140 | { 141 | std::array indices = {1}; 142 | search_all_extra_index(indices); 143 | std::size_t result = max; 144 | std::size_t index = 0; 145 | while (index < max) 146 | { 147 | auto n = indices[index]; 148 | result -= n - 1; 149 | index += n; 150 | } 151 | return result; 152 | } 153 | } 154 | } // namespace magic::details 155 | #endif 156 | 157 | namespace magic 158 | { 159 | template 160 | struct type_info; 161 | 162 | /** 163 | * @brief Retrieve the count of fields of a struct 164 | * @warning cannot get the count of fields of a struct which has reference 165 | * type member in gcc 13 because the internal error occurs in below occasion 166 | * @code 167 | * struct Number { operator int&(); }; 168 | * int& x = { Number{} }; 169 | * 170 | * internal compiler error: in reference_binding, at cp/call.cc:2020 171 | * @endcode 172 | * 173 | */ 174 | template 175 | requires std::is_aggregate_v 176 | consteval auto field_count_of() 177 | { 178 | if constexpr (requires { type_info::count; }) 179 | { 180 | return type_info::count; 181 | } 182 | else 183 | { 184 | #if MAGIC_CPP_C_ARRAY_SUPPORT 185 | return details::true_count_of_fields(); 186 | #else 187 | return details::total_count_of_fields(); 188 | #endif 189 | } 190 | } 191 | } // namespace magic 192 | 193 | #endif // MAGIC_CPP_FIELD_COUNT_H -------------------------------------------------------------------------------- /include/magic/function_traits.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_FUNCTION_TRAITS 2 | #define MAGIC_CPP_FUNCTION_TRAITS 3 | 4 | #include 5 | 6 | namespace magic::details 7 | { 8 | template 9 | struct function_traits 10 | { 11 | constexpr static bool is_const = false; 12 | constexpr static bool is_volatile = false; 13 | constexpr static bool is_lvalue_ref = false; 14 | constexpr static bool is_rvalue_ref = false; 15 | constexpr static bool is_noexcept = false; 16 | constexpr static bool is_c_variadic = false; 17 | }; 18 | 19 | #define MAGIC_CPP_FUNCTION_TRAITS_IMPL(modifier, const, volatile, lref, rref, noexcept) \ 20 | template \ 21 | struct function_traits \ 22 | { \ 23 | using return_type = R; \ 24 | using args_type = std::tuple; \ 25 | using primary_type = R(Args...); \ 26 | constexpr static bool is_const = const; \ 27 | constexpr static bool is_volatile = volatile; \ 28 | constexpr static bool is_lvalue_ref = lref; \ 29 | constexpr static bool is_rvalue_ref = rref; \ 30 | constexpr static bool is_noexcept = noexcept; \ 31 | constexpr static bool is_c_variadic = false; \ 32 | }; 33 | 34 | #define MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(modifier, const, volatile, lref, rref, noexcept) \ 35 | template \ 36 | struct function_traits \ 37 | { \ 38 | using return_type = R; \ 39 | using args_type = std::tuple; \ 40 | using primary_type = R(Args...); \ 41 | constexpr static bool is_const = const; \ 42 | constexpr static bool is_volatile = volatile; \ 43 | constexpr static bool is_lvalue_ref = lref; \ 44 | constexpr static bool is_rvalue_ref = rref; \ 45 | constexpr static bool is_noexcept = noexcept; \ 46 | constexpr static bool is_c_variadic = true; \ 47 | }; 48 | 49 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(, false, false, false, false, false) 50 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const, true, false, false, false, false) 51 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(volatile, false, true, false, false, false) 52 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const volatile, true, true, false, false, false) 53 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(&, false, false, true, false, false) 54 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const&, true, false, true, false, false) 55 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(volatile&, false, true, true, false, false) 56 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const volatile&, true, true, true, false, false) 57 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(&&, false, false, false, true, false) 58 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const&&, true, false, false, true, false) 59 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(volatile&&, false, true, false, true, false) 60 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const volatile&&, true, true, false, true, false) 61 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(noexcept, false, false, false, false, true) 62 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const noexcept, true, false, false, false, true) 63 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(volatile noexcept, false, true, false, false, true) 64 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const volatile noexcept, true, true, false, false, true) 65 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(& noexcept, false, false, true, false, true) 66 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const& noexcept, true, false, true, false, true) 67 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(volatile& noexcept, false, true, true, false, true) 68 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const volatile& noexcept, true, true, true, false, true) 69 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(&& noexcept, false, false, false, true, true) 70 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const&& noexcept, true, false, false, true, true) 71 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(volatile&& noexcept, false, true, false, true, true) 72 | MAGIC_CPP_FUNCTION_TRAITS_IMPL(const volatile&& noexcept, true, true, false, true, true) 73 | 74 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(, false, false, false, false, false) 75 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const, true, false, false, false, false) 76 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(volatile, false, true, false, false, false) 77 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const volatile, true, true, false, false, false) 78 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(&, false, false, true, false, false) 79 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const&, true, false, true, false, false) 80 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(volatile&, false, true, true, false, false) 81 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const volatile&, true, true, true, false, false) 82 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(&&, false, false, false, true, false) 83 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const&&, true, false, false, true, false) 84 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(volatile&&, false, true, false, true, false) 85 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const volatile&&, true, true, false, true, false) 86 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(noexcept, false, false, false, false, true) 87 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const noexcept, true, false, false, false, true) 88 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(volatile noexcept, false, true, false, false, true) 89 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const volatile noexcept, true, true, false, false, true) 90 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(& noexcept, false, false, true, false, true) 91 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const& noexcept, true, false, true, false, true) 92 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(volatile& noexcept, false, true, true, false, true) 93 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const volatile& noexcept, true, true, true, false, true) 94 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(&& noexcept, false, false, false, true, true) 95 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const&& noexcept, true, false, false, true, true) 96 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(volatile&& noexcept, false, true, false, true, true) 97 | MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL(const volatile&& noexcept, true, true, false, true, true) 98 | 99 | #undef MAGIC_CPP_FUNCTION_TRAITS_IMPL 100 | #undef MAGIC_CPP_FUNCTION_TRAITS_VARIADIC_IMPL 101 | 102 | template 103 | struct args_type_of_impl; 104 | 105 | template 106 | struct args_type_of_impl>> 107 | { 108 | using type = typename function_traits::args_type; 109 | }; 110 | } // namespace magic::details 111 | 112 | namespace magic 113 | { 114 | template 115 | using return_type_of = typename details::function_traits::return_type; 116 | 117 | template 118 | using args_type_of = typename details::args_type_of_impl::type; 119 | 120 | template 121 | using first_arg_type_of = std::tuple_element_t<0, args_type_of>; 122 | 123 | template 124 | using second_arg_type_of = std::tuple_element_t<1, args_type_of>; 125 | 126 | template 127 | using third_arg_type_of = std::tuple_element_t<2, args_type_of>; 128 | 129 | template 130 | using primary_type_of = typename details::function_traits::primary_type; 131 | 132 | template 133 | constexpr static std::size_t fn_arity_v = std::tuple_size_v>; 134 | 135 | template 136 | constexpr static bool is_const_fn_v = details::function_traits::is_const; 137 | 138 | template 139 | constexpr static bool is_volatile_fn_v = details::function_traits::is_volatile; 140 | 141 | template 142 | constexpr static bool is_lvalue_ref_fn_v = details::function_traits::is_lvalue_ref; 143 | 144 | template 145 | constexpr static bool is_rvalue_ref_fn_v = details::function_traits::is_rvalue_ref; 146 | 147 | template 148 | constexpr static bool is_noexcept_fn_v = details::function_traits::is_noexcept; 149 | 150 | template 151 | constexpr static bool is_c_variadic_fn_v = details::function_traits::is_c_variadic; 152 | } // namespace magic 153 | 154 | #endif // MAGIC_CPP_FUNCTION_TRAITS 155 | -------------------------------------------------------------------------------- /include/magic/generate/struct_bind_of_field_access.code: -------------------------------------------------------------------------------- 1 | if constexpr (N == 0) 2 | { 3 | static_assert(N != 0, "the object has no fields"); 4 | } 5 | else if constexpr (N == 1) 6 | { 7 | auto&& [v0] = object; 8 | return std::get (std::forward_as_tuple(v0)); 9 | } 10 | else if constexpr (N == 2) 11 | { 12 | auto&& [v0, v1] = object; 13 | return std::get (std::forward_as_tuple(v0, v1)); 14 | } 15 | else if constexpr (N == 3) 16 | { 17 | auto&& [v0, v1, v2] = object; 18 | return std::get (std::forward_as_tuple(v0, v1, v2)); 19 | } 20 | else if constexpr (N == 4) 21 | { 22 | auto&& [v0, v1, v2, v3] = object; 23 | return std::get (std::forward_as_tuple(v0, v1, v2, v3)); 24 | } 25 | else if constexpr (N == 5) 26 | { 27 | auto&& [v0, v1, v2, v3, v4] = object; 28 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4)); 29 | } 30 | else if constexpr (N == 6) 31 | { 32 | auto&& [v0, v1, v2, v3, v4, v5] = object; 33 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5)); 34 | } 35 | else if constexpr (N == 7) 36 | { 37 | auto&& [v0, v1, v2, v3, v4, v5, v6] = object; 38 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6)); 39 | } 40 | else if constexpr (N == 8) 41 | { 42 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7] = object; 43 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7)); 44 | } 45 | else if constexpr (N == 9) 46 | { 47 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8] = object; 48 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8)); 49 | } 50 | else if constexpr (N == 10) 51 | { 52 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9] = object; 53 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9)); 54 | } 55 | else if constexpr (N == 11) 56 | { 57 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] = object; 58 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)); 59 | } 60 | else if constexpr (N == 12) 61 | { 62 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11] = object; 63 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)); 64 | } 65 | else if constexpr (N == 13) 66 | { 67 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12] = object; 68 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)); 69 | } 70 | else if constexpr (N == 14) 71 | { 72 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13] = object; 73 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)); 74 | } 75 | else if constexpr (N == 15) 76 | { 77 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14] = object; 78 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)); 79 | } 80 | else if constexpr (N == 16) 81 | { 82 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15] = object; 83 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)); 84 | } 85 | else if constexpr (N == 17) 86 | { 87 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16] = object; 88 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)); 89 | } 90 | else if constexpr (N == 18) 91 | { 92 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17] = object; 93 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)); 94 | } 95 | else if constexpr (N == 19) 96 | { 97 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18] = object; 98 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)); 99 | } 100 | else if constexpr (N == 20) 101 | { 102 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19] = object; 103 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)); 104 | } 105 | else if constexpr (N == 21) 106 | { 107 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20] = object; 108 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)); 109 | } 110 | else if constexpr (N == 22) 111 | { 112 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21] = object; 113 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)); 114 | } 115 | else if constexpr (N == 23) 116 | { 117 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22] = object; 118 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)); 119 | } 120 | else if constexpr (N == 24) 121 | { 122 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23] = object; 123 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)); 124 | } 125 | else if constexpr (N == 25) 126 | { 127 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24] = object; 128 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)); 129 | } 130 | else if constexpr (N == 26) 131 | { 132 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25] = object; 133 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)); 134 | } 135 | else if constexpr (N == 27) 136 | { 137 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26] = object; 138 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)); 139 | } 140 | else if constexpr (N == 28) 141 | { 142 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27] = object; 143 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)); 144 | } 145 | else if constexpr (N == 29) 146 | { 147 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28] = object; 148 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)); 149 | } 150 | else if constexpr (N == 30) 151 | { 152 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29] = object; 153 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)); 154 | } 155 | else if constexpr (N == 31) 156 | { 157 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30] = object; 158 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)); 159 | } 160 | else if constexpr (N == 32) 161 | { 162 | auto&& [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31] = object; 163 | return std::get (std::forward_as_tuple(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)); 164 | } 165 | else 166 | { 167 | static_assert(N <= 32, "the max of supported fields is 32"); 168 | } -------------------------------------------------------------------------------- /include/magic/generate/struct_bind_of_field_types.code: -------------------------------------------------------------------------------- 1 | 2 | if constexpr (N == 0) 3 | { 4 | return std::type_identity>{}; 5 | } 6 | else if constexpr (N == 1) 7 | { 8 | auto [v0] = object; 9 | return std::type_identity>{}; 10 | } 11 | else if constexpr (N == 2) 12 | { 13 | auto [v0, v1] = object; 14 | return std::type_identity>{}; 15 | } 16 | else if constexpr (N == 3) 17 | { 18 | auto [v0, v1, v2] = object; 19 | return std::type_identity>{}; 20 | } 21 | else if constexpr (N == 4) 22 | { 23 | auto [v0, v1, v2, v3] = object; 24 | return std::type_identity>{}; 25 | } 26 | else if constexpr (N == 5) 27 | { 28 | auto [v0, v1, v2, v3, v4] = object; 29 | return std::type_identity>{}; 30 | } 31 | else if constexpr (N == 6) 32 | { 33 | auto [v0, v1, v2, v3, v4, v5] = object; 34 | return std::type_identity>{}; 35 | } 36 | else if constexpr (N == 7) 37 | { 38 | auto [v0, v1, v2, v3, v4, v5, v6] = object; 39 | return std::type_identity>{}; 40 | } 41 | else if constexpr (N == 8) 42 | { 43 | auto [v0, v1, v2, v3, v4, v5, v6, v7] = object; 44 | return std::type_identity>{}; 45 | } 46 | else if constexpr (N == 9) 47 | { 48 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8] = object; 49 | return std::type_identity>{}; 50 | } 51 | else if constexpr (N == 10) 52 | { 53 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9] = object; 54 | return std::type_identity>{}; 55 | } 56 | else if constexpr (N == 11) 57 | { 58 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] = object; 59 | return std::type_identity>{}; 60 | } 61 | else if constexpr (N == 12) 62 | { 63 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11] = object; 64 | return std::type_identity>{}; 65 | } 66 | else if constexpr (N == 13) 67 | { 68 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12] = object; 69 | return std::type_identity>{}; 70 | } 71 | else if constexpr (N == 14) 72 | { 73 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13] = object; 74 | return std::type_identity>{}; 75 | } 76 | else if constexpr (N == 15) 77 | { 78 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14] = object; 79 | return std::type_identity>{}; 80 | } 81 | else if constexpr (N == 16) 82 | { 83 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15] = object; 84 | return std::type_identity>{}; 85 | } 86 | else if constexpr (N == 17) 87 | { 88 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16] = object; 89 | return std::type_identity>{}; 90 | } 91 | else if constexpr (N == 18) 92 | { 93 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17] = object; 94 | return std::type_identity>{}; 95 | } 96 | else if constexpr (N == 19) 97 | { 98 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18] = object; 99 | return std::type_identity>{}; 100 | } 101 | else if constexpr (N == 20) 102 | { 103 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19] = object; 104 | return std::type_identity>{}; 105 | } 106 | else if constexpr (N == 21) 107 | { 108 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20] = object; 109 | return std::type_identity>{}; 110 | } 111 | else if constexpr (N == 22) 112 | { 113 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21] = object; 114 | return std::type_identity>{}; 115 | } 116 | else if constexpr (N == 23) 117 | { 118 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22] = object; 119 | return std::type_identity>{}; 120 | } 121 | else if constexpr (N == 24) 122 | { 123 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23] = object; 124 | return std::type_identity>{}; 125 | } 126 | else if constexpr (N == 25) 127 | { 128 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24] = object; 129 | return std::type_identity>{}; 130 | } 131 | else if constexpr (N == 26) 132 | { 133 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25] = object; 134 | return std::type_identity>{}; 135 | } 136 | else if constexpr (N == 27) 137 | { 138 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26] = object; 139 | return std::type_identity>{}; 140 | } 141 | else if constexpr (N == 28) 142 | { 143 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27] = object; 144 | return std::type_identity>{}; 145 | } 146 | else if constexpr (N == 29) 147 | { 148 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28] = object; 149 | return std::type_identity>{}; 150 | } 151 | else if constexpr (N == 30) 152 | { 153 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29] = object; 154 | return std::type_identity>{}; 155 | } 156 | else if constexpr (N == 31) 157 | { 158 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30] = object; 159 | return std::type_identity>{}; 160 | } 161 | else if constexpr (N == 32) 162 | { 163 | auto [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31] = object; 164 | return std::type_identity>{}; 165 | } 166 | else 167 | { 168 | static_assert(N <= 32, "the max of supported fields is 32"); 169 | } -------------------------------------------------------------------------------- /include/magic/generate/template.code: -------------------------------------------------------------------------------- 1 | 2 | template 3 | struct template_traits_1 : std::false_type {}; 4 | 5 | template class U> 6 | constexpr auto template_full_name_1() 7 | { 8 | return MAGIC_CPP_FUNCTION_NAME; 9 | } 10 | template class T, typename... Ts> 11 | struct template_traits_1> : std::true_type 12 | { 13 | constexpr static auto full_name = template_full_name_1(); 14 | using args_type = std::tuple...>; 15 | }; 16 | 17 | template class U> 18 | constexpr auto template_full_name_1() 19 | { 20 | return MAGIC_CPP_FUNCTION_NAME; 21 | } 22 | template class T, auto... Ts> 23 | struct template_traits_1> : std::true_type 24 | { 25 | constexpr static auto full_name = template_full_name_1(); 26 | using args_type = std::tuple...>; 27 | }; 28 | 29 | template 30 | struct template_traits_2 : std::false_type {}; 31 | 32 | template class U> 33 | constexpr auto template_full_name_2() 34 | { 35 | return MAGIC_CPP_FUNCTION_NAME; 36 | } 37 | template class T, typename T1, auto... Ts> 38 | struct template_traits_2> : std::true_type 39 | { 40 | constexpr static auto full_name = template_full_name_2(); 41 | using args_type = std::tuple, identity...>; 42 | }; 43 | 44 | template class U> 45 | constexpr auto template_full_name_2() 46 | { 47 | return MAGIC_CPP_FUNCTION_NAME; 48 | } 49 | template class T, auto T1, typename... Ts> 50 | struct template_traits_2> : std::true_type 51 | { 52 | constexpr static auto full_name = template_full_name_2(); 53 | using args_type = std::tuple, identity...>; 54 | }; 55 | 56 | template 57 | struct template_traits_3 : std::false_type {}; 58 | 59 | template class U> 60 | constexpr auto template_full_name_3() 61 | { 62 | return MAGIC_CPP_FUNCTION_NAME; 63 | } 64 | template class T, typename T1, typename T2, auto... Ts> 65 | struct template_traits_3> : std::true_type 66 | { 67 | constexpr static auto full_name = template_full_name_3(); 68 | using args_type = std::tuple, identity, identity...>; 69 | }; 70 | 71 | template class U> 72 | constexpr auto template_full_name_3() 73 | { 74 | return MAGIC_CPP_FUNCTION_NAME; 75 | } 76 | template class T, typename T1, auto T2, typename... Ts> 77 | struct template_traits_3> : std::true_type 78 | { 79 | constexpr static auto full_name = template_full_name_3(); 80 | using args_type = std::tuple, identity, identity...>; 81 | }; 82 | 83 | template class U> 84 | constexpr auto template_full_name_3() 85 | { 86 | return MAGIC_CPP_FUNCTION_NAME; 87 | } 88 | template class T, auto T1, typename T2, auto... Ts> 89 | struct template_traits_3> : std::true_type 90 | { 91 | constexpr static auto full_name = template_full_name_3(); 92 | using args_type = std::tuple, identity, identity...>; 93 | }; 94 | 95 | template class U> 96 | constexpr auto template_full_name_3() 97 | { 98 | return MAGIC_CPP_FUNCTION_NAME; 99 | } 100 | template class T, auto T1, auto T2, typename... Ts> 101 | struct template_traits_3> : std::true_type 102 | { 103 | constexpr static auto full_name = template_full_name_3(); 104 | using args_type = std::tuple, identity, identity...>; 105 | }; 106 | 107 | template 108 | struct template_traits_4 : std::false_type {}; 109 | 110 | template class U> 111 | constexpr auto template_full_name_4() 112 | { 113 | return MAGIC_CPP_FUNCTION_NAME; 114 | } 115 | template class T, typename T1, typename T2, typename T3, auto... Ts> 116 | struct template_traits_4> : std::true_type 117 | { 118 | constexpr static auto full_name = template_full_name_4(); 119 | using args_type = std::tuple, identity, identity, identity...>; 120 | }; 121 | 122 | template class U> 123 | constexpr auto template_full_name_4() 124 | { 125 | return MAGIC_CPP_FUNCTION_NAME; 126 | } 127 | template class T, typename T1, typename T2, auto T3, typename... Ts> 128 | struct template_traits_4> : std::true_type 129 | { 130 | constexpr static auto full_name = template_full_name_4(); 131 | using args_type = std::tuple, identity, identity, identity...>; 132 | }; 133 | 134 | template class U> 135 | constexpr auto template_full_name_4() 136 | { 137 | return MAGIC_CPP_FUNCTION_NAME; 138 | } 139 | template class T, typename T1, auto T2, typename T3, auto... Ts> 140 | struct template_traits_4> : std::true_type 141 | { 142 | constexpr static auto full_name = template_full_name_4(); 143 | using args_type = std::tuple, identity, identity, identity...>; 144 | }; 145 | 146 | template class U> 147 | constexpr auto template_full_name_4() 148 | { 149 | return MAGIC_CPP_FUNCTION_NAME; 150 | } 151 | template class T, typename T1, auto T2, auto T3, typename... Ts> 152 | struct template_traits_4> : std::true_type 153 | { 154 | constexpr static auto full_name = template_full_name_4(); 155 | using args_type = std::tuple, identity, identity, identity...>; 156 | }; 157 | 158 | template class U> 159 | constexpr auto template_full_name_4() 160 | { 161 | return MAGIC_CPP_FUNCTION_NAME; 162 | } 163 | template class T, auto T1, typename T2, typename T3, auto... Ts> 164 | struct template_traits_4> : std::true_type 165 | { 166 | constexpr static auto full_name = template_full_name_4(); 167 | using args_type = std::tuple, identity, identity, identity...>; 168 | }; 169 | 170 | template class U> 171 | constexpr auto template_full_name_4() 172 | { 173 | return MAGIC_CPP_FUNCTION_NAME; 174 | } 175 | template class T, auto T1, typename T2, auto T3, typename... Ts> 176 | struct template_traits_4> : std::true_type 177 | { 178 | constexpr static auto full_name = template_full_name_4(); 179 | using args_type = std::tuple, identity, identity, identity...>; 180 | }; 181 | 182 | template class U> 183 | constexpr auto template_full_name_4() 184 | { 185 | return MAGIC_CPP_FUNCTION_NAME; 186 | } 187 | template class T, auto T1, auto T2, typename T3, auto... Ts> 188 | struct template_traits_4> : std::true_type 189 | { 190 | constexpr static auto full_name = template_full_name_4(); 191 | using args_type = std::tuple, identity, identity, identity...>; 192 | }; 193 | 194 | template class U> 195 | constexpr auto template_full_name_4() 196 | { 197 | return MAGIC_CPP_FUNCTION_NAME; 198 | } 199 | template class T, auto T1, auto T2, auto T3, typename... Ts> 200 | struct template_traits_4> : std::true_type 201 | { 202 | constexpr static auto full_name = template_full_name_4(); 203 | using args_type = std::tuple, identity, identity, identity...>; 204 | }; 205 | 206 | template 207 | constexpr bool is_template() 208 | { 209 | if constexpr(template_traits_1::value) 210 | { 211 | return true; 212 | } 213 | else if constexpr(template_traits_2::value) 214 | { 215 | return true; 216 | } 217 | else if constexpr(template_traits_3::value) 218 | { 219 | return true; 220 | } 221 | else if constexpr(template_traits_4::value) 222 | { 223 | return true; 224 | } 225 | else 226 | { 227 | return false; 228 | } 229 | } 230 | 231 | template 232 | constexpr auto template_traits_impl() 233 | { 234 | if constexpr(template_traits_1::value) 235 | { 236 | return template_traits_1(); 237 | } 238 | else if constexpr(template_traits_2::value) 239 | { 240 | return template_traits_2(); 241 | } 242 | else if constexpr(template_traits_3::value) 243 | { 244 | return template_traits_3(); 245 | } 246 | else if constexpr(template_traits_4::value) 247 | { 248 | return template_traits_4(); 249 | } 250 | else 251 | { 252 | static_assert(is_template(), "not supported"); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /include/magic/macro.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_MACRO_H 2 | #define MAGIC_CPP_MACRO_H 3 | 4 | #if __has_include() 5 | #include 6 | #endif 7 | 8 | #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L 9 | #define MAGIC_CPP_20_SUPPORT 10 | #else 11 | 12 | #endif 13 | 14 | #include 15 | // fix for msvc-clang, whose function_name will not show the full name of the function 16 | 17 | namespace magic 18 | { 19 | 20 | /** 21 | * if the compiler supports std::source_location, then use it to get the function name 22 | * otherwise, use the macro __PRETTY_FUNCTION__ or __FUNCSIG__ to get the function name 23 | * special case for msvc-clang, whose function_name in sourec_location will not show the full name of the function 24 | * so we use __FUNCSIG__ to get the function name 25 | */ 26 | 27 | #if __clang__ && _MSC_VER 28 | #define MAGIC_CPP_FUNCTION_NAME (__FUNCSIG__) 29 | 30 | #elif __cpp_lib_source_location 31 | #define MAGIC_CPP_FUNCTION_NAME (std::source_location::current().function_name()) 32 | 33 | #elif (__clang__ || __GNUC__) && (!_MSC_VER) 34 | #define MAGIC_CPP_FUNCTION_NAME (__PRETTY_FUNCTION__) 35 | 36 | #elif _MSC_VER 37 | #define MAGIC_CPP_FUNCTION_NAME (__FUNCSIG__) 38 | 39 | #else 40 | staic_assert(false, "Unsupported compiler"); 41 | 42 | #endif // source_location 43 | 44 | inline void unreachable [[noreturn]] () 45 | { 46 | // Uses compiler specific extensions if possible. 47 | // Even if no extension is used, undefined behavior is still raised by 48 | // an empty function body and the noreturn attribute. 49 | #if __GNUC__ || __clang__ // GCC, Clang, ICC 50 | __builtin_unreachable(); 51 | #elif _MSC_VER // MSVC 52 | __assume(false); 53 | #endif 54 | } 55 | } // namespace magic 56 | 57 | #endif // MAGIC_CPP_MACRO_H -------------------------------------------------------------------------------- /include/magic/raw_name.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_RAW_NAME_H 2 | #define MAGIC_CPP_RAW_NAME_H 3 | 4 | #include "template_traits.h" 5 | #include 6 | 7 | namespace magic 8 | { 9 | template 10 | constexpr auto raw_name_of() 11 | { 12 | std::string_view name = MAGIC_CPP_FUNCTION_NAME; 13 | #if __GNUC__ || __clang__ 14 | std::size_t start = name.find('=') + 2; 15 | std::size_t end = name.size() - 1; 16 | return std::string_view{name.data() + start, end - start}; 17 | #elif _MSC_VER 18 | std::size_t start = name.find('<') + 1; 19 | std::size_t end = name.rfind(">("); 20 | name = std::string_view{name.data() + start, end - start}; 21 | start = name.find(' '); 22 | return start == std::string_view::npos ? name : std::string_view{name.data() + start + 1, name.size() - start - 1}; 23 | #else 24 | static_assert(false, "Unsupported compiler"); 25 | #endif 26 | } 27 | 28 | template 29 | constexpr auto raw_name_of_template() 30 | { 31 | std::string_view name = details::template_traits::full_name; 32 | #if __GNUC__ || __clang__ 33 | std::size_t start = name.find('=') + 2; 34 | std::size_t end = name.size() - 1; 35 | return std::string_view{name.data() + start, end - start}; 36 | #elif _MSC_VER 37 | std::size_t start = name.find('<') + 1; 38 | std::size_t end = name.rfind(">("); 39 | name = std::string_view{name.data() + start, end - start}; 40 | start = name.find(' '); 41 | return start == std::string_view::npos ? name : std::string_view{name.data() + start + 1, name.size() - start - 1}; 42 | #else 43 | static_assert(false, "Unsupported compiler"); 44 | #endif 45 | } 46 | 47 | template 48 | constexpr auto raw_name_of() 49 | { 50 | std::string_view name = MAGIC_CPP_FUNCTION_NAME; 51 | #if __GNUC__ || __clang__ 52 | std::size_t start = name.find('=') + 2; 53 | std::size_t end = name.size() - 1; 54 | return std::string_view{name.data() + start, end - start}; 55 | #elif _MSC_VER 56 | std::size_t start = name.find('<') + 1; 57 | std::size_t end = name.rfind(">("); 58 | name = std::string_view{name.data() + start, end - start}; 59 | start = name.find(' '); 60 | return start == std::string_view::npos ? name : std::string_view{name.data() + start + 1, name.size() - start - 1}; 61 | #else 62 | static_assert(false, "Unsupported compiler"); 63 | #endif 64 | } 65 | 66 | template 67 | constexpr auto raw_name_of_enum() 68 | { 69 | std::string_view name = MAGIC_CPP_FUNCTION_NAME; 70 | #if __GNUC__ || __clang__ 71 | std::size_t start = name.find('=') + 2; 72 | std::size_t end = name.size() - 1; 73 | name = std::string_view{name.data() + start, end - start}; 74 | start = name.rfind("::"); 75 | return start == std::string_view::npos ? name : std::string_view{name.data() + start + 2, name.size() - start - 2}; 76 | #elif _MSC_VER 77 | std::size_t start = name.find('<') + 1; 78 | std::size_t end = name.rfind(">("); 79 | name = std::string_view{name.data() + start, end - start}; 80 | start = name.rfind("::"); 81 | return start == std::string_view::npos ? name : std::string_view{name.data() + start + 2, name.size() - start - 2}; 82 | #else 83 | static_assert(false, "Unsupported compiler"); 84 | #endif 85 | } 86 | 87 | #ifdef MAGIC_CPP_20_SUPPORT 88 | template 89 | struct Wrapper 90 | { 91 | T a; 92 | constexpr Wrapper(T value) : a(value) {} 93 | }; 94 | 95 | template 96 | constexpr auto raw_name_of_member() 97 | { 98 | std::string_view name = MAGIC_CPP_FUNCTION_NAME; 99 | #if __GNUC__ && (!__clang__) && (!_MSC_VER) 100 | std::size_t start = name.rfind("::") + 2; 101 | std::size_t end = name.rfind(')'); 102 | return name.substr(start, end - start); 103 | #elif __clang__ 104 | std::size_t start = name.rfind(".") + 1; 105 | std::size_t end = name.rfind('}'); 106 | return name.substr(start, end - start); 107 | #elif _MSC_VER 108 | std::size_t start = name.rfind("->") + 2; 109 | std::size_t end = name.rfind('}'); 110 | return name.substr(start, end - start); 111 | #else 112 | static_assert(false, "Not supported compiler"); 113 | #endif 114 | } 115 | #endif // MAGIC_CPP_20_SUPPORT 116 | } // namespace magic 117 | 118 | #endif // MAGIC_CPP_RAW_NAME_H -------------------------------------------------------------------------------- /include/magic/struct.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_STRUCT_H 2 | #define MAGIC_CPP_STRUCT_H 3 | 4 | #include "macro.h" 5 | 6 | #ifdef MAGIC_CPP_20_SUPPORT 7 | 8 | #include "field_count.h" 9 | #include "raw_name.h" 10 | 11 | namespace magic::details 12 | { 13 | 14 | template 15 | constexpr auto field_types_of_impl(T object) 16 | { 17 | constexpr auto N = field_count_of(); 18 | #include "generate/struct_bind_of_field_types.code" 19 | } 20 | 21 | template 22 | constexpr auto&& field_of_impl(auto&& object) 23 | { 24 | using T = std::remove_cvref_t; 25 | constexpr auto N = field_count_of(); 26 | #include "generate/struct_bind_of_field_access.code" 27 | } 28 | 29 | } // namespace magic::details 30 | 31 | namespace magic 32 | { 33 | template 34 | requires std::is_aggregate_v 35 | using field_types_of = typename decltype(details::field_types_of_impl(std::declval()))::type; 36 | 37 | template 38 | requires std::is_aggregate_v 39 | using field_type_of = std::tuple_element_t>; 40 | 41 | template 42 | constexpr auto&& field_of(auto&& object) requires std::is_aggregate_v> 43 | { 44 | return details::field_of_impl(std::forward(object)); 45 | } 46 | } // namespace magic 47 | 48 | namespace magic::details 49 | { 50 | template 51 | struct Storage 52 | { 53 | inline static T value{}; 54 | }; 55 | 56 | template 57 | struct Names_Storage 58 | { 59 | constexpr static auto value = [](std::index_sequence) 60 | { 61 | constexpr auto& object = Storage::value; 62 | return std::array{raw_name_of_member<&field_of_impl(object)>()...}; 63 | }(std::make_index_sequence()>{}); 64 | }; 65 | 66 | } // namespace magic::details 67 | 68 | namespace magic 69 | { 70 | template 71 | requires(std::is_aggregate_v && std::is_default_constructible_v) 72 | constexpr auto& field_names_of() 73 | { 74 | return details::Names_Storage::value; 75 | } 76 | 77 | template 78 | requires(std::is_aggregate_v && std::is_default_constructible_v) 79 | constexpr std::string_view field_name_of(std::size_t Index) 80 | { 81 | return field_names_of()[Index]; 82 | } 83 | 84 | template 85 | struct Field 86 | { 87 | private: 88 | T m_value; 89 | 90 | public: 91 | constexpr Field(T value) : m_value(std::forward(value)) {} 92 | 93 | using type = field_type_of, N>; 94 | 95 | constexpr static std::string_view name() { return field_name_of>(N); } 96 | 97 | constexpr static std::string_view type_name() { return raw_name_of(); } 98 | 99 | constexpr static std::size_t index() { return N; } 100 | 101 | constexpr auto&& value() { return field_of(std::forward(m_value)); } 102 | 103 | operator auto &&() { return value(); } 104 | 105 | template 106 | friend constexpr void foreach (Object&& object, auto&& functor); 107 | }; 108 | 109 | template 110 | concept FIELD = requires(T t) { 111 | { 112 | t.name() 113 | } -> std::same_as; 114 | { 115 | t.type_name() 116 | } -> std::same_as; 117 | { 118 | t.index() 119 | } -> std::same_as; 120 | { 121 | t.value() 122 | }; 123 | }; 124 | 125 | template 126 | constexpr void foreach (Object&& object, auto&& functor) 127 | { 128 | using T = std::remove_cvref_t; 129 | constexpr auto condition = std::is_aggregate_v && std::is_default_constructible_v; 130 | static_assert(condition, "T must be an aggregate type and default constructible"); 131 | if constexpr (condition) 132 | { 133 | [&](std::index_sequence) 134 | { (functor(Field{std::forward(object)}), ...); }(std::make_index_sequence()>{}); 135 | } 136 | } 137 | } // namespace magic 138 | #endif 139 | #endif // MAGIC_CPP_STRUCT_H -------------------------------------------------------------------------------- /include/magic/template_traits.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_TEMPLATE_TRAITS_H 2 | #define MAGIC_CPP_TEMPLATE_TRAITS_H 3 | 4 | #include "macro.h" 5 | #include 6 | 7 | namespace magic 8 | { 9 | template 10 | struct identity 11 | { 12 | using type = T; 13 | constexpr static bool has_value = false; 14 | }; 15 | 16 | template 17 | struct identity 18 | { 19 | using type = T; 20 | constexpr static T value = Value; 21 | constexpr static bool has_value = true; 22 | }; 23 | } // namespace magic 24 | 25 | namespace magic::details 26 | { 27 | // clang-format off 28 | #include "generate/template.code" 29 | // clang-format on 30 | 31 | template 32 | using template_traits = decltype(details::template_traits_impl()); 33 | 34 | template 35 | struct args_type_of_impl; 36 | 37 | template 38 | struct args_type_of_impl(), void>>> 39 | { 40 | using type = typename template_traits::args_type; 41 | }; 42 | 43 | } // namespace magic::details 44 | 45 | namespace magic 46 | { 47 | template 48 | constexpr static bool is_template_class_v = details::is_template(); 49 | 50 | template 51 | using args_type_of = typename details::args_type_of_impl::type; 52 | 53 | template 54 | constexpr static std::size_t template_arity_v = std::tuple_size_v>; 55 | 56 | } // namespace magic 57 | 58 | #endif // MAGIC_CPP_TEMPLATE_TRAITS_H -------------------------------------------------------------------------------- /include/magic/type_traits.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_TYPE_TRAITS_H 2 | #define MAGIC_CPP_TYPE_TRAITS_H 3 | 4 | #include "function_traits.h" 5 | #include "macro.h" 6 | #include "template_traits.h" 7 | 8 | namespace magic 9 | { 10 | 11 | template 12 | struct member_ptr_traits; 13 | 14 | template 15 | struct member_ptr_traits 16 | { 17 | using class_type = C; 18 | using member_type = M; 19 | }; 20 | 21 | template 22 | using class_type_of_pointer = typename member_ptr_traits::class_type; 23 | 24 | template 25 | using member_type_of_pointer = typename member_ptr_traits::member_type; 26 | 27 | } // namespace magic 28 | 29 | #endif -------------------------------------------------------------------------------- /include/magic/type_tree.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_TYPE_TREE_H 2 | #define MAGIC_CPP_TYPE_TREE_H 3 | 4 | #include "raw_name.h" 5 | #include "type_traits.h" 6 | #include 7 | #include 8 | #include // for std::uint*_t 9 | 10 | namespace magic 11 | { 12 | template 13 | struct type_info; 14 | } 15 | 16 | namespace magic::details 17 | { 18 | template 19 | struct has_name : std::false_type 20 | { 21 | }; 22 | 23 | template 24 | struct has_name::name)>> : std::true_type 25 | { 26 | }; 27 | 28 | enum class TypeKind 29 | { 30 | POINTER, 31 | REFERENCE, 32 | ARRAY, 33 | FUNCTION, 34 | MEMBER, 35 | TEMPLATE, 36 | BASIC, 37 | NTTP 38 | }; 39 | 40 | struct Type 41 | { 42 | virtual ~Type() = default; 43 | virtual TypeKind Kind() const = 0; 44 | }; 45 | 46 | struct BasicType : public Type 47 | { 48 | std::string name; 49 | bool is_const; 50 | bool is_volatile; 51 | 52 | virtual ~BasicType(){}; 53 | virtual TypeKind Kind() const override { return TypeKind::BASIC; } 54 | }; 55 | 56 | struct NTTP : public Type 57 | { 58 | Type* type; 59 | std::string name; 60 | 61 | virtual ~NTTP(){}; 62 | virtual TypeKind Kind() const override { return TypeKind::NTTP; } 63 | }; 64 | 65 | struct Pointer : public Type 66 | { 67 | Type* pointee; 68 | bool is_const; 69 | bool is_volatile; 70 | 71 | virtual ~Pointer() { delete pointee; } 72 | virtual TypeKind Kind() const override { return TypeKind::POINTER; } 73 | }; 74 | 75 | struct Reference : public Type 76 | { 77 | Type* referencee; 78 | bool is_lvalue_ref; 79 | 80 | virtual ~Reference() { delete referencee; } 81 | virtual TypeKind Kind() const override { return TypeKind::REFERENCE; } 82 | }; 83 | 84 | struct Array : public Type 85 | { 86 | Type* element; 87 | std::size_t size; 88 | 89 | virtual ~Array() { delete element; } 90 | virtual TypeKind Kind() const override { return TypeKind::ARRAY; } 91 | }; 92 | 93 | struct Member : public Type 94 | { 95 | Type* class_type; 96 | Type* member_type; 97 | bool is_const; 98 | bool is_volatile; 99 | 100 | virtual ~Member() 101 | { 102 | delete class_type; 103 | delete member_type; 104 | } 105 | 106 | virtual TypeKind Kind() const override { return TypeKind::MEMBER; } 107 | }; 108 | 109 | struct Template : public Type 110 | { 111 | std::string name; 112 | std::vector parameters; 113 | bool is_const; 114 | bool is_volatile; 115 | 116 | virtual ~Template() 117 | { 118 | for (auto parameter : parameters) { delete parameter; } 119 | } 120 | 121 | virtual TypeKind Kind() const override { return TypeKind::TEMPLATE; } 122 | }; 123 | 124 | struct Function : public Type 125 | { 126 | Type* return_type; 127 | std::vector parameters; 128 | std::uint8_t flag; 129 | 130 | virtual ~Function() 131 | { 132 | delete return_type; 133 | for (auto parameter : parameters) { delete parameter; } 134 | } 135 | 136 | void setflag(bool is_const, bool is_volatile, bool is_lvalue_ref, bool is_rvalue_ref, bool is_noexcept, bool is_variadic) 137 | { 138 | flag = 0; 139 | flag |= is_const ? 1 : 0; 140 | flag |= is_volatile ? 2 : 0; 141 | flag |= is_lvalue_ref ? 4 : 0; 142 | flag |= is_rvalue_ref ? 8 : 0; 143 | flag |= is_noexcept ? 16 : 0; 144 | flag |= is_variadic ? 32 : 0; 145 | } 146 | 147 | bool isConst() { return flag & 1; } 148 | bool isVolatile() { return flag & 2; } 149 | bool isLvalueRef() { return flag & 4; } 150 | bool isRvalueRef() { return flag & 8; } 151 | bool isNoexcept() { return flag & 16; } 152 | bool isVariadic() { return flag & 32; } 153 | 154 | virtual TypeKind Kind() const override { return TypeKind::FUNCTION; } 155 | }; 156 | 157 | struct never_functor 158 | { 159 | }; 160 | 161 | struct always_functor 162 | { 163 | void operator()(); 164 | }; 165 | 166 | template 167 | struct is_functor_impl : always_functor, std::conditional_t, T, never_functor> 168 | { 169 | }; 170 | 171 | template 172 | struct is_functor : std::true_type 173 | { 174 | }; 175 | 176 | template 177 | struct is_functor::operator())>> : std::false_type 178 | { 179 | }; 180 | 181 | template 182 | constexpr bool is_functor_v = is_functor::value; 183 | 184 | template 185 | constexpr bool is_lambda() 186 | { 187 | if constexpr (is_functor_v) 188 | { 189 | constexpr auto name = raw_name_of(); 190 | return name.find("lambda") != std::string_view::npos; 191 | } 192 | else 193 | { 194 | return false; 195 | } 196 | } 197 | template 198 | Type* parse(bool is_full_name); 199 | 200 | template 201 | Type* parse_nttp(bool is_full_name) 202 | { 203 | NTTP* nttp = new NTTP{}; 204 | nttp->type = parse>(is_full_name); 205 | using Type = decltype(Value); 206 | if constexpr (std::is_enum_v) 207 | { 208 | nttp->name = raw_name_of_enum(); 209 | } 210 | else if constexpr (std::is_same_v) 211 | { 212 | nttp->name = std::string{Value, 1}; 213 | } 214 | else if constexpr (std::is_integral_v || std::is_floating_point_v) 215 | { 216 | nttp->name = std::to_string(Value); 217 | } 218 | else if constexpr (is_lambda()) 219 | { 220 | nttp->name = ""; 221 | } 222 | else 223 | { 224 | nttp->name = raw_name_of(); 225 | } 226 | return nttp; 227 | } 228 | 229 | inline std::size_t lambda_id = 0; 230 | 231 | template 232 | std::string resolve_lambda() 233 | { 234 | static std::size_t id = lambda_id++; 235 | return ""; 236 | } 237 | 238 | template 239 | void parse_function_params(std::index_sequence, std::vector& parameters, bool is_full_name) 240 | { 241 | ((parameters[Is] = (parse>(is_full_name))), ...); 242 | } 243 | 244 | template 245 | void parse_template_params(std::index_sequence, std::vector& parameters, bool is_full_name) 246 | { 247 | std::size_t index = 0; 248 | auto f = [&](auto param) 249 | { 250 | using Param = decltype(param); 251 | if constexpr (!Param::has_value) 252 | { 253 | parameters[index] = parse(is_full_name); 254 | } 255 | else 256 | { 257 | parameters[index] = parse_nttp(is_full_name); 258 | } 259 | index += 1; 260 | }; 261 | (f(std::tuple_element_t{}), ...); 262 | } 263 | 264 | template 265 | Type* parse(bool is_full_name) 266 | { 267 | constexpr auto is_const = std::is_const_v; 268 | constexpr auto is_volatile = std::is_volatile_v; 269 | using Primary = std::remove_cv_t; 270 | 271 | if constexpr (has_name::value) 272 | { 273 | if (!is_full_name) 274 | { 275 | BasicType* basic_type = new BasicType{}; 276 | basic_type->name = type_info::name; 277 | basic_type->is_const = false; 278 | basic_type->is_volatile = false; 279 | return basic_type; 280 | } 281 | } 282 | else if constexpr (has_name::value) 283 | { 284 | if (!is_full_name) 285 | { 286 | BasicType* basic_type = new BasicType{}; 287 | basic_type->name = type_info::name; 288 | basic_type->is_const = is_const; 289 | basic_type->is_volatile = is_volatile; 290 | return basic_type; 291 | } 292 | } 293 | 294 | if constexpr (std::is_pointer_v) 295 | { 296 | Type* pointee = parse>(is_full_name); 297 | Pointer* pointer = new Pointer{}; 298 | pointer->pointee = pointee; 299 | pointer->is_const = is_const; 300 | pointer->is_volatile = is_volatile; 301 | return pointer; 302 | } 303 | else if constexpr (std::is_reference_v) 304 | { 305 | Type* referencee = parse>(is_full_name); 306 | Reference* reference = new Reference{}; 307 | reference->referencee = referencee; 308 | reference->is_lvalue_ref = std::is_lvalue_reference_v; 309 | return reference; 310 | } 311 | else if constexpr (std::is_array_v) 312 | { 313 | Type* element = parse>(is_full_name); 314 | Array* array = new Array{}; 315 | array->element = element; 316 | array->size = std::extent_v; 317 | return array; 318 | } 319 | else if constexpr (std::is_member_pointer_v) 320 | { 321 | Type* class_type = parse>(is_full_name); 322 | Type* member_type = parse>(is_full_name); 323 | Member* member = new Member{}; 324 | member->class_type = class_type; 325 | member->member_type = member_type; 326 | member->is_const = is_const; 327 | member->is_volatile = is_volatile; 328 | return member; 329 | } 330 | else if constexpr (std::is_function_v) 331 | { 332 | Type* return_type = parse>(is_full_name); 333 | 334 | using Args = args_type_of; 335 | constexpr std::size_t arity = fn_arity_v; 336 | std::vector parameters(arity); 337 | parse_function_params(std::make_index_sequence{}, parameters, is_full_name); 338 | 339 | Function* function = new Function{}; 340 | function->return_type = return_type; 341 | function->parameters = std::move(parameters); 342 | function->setflag(is_const_fn_v, 343 | is_volatile_fn_v, 344 | is_lvalue_ref_fn_v, 345 | is_rvalue_ref_fn_v, 346 | is_noexcept_fn_v, 347 | is_c_variadic_fn_v); 348 | return function; 349 | } 350 | else if constexpr (is_template_class_v) 351 | { 352 | using Args = args_type_of; 353 | constexpr auto size = template_arity_v; 354 | std::vector parameters(size); 355 | parse_template_params(std::make_index_sequence{}, parameters, is_full_name); 356 | Template* template_type = new Template{}; 357 | template_type->name = raw_name_of_template(); 358 | template_type->parameters = std::move(parameters); 359 | template_type->is_const = is_const; 360 | template_type->is_volatile = is_volatile; 361 | return template_type; 362 | } 363 | else 364 | { 365 | BasicType* basic_type = new BasicType{}; 366 | if constexpr (is_lambda()) 367 | { 368 | basic_type->name = resolve_lambda(); 369 | } 370 | else 371 | { 372 | basic_type->name = raw_name_of(); 373 | } 374 | basic_type->is_const = is_const; 375 | basic_type->is_volatile = is_volatile; 376 | return basic_type; 377 | } 378 | } 379 | } // namespace magic::details 380 | 381 | namespace magic 382 | { 383 | using details::parse; 384 | using details::Type; 385 | using details::TypeKind; 386 | } // namespace magic 387 | #endif -------------------------------------------------------------------------------- /include/magic/visualize.h: -------------------------------------------------------------------------------- 1 | #ifndef MAGIC_CPP_VISUALIZE_H 2 | #define MAGIC_CPP_VISUALIZE_H 3 | 4 | #include 5 | #include 6 | #include // for std::accumulate 7 | #include // for std::pair 8 | #include // for std::vector 9 | #if __has_include() 10 | #include 11 | #endif 12 | 13 | #include "customization.h" 14 | #include "type_tree.h" 15 | #include 16 | #include 17 | 18 | #include // for std::uint*_t 19 | 20 | namespace magic 21 | { 22 | struct VisualizeOption 23 | { 24 | bool utf_support = true; 25 | bool color_support = true; 26 | bool full_name = false; 27 | }; 28 | 29 | struct HighlightConfig 30 | { 31 | std::uint32_t type; 32 | std::uint32_t nttp; 33 | std::uint32_t tmpl; 34 | std::uint32_t builtin; 35 | std::uint32_t modifier; 36 | std::uint32_t tag; 37 | }; 38 | 39 | constexpr static inline HighlightConfig Dark = { 40 | .type = 0xE5C07B, 41 | .nttp = 0xD19A66, 42 | .tmpl = 0x0087CE, 43 | .builtin = 0xC678DD, 44 | .modifier = 0x98C379, 45 | .tag = 0x5C6370, 46 | }; 47 | 48 | constexpr static inline HighlightConfig Light = { 49 | .type = 0x4285F4, 50 | .nttp = 0x0F9D58, 51 | .tmpl = 0xFF5722, 52 | .builtin = 0x7C4DFF, 53 | .modifier = 0xFBC02D, 54 | .tag = 0x03A9F4, 55 | }; 56 | 57 | template 58 | std::string visualize(const VisualizeOption& option = {}, const HighlightConfig& color = Dark); 59 | 60 | } // namespace magic 61 | 62 | namespace magic::details 63 | { 64 | 65 | #ifdef __cpp_lib_format 66 | using std::format; 67 | #else 68 | /** 69 | * the format function below is just used for internal. No fmt args checking. 70 | */ 71 | template 72 | std::string format(std::string_view fmt, Args&&... args) 73 | { 74 | std::array buffer{}; 75 | std::size_t args_index = 0; 76 | std::array args_str{}; 77 | auto make_str = [&](auto&& arg) 78 | { 79 | using Type = std::decay_t; 80 | if constexpr (std::is_integral_v || std::is_floating_point_v) 81 | { 82 | args_str[args_index] = std::to_string(arg); 83 | } 84 | else if constexpr (std::is_same_v) 85 | { 86 | args_str[args_index] = std::forward(arg); 87 | } 88 | else if constexpr (std::is_constructible_v) 89 | { 90 | args_str[args_index] = std::string{arg}; 91 | } 92 | args_index += 1; 93 | }; 94 | (make_str(std::forward(args)), ...); 95 | 96 | args_index = 0; 97 | std::size_t buffer_index = 0; 98 | for (std::size_t fmt_index = 0; fmt_index < fmt.size();) 99 | { 100 | if (fmt[fmt_index] == '{') 101 | { 102 | fmt_index += 2; 103 | std::size_t size = args_str[args_index].size(); 104 | memcpy(buffer.data() + buffer_index, args_str[args_index].data(), size); 105 | buffer_index += size; 106 | args_index += 1; 107 | } 108 | else 109 | { 110 | buffer[buffer_index] = fmt[fmt_index]; 111 | buffer_index += 1; 112 | fmt_index += 1; 113 | } 114 | } 115 | return std::string{buffer.data(), buffer_index}; 116 | } 117 | #endif // __cpp_lib_format 118 | 119 | class VisualizationImpl 120 | { 121 | template 122 | inline friend std::string magic::visualize(const VisualizeOption& option, const HighlightConfig& color); 123 | struct DirectoryTreeSymbols 124 | { 125 | std::string_view branch; 126 | std::string_view vertical; 127 | std::string_view corner; 128 | std::string_view space; 129 | }; 130 | 131 | std::string result; 132 | HighlightConfig config; 133 | DirectoryTreeSymbols symbols; 134 | bool color_support; 135 | 136 | public: 137 | VisualizationImpl(const VisualizeOption& option, const HighlightConfig& config) 138 | : result(), config(config), color_support(option.color_support) 139 | { 140 | if (option.utf_support) 141 | { 142 | symbols = {"├── ", "│ ", "└── ", " "}; 143 | } 144 | else 145 | { 146 | symbols = {"|-- ", "| ", "`-- ", " "}; 147 | } 148 | } 149 | 150 | template 151 | std::string colorize(T&& text, std::uint32_t color) 152 | { 153 | if (!color_support) 154 | { 155 | return std::forward(text); 156 | } 157 | std::uint8_t R = (color >> 16) & 0xFF; 158 | std::uint8_t G = (color >> 8) & 0xFF; 159 | std::uint8_t B = color & 0xFF; 160 | return format("\033[38;2;{};{};{}m{}\033[0m", R, G, B, std::forward(text)); 161 | } 162 | 163 | void visualize(std::string&& branch, std::string&& name, std::string&& modifier) 164 | { 165 | if (modifier.empty()) 166 | { 167 | result += format("{}{}\n", std::move(branch), std::move(name)); 168 | } 169 | else 170 | { 171 | modifier = colorize(std::move(modifier), config.modifier); 172 | result += format("{}{} [{}]\n", std::move(branch), std::move(name), std::move(modifier)); 173 | } 174 | } 175 | 176 | void visualize(Type* type, std::string prefix, std::string tag, bool is_last) 177 | { 178 | std::string branch = format("{}{}{}", prefix, (is_last ? symbols.corner : symbols.branch), colorize(tag, config.tag)); 179 | prefix += (is_last ? symbols.space : symbols.vertical); 180 | 181 | auto build_boolean_modifiers = [](const std::vector>& modifier_map) 182 | { 183 | std::vector modifiers; 184 | 185 | for (auto const& [pred, mod] : modifier_map) 186 | { 187 | if (pred) 188 | { 189 | modifiers.push_back(mod); 190 | } 191 | } 192 | 193 | return std::accumulate(begin(modifiers), 194 | end(modifiers), 195 | std::string{}, 196 | [](const std::string& lhs, const std::string_view& rhs) 197 | { return lhs.empty() ? std::string{rhs} : lhs + " " + std::string{rhs}; }); 198 | }; 199 | auto build_cxx_modifiers = 200 | [&](bool is_const = false, bool is_volatile = false, bool is_lref = false, bool is_rref = false, bool is_noexcept = false) 201 | { 202 | return build_boolean_modifiers({ 203 | {is_const, "const" }, 204 | {is_volatile, "volatile"}, 205 | {is_lref, "&" }, 206 | {is_rref, "&&" }, 207 | {is_noexcept, "noxcept" } 208 | }); 209 | }; 210 | 211 | for (std::size_t i = 0; i < tag.size(); i++) { prefix.push_back(' '); } 212 | if (type->Kind() == TypeKind::BASIC) 213 | { 214 | BasicType* basic = static_cast(type); 215 | std::string name = colorize(std::move(basic->name), config.type); 216 | std::string modifier = build_cxx_modifiers(basic->is_const, basic->is_volatile); 217 | visualize(std::move(branch), std::move(name), std::move(modifier)); 218 | } 219 | else if (type->Kind() == TypeKind::POINTER) 220 | { 221 | Pointer* pointer = static_cast(type); 222 | std::string name = colorize("ptr", config.builtin); 223 | std::string modifier = build_cxx_modifiers(pointer->is_const, pointer->is_volatile); 224 | visualize(std::move(branch), std::move(name), std::move(modifier)); 225 | visualize(pointer->pointee, prefix, "", true); 226 | } 227 | else if (type->Kind() == TypeKind::REFERENCE) 228 | { 229 | Reference* ref = static_cast(type); 230 | std::string name = colorize("ref", config.builtin); 231 | std::string modifier = build_cxx_modifiers(false, false, ref->is_lvalue_ref, !ref->is_lvalue_ref); 232 | visualize(std::move(branch), std::move(name), std::move(modifier)); 233 | visualize(ref->referencee, prefix, "", true); 234 | } 235 | else if (type->Kind() == TypeKind::ARRAY) 236 | { 237 | Array* array = static_cast(type); 238 | std::string name = colorize("array", config.builtin); 239 | // non-boolean modifier 240 | // need not to colorize it here, `visualize(branch, name, modifier)` will perform colorize 241 | std::string modifier = format("N = {}", array->size); 242 | visualize(std::move(branch), std::move(name), std::move(modifier)); 243 | visualize(array->element, prefix, "", true); 244 | } 245 | else if (type->Kind() == TypeKind::FUNCTION) 246 | { 247 | Function* function = static_cast(type); 248 | std::string name = colorize("function", config.builtin); 249 | std::string modifier = build_cxx_modifiers(function->isConst(), 250 | function->isVolatile(), 251 | function->isLvalueRef(), 252 | function->isLvalueRef(), 253 | function->isNoexcept()); 254 | 255 | visualize(std::move(branch), std::move(name), std::move(modifier)); 256 | 257 | std::vector& params = function->parameters; 258 | const auto size = params.size(); 259 | visualize(function->return_type, prefix, "R: ", false); 260 | 261 | for (std::size_t index = 0; index < size; index++) 262 | { 263 | Type* param = params[index]; 264 | is_last = (index == size - 1) && !function->isVariadic(); 265 | visualize(param, prefix, format("{}: ", index), is_last); 266 | } 267 | 268 | tag = colorize(format("{}: ", size), config.tag); 269 | if (function->isVariadic()) 270 | { 271 | result += format("{}{}{}\n", prefix += symbols.corner, tag, colorize("<...>", config.builtin)); 272 | } 273 | else if (params.empty()) 274 | { 275 | result += format("{}{}{}\n", prefix += symbols.corner, tag, colorize("", config.builtin)); 276 | } 277 | } 278 | else if (type->Kind() == TypeKind::MEMBER) 279 | { 280 | Member* member = static_cast(type); 281 | std::string name = colorize("member ptr", config.builtin); 282 | std::string modifier = build_cxx_modifiers(member->is_const, member->is_volatile); 283 | visualize(std::move(branch), std::move(name), std::move(modifier)); 284 | visualize(member->class_type, prefix, "C: ", false); 285 | visualize(member->member_type, prefix, "M: ", true); 286 | } 287 | else if (type->Kind() == TypeKind::TEMPLATE) 288 | { 289 | Template* template_ = static_cast(type); 290 | std::string name = colorize(std::move(template_->name), config.tmpl); 291 | std::string modifier = build_boolean_modifiers({ 292 | {true, "template"}, 293 | {template_->is_const, "const" }, 294 | {template_->is_volatile, "volatile"}, 295 | }); 296 | visualize(std::move(branch), std::move(name), std::move(modifier)); 297 | 298 | for (std::size_t index = 0; index < template_->parameters.size(); index++) 299 | { 300 | Type* parameter = template_->parameters[index]; 301 | is_last = index == template_->parameters.size() - 1; 302 | visualize(parameter, prefix, format("{}: ", index), is_last); 303 | } 304 | } 305 | else if (type->Kind() == TypeKind::NTTP) 306 | { 307 | NTTP* nttp = static_cast(type); 308 | std::string name = colorize("nttp", config.builtin); 309 | result += format("{}{}\n", branch, std::move(name)); 310 | visualize(nttp->type, prefix, "T: ", false); 311 | name = colorize(nttp->name, config.nttp); 312 | tag = colorize("V: ", config.tag); 313 | result += format("{}{}{}\n", prefix += symbols.corner, tag, std::move(name)); 314 | } 315 | else 316 | { 317 | magic::unreachable(); 318 | } 319 | } 320 | }; 321 | 322 | inline void display_name_of(std::string& result, Type* type, bool is_full_name) {} 323 | 324 | } // namespace magic::details 325 | 326 | namespace magic 327 | { 328 | template 329 | std::string visualize(const VisualizeOption& option, const HighlightConfig& config) 330 | { 331 | std::string result; 332 | Type* type = details::parse(option.full_name); 333 | details::VisualizationImpl visualizationImpl{option, config}; 334 | visualizationImpl.visualize(type, "", "", true); 335 | delete type; 336 | return std::move(visualizationImpl.result); 337 | } 338 | 339 | } // namespace magic 340 | 341 | #endif -------------------------------------------------------------------------------- /script/struct_bind.py: -------------------------------------------------------------------------------- 1 | # the generate_struct_bind accept a number of max fields, and generate the the struct bind of it 2 | # for example, if the max is 2, then the code will be like this: 3 | 4 | # :param max: the max number of fields that you want to support 5 | # :return: the final code of generation 6 | 7 | # if constexpr (N == 0) 8 | # { 9 | # return std::type_identity>{}; 10 | # } 11 | # else if constexpr (N == 1) 12 | # { 13 | # auto [var0] = object; 14 | # return std::type_identity>{}; 15 | # } 16 | # else if constexpr (N == 2) 17 | # { 18 | # auto [var0, var1] = object; 19 | # return std::type_identity>{}; 20 | # } 21 | # else 22 | # { 23 | # static_assert(N <= 2, "the max of supported fields is 2"); 24 | # } 25 | 26 | def generate_struct_bind_of_field_types(max: int): 27 | 28 | # handle the case of 0 29 | code = f""" 30 | if constexpr (N == 0) 31 | {{ 32 | return std::type_identity>{{}}; 33 | }}""" 34 | 35 | for num in range(max): 36 | vars = [] 37 | for index in range(num + 1): 38 | vars.append(f"v{index}") 39 | 40 | variables = ", ".join(vars) 41 | # variables just like: v0, v1, v2, ... 42 | 43 | types: str = ", ".join([f"decltype({var})" for var in vars]) 44 | # types just like: decltype(v0), decltype(v1), decltype(v2), ... 45 | 46 | code += f""" 47 | else if constexpr (N == {len(vars)}) 48 | {{ 49 | auto [{variables}] = object; 50 | return std::type_identity>{{}}; 51 | }}""" 52 | 53 | # handle the case of N > max 54 | code += f""" 55 | else 56 | {{ 57 | static_assert(N <= {max}, "the max of supported fields is {max}"); 58 | }}""" 59 | return code 60 | 61 | 62 | def generate_struct_bind_of_field_access(max: int): 63 | code = f"""if constexpr (N == 0) 64 | {{ 65 | static_assert(N != 0, "the object has no fields"); 66 | }}""" 67 | 68 | for num in range(max): 69 | vars = [] 70 | for index in range(num+1): 71 | vars.append(f"v{index}") 72 | 73 | variables = ", ".join(vars) 74 | # variables just like: v0, v1, v2, ... 75 | 76 | code += f""" 77 | else if constexpr (N == {len(vars)}) 78 | {{ 79 | auto&& [{variables}] = object; 80 | return std::get (std::forward_as_tuple({variables})); 81 | }}""" 82 | 83 | code += f""" 84 | else 85 | {{ 86 | static_assert(N <= {max}, "the max of supported fields is {max}"); 87 | }}""" 88 | return code 89 | -------------------------------------------------------------------------------- /script/template.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | 3 | 4 | def generate_template_traits_n(n: int): 5 | all_combination = [] 6 | for combination in product([0, 1], repeat=n): 7 | if (len(combination) == 1) or (combination[-1] != combination[-2]): 8 | all_combination.append(combination) 9 | code = f""" 10 | template 11 | struct template_traits_{n} : std::false_type {{}}; 12 | """ 13 | 14 | for combination in all_combination: 15 | 16 | # generate template template parameter 17 | # e.g. combination = (0, 1), "template class T" 18 | # e.g. combination = (1, 0), "template class T" 19 | # e.g. combination = (0, 0, 1), "template class T" 20 | template_template_params = "" 21 | for element in combination[:-1]: 22 | if element == 0: 23 | template_template_params += "typename, " 24 | else: 25 | template_template_params += "auto, " 26 | template_template_params += "typename..." if combination[-1] == 0 else "auto..." 27 | 28 | # generate template parameter 29 | # e.g. combination = (0, 1), "typename T1, auto... Ts" 30 | # e.g. combination = (1, 0), "auto T1, typename... Ts" 31 | # e.g. combination = (0, 0, 1), "typename T1, typename T2, auto... Ts" 32 | template_params = "" 33 | for index, element in list(enumerate(combination, start=1))[:-1]: 34 | if element == 0: 35 | template_params += f"typename T{index}, " 36 | else: 37 | template_params += f"auto T{index}, " 38 | template_params += "typename... Ts" if combination[-1] == 0 else "auto... Ts" 39 | 40 | # generate specialization parameter 41 | # e.g. combination = (0, 1), "T1, Ts..." 42 | # e.g. combination = (1, 0), "T1, Ts..." 43 | # e.g. combination = (0, 0, 1), "T1, T2, Ts..." 44 | specialization_params_code = "" 45 | for index in range(1, len(combination)): 46 | specialization_params_code += f"T{index}, " 47 | specialization_params_code += "Ts..." 48 | 49 | # generate args parameter 50 | # e.g. combination = (0, 1), "identity, identity, Ts>..." 51 | # e.g. combination = (1, 0), "identity, T1>, identity..." 52 | # e.g. combination = (0, 0, 1), "identity, identity, identity, Ts>..." 53 | 54 | args_code = "" 55 | for index, element in list(enumerate(combination, start=1))[:-1]: 56 | if element == 0: 57 | args_code += f"identity, " 58 | else: 59 | args_code += f"identity, " 60 | if combination[-1] == 0: 61 | args_code += f"identity..." 62 | else: 63 | args_code += f"identity..." 64 | 65 | code += f""" 66 | template class U> 67 | constexpr auto template_full_name_{n}() 68 | {{ 69 | return MAGIC_CPP_FUNCTION_NAME; 70 | }}""" 71 | 72 | code += f""" 73 | template class T, {template_params}> 74 | struct template_traits_{n}> : std::true_type 75 | {{ 76 | constexpr static auto full_name = template_full_name_{n}(); 77 | using args_type = std::tuple<{args_code}>; 78 | }}; 79 | """ 80 | return code 81 | 82 | 83 | def generate_template_traits(max: int): 84 | result = "" 85 | for i in range(1, max + 1): 86 | result += generate_template_traits_n(i) 87 | 88 | branchs = "" 89 | for i in range(1, max + 1): 90 | branchs += f""" 91 | {"if"if i == 1 else "else if"} constexpr(template_traits_{i}::value) 92 | {{ 93 | return true; 94 | }}""" 95 | 96 | result += f""" 97 | template 98 | constexpr bool is_template() 99 | {{{branchs} 100 | else 101 | {{ 102 | return false; 103 | }} 104 | }} 105 | """ 106 | 107 | branchs = "" 108 | for i in range(1, max + 1): 109 | branchs += f""" 110 | {"if" if i == 1 else "else if"} constexpr(template_traits_{i}::value) 111 | {{ 112 | return template_traits_{i}(); 113 | }}""" 114 | 115 | result += f""" 116 | template 117 | constexpr auto template_traits_impl() 118 | {{{branchs} 119 | else 120 | {{ 121 | static_assert(is_template(), "not supported"); 122 | }} 123 | }} 124 | """ 125 | 126 | return result 127 | 128 | -------------------------------------------------------------------------------- /test/field_count_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace magic; 5 | 6 | TEST(Field_Count, NoRef_NoArray) 7 | { 8 | struct Vec3 9 | { 10 | float x; 11 | float y; 12 | float z; 13 | }; 14 | 15 | ASSERT_EQ(field_count_of(), 3); 16 | 17 | struct Line 18 | { 19 | Vec3 start; 20 | Vec3 end; 21 | }; 22 | 23 | ASSERT_EQ(field_count_of(), 2); 24 | 25 | struct PairPair 26 | { 27 | std::pair pair1; 28 | std::pair pair2; 29 | }; 30 | 31 | ASSERT_EQ(field_count_of(), 2); 32 | } 33 | 34 | TEST(Field_Count, Ref) 35 | { 36 | struct Vec3 37 | { 38 | float x; 39 | float y; 40 | float z; 41 | }; 42 | 43 | ASSERT_EQ(field_count_of(), 3); 44 | 45 | struct LRef 46 | { 47 | Vec3& start; 48 | }; 49 | 50 | ASSERT_EQ(field_count_of(), 1); 51 | 52 | struct RRef 53 | { 54 | Vec3&& start; 55 | }; 56 | 57 | ASSERT_EQ(field_count_of(), 1); 58 | 59 | struct ConstRef 60 | { 61 | const Vec3& start; 62 | }; 63 | 64 | ASSERT_EQ(field_count_of(), 1); 65 | 66 | struct LRRef 67 | { 68 | Vec3& start; 69 | Vec3&& end; 70 | }; 71 | ASSERT_EQ(field_count_of(), 2); 72 | 73 | struct LConstRef 74 | { 75 | Vec3& start; 76 | const Vec3& end; 77 | }; 78 | ASSERT_EQ(field_count_of(), 2); 79 | 80 | struct RConstRef 81 | { 82 | Vec3&& start; 83 | const Vec3& end; 84 | }; 85 | ASSERT_EQ(field_count_of(), 2); 86 | 87 | struct LRConstRef 88 | { 89 | Vec3& start; 90 | Vec3&& end; 91 | const Vec3& end2; 92 | }; 93 | 94 | ASSERT_EQ(field_count_of(), 3); 95 | 96 | struct ConstLRRef 97 | { 98 | const Vec3& start; 99 | Vec3& end; 100 | Vec3&& end2; 101 | }; 102 | 103 | ASSERT_EQ(field_count_of(), 3); 104 | 105 | struct VLRConstRef 106 | { 107 | Vec3 start; 108 | Vec3& end; 109 | Vec3&& end2; 110 | const Vec3& end3; 111 | }; 112 | 113 | ASSERT_EQ(field_count_of(), 4); 114 | } 115 | 116 | #if MAGIC_CPP_C_ARRAY_SUPPORT 117 | TEST(Field_Count, Array) 118 | { 119 | struct Vec3 120 | { 121 | float x; 122 | float y; 123 | float z; 124 | }; 125 | 126 | ASSERT_EQ(field_count_of(), 3); 127 | 128 | struct Vec3Array 129 | { 130 | Vec3 array[3]; 131 | }; 132 | 133 | ASSERT_EQ(field_count_of(), 1); 134 | 135 | struct Vec3Array2 136 | { 137 | Vec3 array[2][3]; 138 | }; 139 | 140 | ASSERT_EQ(field_count_of(), 1); 141 | 142 | struct Vec3Array3 143 | { 144 | Vec3 array[3]; 145 | Vec3 array2[2]; 146 | Vec3 point; 147 | }; 148 | 149 | ASSERT_EQ(field_count_of(), 3); 150 | } 151 | #endif -------------------------------------------------------------------------------- /test/function_traits_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace magic; 5 | 6 | template 7 | constexpr static bool Same = std::is_same_v; 8 | 9 | TEST(Function_Traits, None) 10 | { 11 | using T = int(int, int); 12 | EXPECT_TRUE((Same, int>)); 13 | EXPECT_TRUE((Same, std::tuple>)); 14 | EXPECT_TRUE((Same, int(int, int)>)); 15 | EXPECT_TRUE((fn_arity_v == 2)); 16 | EXPECT_TRUE((is_const_fn_v == false)); 17 | EXPECT_TRUE((is_volatile_fn_v == false)); 18 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 19 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 20 | EXPECT_TRUE((is_noexcept_fn_v == false)); 21 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 22 | } 23 | 24 | TEST(Function_Traits, Const) 25 | { 26 | using T = int(int, int) const; 27 | EXPECT_TRUE((is_const_fn_v == true)); 28 | EXPECT_TRUE((is_volatile_fn_v == false)); 29 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 30 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 31 | EXPECT_TRUE((is_noexcept_fn_v == false)); 32 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 33 | } 34 | 35 | TEST(Function_Traits, Volatile) 36 | { 37 | using T = int(int, int) volatile; 38 | EXPECT_TRUE((is_const_fn_v == false)); 39 | EXPECT_TRUE((is_volatile_fn_v == true)); 40 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 41 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 42 | EXPECT_TRUE((is_noexcept_fn_v == false)); 43 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 44 | } 45 | 46 | TEST(Function_Traits, Const_Volatile) 47 | { 48 | using T = int(int, int) const volatile; 49 | EXPECT_TRUE((is_const_fn_v == true)); 50 | EXPECT_TRUE((is_volatile_fn_v == true)); 51 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 52 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 53 | EXPECT_TRUE((is_noexcept_fn_v == false)); 54 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 55 | } 56 | 57 | TEST(Function_Traits, LRef) 58 | { 59 | using T = int(int, int)&; 60 | EXPECT_TRUE((is_const_fn_v == false)); 61 | EXPECT_TRUE((is_volatile_fn_v == false)); 62 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 63 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 64 | EXPECT_TRUE((is_noexcept_fn_v == false)); 65 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 66 | } 67 | 68 | TEST(Function_Traits, Const_LRef) 69 | { 70 | using T = int(int, int) const&; 71 | EXPECT_TRUE((is_const_fn_v == true)); 72 | EXPECT_TRUE((is_volatile_fn_v == false)); 73 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 74 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 75 | EXPECT_TRUE((is_noexcept_fn_v == false)); 76 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 77 | } 78 | 79 | TEST(Function_Traits, Volatile_LRef) 80 | { 81 | using T = int(int, int, char) volatile&; 82 | EXPECT_TRUE((is_const_fn_v == false)); 83 | EXPECT_TRUE((is_volatile_fn_v == true)); 84 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 85 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 86 | EXPECT_TRUE((is_noexcept_fn_v == false)); 87 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 88 | } 89 | 90 | TEST(Function_Traits, Const_Volatile_LRef) 91 | { 92 | using T = int(int, int) const volatile&; 93 | EXPECT_TRUE((is_const_fn_v == true)); 94 | EXPECT_TRUE((is_volatile_fn_v == true)); 95 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 96 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 97 | EXPECT_TRUE((is_noexcept_fn_v == false)); 98 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 99 | } 100 | 101 | TEST(Function_Traits, RRef) 102 | { 103 | using T = int(int, int, char)&&; 104 | EXPECT_TRUE((is_const_fn_v == false)); 105 | EXPECT_TRUE((is_volatile_fn_v == false)); 106 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 107 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 108 | EXPECT_TRUE((is_noexcept_fn_v == false)); 109 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 110 | } 111 | 112 | TEST(Function_Traits, Const_RRef) 113 | { 114 | using T = int(int, int, char) const&&; 115 | EXPECT_TRUE((is_const_fn_v == true)); 116 | EXPECT_TRUE((is_volatile_fn_v == false)); 117 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 118 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 119 | EXPECT_TRUE((is_noexcept_fn_v == false)); 120 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 121 | } 122 | 123 | TEST(Function_Traits, Volatile_RRef) 124 | { 125 | using T = int(int, int, char) volatile&&; 126 | EXPECT_TRUE((is_const_fn_v == false)); 127 | EXPECT_TRUE((is_volatile_fn_v == true)); 128 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 129 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 130 | EXPECT_TRUE((is_noexcept_fn_v == false)); 131 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 132 | } 133 | 134 | TEST(Function_Traits, Const_Volatile_RRef) 135 | { 136 | using T = int(int, int, char) const volatile&&; 137 | EXPECT_TRUE((is_const_fn_v == true)); 138 | EXPECT_TRUE((is_volatile_fn_v == true)); 139 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 140 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 141 | EXPECT_TRUE((is_noexcept_fn_v == false)); 142 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 143 | } 144 | 145 | TEST(Function_Traits, Noexcept) 146 | { 147 | using T = int(int, int) noexcept; 148 | EXPECT_TRUE((is_const_fn_v == false)); 149 | EXPECT_TRUE((is_volatile_fn_v == false)); 150 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 151 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 152 | EXPECT_TRUE((is_noexcept_fn_v == true)); 153 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 154 | } 155 | 156 | TEST(Function_Traits, Const_Noexcept) 157 | { 158 | using T = int(int, int) const noexcept; 159 | EXPECT_TRUE((is_const_fn_v == true)); 160 | EXPECT_TRUE((is_volatile_fn_v == false)); 161 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 162 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 163 | EXPECT_TRUE((is_noexcept_fn_v == true)); 164 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 165 | } 166 | 167 | TEST(Function_Traits, Volatile_Noexcept) 168 | { 169 | using T = int(int, int) volatile noexcept; 170 | EXPECT_TRUE((is_const_fn_v == false)); 171 | EXPECT_TRUE((is_volatile_fn_v == true)); 172 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 173 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 174 | EXPECT_TRUE((is_noexcept_fn_v == true)); 175 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 176 | } 177 | 178 | TEST(Function_Traits, Const_Volatile_Noexcept) 179 | { 180 | using T = int(int, int) const volatile noexcept; 181 | EXPECT_TRUE((is_const_fn_v == true)); 182 | EXPECT_TRUE((is_volatile_fn_v == true)); 183 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 184 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 185 | EXPECT_TRUE((is_noexcept_fn_v == true)); 186 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 187 | } 188 | 189 | TEST(Function_Traits, LRef_Noexcept) 190 | { 191 | using T = int(int, int)& noexcept; 192 | EXPECT_TRUE((is_const_fn_v == false)); 193 | EXPECT_TRUE((is_volatile_fn_v == false)); 194 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 195 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 196 | EXPECT_TRUE((is_noexcept_fn_v == true)); 197 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 198 | } 199 | 200 | TEST(Function_Traits, Const_LRef_Noexcept) 201 | { 202 | using T = int(int, int) const& noexcept; 203 | EXPECT_TRUE((is_const_fn_v == true)); 204 | EXPECT_TRUE((is_volatile_fn_v == false)); 205 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 206 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 207 | EXPECT_TRUE((is_noexcept_fn_v == true)); 208 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 209 | } 210 | 211 | TEST(Function_Traits, Volatile_LRef_Noexcept) 212 | { 213 | using T = int(int, int, char) volatile& noexcept; 214 | EXPECT_TRUE((is_const_fn_v == false)); 215 | EXPECT_TRUE((is_volatile_fn_v == true)); 216 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 217 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 218 | EXPECT_TRUE((is_noexcept_fn_v == true)); 219 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 220 | } 221 | 222 | TEST(Function_Traits, Const_Volatile_LRef_Noexcept) 223 | { 224 | using T = int(int, int) const volatile& noexcept; 225 | EXPECT_TRUE((is_const_fn_v == true)); 226 | EXPECT_TRUE((is_volatile_fn_v == true)); 227 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 228 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 229 | EXPECT_TRUE((is_noexcept_fn_v == true)); 230 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 231 | } 232 | 233 | TEST(Function_Traits, RRef_Noexcept) 234 | { 235 | using T = int(int, int, char)&& noexcept; 236 | EXPECT_TRUE((is_const_fn_v == false)); 237 | EXPECT_TRUE((is_volatile_fn_v == false)); 238 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 239 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 240 | EXPECT_TRUE((is_noexcept_fn_v == true)); 241 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 242 | } 243 | 244 | TEST(Function_Traits, Const_RRef_Noexcept) 245 | { 246 | using T = int(int, int, char) const&& noexcept; 247 | EXPECT_TRUE((is_const_fn_v == true)); 248 | EXPECT_TRUE((is_volatile_fn_v == false)); 249 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 250 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 251 | EXPECT_TRUE((is_noexcept_fn_v == true)); 252 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 253 | } 254 | 255 | TEST(Function_Traits, Volatile_RRef_Noexcept) 256 | { 257 | using T = int(int, int, char) volatile&& noexcept; 258 | EXPECT_TRUE((is_const_fn_v == false)); 259 | EXPECT_TRUE((is_volatile_fn_v == true)); 260 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 261 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 262 | EXPECT_TRUE((is_noexcept_fn_v == true)); 263 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 264 | } 265 | 266 | TEST(Function_Traits, Const_Volatile_RRef_Noexcept) 267 | { 268 | using T = int(int, int, char) const volatile&& noexcept; 269 | EXPECT_TRUE((is_const_fn_v == true)); 270 | EXPECT_TRUE((is_volatile_fn_v == true)); 271 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 272 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 273 | EXPECT_TRUE((is_noexcept_fn_v == true)); 274 | EXPECT_TRUE((is_c_variadic_fn_v == false)); 275 | } 276 | 277 | TEST(Function_Traits, Variadic) 278 | { 279 | using T = int(int, int, char, ...); 280 | EXPECT_TRUE((is_const_fn_v == false)); 281 | EXPECT_TRUE((is_volatile_fn_v == false)); 282 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 283 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 284 | EXPECT_TRUE((is_noexcept_fn_v == false)); 285 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 286 | } 287 | 288 | TEST(Function_Traits, Const_Variadic) 289 | { 290 | using T = int(int, int, char, ...) const; 291 | EXPECT_TRUE((is_const_fn_v == true)); 292 | EXPECT_TRUE((is_volatile_fn_v == false)); 293 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 294 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 295 | EXPECT_TRUE((is_noexcept_fn_v == false)); 296 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 297 | } 298 | 299 | TEST(Function_Traits, Volatile_Variadic) 300 | { 301 | using T = int(int, int, char, ...) volatile; 302 | EXPECT_TRUE((is_const_fn_v == false)); 303 | EXPECT_TRUE((is_volatile_fn_v == true)); 304 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 305 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 306 | EXPECT_TRUE((is_noexcept_fn_v == false)); 307 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 308 | } 309 | 310 | TEST(Function_Traits, Const_Volatile_Variadic) 311 | { 312 | using T = int(int, int, char, ...) const volatile; 313 | EXPECT_TRUE((is_const_fn_v == true)); 314 | EXPECT_TRUE((is_volatile_fn_v == true)); 315 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 316 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 317 | EXPECT_TRUE((is_noexcept_fn_v == false)); 318 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 319 | } 320 | 321 | TEST(Function_Traits, LRef_Variadic) 322 | { 323 | using T = int(int, int, char, ...)&; 324 | EXPECT_TRUE((is_const_fn_v == false)); 325 | EXPECT_TRUE((is_volatile_fn_v == false)); 326 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 327 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 328 | EXPECT_TRUE((is_noexcept_fn_v == false)); 329 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 330 | } 331 | 332 | TEST(Function_Traits, Const_LRef_Variadic) 333 | { 334 | using T = int(int, int, char, ...) const&; 335 | EXPECT_TRUE((is_const_fn_v == true)); 336 | EXPECT_TRUE((is_volatile_fn_v == false)); 337 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 338 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 339 | EXPECT_TRUE((is_noexcept_fn_v == false)); 340 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 341 | } 342 | 343 | TEST(Function_Traits, Volatile_LRef_Variadic) 344 | { 345 | using T = int(int, int, char, ...) volatile&; 346 | EXPECT_TRUE((is_const_fn_v == false)); 347 | EXPECT_TRUE((is_volatile_fn_v == true)); 348 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 349 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 350 | EXPECT_TRUE((is_noexcept_fn_v == false)); 351 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 352 | } 353 | 354 | TEST(Function_Traits, Const_Volatile_LRef_Variadic) 355 | { 356 | using T = int(int, int, char, ...) const volatile&; 357 | EXPECT_TRUE((is_const_fn_v == true)); 358 | EXPECT_TRUE((is_volatile_fn_v == true)); 359 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 360 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 361 | EXPECT_TRUE((is_noexcept_fn_v == false)); 362 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 363 | } 364 | 365 | TEST(Function_Traits, RRef_Variadic) 366 | { 367 | using T = int(int, int, char, ...)&&; 368 | EXPECT_TRUE((is_const_fn_v == false)); 369 | EXPECT_TRUE((is_volatile_fn_v == false)); 370 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 371 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 372 | EXPECT_TRUE((is_noexcept_fn_v == false)); 373 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 374 | } 375 | 376 | TEST(Function_Traits, Const_RRef_Variadic) 377 | { 378 | using T = int(int, int, char, ...) const&&; 379 | EXPECT_TRUE((is_const_fn_v == true)); 380 | EXPECT_TRUE((is_volatile_fn_v == false)); 381 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 382 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 383 | EXPECT_TRUE((is_noexcept_fn_v == false)); 384 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 385 | } 386 | 387 | TEST(Function_Traits, Volatile_RRef_Variadic) 388 | { 389 | using T = int(int, int, char, ...) volatile&&; 390 | EXPECT_TRUE((is_const_fn_v == false)); 391 | EXPECT_TRUE((is_volatile_fn_v == true)); 392 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 393 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 394 | EXPECT_TRUE((is_noexcept_fn_v == false)); 395 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 396 | } 397 | 398 | TEST(Function_Traits, Const_Volatile_RRef_Variadic) 399 | { 400 | using T = int(int, int, char, ...) const volatile&&; 401 | EXPECT_TRUE((is_const_fn_v == true)); 402 | EXPECT_TRUE((is_volatile_fn_v == true)); 403 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 404 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 405 | EXPECT_TRUE((is_noexcept_fn_v == false)); 406 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 407 | } 408 | 409 | TEST(Function_Traits, Noexcept_Variadic) 410 | { 411 | using T = int(int, int, char, ...) noexcept; 412 | EXPECT_TRUE((is_const_fn_v == false)); 413 | EXPECT_TRUE((is_volatile_fn_v == false)); 414 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 415 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 416 | EXPECT_TRUE((is_noexcept_fn_v == true)); 417 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 418 | } 419 | 420 | TEST(Function_Traits, Const_Noexcept_Variadic) 421 | { 422 | using T = int(int, int, char, ...) const noexcept; 423 | EXPECT_TRUE((is_const_fn_v == true)); 424 | EXPECT_TRUE((is_volatile_fn_v == false)); 425 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 426 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 427 | EXPECT_TRUE((is_noexcept_fn_v == true)); 428 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 429 | } 430 | 431 | TEST(Function_Traits, Volatile_Noexcept_Variadic) 432 | { 433 | using T = int(int, int, char, ...) volatile noexcept; 434 | EXPECT_TRUE((is_const_fn_v == false)); 435 | EXPECT_TRUE((is_volatile_fn_v == true)); 436 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 437 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 438 | EXPECT_TRUE((is_noexcept_fn_v == true)); 439 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 440 | } 441 | 442 | TEST(Function_Traits, Const_Volatile_Noexcept_Variadic) 443 | { 444 | using T = int(int, int, char, ...) const volatile noexcept; 445 | EXPECT_TRUE((is_const_fn_v == true)); 446 | EXPECT_TRUE((is_volatile_fn_v == true)); 447 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 448 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 449 | EXPECT_TRUE((is_noexcept_fn_v == true)); 450 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 451 | } 452 | 453 | TEST(Function_Traits, LRef_Noexcept_Variadic) 454 | { 455 | using T = int(int, int, char, ...)& noexcept; 456 | EXPECT_TRUE((is_const_fn_v == false)); 457 | EXPECT_TRUE((is_volatile_fn_v == false)); 458 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 459 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 460 | EXPECT_TRUE((is_noexcept_fn_v == true)); 461 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 462 | } 463 | 464 | TEST(Function_Traits, Const_LRef_Noexcept_Variadic) 465 | { 466 | using T = int(int, int, char, ...) const& noexcept; 467 | EXPECT_TRUE((is_const_fn_v == true)); 468 | EXPECT_TRUE((is_volatile_fn_v == false)); 469 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 470 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 471 | EXPECT_TRUE((is_noexcept_fn_v == true)); 472 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 473 | } 474 | 475 | TEST(Function_Traits, Volatile_LRef_Noexcept_Variadic) 476 | { 477 | using T = int(int, int, char, ...) volatile& noexcept; 478 | EXPECT_TRUE((is_const_fn_v == false)); 479 | EXPECT_TRUE((is_volatile_fn_v == true)); 480 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 481 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 482 | EXPECT_TRUE((is_noexcept_fn_v == true)); 483 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 484 | } 485 | 486 | TEST(Function_Traits, Const_Volatile_LRef_Noexcept_Variadic) 487 | { 488 | using T = int(int, int, char, ...) const volatile& noexcept; 489 | EXPECT_TRUE((is_const_fn_v == true)); 490 | EXPECT_TRUE((is_volatile_fn_v == true)); 491 | EXPECT_TRUE((is_lvalue_ref_fn_v == true)); 492 | EXPECT_TRUE((is_rvalue_ref_fn_v == false)); 493 | EXPECT_TRUE((is_noexcept_fn_v == true)); 494 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 495 | } 496 | 497 | TEST(Function_Traits, RRef_Noexcept_Variadic) 498 | { 499 | using T = int(int, int, char, ...)&& noexcept; 500 | EXPECT_TRUE((is_const_fn_v == false)); 501 | EXPECT_TRUE((is_volatile_fn_v == false)); 502 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 503 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 504 | EXPECT_TRUE((is_noexcept_fn_v == true)); 505 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 506 | } 507 | 508 | TEST(Function_Traits, Const_RRef_Noexcept_Variadic) 509 | { 510 | using T = int(int, int, char, ...) const&& noexcept; 511 | EXPECT_TRUE((is_const_fn_v == true)); 512 | EXPECT_TRUE((is_volatile_fn_v == false)); 513 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 514 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 515 | EXPECT_TRUE((is_noexcept_fn_v == true)); 516 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 517 | } 518 | 519 | TEST(Function_Traits, Volatile_RRef_Noexcept_Variadic) 520 | { 521 | using T = int(int, int, char, ...) volatile&& noexcept; 522 | EXPECT_TRUE((is_const_fn_v == false)); 523 | EXPECT_TRUE((is_volatile_fn_v == true)); 524 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 525 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 526 | EXPECT_TRUE((is_noexcept_fn_v == true)); 527 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 528 | } 529 | 530 | TEST(Function_Traits, Const_Volatile_RRef_Noexcept_Variadic) 531 | { 532 | using T = int(int, int, char, ...) const volatile&& noexcept; 533 | EXPECT_TRUE((is_const_fn_v == true)); 534 | EXPECT_TRUE((is_volatile_fn_v == true)); 535 | EXPECT_TRUE((is_lvalue_ref_fn_v == false)); 536 | EXPECT_TRUE((is_rvalue_ref_fn_v == true)); 537 | EXPECT_TRUE((is_noexcept_fn_v == true)); 538 | EXPECT_TRUE((is_c_variadic_fn_v == true)); 539 | } -------------------------------------------------------------------------------- /test/raw_name_test.cpp: -------------------------------------------------------------------------------- 1 | #include "magic/raw_name.h" 2 | #include 3 | 4 | using namespace magic; 5 | 6 | #define EQUAL(TYPE, name) ASSERT_EQ((raw_name_of()), name) << "test for " #name 7 | 8 | TEST(Raw_Name_Of, Fundamental) 9 | { 10 | EQUAL(int, "int"); 11 | EQUAL(char, "char"); 12 | EQUAL(float, "float"); 13 | } 14 | 15 | struct A 16 | { 17 | }; 18 | class B 19 | { 20 | }; 21 | 22 | TEST(Raw_Name_Of, Class) 23 | { 24 | EQUAL(A, "A") << raw_name_of(); 25 | EQUAL(B, "B") << raw_name_of(); 26 | } 27 | 28 | TEST(Raw_Name_Of, Enum) 29 | { 30 | enum E 31 | { 32 | A, 33 | B, 34 | C 35 | }; 36 | 37 | ASSERT_EQ((raw_name_of_enum()), "A") << "test for enum"; 38 | ASSERT_EQ((raw_name_of_enum()), "B") << "test for enum"; 39 | ASSERT_EQ((raw_name_of_enum()), "C") << "test for enum"; 40 | 41 | enum class CE 42 | { 43 | A, 44 | B, 45 | C 46 | }; 47 | ASSERT_EQ((raw_name_of_enum()), "A") << "test for enum"; 48 | ASSERT_EQ((raw_name_of_enum()), "B") << "test for enum"; 49 | ASSERT_EQ((raw_name_of_enum()), "C") << "test for enum"; 50 | } 51 | 52 | #ifdef MAGIC_CPP_20_SUPPORT 53 | 54 | struct X 55 | { 56 | int member1; 57 | int member2; 58 | int member_3; 59 | }; 60 | 61 | X x; 62 | 63 | TEST(Raw_Name_Of, Member) 64 | { 65 | ASSERT_EQ((raw_name_of_member<&x.member1>()), "member1"); 66 | ASSERT_EQ((raw_name_of_member<&x.member2>()), "member2"); 67 | ASSERT_EQ((raw_name_of_member<&x.member_3>()), "member_3"); 68 | } 69 | 70 | #endif -------------------------------------------------------------------------------- /test/template_traits_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | using namespace magic; 6 | 7 | TEST(Template_Traits, None) 8 | { 9 | using T = std::vector; 10 | using args = magic::args_type_of; 11 | EXPECT_TRUE((std::is_same_v, identity>>>)); 12 | } -------------------------------------------------------------------------------- /xmake.lua: -------------------------------------------------------------------------------- 1 | set_project("magic") 2 | 3 | set_version("0.0.1") 4 | 5 | set_xmakever("2.8.6") 6 | 7 | set_allowedplats("windows", "linux") -- tested in x86_64 linux 8 | set_allowedmodes("debug", "release") 9 | 10 | option("test", {showmenu = true, default = false}) 11 | 12 | set_languages("c++20") 13 | 14 | set_warnings("all") 15 | add_rules("mode.debug", "mode.release") 16 | 17 | if is_plat("linux") then 18 | set_toolchains("gcc") -- tested with gcc 19 | end 20 | 21 | if is_plat("windows") then 22 | set_runtimes("MD") 23 | add_cxflags("/permissive-", {tools = "cl"}) 24 | end 25 | 26 | if has_config("test") then 27 | add_requires("gtest", {system = false, configs = {main = true, gmock = false}}) 28 | end 29 | 30 | target("magic") 31 | set_kind("headeronly") 32 | add_includedirs("include", {interface = true}) 33 | add_headerfiles("include/(magic/*.h)") 34 | 35 | target("test") 36 | set_kind("binary") 37 | set_default(false) 38 | add_files(os.files("test/*.cpp")) 39 | 40 | if is_plat("windows") then 41 | add_ldflags("/subsystem:console") 42 | end 43 | 44 | add_deps("magic") 45 | add_packages("gtest") 46 | 47 | add_tests("default") 48 | --------------------------------------------------------------------------------