├── .clang-format ├── .codedocs ├── .gitignore ├── .travis.yml ├── .ycm_extra_conf.py ├── 3rdparty └── catch │ ├── CMakeLists.txt │ ├── catch.hpp │ └── update_catch.sh ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake ├── BuildConfig.json.in ├── Findrapidjson.cmake ├── ProjectGlobalMacros.cmake ├── ProjectTestFunctions.cmake └── SanitizerBlacklist.txt.in ├── codecov.yml ├── docs ├── doxygen │ └── source │ │ ├── doxyhtml.conf │ │ └── doxyxml.conf └── sphinx │ ├── Makefile │ ├── make.bat │ └── source │ ├── conf.py │ ├── index.rst │ └── requirements.txt ├── includes ├── named_types │ ├── extensions │ │ ├── factory.hpp │ │ ├── generation_tools.hpp │ │ ├── parsing_tools.hpp │ │ ├── rapidjson.hpp │ │ └── type_traits.hpp │ ├── literals │ │ ├── integral_string_literal.hpp │ │ └── string_literal.hpp │ ├── named_tag.hpp │ ├── named_tuple.hpp │ ├── rt_named_tag.hpp │ └── rt_named_tuple.hpp └── std │ └── experimental │ └── tagged.hpp ├── readthedocs.yml └── test ├── CMakeLists.txt ├── cmake └── Findrapidjson.cmake ├── demo1.cc ├── demo2.cc ├── demo3.cc ├── demo4.cc ├── demo5.cc ├── demo6.cc ├── demo7.cc ├── examples ├── CMakeLists.txt └── factory.cc ├── named_tuple_extensions_tests.cc ├── named_tuple_rapidjson_tests.cc ├── named_tuple_tests.cc ├── named_tuple_tests_cpp1z.cc └── test-main.cc /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -1 5 | ConstructorInitializerIndentWidth: 4 6 | AlignEscapedNewlinesLeft: false 7 | AlignTrailingComments: true 8 | AllowAllParametersOfDeclarationOnNextLine: true 9 | AllowShortBlocksOnASingleLine: false 10 | AllowShortIfStatementsOnASingleLine: false 11 | AllowShortLoopsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AlwaysBreakTemplateDeclarations: false 14 | AlwaysBreakBeforeMultilineStrings: false 15 | BreakBeforeBinaryOperators: false 16 | BreakBeforeTernaryOperators: true 17 | BreakConstructorInitializersBeforeComma: true 18 | BinPackParameters: false 19 | ColumnLimit: 80 20 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 21 | DerivePointerAlignment: false 22 | ExperimentalAutoDetectBinPacking: false 23 | IndentCaseLabels: false 24 | IndentWrappedFunctionNames: false 25 | IndentFunctionDeclarationAfterType: false 26 | MaxEmptyLinesToKeep: 1 27 | KeepEmptyLinesAtTheStartOfBlocks: true 28 | NamespaceIndentation: None 29 | ObjCSpaceAfterProperty: false 30 | ObjCSpaceBeforeProtocolList: true 31 | PenaltyBreakBeforeFirstCallParameter: 19 32 | PenaltyBreakComment: 300 33 | PenaltyBreakString: 1000 34 | PenaltyBreakFirstLessLess: 120 35 | PenaltyExcessCharacter: 1000000 36 | PenaltyReturnTypeOnItsOwnLine: 60 37 | PointerAlignment: Left 38 | SpacesBeforeTrailingComments: 1 39 | Cpp11BracedListStyle: true 40 | Standard: Cpp11 41 | IndentWidth: 2 42 | TabWidth: 8 43 | UseTab: Never 44 | BreakBeforeBraces: Attach 45 | SpacesInParentheses: false 46 | SpacesInAngles: false 47 | SpaceInEmptyParentheses: false 48 | SpacesInCStyleCastParentheses: false 49 | SpacesInContainerLiterals: true 50 | SpaceBeforeAssignmentOperators: true 51 | ContinuationIndentWidth: 4 52 | CommentPragmas: '^ IWYU pragma:' 53 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 54 | SpaceBeforeParens: ControlStatements 55 | DisableFormat: false 56 | ... 57 | 58 | -------------------------------------------------------------------------------- /.codedocs: -------------------------------------------------------------------------------- 1 | DOXYFILE = docs/doxygen/source/doxyhtml.conf 2 | TAGLINKS = 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **.pyc 2 | **.pyo 3 | BuildConfig.json 4 | /build/ 5 | /docs/doxygen/build/ 6 | /docs/sphinx/build/ 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | dist: trusty 4 | 5 | matrix: 6 | include: 7 | # 1/ Linux GCC Builds 8 | # 9 | - compiler: gcc 10 | addons: 11 | apt: 12 | sources: 13 | - ubuntu-toolchain-r-test 14 | packages: 15 | - g++-5 16 | env: C_COMPILER=gcc-5 CXX_COMPILER=g++-5 BUILD_TYPE='Release' SANITIZER="" 17 | # 18 | - compiler: gcc 19 | addons: 20 | apt: 21 | sources: 22 | - ubuntu-toolchain-r-test 23 | packages: 24 | - g++-5 25 | env: C_COMPILER=gcc-5 CXX_COMPILER=g++-5 BUILD_TYPE='Coverage' SANITIZER="" 26 | # 27 | #- compiler: gcc 28 | #addons: 29 | #apt: 30 | #sources: 31 | #- ubuntu-toolchain-r-test 32 | #packages: 33 | #- g++-5 34 | #env: C_COMPILER=gcc-5 CXX_COMPILER=g++-5 BUILD_TYPE='Debug' SANITIZER="address" 35 | # Not supported on travis, libtsan is missing 36 | #- compiler: gcc 37 | #addons: 38 | #apt: 39 | #sources: 40 | #- ubuntu-toolchain-r-test 41 | #packages: 42 | #- g++-5 43 | #env: C_COMPILER=gcc-5 CXX_COMPILER=g++-5 BUILD_TYPE='Debug' SANITIZER="thread" 44 | # 45 | - compiler: gcc 46 | addons: 47 | apt: 48 | sources: 49 | - ubuntu-toolchain-r-test 50 | packages: 51 | - g++-5 52 | env: C_COMPILER=gcc-5 CXX_COMPILER=g++-5 BUILD_TYPE='Debug' SANITIZER="undefined" 53 | 54 | # 2/ Linux Clang Builds 55 | # 56 | - compiler: clang 57 | addons: 58 | apt: 59 | sources: 60 | - ubuntu-toolchain-r-test 61 | - llvm-toolchain-precise-3.8 62 | packages: 63 | - g++-5 64 | - clang-3.8 65 | env: C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8 BUILD_TYPE='Release' SANITIZER="" 66 | # 67 | - compiler: clang 68 | addons: 69 | apt: 70 | sources: 71 | - ubuntu-toolchain-r-test 72 | - llvm-toolchain-precise-3.8 73 | packages: 74 | - g++-5 75 | - clang-3.8 76 | env: C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8 BUILD_TYPE='Debug' SANITIZER="address" 77 | # Disabled for now because of false positive and failing blacklist 78 | #- compiler: clang 79 | #addons: 80 | #apt: 81 | #sources: 82 | #- ubuntu-toolchain-r-test 83 | #- llvm-toolchain-precise-3.8 84 | #packages: 85 | #- clang-3.8 86 | #env: C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8 BUILD_TYPE='Debug' SANITIZER="memory" 87 | # 88 | - compiler: clang 89 | addons: 90 | apt: 91 | sources: 92 | - ubuntu-toolchain-r-test 93 | - llvm-toolchain-precise-3.8 94 | packages: 95 | - g++-5 96 | - clang-3.8 97 | env: C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8 BUILD_TYPE='Debug' SANITIZER="thread" 98 | # 99 | - compiler: clang 100 | addons: 101 | apt: 102 | sources: 103 | - ubuntu-toolchain-r-test 104 | - llvm-toolchain-precise-3.8 105 | packages: 106 | - g++-5 107 | - clang-3.8 108 | env: C_COMPILER=clang-3.8 CXX_COMPILER=clang++-3.8 BUILD_TYPE='Debug' SANITIZER="undefined" 109 | 110 | # 3/ OSX Clang Builds 111 | # 112 | - os: osx 113 | osx_image: xcode8 114 | compiler: clang 115 | env: C_COMPILER=clang CXX_COMPILER='clang++' BUILD_TYPE='Release' SANITIZER="" 116 | - os: osx 117 | osx_image: xcode8 118 | compiler: clang 119 | env: C_COMPILER=clang CXX_COMPILER='clang++' BUILD_TYPE='Debug' SANITIZER="address" ASAN_OPTIONS="handle_segv=0:allow_user_segv_handler=1" 120 | # Currently unsupported 121 | #- os: osx 122 | #osx_image: xcode8 123 | #compiler: clang 124 | #env: COMPILER='clang++' BUILD_TYPE='Debug' SANITIZER="memory" 125 | # 126 | - os: osx 127 | osx_image: xcode8 128 | compiler: clang 129 | env: C_COMPILER=clang CXX_COMPILER='clang++' BUILD_TYPE='Debug' SANITIZER="thread" 130 | # Should be supported but fails at link 131 | #- os: osx 132 | #osx_image: xcode8 133 | #compiler: clang 134 | #env: C_COMPILER=clang CXX_COMPILER='clang++' BUILD_TYPE='Debug' SANITIZER="undefined" 135 | 136 | install: 137 | - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" 138 | - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} 139 | 140 | before_script: 141 | - export CC=${C_COMPILER} 142 | - export CXX=${CXX_COMPILER} 143 | - cd ${TRAVIS_BUILD_DIR} 144 | - mkdir -p Build 145 | - cd Build 146 | - cmake --version 147 | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DPROJECT_BUILD_SANITIZER_TYPE=${SANITIZER} 148 | 149 | script: 150 | - make -j2 151 | - ctest -V 152 | 153 | after_success: 154 | - | 155 | if [[ "${BUILD_TYPE}" == "Coverage" ]]; then 156 | bash <(curl -s https://codecov.io/bash) 157 | fi 158 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | # This file is NOT licensed under the GPLv3, which is the license for the rest 2 | # of YouCompleteMe. 3 | # 4 | # Here's the license text for this file: 5 | # 6 | # This is free and unencumbered software released into the public domain. 7 | # 8 | # Anyone is free to copy, modify, publish, use, compile, sell, or 9 | # distribute this software, either in source code form or as a compiled 10 | # binary, for any purpose, commercial or non-commercial, and by any 11 | # means. 12 | # 13 | # In jurisdictions that recognize copyright laws, the author or authors 14 | # of this software dedicate any and all copyright interest in the 15 | # software to the public domain. We make this dedication for the benefit 16 | # of the public at large and to the detriment of our heirs and 17 | # successors. We intend this dedication to be an overt act of 18 | # relinquishment in perpetuity of all present and future rights to this 19 | # software under copyright law. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | # OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | 30 | import os 31 | import ycm_core 32 | import json 33 | 34 | flags = [ 35 | '-Wall', 36 | '-Wextra', 37 | '-Werror', 38 | '-Wc++98-compat', 39 | '-Wno-long-long', 40 | '-Wno-variadic-macros', 41 | '-fexceptions', 42 | '-DNDEBUG', 43 | '-DUSE_CLANG_COMPLETER', 44 | '-std=c++14', 45 | '-x', 46 | 'c++', 47 | '-isystem', 48 | '../BoostParts', 49 | '-isystem', 50 | '/System/Library/Frameworks/Python.framework/Headers', 51 | '-isystem', 52 | '../llvm/include', 53 | '-isystem', 54 | '../llvm/tools/clang/include', 55 | '-I', 56 | '.', 57 | '-I', 58 | './ClangCompleter', 59 | '-isystem', 60 | './tests/gmock/gtest', 61 | '-isystem', 62 | './tests/gmock/gtest/include', 63 | '-isystem', 64 | './tests/gmock', 65 | '-isystem', 66 | './tests/gmock/include', 67 | ] 68 | 69 | 70 | # Set this to the absolute path to the folder (NOT the file!) containing the 71 | # compile_commands.json file to use that instead of 'flags'. See here for 72 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 73 | # 74 | # You can get CMake to generate this file for you by adding: 75 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) 76 | # to your CMakeLists.txt file. 77 | # 78 | # Most projects will NOT need to set this to anything; you can just change the 79 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 80 | 81 | def DirectoryOfThisScript(): 82 | return os.path.dirname( os.path.abspath( __file__ ) ) 83 | 84 | compilation_database_folder = '' 85 | with open('%s/BuildConfig.json' % DirectoryOfThisScript()) as build_config_file: 86 | json_data = json.load(build_config_file) 87 | compilation_database_folder = json_data['rtp'].encode('ascii','replace') 88 | 89 | database = None 90 | if os.path.exists( compilation_database_folder ): 91 | database = ycm_core.CompilationDatabase( compilation_database_folder ) 92 | 93 | SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] 94 | 95 | 96 | 97 | def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): 98 | if not working_directory: 99 | return list( flags ) 100 | new_flags = [] 101 | make_next_absolute = False 102 | path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] 103 | for flag in flags: 104 | new_flag = flag 105 | 106 | if make_next_absolute: 107 | make_next_absolute = False 108 | if not flag.startswith( '/' ): 109 | new_flag = os.path.join( working_directory, flag ) 110 | 111 | for path_flag in path_flags: 112 | if flag == path_flag: 113 | make_next_absolute = True 114 | break 115 | 116 | if flag.startswith( path_flag ): 117 | path = flag[ len( path_flag ): ] 118 | new_flag = path_flag + os.path.join( working_directory, path ) 119 | break 120 | 121 | if new_flag: 122 | new_flags.append( new_flag ) 123 | return new_flags 124 | 125 | 126 | def IsHeaderFile( filename ): 127 | extension = os.path.splitext( filename )[ 1 ] 128 | return extension in [ '.h', '.hxx', '.hpp', '.hh' ] 129 | 130 | 131 | def GetCompilationInfoForFile( filename ): 132 | # The compilation_commands.json file generated by CMake does not have entries 133 | # for header files. So we do our best by asking the db for flags for a 134 | # corresponding source file, if any. If one exists, the flags for that file 135 | # should be good enough. 136 | if IsHeaderFile( filename ): 137 | basename = os.path.splitext( filename )[ 0 ] 138 | for extension in SOURCE_EXTENSIONS: 139 | replacement_file = basename + extension 140 | if os.path.exists( replacement_file ): 141 | compilation_info = database.GetCompilationInfoForFile( 142 | replacement_file ) 143 | if compilation_info.compiler_flags_: 144 | return compilation_info 145 | return None 146 | return database.GetCompilationInfoForFile( filename ) 147 | 148 | 149 | def FlagsForFile( filename, **kwargs ): 150 | if database: 151 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 152 | # python list, but a "list-like" StringVec object 153 | compilation_info = GetCompilationInfoForFile( filename ) 154 | if not compilation_info: 155 | return None 156 | 157 | final_flags = MakeRelativePathsInFlagsAbsolute( 158 | compilation_info.compiler_flags_, 159 | compilation_info.compiler_working_dir_ ) 160 | 161 | # NOTE: This is just for YouCompleteMe; it's highly likely that your project 162 | # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR 163 | # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. 164 | try: 165 | final_flags.remove( '-stdlib=libc++' ) 166 | except ValueError: 167 | pass 168 | else: 169 | relative_to = DirectoryOfThisScript() 170 | final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) 171 | 172 | return { 173 | 'flags': final_flags, 174 | 'do_cache': True 175 | } 176 | -------------------------------------------------------------------------------- /3rdparty/catch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(catch INTERFACE) 2 | target_include_directories(catch INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 3 | -------------------------------------------------------------------------------- /3rdparty/catch/update_catch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" 4 | URL="https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp" 5 | wget "${URL}" -O "${SCRIPTPATH}/catch.hpp" 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # C++ Project template 2 | # 3 | # Proudly bootstrapped by git@github.com:duckie/cpp_project_template.git 4 | # 5 | 6 | # Version guard 7 | cmake_minimum_required (VERSION 3.2) 8 | 9 | # Cmake modules 10 | include(CheckCXXSourceCompiles) 11 | include(CheckCXXCompilerFlag) 12 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") 13 | include(ProjectGlobalMacros) 14 | include(ProjectTestFunctions) 15 | 16 | # Project configuration 17 | project (named_types) 18 | enable_testing() 19 | set(CMAKE_VERBOSE_MAKEFILE OFF) 20 | 21 | # Check for C++11/14 support 22 | project_check_cpp_version() 23 | 24 | ## Snippets to enforce a C++ version 25 | #if (not CPP14_SUPPORT) 26 | # message(FATAL_ERROR "C++14 support is required.") 27 | #endif() 28 | #if (not CPP11_SUPPORT) 29 | # message(FATAL_ERROR "C++11 support is required.") 30 | #endif() 31 | 32 | # Trace compilation for tools (ex: YouCompleteMe) 33 | set(CMAKE_EXPORT_COMPILE_COMMANDS 1) 34 | configure_file(${PROJECT_SOURCE_DIR}/cmake/BuildConfig.json.in ${PROJECT_SOURCE_DIR}/BuildConfig.json) 35 | 36 | # Tooling - some must be declared before adding other subdirectories 37 | project_enable_coverage_build() 38 | project_enable_sanitizer_build() 39 | project_enable_clang_format() 40 | project_enable_documentation() 41 | 42 | 43 | ### MANUAL_INCLUDE_DIRS is useful to force ides to find some includes (useless for compilation) ### 44 | ### To be used by editing the cache manually 45 | include_directories(${MANUAL_INCLUDE_DIRS}) 46 | 47 | project_add_3rdparty(catch) 48 | 49 | # By default we put binaries into this directory 50 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) 51 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) 52 | 53 | add_subdirectory(test) 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jean-Bernard Jansen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | named\_types 2 | ================== 3 | 4 | [![Travis CI Build Status](https://api.travis-ci.org/duckie/named_types.svg?branch=master)](https://travis-ci.org/duckie/named_types) 5 | [![codecov.io](http://codecov.io/github/duckie/named_types/coverage.svg?branch=master)](http://codecov.io/github/duckie/named_types?branch=master) 6 | [![Documentation Status](https://readthedocs.org/projects/cpp-project-template/badge/?version=latest)](http://named-types.readthedocs.io/en/latest) 7 | 8 | `named_types` is a C++14/1z named types implementation. It interacts well with the standard library. `named_types` is a header-only library. The current implementation offers the `named_tuple` facility and tools to manipulate compile-time strings. `named_variant` and `named_any` are planned. 9 | 10 | `named_types` can be compiled with: 11 | 12 | - *GCC* `5.3.1` or higher 13 | - *Clang* `3.9` or higher 14 | - ~~Visual C++ `14.0.23107.0 D14REL` or higher~~ not test with latest version 15 | 16 | ## What can I do with it ? 17 | 18 | - Write code more robust to future changes 19 | - Make different parts of a software to communicate without sharing complex types 20 | - Generate flexible factories with one line ([see an example](test/examples/factory.cc)) 21 | - Generate JSON data from statically defined structures without the boilerplate hassle ([see an example](test/demo6.cc)) 22 | - Project JSON data onto statically defined structures ([see examples](test/named_tuple_extensions_tests.cc)) 23 | 24 | ## named\_tuple 25 | 26 | #### With literal operator template for strings ([N3599](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3599.html)), `GCC` and `Clang` only 27 | 28 | ```c++ 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | using namespace named_types; 35 | namespace { 36 | template constexpr named_tag> operator ""_t () { return {}; } 37 | } 38 | 39 | int main() { 40 | auto test = make_named_tuple( 41 | "nom"_t = std::string("Roger") 42 | , "age"_t = 47 43 | , "taille"_t = 1.92 44 | , "liste"_t = std::vector({1,2,3}) 45 | ); 46 | 47 | std::cout 48 | << "nom"_t(test) << "\n" 49 | << "age"_t(test) << "\n" 50 | << "taille"_t(test) << "\n" 51 | << "liste"_t(test).size() << std::endl; 52 | 53 | std::get(test) = "Marcel"; 54 | ++std::get<1>(test); 55 | "taille"_t(test) = 1.93; 56 | 57 | return 0; 58 | } 59 | ``` 60 | 61 | ####Standard `C++14` 62 | 63 | ```c++ 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | using namespace named_types; 71 | namespace { 72 | size_t constexpr operator "" _h(const char* c, size_t s) { return const_hash(c); } 73 | 74 | template 75 | constexpr named_tag> at() { return {}; } 76 | 77 | template constexpr decltype(auto) 78 | at(Tuple&& in) { return at()(std::forward(in)); } 79 | } 80 | 81 | int main() { 82 | auto test = make_named_tuple( 83 | at<"name"_h>() = std::string("Roger") 84 | , at<"age"_h>() = 47 85 | , at<"size"_h>() = 1.92 86 | , at<"list"_h>() = std::vector {1,2,3} 87 | ); 88 | 89 | std::cout 90 | << at<"name"_h>(test) << "\n" 91 | << at<"age"_h>(test) << "\n" 92 | << at<"size"_h>(test) << "\n" 93 | << at<"list"_h>(test).size() 94 | << std::endl; 95 | 96 | std::get())>(test) = "Marcel"; 97 | ++std::get<1>(test); 98 | at<"size"_h>(test) = 1.93; 99 | return 0; 100 | } 101 | ``` 102 | 103 | ### Introduction 104 | 105 | The aim of a `named_tuple` is to provide compile time access to elements by name, as a classic `struct` would, __and__ compile time access to elements by their index, as a `std::tuple` would. 106 | 107 | `named_tuple` has no overhead as long as you enable inlining (most of the time by enabling optimizations). The overhead is still tiny when disabling inlining. 108 | 109 | ### Features 110 | 111 | #### Code readability 112 | 113 | A `named_tuple` makes code cleaner since it provides more meaningful access for attributes and let code using them more robust when attributes are inserted or deleted. 114 | 115 | #### Simple declaration 116 | 117 | As named tuples are meant to store data, it is important to keep a readable declarative syntax to use them as members or as non-templated function arguments if needed. 118 | 119 | ```c++ 120 | named_tuple test; 121 | ``` 122 | 123 | #### Compliancy with `std::tuple` 124 | 125 | A `named_tuple` inherits from `std::tuple` with no additional data member, making it as efficient as a `std::tuple` and higly compliant with source code using `std::tuple`. 126 | 127 | ```c++ 128 | auto test = make_named_tuple( 129 | _() = std::string("Roger") 130 | , _() = 47 131 | ); 132 | 133 | std::tuple tuple1(test); 134 | named_tuple test2 = tuple1; 135 | std::string name_val; 136 | std::tie(name_val, std::ignore) = test2; 137 | ``` 138 | 139 | #### Tuple promotion 140 | 141 | A given tuple can automatically be promoted to another if each common member is implicitly convertible. 142 | ```c++ 143 | void start(named_tuple const& conf) { 144 | std::cout << "Host " << _(conf) << " on port " << _(conf) << "\n"; 145 | } 146 | 147 | int main() { 148 | start(make_named_tuple(_() = std::string("mywebsite"))); 149 | start(make_named_tuple(_() = 441u)); 150 | return 0; 151 | } 152 | ``` 153 | 154 | #### Tuple injection 155 | 156 | Promotion has a drawback : the values not extracted from the promoted tuple takes their default values. It is either impossible (no default constructor for instance) or unwanted. You can affect any named tuple to any other named tuple : common members will be copied or moved, uncommon members will be left untouched. 157 | ```c++ 158 | template void configure(T&& values) { 159 | // Default values 160 | auto conf = make_named_tuple( 161 | _() = std::string("defaulthost") 162 | , _() = 80 163 | ); 164 | // Inject values 165 | conf = std::forward(values); 166 | std::cout << "Host " << _(conf) << " on port " << _(conf) << "\n"; 167 | } 168 | 169 | int main() { 170 | configure(make_named_tuple(_() = std::string("mywebsite"))); 171 | configure(make_named_tuple(_() = 441u)); 172 | return 0; 173 | } 174 | ``` 175 | 176 | #### Compile time introspection 177 | 178 | `named_tuple` members can be looped over at compile time. 179 | 180 | ```c++ 181 | size_t constexpr operator "" _s(const char* c, size_t s) 182 | { return basic_lowcase_charset_format::encode(c,s); } 183 | 184 | template constexpr named_tag::type> 185 | at() { return {}; } 186 | 187 | template constexpr decltype(auto) at(Tuple&& in) 188 | { return at()(std::forward(in)); } 189 | 190 | template class Serializer { 191 | std::ostringstream& output_; 192 | public: 193 | Serializer(std::ostringstream& output) : output_(output) {} 194 | 195 | template 196 | void operator() (Tag const&, Type const& value) { 197 | output_ 198 | << ((0 < Tuple::template tag_index::value)?",":"") 199 | << '"' << typename Tag::value_type().str() << "\":\"" << value << "\""; 200 | } 201 | 202 | void stream(Tuple const& t) { 203 | output_ << '{'; 204 | for_each(*this,t); 205 | output_ << '}'; 206 | } 207 | }; 208 | 209 | template std::string Serialize(Tuple const& t) { 210 | std::ostringstream output; 211 | Serializer(output).stream(t); 212 | return output.str(); 213 | } 214 | 215 | int main() { 216 | auto test = make_named_tuple( 217 | at<"name"_s>() = std::string("Roger") 218 | , at<"lastname"_s>() = std::string("Lefouard") 219 | , at<"age"_s>() = 45 220 | , at<"size"_s>() = 1.92f 221 | ); 222 | 223 | std::cout << Serialize(test) << std::endl; 224 | return 0; 225 | } 226 | ``` 227 | 228 | ## Compile time strings 229 | 230 | All over the examples, a use is made of a very simple templated string. 231 | 232 | ```c++ 233 | template string_literal; 234 | ``` 235 | 236 | This types is able to generate the corresponding ``char const*``, its size, a hash code and to concatenate with its peers. 237 | 238 | ### String literals with literal operator template 239 | 240 | This is the easiest and cleanest way to use them, unfortunately, it is not standard C++ and is not compliant with *Visual Studio*. It can be used in *Clang* and *GCC* as a GNU extension. 241 | 242 | ```c++ 243 | template constexpr named_tag> 244 | operator ""_t () { return {}; } 245 | ``` 246 | 247 | ### String literals encoded on unsigned integers 248 | 249 | The ``named_types`` project provides a facility to encode strings on unsigned integers. For instance, a 64 bits unsigned integer can store up to 8 characters. By narrowing the charset, you can store more. ``named_types`` can encode any charset (up to 255 chars with *Visual Studio*, due to a constexpr limitation) on any unsigned integer. For instance, any string made of *[0-9][a-b]-_* can be stored up to 12 characters on a 64 bits unsigned integer. If you add capital letters to it, it falls down to 10 characters. If you really need to use longer strings with this tool, they must be concatenated. 250 | 251 | ```c++ 252 | uint64_t constexpr operator "" _s(const char* c, size_t s) 253 | { return basic_lowcase_charset_format::encode(c,s); } 254 | 255 | template constexpr char const* decode() { 256 | return typename basic_lowcase_charset_format::decode::type().str(); 257 | } 258 | // ... 259 | std::cout << decode<"atmost12char"_s>() << std::endl; 260 | ``` 261 | 262 | ```c++ 263 | uint64_t constexpr operator "" _s(const char* c, size_t s) 264 | { return ascii_charset_format::encode(c,s); } 265 | 266 | template constexpr char const* decode() { 267 | return typename ascii_charset_format::decode::type().str(); 268 | } 269 | // ... 270 | std::cout << decode<"Max9Char!"_s>() << std::endl; 271 | ``` 272 | 273 | You can use a charset of your own: 274 | 275 | ```c++ 276 | // Size of the longest string made of 'a' and 'b' storable on a uint32_t 277 | std::cout << integral_string_format::max_length_value << std:endl; 278 | ``` 279 | 280 | ## Build 281 | 282 | You dont need to build anything to use it, ``named_tuple`` is header-only. 283 | 284 | #### Build and run tests 285 | 286 | Tests can be built and ran with CTest. 287 | 288 | ``` 289 | cmake ${named_types_dir} 290 | make 291 | make test 292 | ``` 293 | 294 | ## References 295 | 296 | `named_tuple` is not the only project with such goals in mind. You migh consider the following resources: 297 | 298 | * Discussions on [StackOverflow](http://stackoverflow.com/questions/13065166/c11-tagged-tuple) and [GoogleGroups](https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/N-kIXNrkTUk) 299 | * [Inline Object Declaration](https://github.com/matt-42/iod) 300 | 301 | If you are looking for similar things but at runtime (dynamic structures), head to [this project](https://github.com/duckie/CppNestedContainer) and other resources referenced in it. 302 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Unfortunately, the AppVeyor compiler versiin is not 2 | # fresh enough to compule named_types 3 | environment: 4 | matrix: 5 | - config: Debug 6 | - config: RelWithDebInfo 7 | 8 | shallow_clone: true 9 | 10 | # Operating system (build VM template) 11 | os: Visual Studio 2015 12 | 13 | # scripts that are called at very beginning, before repo cloning 14 | init: 15 | 16 | # clone directory 17 | clone_folder: c:\projects\named_types 18 | 19 | platform: x64 20 | 21 | install: 22 | - set 23 | #- echo cmake on AppVeyor 24 | #- cmake -version 25 | #- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 26 | 27 | build_script: 28 | #- cd c:\projects\named_types 29 | #- mkdir build 30 | #- cd build 31 | - echo %config% 32 | # This will produce lots of LNK4099 warnings which can be ignored. 33 | # Unfortunately they can't be disabled, see 34 | # http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings 35 | #- cmake -LA -G "Visual Studio 14 Win64" 36 | #-DCMAKE_BUILD_TYPE=%config% 37 | #.. 38 | #- msbuild named_types.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140 39 | #- cmake .. -LA -G "NMake Makefiles" 40 | #-DCMAKE_BUILD_TYPE=%config% 41 | #- nmake 42 | 43 | test_script: 44 | - echo "Project not supported on Appveyor" 45 | # "-E testdata-overview" exempts one test we know fails on Appveyor 46 | # because we currently don't have spatialite support. 47 | #- ctest --output-on-failure 48 | #-C %config% 49 | #-E testdata-overview 50 | -------------------------------------------------------------------------------- /cmake/BuildConfig.json.in: -------------------------------------------------------------------------------- 1 | {"rtp":"${PROJECT_BINARY_DIR}"} 2 | -------------------------------------------------------------------------------- /cmake/Findrapidjson.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011 Milo Yip (miloyip@gmail.com) 2 | # Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com) 3 | # Distributed under the MIT License (see license.txt file) 4 | 5 | # ----------------------------------------------------------------------------------- 6 | # 7 | # Finds the rapidjson library 8 | # 9 | # ----------------------------------------------------------------------------------- 10 | # 11 | # Variables used by this module, they can change the default behaviour. 12 | # Those variables need to be either set before calling find_package 13 | # or exported as environment variables before running CMake: 14 | # 15 | # RAPIDJSON_INCLUDEDIR - Set custom include path, useful when rapidjson headers are 16 | # outside system paths 17 | # RAPIDJSON_USE_SSE2 - Configure rapidjson to take advantage of SSE2 capabilities 18 | # RAPIDJSON_USE_SSE42 - Configure rapidjson to take advantage of SSE4.2 capabilities 19 | # 20 | # ----------------------------------------------------------------------------------- 21 | # 22 | # Variables defined by this module: 23 | # 24 | # RAPIDJSON_FOUND - True if rapidjson was found 25 | # RAPIDJSON_INCLUDE_DIRS - Path to rapidjson include directory 26 | # RAPIDJSON_CXX_FLAGS - Extra C++ flags required for compilation with rapidjson 27 | # 28 | # ----------------------------------------------------------------------------------- 29 | # 30 | # Example usage: 31 | # 32 | # set(RAPIDJSON_USE_SSE2 ON) 33 | # set(RAPIDJSON_INCLUDEDIR "/opt/github.com/rjeczalik/rapidjson/include") 34 | # 35 | # find_package(rapidjson REQUIRED) 36 | # 37 | # include_directories("${RAPIDJSON_INCLUDE_DIRS}") 38 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}") 39 | # add_executable(foo foo.cc) 40 | # 41 | # ----------------------------------------------------------------------------------- 42 | 43 | foreach(opt RAPIDJSON_INCLUDEDIR RAPIDJSON_USE_SSE2 RAPIDJSON_USE_SSE42) 44 | if(${opt} AND DEFINED ENV{${opt}} AND NOT ${opt} STREQUAL "$ENV{${opt}}") 45 | message(WARNING "Conflicting ${opt} values: ignoring environment variable and using CMake cache entry.") 46 | elseif(DEFINED ENV{${opt}} AND NOT ${opt}) 47 | set(${opt} "$ENV{${opt}}") 48 | endif() 49 | endforeach() 50 | 51 | find_path( 52 | RAPIDJSON_INCLUDE_DIRS 53 | NAMES rapidjson/rapidjson.h 54 | PATHS ${RAPIDJSON_INCLUDEDIR} 55 | DOC "Include directory for the rapidjson library." 56 | ) 57 | 58 | mark_as_advanced(RAPIDJSON_INCLUDE_DIRS) 59 | 60 | if(RAPIDJSON_INCLUDE_DIRS) 61 | set(RAPIDJSON_FOUND TRUE) 62 | endif() 63 | 64 | mark_as_advanced(RAPIDJSON_FOUND) 65 | 66 | if(RAPIDJSON_USE_SSE42) 67 | set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE42") 68 | if(MSVC) 69 | set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE4.2") 70 | else() 71 | set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse4.2") 72 | endif() 73 | else() 74 | if(RAPIDJSON_USE_SSE2) 75 | set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE2") 76 | if(MSVC) 77 | set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE2") 78 | else() 79 | set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse2") 80 | endif() 81 | endif() 82 | endif() 83 | 84 | mark_as_advanced(RAPIDJSON_CXX_FLAGS) 85 | 86 | if(RAPIDJSON_FOUND) 87 | if(NOT rapidjson_FIND_QUIETLY) 88 | message(STATUS "Found rapidjson header files in ${RAPIDJSON_INCLUDE_DIRS}") 89 | if(DEFINED RAPIDJSON_CXX_FLAGS) 90 | message(STATUS "Found rapidjson C++ extra compilation flags: ${RAPIDJSON_CXX_FLAGS}") 91 | endif() 92 | endif() 93 | elseif(rapidjson_FIND_REQUIRED) 94 | message(FATAL_ERROR "Could not find rapidjson") 95 | else() 96 | message(STATUS "Optional package rapidjson was not found") 97 | endif() 98 | -------------------------------------------------------------------------------- /cmake/ProjectGlobalMacros.cmake: -------------------------------------------------------------------------------- 1 | # Feature detection 2 | find_program(MEMORYCHECK_COMMAND valgrind) 3 | find_program(GCOV_EXE gcov) 4 | find_program(LCOV_EXE lcov) 5 | find_program(GENHTML_EXE genhtml) 6 | find_program(CLANG_FORMAT_EXE clang-format) 7 | find_package(PythonInterp) 8 | find_program(MAKE_EXE make) 9 | find_program(DOXYGEN_EXE doxygen) 10 | 11 | # Check C++ version 12 | macro(project_check_cpp_version) 13 | if (NOT MSVC) 14 | # Tests for Clang and GCC 15 | check_cxx_compiler_flag(-std=c++1y CPP14_SUPPORT) 16 | if (CPP14_SUPPORT) 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y") 18 | message("-- C++14 support found.") 19 | else() 20 | check_cxx_compiler_flag(-std=c++11 CPP11_SUPPORT) 21 | if (CPP11_SUPPORT) 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 23 | message("-- C++11 support found.") 24 | endif() 25 | endif() 26 | else() 27 | # Tests for MSVC 28 | # Unfortunately, due to various unsupported things in msvc versions, 29 | # this is poor informatiion about actual support 30 | check_cxx_source_compiles("#include \nusing std::integer_sequence;\n int main(){return 0;}" CPP14_SUPPORT) 31 | if (CPP14_SUPPORT) 32 | message("-- C++14 support found.") 33 | else() 34 | check_cxx_source_compiles("static constexpr int TEST=0;\n int main(){return 0;}" CPP11_SUPPORT) 35 | if (CPP11_SUPPORT) 36 | message("-- C++11 support found.") 37 | endif() 38 | endif () 39 | endif() 40 | endmacro(project_check_cpp_version) 41 | 42 | # Enable memory checks for people using bizarre ctest builds 43 | macro(project_enable_memcheck) 44 | if (NOT MSVC) 45 | set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full") 46 | set(MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/.valgrind_suppress.txt") 47 | else() 48 | endif() 49 | endmacro(project_enable_memcheck) 50 | 51 | # Add 3rdparty for main file 52 | macro(project_add_3rdparty name) 53 | add_subdirectory(3rdparty/${name}) 54 | endmacro(project_add_3rdparty) 55 | 56 | # Add module for main file 57 | macro(project_add_module name) 58 | add_subdirectory(src/${name}) 59 | endmacro(project_add_module) 60 | 61 | # Enable coverage 62 | macro(project_enable_coverage_build) 63 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 64 | set(CMAKE_CXX_FLAGS_COVERAGE "-g -O0 -Wall --coverage") # -fprofile-arcs -ftest-coverage") 65 | set(CMAKE_C_FLAGS_COVERAGE "-g -O0 -Wall --coverage") # -fprofile-arcs -ftest-coverage") 66 | set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "--coverage") # -fprofile-arcs -ftest-coverage") 67 | set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "--coverage")# -fprofile-arcs -ftest-coverage") 68 | set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1) 69 | 70 | if ("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") 71 | # gcov 72 | if (NOT ${GCOV_EXE} STREQUAL GCOV_EXE-NOTFOUND) 73 | file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/coverage/gcov) 74 | message("-- gcov found, coverage reports available through target 'gcov'") 75 | add_custom_target(gcov 76 | COMMAND find ${PROJECT_BINARY_DIR} -type f -name *.gcno -exec ${GCOV_EXE} -pb {} '\;' > ${PROJECT_BINARY_DIR}/coverage/gcov/coverage.info 77 | COMMAND echo "Generated coverage report: " ${PROJECT_BINARY_DIR}/coverage/gcov/coverage.info 78 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/coverage/gcov 79 | ) 80 | endif() 81 | 82 | # lcov 83 | if (NOT ${LCOV_EXE} STREQUAL LCOV_EXE-NOTFOUND AND NOT ${GENHTML_EXE} STREQUAL GENHTML_EXE-NOTFOUND) 84 | message("-- lcov and genhtml found, html reports available through target 'lcov'") 85 | file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/coverage/lcov/html) 86 | add_custom_target(lcov 87 | COMMAND lcov --capture --directory ${PROJECT_BINARY_DIR} --output-file coverage.info 88 | COMMAND genhtml coverage.info --output-directory html 89 | COMMAND echo "HTML report generated in: " ${PROJECT_BINARY_DIR}/coverage/lcov/html 90 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/coverage/lcov 91 | ) 92 | endif() 93 | endif() 94 | endif() 95 | endmacro(project_enable_coverage_build) 96 | 97 | # Enable sanitizers builds 98 | macro(project_enable_sanitizer_build) 99 | configure_file(${PROJECT_SOURCE_DIR}/cmake/SanitizerBlacklist.txt.in ${PROJECT_BINARY_DIR}/SanitizerBlacklist.txt) 100 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 101 | set(SAN ${PROJECT_BUILD_SANITIZER_TYPE}) 102 | if (NOT ${SAN} STREQUAL "") 103 | if (${SAN} STREQUAL "address" 104 | OR ${SAN} STREQUAL "memory" 105 | OR ${SAN} STREQUAL "thread" 106 | OR ${SAN} STREQUAL "undefined") 107 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${SAN} -fsanitize-blacklist=${PROJECT_BINARY_DIR}/SanitizerBlacklist.txt") 108 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${SAN} -fsanitize-blacklist=${PROJECT_BINARY_DIR}/SanitizerBlacklist.txt") 109 | else() 110 | message(FATAL_ERROR "Clang sanitizer ${SAN} is unknown.") 111 | endif() 112 | endif() 113 | endif() 114 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") 115 | set(SAN ${PROJECT_BUILD_SANITIZER_TYPE}) 116 | if (NOT ${SAN} STREQUAL "") 117 | if (${SAN} STREQUAL "address" 118 | OR ${SAN} STREQUAL "thread" 119 | OR ${SAN} STREQUAL "undefined") 120 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${SAN}") 121 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${SAN}") 122 | else() 123 | message(FATAL_ERROR "GCC sanitizer ${SAN} is unknown.") 124 | endif() 125 | endif() 126 | endif() 127 | endmacro(project_enable_sanitizer_build) 128 | 129 | # Format the whole source code with clang-format 130 | macro(project_enable_clang_format) 131 | if (NOT ${CLANG_FORMAT_EXE} STREQUAL "CLANG_FORMAT_EXE-NOTFOUND") 132 | message("-- clang-format found, whole source formatting enabled through 'format' target.") 133 | add_custom_target(format 134 | COMMAND find ./src -type f -regex .*\\.h\\\|.*\\.hpp\\\|.*\\.hxx\\\|.*\\.c\\\|.*\\.cpp\\\|.*\\.cxx\\\|.*\\.cc -exec clang-format -i {} \; 135 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 136 | VERBATIM 137 | ) 138 | endif() 139 | endmacro(project_enable_clang_format) 140 | 141 | # Format the whole source code with clang-format 142 | macro(project_enable_documentation) 143 | add_custom_target(docs) 144 | if(NOT ${DOXYGEN_EXE} STREQUAL "DOXYGEN_EXE-NOTFOUND") 145 | message("-- Doxygen found, targets 'docs-doxygen-html' and 'docs-doxygen-xml' enabled.") 146 | add_custom_target(docs-doxygen-xml 147 | COMMAND ${DOXYGEN_EXE} docs/doxygen/source/doxyxml.conf 148 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 149 | ) 150 | add_custom_target(docs-doxygen-html 151 | COMMAND ${DOXYGEN_EXE} docs/doxygen/source/doxyhtml.conf 152 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 153 | ) 154 | # Dependency to XML will be added by sphinx, not the default 155 | add_dependencies(docs docs-doxygen-html) 156 | 157 | if (PYTHONINTERP_FOUND AND NOT ${MAKE_EXE} STREQUAL "MAKE_EXE-NOTFOUND") 158 | message("-- Python, doxygen and make found, target 'docs-sphinx' enabled.") 159 | add_custom_target(docs-sphinx 160 | DEPENDS docs-doxygen-xml 161 | COMMAND ${MAKE_EXE} html 162 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/docs/sphinx 163 | ) 164 | add_dependencies(docs docs-sphinx) 165 | endif() 166 | endif() 167 | endmacro(project_enable_documentation) 168 | -------------------------------------------------------------------------------- /cmake/ProjectTestFunctions.cmake: -------------------------------------------------------------------------------- 1 | # This file provides function to add tests tp ctest 2 | # with additional tooling 3 | 4 | ## 5 | # project_add_test has the same effect as add_test, but with additional effects : 6 | # - It add a prefix before COMMAND if you want one (ex:run valgrind or perf) 7 | # Use the PROJECT_TEST_COMMANDS_PREFIX to add a prefix. PROJECT_TEST_COMMANDS_PREFIX will be parsed 8 | # in such a way that it can be a full command with quoted arguments 9 | # 10 | # It supports both complete syntaxes of add_test transparently 11 | # 12 | separate_arguments(PARSED_PROJECT_TEST_COMMANDS_PREFIX UNIX_COMMAND ${PROJECT_TEST_COMMANDS_PREFIX}) 13 | function(project_add_test test_name) 14 | # Parse command line arguments to support various add_test syntaxes 15 | set(options OPTIONAL FAST) 16 | set(oneValueArgs NAME WORKING_DIRECTORY) 17 | set(multiValueArgs COMMAND CONFIGURATIONS) 18 | cmake_parse_arguments(project_add_test "${options}" "${oneValueArgs}" "${multiValueArgs}" ${test_name} ${ARGN}) 19 | 20 | if ("${project_add_test_NAME}" STREQUAL "") 21 | # This is the short definition 22 | add_test(${test_name} ${PARSED_PROJECT_TEST_COMMANDS_PREFIX} ${ARGN}) 23 | else() 24 | # Classic standard definitiom 25 | add_test(NAME ${project_add_test_NAME} 26 | COMMAND ${PARSED_PROJECT_TEST_COMMANDS_PREFIX} ${project_add_test_COMMAND} 27 | CONFIGURATIONS ${project_add_test_CONFIGURATIONS} 28 | WORKING_DIRECTORY ${project_add_test_WORKING_DIRECTORY} 29 | ) 30 | endif() 31 | endfunction(project_add_test) 32 | -------------------------------------------------------------------------------- /cmake/SanitizerBlacklist.txt.in: -------------------------------------------------------------------------------- 1 | # Ignore issues in std 2 | fun:std::* 3 | # Ignore issues in 3rdparty 4 | src:${PROJECT_SOURCE_DIR}/3rdparty/* 5 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - "3rdparty/**/*" 4 | codecov: 5 | ci: 6 | - "!circleci.com" 7 | -------------------------------------------------------------------------------- /docs/sphinx/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 16 | 17 | .PHONY: help 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " singlehtml to make a single large HTML file" 23 | @echo " pickle to make pickle files" 24 | @echo " json to make JSON files" 25 | @echo " htmlhelp to make HTML files and a HTML help project" 26 | @echo " qthelp to make HTML files and a qthelp project" 27 | @echo " applehelp to make an Apple Help Book" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " epub3 to make an epub3" 31 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 32 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 33 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 34 | @echo " text to make text files" 35 | @echo " man to make manual pages" 36 | @echo " texinfo to make Texinfo files" 37 | @echo " info to make Texinfo files and run them through makeinfo" 38 | @echo " gettext to make PO message catalogs" 39 | @echo " changes to make an overview of all changed/added/deprecated items" 40 | @echo " xml to make Docutils-native XML files" 41 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 42 | @echo " linkcheck to check all external links for integrity" 43 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 44 | @echo " coverage to run coverage check of the documentation (if enabled)" 45 | @echo " dummy to check syntax errors of document sources" 46 | 47 | .PHONY: clean 48 | clean: 49 | rm -rf $(BUILDDIR)/* 50 | 51 | .PHONY: html 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | .PHONY: dirhtml 58 | dirhtml: 59 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 60 | @echo 61 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 62 | 63 | .PHONY: singlehtml 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | .PHONY: pickle 70 | pickle: 71 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 72 | @echo 73 | @echo "Build finished; now you can process the pickle files." 74 | 75 | .PHONY: json 76 | json: 77 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 78 | @echo 79 | @echo "Build finished; now you can process the JSON files." 80 | 81 | .PHONY: htmlhelp 82 | htmlhelp: 83 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 84 | @echo 85 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 86 | ".hhp project file in $(BUILDDIR)/htmlhelp." 87 | 88 | .PHONY: qthelp 89 | qthelp: 90 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 91 | @echo 92 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 93 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 94 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Cprojecttemplate.qhcp" 95 | @echo "To view the help file:" 96 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Cprojecttemplate.qhc" 97 | 98 | .PHONY: applehelp 99 | applehelp: 100 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 101 | @echo 102 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 103 | @echo "N.B. You won't be able to view it unless you put it in" \ 104 | "~/Library/Documentation/Help or install it in your application" \ 105 | "bundle." 106 | 107 | .PHONY: devhelp 108 | devhelp: 109 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 110 | @echo 111 | @echo "Build finished." 112 | @echo "To view the help file:" 113 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Cprojecttemplate" 114 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Cprojecttemplate" 115 | @echo "# devhelp" 116 | 117 | .PHONY: epub 118 | epub: 119 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 120 | @echo 121 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 122 | 123 | .PHONY: epub3 124 | epub3: 125 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 126 | @echo 127 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 128 | 129 | .PHONY: latex 130 | latex: 131 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 132 | @echo 133 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 134 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 135 | "(use \`make latexpdf' here to do that automatically)." 136 | 137 | .PHONY: latexpdf 138 | latexpdf: 139 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 140 | @echo "Running LaTeX files through pdflatex..." 141 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 142 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 143 | 144 | .PHONY: latexpdfja 145 | latexpdfja: 146 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 147 | @echo "Running LaTeX files through platex and dvipdfmx..." 148 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 149 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 150 | 151 | .PHONY: text 152 | text: 153 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 154 | @echo 155 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 156 | 157 | .PHONY: man 158 | man: 159 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 160 | @echo 161 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 162 | 163 | .PHONY: texinfo 164 | texinfo: 165 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 166 | @echo 167 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 168 | @echo "Run \`make' in that directory to run these through makeinfo" \ 169 | "(use \`make info' here to do that automatically)." 170 | 171 | .PHONY: info 172 | info: 173 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 174 | @echo "Running Texinfo files through makeinfo..." 175 | make -C $(BUILDDIR)/texinfo info 176 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 177 | 178 | .PHONY: gettext 179 | gettext: 180 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 181 | @echo 182 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 183 | 184 | .PHONY: changes 185 | changes: 186 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 187 | @echo 188 | @echo "The overview file is in $(BUILDDIR)/changes." 189 | 190 | .PHONY: linkcheck 191 | linkcheck: 192 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 193 | @echo 194 | @echo "Link check complete; look for any errors in the above output " \ 195 | "or in $(BUILDDIR)/linkcheck/output.txt." 196 | 197 | .PHONY: doctest 198 | doctest: 199 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 200 | @echo "Testing of doctests in the sources finished, look at the " \ 201 | "results in $(BUILDDIR)/doctest/output.txt." 202 | 203 | .PHONY: coverage 204 | coverage: 205 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 206 | @echo "Testing of coverage in the sources finished, look at the " \ 207 | "results in $(BUILDDIR)/coverage/python.txt." 208 | 209 | .PHONY: xml 210 | xml: 211 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 212 | @echo 213 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 214 | 215 | .PHONY: pseudoxml 216 | pseudoxml: 217 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 218 | @echo 219 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 220 | 221 | .PHONY: dummy 222 | dummy: 223 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 224 | @echo 225 | @echo "Build finished. Dummy builder generates no files." 226 | -------------------------------------------------------------------------------- /docs/sphinx/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | set I18NSPHINXOPTS=%SPHINXOPTS% source 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. epub3 to make an epub3 31 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 32 | echo. text to make text files 33 | echo. man to make manual pages 34 | echo. texinfo to make Texinfo files 35 | echo. gettext to make PO message catalogs 36 | echo. changes to make an overview over all changed/added/deprecated items 37 | echo. xml to make Docutils-native XML files 38 | echo. pseudoxml to make pseudoxml-XML files for display purposes 39 | echo. linkcheck to check all external links for integrity 40 | echo. doctest to run all doctests embedded in the documentation if enabled 41 | echo. coverage to run coverage check of the documentation if enabled 42 | echo. dummy to check syntax errors of document sources 43 | goto end 44 | ) 45 | 46 | if "%1" == "clean" ( 47 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 48 | del /q /s %BUILDDIR%\* 49 | goto end 50 | ) 51 | 52 | 53 | REM Check if sphinx-build is available and fallback to Python version if any 54 | %SPHINXBUILD% 1>NUL 2>NUL 55 | if errorlevel 9009 goto sphinx_python 56 | goto sphinx_ok 57 | 58 | :sphinx_python 59 | 60 | set SPHINXBUILD=python -m sphinx.__init__ 61 | %SPHINXBUILD% 2> nul 62 | if errorlevel 9009 ( 63 | echo. 64 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 65 | echo.installed, then set the SPHINXBUILD environment variable to point 66 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 67 | echo.may add the Sphinx directory to PATH. 68 | echo. 69 | echo.If you don't have Sphinx installed, grab it from 70 | echo.http://sphinx-doc.org/ 71 | exit /b 1 72 | ) 73 | 74 | :sphinx_ok 75 | 76 | 77 | if "%1" == "html" ( 78 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 79 | if errorlevel 1 exit /b 1 80 | echo. 81 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 82 | goto end 83 | ) 84 | 85 | if "%1" == "dirhtml" ( 86 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 87 | if errorlevel 1 exit /b 1 88 | echo. 89 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 90 | goto end 91 | ) 92 | 93 | if "%1" == "singlehtml" ( 94 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 95 | if errorlevel 1 exit /b 1 96 | echo. 97 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 98 | goto end 99 | ) 100 | 101 | if "%1" == "pickle" ( 102 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 103 | if errorlevel 1 exit /b 1 104 | echo. 105 | echo.Build finished; now you can process the pickle files. 106 | goto end 107 | ) 108 | 109 | if "%1" == "json" ( 110 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 111 | if errorlevel 1 exit /b 1 112 | echo. 113 | echo.Build finished; now you can process the JSON files. 114 | goto end 115 | ) 116 | 117 | if "%1" == "htmlhelp" ( 118 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 119 | if errorlevel 1 exit /b 1 120 | echo. 121 | echo.Build finished; now you can run HTML Help Workshop with the ^ 122 | .hhp project file in %BUILDDIR%/htmlhelp. 123 | goto end 124 | ) 125 | 126 | if "%1" == "qthelp" ( 127 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 128 | if errorlevel 1 exit /b 1 129 | echo. 130 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 131 | .qhcp project file in %BUILDDIR%/qthelp, like this: 132 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Cprojecttemplate.qhcp 133 | echo.To view the help file: 134 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Cprojecttemplate.ghc 135 | goto end 136 | ) 137 | 138 | if "%1" == "devhelp" ( 139 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 140 | if errorlevel 1 exit /b 1 141 | echo. 142 | echo.Build finished. 143 | goto end 144 | ) 145 | 146 | if "%1" == "epub" ( 147 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 148 | if errorlevel 1 exit /b 1 149 | echo. 150 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 151 | goto end 152 | ) 153 | 154 | if "%1" == "epub3" ( 155 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 156 | if errorlevel 1 exit /b 1 157 | echo. 158 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 159 | goto end 160 | ) 161 | 162 | if "%1" == "latex" ( 163 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 164 | if errorlevel 1 exit /b 1 165 | echo. 166 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdf" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "latexpdfja" ( 181 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 182 | cd %BUILDDIR%/latex 183 | make all-pdf-ja 184 | cd %~dp0 185 | echo. 186 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 187 | goto end 188 | ) 189 | 190 | if "%1" == "text" ( 191 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 192 | if errorlevel 1 exit /b 1 193 | echo. 194 | echo.Build finished. The text files are in %BUILDDIR%/text. 195 | goto end 196 | ) 197 | 198 | if "%1" == "man" ( 199 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 200 | if errorlevel 1 exit /b 1 201 | echo. 202 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 203 | goto end 204 | ) 205 | 206 | if "%1" == "texinfo" ( 207 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 208 | if errorlevel 1 exit /b 1 209 | echo. 210 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 211 | goto end 212 | ) 213 | 214 | if "%1" == "gettext" ( 215 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 216 | if errorlevel 1 exit /b 1 217 | echo. 218 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 219 | goto end 220 | ) 221 | 222 | if "%1" == "changes" ( 223 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 224 | if errorlevel 1 exit /b 1 225 | echo. 226 | echo.The overview file is in %BUILDDIR%/changes. 227 | goto end 228 | ) 229 | 230 | if "%1" == "linkcheck" ( 231 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Link check complete; look for any errors in the above output ^ 235 | or in %BUILDDIR%/linkcheck/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "doctest" ( 240 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of doctests in the sources finished, look at the ^ 244 | results in %BUILDDIR%/doctest/output.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "coverage" ( 249 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Testing of coverage in the sources finished, look at the ^ 253 | results in %BUILDDIR%/coverage/python.txt. 254 | goto end 255 | ) 256 | 257 | if "%1" == "xml" ( 258 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 259 | if errorlevel 1 exit /b 1 260 | echo. 261 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 262 | goto end 263 | ) 264 | 265 | if "%1" == "pseudoxml" ( 266 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 267 | if errorlevel 1 exit /b 1 268 | echo. 269 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 270 | goto end 271 | ) 272 | 273 | if "%1" == "dummy" ( 274 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 275 | if errorlevel 1 exit /b 1 276 | echo. 277 | echo.Build finished. Dummy builder generates no files. 278 | goto end 279 | ) 280 | 281 | :end 282 | -------------------------------------------------------------------------------- /docs/sphinx/source/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # C++ project template documentation build configuration file, created by 5 | # sphinx-quickstart on Fri Jul 29 21:31:04 2016. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # 20 | # import os 21 | # import sys 22 | # sys.path.insert(0, os.path.abspath('.')) 23 | 24 | import os, subprocess, sys 25 | 26 | # -- General configuration ------------------------------------------------ 27 | 28 | read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True' 29 | 30 | # If your documentation needs a minimal Sphinx version, state it here. 31 | # 32 | # needs_sphinx = '1.0' 33 | 34 | # Add any Sphinx extension module names here, as strings. They can be 35 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 36 | # ones. 37 | extensions = [ 38 | 'sphinx.ext.autodoc', 39 | 'sphinx.ext.coverage', 40 | 'sphinx.ext.mathjax', 41 | 'sphinx.ext.viewcode', 42 | 'breathe', 43 | ] 44 | 45 | #if not read_the_docs_build: 46 | #extensions.append('sphinx.ext.githubpages') 47 | 48 | # Add any paths that contain templates here, relative to this directory. 49 | templates_path = ['_templates'] 50 | 51 | # The suffix(es) of source filenames. 52 | # You can specify multiple suffix as a list of string: 53 | # 54 | # source_suffix = ['.rst', '.md'] 55 | source_suffix = '.rst' 56 | 57 | # The encoding of source files. 58 | # 59 | # source_encoding = 'utf-8-sig' 60 | 61 | # The master toctree document. 62 | master_doc = 'index' 63 | 64 | # General information about the project. 65 | project = 'C++ project template' 66 | copyright = '2016, Jean-Bernard Jansen' 67 | author = 'Jean-Bernard Jansen' 68 | 69 | # The version info for the project you're documenting, acts as replacement for 70 | # |version| and |release|, also used in various other places throughout the 71 | # built documents. 72 | # 73 | # The short X.Y version. 74 | version = '0.1' 75 | # The full version, including alpha/beta/rc tags. 76 | release = '0.1.1' 77 | 78 | # The language for content autogenerated by Sphinx. Refer to documentation 79 | # for a list of supported languages. 80 | # 81 | # This is also used if you do content translation via gettext catalogs. 82 | # Usually you set "language" from the command line for these cases. 83 | language = None 84 | 85 | # There are two options for replacing |today|: either, you set today to some 86 | # non-false value, then it is used: 87 | # 88 | # today = '' 89 | # 90 | # Else, today_fmt is used as the format for a strftime call. 91 | # 92 | # today_fmt = '%B %d, %Y' 93 | 94 | # List of patterns, relative to source directory, that match files and 95 | # directories to ignore when looking for source files. 96 | # This patterns also effect to html_static_path and html_extra_path 97 | exclude_patterns = [] 98 | 99 | # The reST default role (used for this markup: `text`) to use for all 100 | # documents. 101 | # 102 | # default_role = None 103 | 104 | # If true, '()' will be appended to :func: etc. cross-reference text. 105 | # 106 | # add_function_parentheses = True 107 | 108 | # If true, the current module name will be prepended to all description 109 | # unit titles (such as .. function::). 110 | # 111 | # add_module_names = True 112 | 113 | # If true, sectionauthor and moduleauthor directives will be shown in the 114 | # output. They are ignored by default. 115 | # 116 | # show_authors = False 117 | 118 | # The name of the Pygments (syntax highlighting) style to use. 119 | pygments_style = 'sphinx' 120 | 121 | # A list of ignored prefixes for module index sorting. 122 | # modindex_common_prefix = [] 123 | 124 | # If true, keep warnings as "system message" paragraphs in the built documents. 125 | # keep_warnings = False 126 | 127 | # If true, `todo` and `todoList` produce output, else they produce nothing. 128 | todo_include_todos = False 129 | 130 | 131 | # -- Options for HTML output ---------------------------------------------- 132 | 133 | # The theme to use for HTML and HTML Help pages. See the documentation for 134 | # a list of builtin themes. 135 | # 136 | html_theme = 'alabaster' 137 | 138 | # Theme options are theme-specific and customize the look and feel of a theme 139 | # further. For a list of options available for each theme, see the 140 | # documentation. 141 | # 142 | # html_theme_options = {} 143 | 144 | # Add any paths that contain custom themes here, relative to this directory. 145 | # html_theme_path = [] 146 | 147 | # The name for this set of Sphinx documents. 148 | # " v documentation" by default. 149 | # 150 | # html_title = 'C++ project template v0.1.1' 151 | 152 | # A shorter title for the navigation bar. Default is the same as html_title. 153 | # 154 | # html_short_title = None 155 | 156 | # The name of an image file (relative to this directory) to place at the top 157 | # of the sidebar. 158 | # 159 | # html_logo = None 160 | 161 | # The name of an image file (relative to this directory) to use as a favicon of 162 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 163 | # pixels large. 164 | # 165 | # html_favicon = None 166 | 167 | # Add any paths that contain custom static files (such as style sheets) here, 168 | # relative to this directory. They are copied after the builtin static files, 169 | # so a file named "default.css" will overwrite the builtin "default.css". 170 | html_static_path = ['_static'] 171 | 172 | # Add any extra paths that contain custom files (such as robots.txt or 173 | # .htaccess) here, relative to this directory. These files are copied 174 | # directly to the root of the documentation. 175 | # 176 | # html_extra_path = [] 177 | 178 | # If not None, a 'Last updated on:' timestamp is inserted at every page 179 | # bottom, using the given strftime format. 180 | # The empty string is equivalent to '%b %d, %Y'. 181 | # 182 | # html_last_updated_fmt = None 183 | 184 | # If true, SmartyPants will be used to convert quotes and dashes to 185 | # typographically correct entities. 186 | # 187 | # html_use_smartypants = True 188 | 189 | # Custom sidebar templates, maps document names to template names. 190 | # 191 | # html_sidebars = {} 192 | 193 | # Additional templates that should be rendered to pages, maps page names to 194 | # template names. 195 | # 196 | # html_additional_pages = {} 197 | 198 | # If false, no module index is generated. 199 | # 200 | # html_domain_indices = True 201 | 202 | # If false, no index is generated. 203 | # 204 | # html_use_index = True 205 | 206 | # If true, the index is split into individual pages for each letter. 207 | # 208 | # html_split_index = False 209 | 210 | # If true, links to the reST sources are added to the pages. 211 | # 212 | # html_show_sourcelink = True 213 | 214 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 215 | # 216 | # html_show_sphinx = True 217 | 218 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 219 | # 220 | # html_show_copyright = True 221 | 222 | # If true, an OpenSearch description file will be output, and all pages will 223 | # contain a tag referring to it. The value of this option must be the 224 | # base URL from which the finished HTML is served. 225 | # 226 | # html_use_opensearch = '' 227 | 228 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 229 | # html_file_suffix = None 230 | 231 | # Language to be used for generating the HTML full-text search index. 232 | # Sphinx supports the following languages: 233 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' 234 | # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh' 235 | # 236 | # html_search_language = 'en' 237 | 238 | # A dictionary with options for the search language support, empty by default. 239 | # 'ja' uses this config value. 240 | # 'zh' user can custom change `jieba` dictionary path. 241 | # 242 | # html_search_options = {'type': 'default'} 243 | 244 | # The name of a javascript file (relative to the configuration directory) that 245 | # implements a search results scorer. If empty, the default will be used. 246 | # 247 | # html_search_scorer = 'scorer.js' 248 | 249 | # Output file base name for HTML help builder. 250 | htmlhelp_basename = 'Cprojecttemplatedoc' 251 | 252 | # -- Options for LaTeX output --------------------------------------------- 253 | 254 | latex_elements = { 255 | # The paper size ('letterpaper' or 'a4paper'). 256 | # 257 | # 'papersize': 'letterpaper', 258 | 259 | # The font size ('10pt', '11pt' or '12pt'). 260 | # 261 | # 'pointsize': '10pt', 262 | 263 | # Additional stuff for the LaTeX preamble. 264 | # 265 | # 'preamble': '', 266 | 267 | # Latex figure (float) alignment 268 | # 269 | # 'figure_align': 'htbp', 270 | } 271 | 272 | # Grouping the document tree into LaTeX files. List of tuples 273 | # (source start file, target name, title, 274 | # author, documentclass [howto, manual, or own class]). 275 | latex_documents = [ 276 | (master_doc, 'Cprojecttemplate.tex', 'C++ project template Documentation', 277 | 'Jean-Bernard Jansen', 'manual'), 278 | ] 279 | 280 | # The name of an image file (relative to this directory) to place at the top of 281 | # the title page. 282 | # 283 | # latex_logo = None 284 | 285 | # For "manual" documents, if this is true, then toplevel headings are parts, 286 | # not chapters. 287 | # 288 | # latex_use_parts = False 289 | 290 | # If true, show page references after internal links. 291 | # 292 | # latex_show_pagerefs = False 293 | 294 | # If true, show URL addresses after external links. 295 | # 296 | # latex_show_urls = False 297 | 298 | # Documents to append as an appendix to all manuals. 299 | # 300 | # latex_appendices = [] 301 | 302 | # It false, will not define \strong, \code, itleref, \crossref ... but only 303 | # \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added 304 | # packages. 305 | # 306 | # latex_keep_old_macro_names = True 307 | 308 | # If false, no module index is generated. 309 | # 310 | # latex_domain_indices = True 311 | 312 | 313 | # -- Options for manual page output --------------------------------------- 314 | 315 | # One entry per manual page. List of tuples 316 | # (source start file, name, description, authors, manual section). 317 | man_pages = [ 318 | (master_doc, 'cprojecttemplate', 'C++ project template Documentation', 319 | [author], 1) 320 | ] 321 | 322 | # If true, show URL addresses after external links. 323 | # 324 | # man_show_urls = False 325 | 326 | 327 | # -- Options for Texinfo output ------------------------------------------- 328 | 329 | # Grouping the document tree into Texinfo files. List of tuples 330 | # (source start file, target name, title, author, 331 | # dir menu entry, description, category) 332 | texinfo_documents = [ 333 | (master_doc, 'Cprojecttemplate', 'C++ project template Documentation', 334 | author, 'Cprojecttemplate', 'One line description of project.', 335 | 'Miscellaneous'), 336 | ] 337 | 338 | # Documents to append as an appendix to all manuals. 339 | # 340 | # texinfo_appendices = [] 341 | 342 | # If false, no module index is generated. 343 | # 344 | # texinfo_domain_indices = True 345 | 346 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 347 | # 348 | # texinfo_show_urls = 'footnote' 349 | 350 | # If true, do not generate a @detailmenu in the "Top" node's menu. 351 | # 352 | # texinfo_no_detailmenu = False 353 | 354 | 355 | # -- Options for Epub output ---------------------------------------------- 356 | 357 | # Bibliographic Dublin Core info. 358 | epub_title = project 359 | epub_author = author 360 | epub_publisher = author 361 | epub_copyright = copyright 362 | 363 | # The basename for the epub file. It defaults to the project name. 364 | # epub_basename = project 365 | 366 | # The HTML theme for the epub output. Since the default themes are not 367 | # optimized for small screen space, using the same theme for HTML and epub 368 | # output is usually not wise. This defaults to 'epub', a theme designed to save 369 | # visual space. 370 | # 371 | # epub_theme = 'epub' 372 | 373 | # The language of the text. It defaults to the language option 374 | # or 'en' if the language is not set. 375 | # 376 | # epub_language = '' 377 | 378 | # The scheme of the identifier. Typical schemes are ISBN or URL. 379 | # epub_scheme = '' 380 | 381 | # The unique identifier of the text. This can be a ISBN number 382 | # or the project homepage. 383 | # 384 | # epub_identifier = '' 385 | 386 | # A unique identification for the text. 387 | # 388 | # epub_uid = '' 389 | 390 | # A tuple containing the cover image and cover page html template filenames. 391 | # 392 | # epub_cover = () 393 | 394 | # A sequence of (type, uri, title) tuples for the guide element of content.opf. 395 | # 396 | # epub_guide = () 397 | 398 | # HTML files that should be inserted before the pages created by sphinx. 399 | # The format is a list of tuples containing the path and title. 400 | # 401 | # epub_pre_files = [] 402 | 403 | # HTML files that should be inserted after the pages created by sphinx. 404 | # The format is a list of tuples containing the path and title. 405 | # 406 | # epub_post_files = [] 407 | 408 | # A list of files that should not be packed into the epub file. 409 | epub_exclude_files = ['search.html'] 410 | 411 | # The depth of the table of contents in toc.ncx. 412 | # 413 | # epub_tocdepth = 3 414 | 415 | # Allow duplicate toc entries. 416 | # 417 | # epub_tocdup = True 418 | 419 | # Choose between 'default' and 'includehidden'. 420 | # 421 | # epub_tocscope = 'default' 422 | 423 | # Fix unsupported image types using the Pillow. 424 | # 425 | # epub_fix_images = False 426 | 427 | # Scale large images. 428 | # 429 | # epub_max_image_width = 0 430 | 431 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 432 | # 433 | # epub_show_urls = 'inline' 434 | 435 | # If false, no index is generated. 436 | # 437 | # epub_use_index = True 438 | 439 | # Execute doxygen 440 | process = subprocess.Popen(["doxygen","docs/doxygen/source/doxyxml.conf"],cwd="../../../") 441 | process.wait() 442 | if process.returncode != 0: 443 | print("Doxygen failed to run properly.") 444 | sys.exit(1) 445 | 446 | # Configure breathe 447 | breathe_projects = { "cpp_project_template": "../../doxygen/build/xml" } 448 | breathe_default_project = "cpp_project_template" 449 | 450 | -------------------------------------------------------------------------------- /docs/sphinx/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to C++ project template's documentation! 2 | ================================================ 3 | 4 | This is a default documentation for read the docs. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | .. doxygennamespace:: named_types 10 | 11 | Indices and tables 12 | ================== 13 | 14 | * :ref:`genindex` 15 | * :ref:`modindex` 16 | * :ref:`search` 17 | 18 | -------------------------------------------------------------------------------- /docs/sphinx/source/requirements.txt: -------------------------------------------------------------------------------- 1 | breathe 2 | -------------------------------------------------------------------------------- /includes/named_types/extensions/factory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../named_tuple.hpp" 3 | #include "../rt_named_tuple.hpp" 4 | 5 | namespace named_types { 6 | namespace extensions { 7 | 8 | namespace __factory_impl { 9 | template 10 | std::function make_builder() { 11 | return ([](Args... args) -> Base * 12 | { return new T(std::forward(args)...); }); 13 | } 14 | } // namespace __factory_impl 15 | 16 | template class factory { 17 | // Identity template : useless in theory but needed for MSVC to support the 18 | // functional syntax 19 | template struct id { using type = Type; }; 20 | 21 | public: 22 | template 23 | BaseClass* create(std::string const& name, BuildArgs&&... args) { 24 | using builder_tuple_type = 25 | named_tuple( 26 | __ntuple_tag_spec_t)>::type...>; 27 | static builder_tuple_type const builders_{ 28 | __factory_impl::make_builder<__ntuple_tag_elem_t, 29 | BaseClass, 30 | BuildArgs...>()...}; 31 | static const_rt_view const rt_view_(builders_); 32 | auto builder = 33 | rt_view_.template retrieve>( 34 | name); 35 | return builder ? (*builder)(std::forward(args)...) : nullptr; 36 | } 37 | }; 38 | } // namespace extensions 39 | } // namespace named_types 40 | -------------------------------------------------------------------------------- /includes/named_types/extensions/generation_tools.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "named_types/named_tuple.hpp" 5 | #include "named_types/rt_named_tuple.hpp" 6 | #include "named_types/extensions/type_traits.hpp" 7 | 8 | namespace named_types { 9 | namespace extensions { 10 | namespace generation { 11 | 12 | template struct printf_sequence { 13 | using type = void; 14 | static T evaluate(T value){ return value; }; 15 | }; 16 | 17 | template <> struct printf_sequence { 18 | using type = string_literal; 19 | static inline char const* evaluate(char const* data) { return data; }; 20 | }; 21 | 22 | template <> struct printf_sequence { 23 | using type = string_literal; 24 | static inline char const* evaluate(std::string const& data) { 25 | return data.c_str(); 26 | }; 27 | }; 28 | 29 | template <> struct printf_sequence { 30 | using type = string_literal; 31 | static inline int evaluate(int data) { return data; }; 32 | }; 33 | 34 | template <> struct printf_sequence { 35 | using type = string_literal; 36 | static inline unsigned evaluate(unsigned data) { return data; }; 37 | }; 38 | 39 | template <> struct printf_sequence { 40 | using type = string_literal; 41 | static inline int64_t evaluate(int64_t data) { return data; }; 42 | }; 43 | 44 | template <> struct printf_sequence { 45 | using type = string_literal; 46 | static inline uint64_t evaluate(uint64_t data) { return data; }; 47 | }; 48 | 49 | template <> struct printf_sequence { 50 | using type = string_literal; 51 | static inline int evaluate(bool data) { return data; }; 52 | }; 53 | 54 | template <> struct printf_sequence { 55 | using type = string_literal; 56 | static inline double evaluate(float data) { return data; }; 57 | }; 58 | 59 | template <> struct printf_sequence { 60 | using type = string_literal; 61 | static inline double evaluate(double data) { return data; }; 62 | }; 63 | 64 | //template forward_as_flattened_tuple( 65 | 66 | } // namespace generation 67 | } // namespace extensions 68 | } // namespace named_types 69 | -------------------------------------------------------------------------------- /includes/named_types/extensions/parsing_tools.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "named_types/named_tuple.hpp" 9 | #include "named_types/rt_named_tuple.hpp" 10 | #include "named_types/extensions/type_traits.hpp" 11 | 12 | namespace named_types { 13 | namespace extensions { 14 | namespace parsing { 15 | 16 | // Basic lexical cast 17 | 18 | template 19 | inline std::enable_if_t::value && 20 | is_std_basic_string::value, 21 | To> 22 | lexical_cast(From const& value) { 23 | std::basic_ostringstream output; 26 | output << value; 27 | return output.str(); 28 | } 29 | 30 | template 31 | inline std::enable_if_t::value && 32 | std::is_arithmetic::value, 33 | To> 34 | lexical_cast(From const& value) { 35 | return static_cast(value); 36 | } 37 | 38 | template 39 | inline std::enable_if_t::value && 40 | std::is_arithmetic::value, 41 | To> 42 | lexical_cast(From const& value) { 43 | To result{}; 44 | std::basic_istringstream(value) >> 47 | result; 48 | return result; 49 | } 50 | 51 | template 52 | inline std::enable_if_t::value && 53 | std::is_arithmetic::value, 54 | To> 55 | lexical_cast(From const& value) { 56 | To result{}; 57 | std::istringstream(value) >> result; 58 | return result; 59 | } 60 | 61 | // Assigner for struct parser 62 | template 63 | inline std::enable_if_t::value, 64 | std::function> 65 | make_setter() { 66 | return [](Tuple& tuple, Source&& source) 67 | -> void { std::get(tuple) = std::move(source); }; 68 | } 69 | 70 | template 71 | inline std::enable_if_t< 72 | tuple_member_static_cast_assignable::value, 73 | std::function> 74 | make_setter() { 75 | return [](Tuple& tuple, Source&& source) -> void { 76 | std::get(tuple) = static_cast< 77 | std::remove_reference_t>>( 78 | std::move(source)); 79 | }; 80 | } 81 | 82 | template 83 | inline std::enable_if_t< 84 | tuple_member_not_assignable::value, 85 | std::function> 86 | make_setter() { 87 | return nullptr; 88 | } 89 | 90 | template 91 | struct value_setter_interface; 92 | template 93 | struct sequence_pusher_interface; 94 | 95 | // This interface can be used either for a named_tuple or a map 96 | template 97 | struct value_setter_interface { 98 | virtual ~value_setter_interface() = default; 99 | virtual bool setNull(std::basic_string const&) = 0; 100 | virtual bool setBool(std::basic_string const&, bool) = 0; 101 | virtual bool setInt(std::basic_string const&, int) = 0; 102 | virtual bool setUint(std::basic_string const&, unsigned) = 0; 103 | virtual bool setInt64(std::basic_string const&, int64_t) = 0; 104 | virtual bool setUint64(std::basic_string const&, uint64_t) = 0; 105 | virtual bool setDouble(std::basic_string const&, double) = 0; 106 | virtual bool setString(std::basic_string const&, 107 | const ValueCharT*, 108 | SizeType) = 0; 109 | virtual value_setter_interface* 110 | createChildNode(std::basic_string const&) = 0; 111 | virtual sequence_pusher_interface* 112 | createChildSequence(std::basic_string const&) = 0; 113 | }; 114 | 115 | // This interface can be used either for aby SequenceContainer 116 | template 117 | struct sequence_pusher_interface { 118 | virtual ~sequence_pusher_interface() = default; 119 | virtual bool appendNull() = 0; 120 | virtual bool appendBool(bool) = 0; 121 | virtual bool appendInt(int) = 0; 122 | virtual bool appendUint(unsigned) = 0; 123 | virtual bool appendInt64(int64_t) = 0; 124 | virtual bool appendUint64(uint64_t) = 0; 125 | virtual bool appendDouble(double) = 0; 126 | virtual bool appendString(const ValueCharT*, SizeType) = 0; 127 | virtual value_setter_interface* 128 | appendChildNode() = 0; 129 | virtual sequence_pusher_interface* appendChildSequence() = 0; 130 | }; 131 | 132 | template 133 | class value_setter; 134 | template 135 | class sequence_pusher; 136 | 137 | template 142 | inline std::enable_if_t< 143 | is_sub_object>::value, 144 | std::function< 145 | value_setter_interface*(Tuple&)>> 146 | make_creator() { 147 | return [](Tuple & tuple) 148 | -> value_setter_interface * { 149 | return new value_setter>( 153 | std::get(tuple)); 154 | }; 155 | } 156 | 157 | template 162 | inline std::enable_if_t< 163 | !is_sub_object>::value, 164 | std::function< 165 | value_setter_interface*(Tuple&)>> 166 | make_creator() { 167 | return nullptr; 168 | } 169 | 170 | template 175 | inline std::enable_if_t< 176 | is_sequence_container>::value, 177 | std::function< 178 | sequence_pusher_interface*(Tuple&)>> 179 | make_sequence_creator() { 180 | return [](Tuple & tuple) 181 | -> sequence_pusher_interface * { 182 | return new sequence_pusher>( 186 | std::get(tuple)); 187 | }; 188 | } 189 | 190 | template 195 | inline std::enable_if_t< 196 | !is_sequence_container>::value, 197 | std::function< 198 | sequence_pusher_interface*(Tuple&)>> 199 | make_sequence_creator() { 200 | return nullptr; 201 | } 202 | 203 | // Implementation for associatives containers 204 | template 208 | class value_setter 209 | : public value_setter_interface { 210 | static_assert(is_associative_container::value, 211 | "The used container must be an AssociativeContainer."); 212 | using value_type = typename AssociativeContainer::mapped_type; 213 | 214 | AssociativeContainer& root_; 215 | 216 | template 217 | inline std::enable_if_t::value, bool> 218 | setFrom(std::basic_string const& key, T&& value) { 219 | root_.emplace(key, std::move(value)); 220 | return true; 221 | } 222 | 223 | template 224 | inline std::enable_if_t::value && 225 | !std::is_convertible::value, 226 | bool> 227 | setFrom(std::basic_string const& key, T&& value) { 228 | root_.emplace(key, static_cast(value)); 229 | return true; 230 | } 231 | 232 | template 233 | inline std::enable_if_t::value && 234 | !is_static_cast_assignable::value, 235 | bool> 236 | setFrom(std::basic_string const& key, T&& value) { 237 | return false; 238 | } 239 | 240 | template 241 | inline std::enable_if_t< 242 | is_sub_object::value, 243 | value_setter_interface*> 244 | createChildNode(std::basic_string const& key) { 245 | auto inserted = root_.emplace(key, T{}); 246 | if (inserted.second) 247 | return new value_setter( 248 | inserted.first->second); 249 | else 250 | return nullptr; 251 | } 252 | 253 | template 254 | inline std::enable_if_t< 255 | !is_sub_object::value, 256 | value_setter_interface*> 257 | createChildNode(std::basic_string const& key) { 258 | return nullptr; 259 | } 260 | 261 | template 262 | inline std::enable_if_t< 263 | is_sequence_container::value, 264 | sequence_pusher_interface*> 265 | createChildSequence(std::basic_string const& key) { 266 | auto inserted = root_.emplace(key, T{}); 267 | if (inserted.second) 268 | return new sequence_pusher( 269 | inserted.first->second); 270 | else 271 | return nullptr; 272 | } 273 | 274 | template 275 | inline std::enable_if_t< 276 | !is_sequence_container::value, 277 | sequence_pusher_interface*> 278 | createChildSequence(std::basic_string const& key) { 279 | return nullptr; 280 | } 281 | 282 | public: 283 | value_setter(AssociativeContainer& root) 284 | : value_setter_interface() 285 | , root_(root) {} 286 | 287 | virtual bool setNull(std::basic_string const& key) override { 288 | return setFrom(key, nullptr); 289 | } 290 | 291 | virtual bool setBool(std::basic_string const& key, 292 | bool value) override { 293 | return setFrom(key, std::move(value)); 294 | } 295 | 296 | virtual bool setInt(std::basic_string const& key, 297 | int value) override { 298 | return setFrom(key, std::move(value)); 299 | } 300 | 301 | virtual bool setUint(std::basic_string const& key, 302 | unsigned value) override { 303 | return setFrom(key, std::move(value)); 304 | } 305 | 306 | virtual bool setInt64(std::basic_string const& key, 307 | int64_t value) override { 308 | return setFrom(key, std::move(value)); 309 | } 310 | 311 | virtual bool setUint64(std::basic_string const& key, 312 | uint64_t value) override { 313 | return setFrom(key, std::move(value)); 314 | } 315 | 316 | virtual bool setDouble(std::basic_string const& key, 317 | double value) override { 318 | return setFrom(key, std::move(value)); 319 | } 320 | 321 | virtual bool setString(std::basic_string const& key, 322 | const ValueCharT* data, 323 | SizeType length) override { 324 | return setFrom>( 325 | key, std::basic_string(data)); 326 | } 327 | 328 | virtual value_setter_interface* 329 | createChildNode(std::basic_string const& key) override { 330 | return createChildNode(key); 331 | } 332 | 333 | virtual sequence_pusher_interface* 334 | createChildSequence(std::basic_string const& key) override { 335 | return createChildSequence(key); 336 | } 337 | }; 338 | 339 | // Specialization for the named tuple 340 | template 341 | class value_setter> 342 | : public value_setter_interface { 343 | using Tuple = named_tuple; 344 | 345 | Tuple& root_; 346 | rt_view rt_root_; 347 | 348 | template bool setFrom(size_t field_index, T&& value) { 349 | static std::array, Tuple::size> setters = 350 | {make_setter< 351 | T, 352 | Tuple, 353 | Tuple::template tag_index<__ntuple_tag_spec_t>::value>()...}; 354 | std::function setter( 355 | field_index < setters.size() ? setters[field_index] : nullptr); 356 | if (setter) { 357 | setter(root_, std::move(value)); 358 | return true; 359 | } 360 | return false; 361 | } 362 | 363 | public: 364 | value_setter(Tuple& root) 365 | : value_setter_interface() 366 | , root_(root) 367 | , rt_root_(root) {} 368 | 369 | virtual bool setNull(std::basic_string const& key) override { 370 | return setFrom(rt_root_.index_of(key), nullptr); 371 | } 372 | 373 | virtual bool setBool(std::basic_string const& key, 374 | bool value) override { 375 | return setFrom(rt_root_.index_of(key), std::move(value)); 376 | } 377 | 378 | virtual bool setInt(std::basic_string const& key, 379 | int value) override { 380 | return setFrom(rt_root_.index_of(key), std::move(value)); 381 | } 382 | 383 | virtual bool setUint(std::basic_string const& key, 384 | unsigned value) override { 385 | return setFrom(rt_root_.index_of(key), std::move(value)); 386 | } 387 | 388 | virtual bool setInt64(std::basic_string const& key, 389 | int64_t value) override { 390 | return setFrom(rt_root_.index_of(key), std::move(value)); 391 | } 392 | 393 | virtual bool setUint64(std::basic_string const& key, 394 | uint64_t value) override { 395 | return setFrom(rt_root_.index_of(key), std::move(value)); 396 | } 397 | 398 | virtual bool setDouble(std::basic_string const& key, 399 | double value) override { 400 | return setFrom(rt_root_.index_of(key), std::move(value)); 401 | } 402 | 403 | virtual bool setString(std::basic_string const& key, 404 | const ValueCharT* data, 405 | SizeType length) override { 406 | return setFrom>( 407 | rt_root_.index_of(key), std::basic_string(data)); 408 | } 409 | 410 | virtual value_setter_interface* 411 | createChildNode(std::basic_string const& key) override { 412 | static std::array< 413 | std::function< 414 | value_setter_interface*(Tuple&)>, 415 | Tuple::size> creators = { 416 | make_creator< 417 | KeyCharT, 418 | ValueCharT, 419 | SizeType, 420 | Tuple, 421 | Tuple::template tag_index<__ntuple_tag_spec_t>::value>()...}; 422 | size_t field_index = rt_root_.index_of(key); 423 | if (field_index < creators.size()) { 424 | std::function*( 425 | Tuple&)> creator = creators[field_index]; 426 | if (creator) 427 | return creator(root_); 428 | } 429 | return nullptr; 430 | } 431 | 432 | virtual sequence_pusher_interface* 433 | createChildSequence(std::basic_string const& key) override { 434 | static std::array< 435 | std::function< 436 | sequence_pusher_interface*(Tuple&)>, 437 | Tuple::size> creators = { 438 | make_sequence_creator< 439 | KeyCharT, 440 | ValueCharT, 441 | SizeType, 442 | Tuple, 443 | Tuple::template tag_index<__ntuple_tag_spec_t>::value>()...}; 444 | size_t field_index = rt_root_.index_of(key); 445 | if (field_index < creators.size()) { 446 | std::function*( 447 | Tuple&)> creator = creators[field_index]; 448 | if (creator) 449 | return creator(root_); 450 | } 451 | return nullptr; 452 | } 453 | }; 454 | 455 | // For sequence types 456 | template 457 | class sequence_pusher 458 | : public sequence_pusher_interface { 459 | static_assert(is_sequence_container::value, 460 | "Container must be a SequenceContainer."); 461 | 462 | using value_type = typename Container::value_type; 463 | Container& root_; 464 | std::back_insert_iterator inserter_; 465 | 466 | template 467 | inline std::enable_if_t::value, bool> 468 | appendValue(T&& value) { 469 | inserter_ = std::move(value); 470 | return true; 471 | } 472 | 473 | template 474 | inline std::enable_if_t::value && 475 | !std::is_convertible::value, 476 | bool> 477 | appendValue(T&& value) { 478 | inserter_ = static_cast(value); 479 | return true; 480 | } 481 | 482 | template 483 | inline std::enable_if_t::value && 484 | !is_static_cast_assignable::value, 485 | bool> 486 | appendValue(T&& value) { 487 | return false; 488 | } 489 | 490 | template 491 | inline std::enable_if_t< 492 | is_sub_object::value, 493 | value_setter_interface*> 494 | appendChildNode() { 495 | inserter_ = T{}; 496 | return new value_setter(root_.back()); 497 | } 498 | 499 | template 500 | inline std::enable_if_t< 501 | !is_sub_object::value, 502 | value_setter_interface*> 503 | appendChildNode() { 504 | return nullptr; 505 | } 506 | 507 | template 508 | inline std::enable_if_t< 509 | is_sequence_container::value, 510 | sequence_pusher_interface*> 511 | appendChildSequence() { 512 | inserter_ = T{}; 513 | return new sequence_pusher(root_.back()); 514 | } 515 | 516 | template 517 | inline std::enable_if_t< 518 | !is_sequence_container::value, 519 | sequence_pusher_interface*> 520 | appendChildSequence() { 521 | return nullptr; 522 | } 523 | 524 | public: 525 | sequence_pusher(Container& root) 526 | : sequence_pusher_interface() 527 | , root_(root) 528 | , inserter_(std::back_inserter(root)) {} 529 | 530 | virtual bool appendNull() override { 531 | return appendValue(nullptr); 532 | } 533 | 534 | virtual bool appendBool(bool value) override { 535 | return appendValue(std::move(value)); 536 | } 537 | 538 | virtual bool appendInt(int value) override { 539 | return appendValue(std::move(value)); 540 | } 541 | 542 | virtual bool appendUint(unsigned value) override { 543 | return appendValue(std::move(value)); 544 | } 545 | 546 | virtual bool appendInt64(int64_t value) override { 547 | return appendValue(std::move(value)); 548 | } 549 | 550 | virtual bool appendUint64(uint64_t value) override { 551 | return appendValue(std::move(value)); 552 | } 553 | 554 | virtual bool appendDouble(double value) override { 555 | return appendValue(std::move(value)); 556 | } 557 | 558 | virtual bool appendString(const ValueCharT* data, SizeType length) override { 559 | return appendValue>(data); 560 | } 561 | 562 | virtual value_setter_interface* 563 | appendChildNode() override { 564 | return appendChildNode(); 565 | } 566 | 567 | virtual sequence_pusher_interface* 568 | appendChildSequence() override { 569 | return appendChildSequence(); 570 | }; 571 | }; 572 | 573 | } // namespace parsing 574 | } // namespace extensions 575 | } // namespace named_types 576 | -------------------------------------------------------------------------------- /includes/named_types/extensions/rapidjson.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "named_types/named_tuple.hpp" 7 | #include "named_types/extensions/type_traits.hpp" 8 | #include 9 | #include "named_types/rt_named_tuple.hpp" 10 | 11 | namespace named_types { 12 | namespace extensions { 13 | namespace rapidjson { 14 | 15 | template class reader_handler; 16 | 17 | template 18 | class reader_handler : public ::rapidjson::BaseReaderHandler< 19 | Encoding, 20 | reader_handler> { 21 | static_assert(is_sub_object::value || 22 | is_sequence_container::value, 23 | "Root type of a handler must either be a named_tuple, an " 24 | "AssociativeContainer or a SequenceContainer."); 25 | 26 | enum class State { 27 | wait_start_object, 28 | wait_key, 29 | wait_value, 30 | wait_end_object, 31 | wait_start_sequence, 32 | wait_element, 33 | wait_end_sequence 34 | }; 35 | 36 | using Ch = typename Encoding::Ch; 37 | using SizeType = ::rapidjson::SizeType; 38 | using StdString = std::basic_string; 39 | 40 | struct Node { 41 | std::unique_ptr> obj_node; 42 | std::unique_ptr> 43 | array_node; 44 | 45 | Node(parsing::value_setter_interface* obj_interface, 46 | parsing::sequence_pusher_interface* array_interface) 47 | : obj_node(obj_interface) 48 | , array_node(array_interface) {} 49 | }; 50 | 51 | RootType& root_; 52 | std::stack nodes_; 53 | State state_; 54 | std::string current_key_; 55 | size_t current_index_; 56 | 57 | template 58 | inline typename std::enable_if< 59 | is_sub_object::value, 60 | parsing::value_setter_interface*>::type 61 | createRootNode(T& root) { 62 | return new parsing::value_setter(root); 63 | } 64 | 65 | template 66 | inline typename std::enable_if< 67 | !is_sub_object::value, 68 | parsing::value_setter_interface*>::type 69 | createRootNode(T& root) { 70 | return nullptr; 71 | } 72 | 73 | template 74 | inline typename std::enable_if< 75 | is_sequence_container::value, 76 | parsing::sequence_pusher_interface*>::type 77 | createRootSequence(T& root) { 78 | return new parsing::sequence_pusher(root); 79 | } 80 | 81 | template 82 | inline typename std::enable_if< 83 | !is_sequence_container::value, 84 | parsing::sequence_pusher_interface*>::type 85 | createRootSequence(T& root) { 86 | return nullptr; 87 | } 88 | 89 | public: 90 | reader_handler(RootType& root) 91 | : ::rapidjson::BaseReaderHandler() 92 | , root_(root) 93 | , state_(is_sub_object::value ? State::wait_start_object 94 | : State::wait_start_sequence) 95 | , current_key_() 96 | , current_index_(0) {} 97 | 98 | bool Null() { 99 | if (State::wait_value == state_ && nodes_.top().obj_node) { 100 | nodes_.top().obj_node->setNull(current_key_); 101 | state_ = State::wait_key; 102 | return true; 103 | } else if (State::wait_element == state_ && nodes_.top().array_node) { 104 | nodes_.top().array_node->appendNull(); 105 | return true; 106 | } 107 | return false; 108 | } 109 | 110 | bool Bool(bool value) { 111 | if (State::wait_value == state_ && nodes_.top().obj_node) { 112 | nodes_.top().obj_node->setBool(current_key_, value); 113 | state_ = State::wait_key; 114 | return true; 115 | } else if (State::wait_element == state_ && nodes_.top().array_node) { 116 | nodes_.top().array_node->appendBool(value); 117 | return true; 118 | } 119 | return false; 120 | } 121 | 122 | bool Int(int value) { 123 | if (State::wait_value == state_ && nodes_.top().obj_node) { 124 | nodes_.top().obj_node->setInt(current_key_, value); 125 | state_ = State::wait_key; 126 | return true; 127 | } else if (State::wait_element == state_ && nodes_.top().array_node) { 128 | nodes_.top().array_node->appendInt(value); 129 | return true; 130 | } 131 | return false; 132 | } 133 | 134 | bool Uint(unsigned value) { 135 | if (State::wait_value == state_ && nodes_.top().obj_node) { 136 | nodes_.top().obj_node->setUint(current_key_, value); 137 | state_ = State::wait_key; 138 | return true; 139 | } else if (State::wait_element == state_ && nodes_.top().array_node) { 140 | nodes_.top().array_node->appendUint(value); 141 | return true; 142 | } 143 | return false; 144 | } 145 | 146 | bool Int64(int64_t value) { 147 | if (State::wait_value == state_ && nodes_.top().obj_node) { 148 | nodes_.top().obj_node->setInt64(current_key_, value); 149 | state_ = State::wait_key; 150 | return true; 151 | } else if (State::wait_element == state_ && nodes_.top().array_node) { 152 | nodes_.top().array_node->appendInt64(value); 153 | return true; 154 | } 155 | return false; 156 | } 157 | 158 | bool Uint64(uint64_t value) { 159 | if (State::wait_value == state_ && nodes_.top().obj_node) { 160 | nodes_.top().obj_node->setUint64(current_key_, value); 161 | state_ = State::wait_key; 162 | return true; 163 | } else if (State::wait_element == state_ && nodes_.top().array_node) { 164 | nodes_.top().array_node->appendUint64(value); 165 | return true; 166 | } 167 | return false; 168 | } 169 | 170 | bool Double(double value) { 171 | if (State::wait_value == state_ && nodes_.top().obj_node) { 172 | nodes_.top().obj_node->setDouble(current_key_, value); 173 | state_ = State::wait_key; 174 | return true; 175 | } else if (State::wait_element == state_ && nodes_.top().array_node) { 176 | nodes_.top().array_node->appendDouble(value); 177 | return true; 178 | } 179 | return false; 180 | } 181 | 182 | bool String(const Ch* data, SizeType length, bool) { 183 | if (State::wait_value == state_ && nodes_.top().obj_node) { 184 | nodes_.top().obj_node->setString(current_key_, data, length); 185 | state_ = State::wait_key; 186 | return true; 187 | } else if (State::wait_element == state_ && nodes_.top().array_node) { 188 | nodes_.top().array_node->appendString(data, length); 189 | return true; 190 | } 191 | return false; 192 | } 193 | 194 | bool StartObject() { 195 | if (State::wait_start_object != state_ && State::wait_value != state_ && 196 | State::wait_element != state_) 197 | return false; 198 | 199 | parsing::value_setter_interface* interface = nullptr; 200 | if (nodes_.empty()) { 201 | interface = createRootNode(root_); 202 | } else if (nodes_.top().obj_node) { 203 | interface = nodes_.top().obj_node->createChildNode(current_key_); 204 | } else if (nodes_.top().array_node) { 205 | interface = nodes_.top().array_node->appendChildNode(); 206 | } 207 | 208 | if (interface) { 209 | state_ = State::wait_key; 210 | nodes_.emplace(interface, nullptr); 211 | return true; 212 | } 213 | 214 | return false; 215 | } 216 | 217 | bool Key(const Ch* str, SizeType len, bool copy) { 218 | if (state_ != State::wait_key) 219 | return false; 220 | 221 | current_key_ = std::string(str); 222 | state_ = State::wait_value; 223 | return true; 224 | } 225 | 226 | bool EndObject(SizeType) { 227 | if (State::wait_key != state_ && State::wait_end_object != state_) 228 | return false; 229 | nodes_.pop(); 230 | if (!nodes_.empty()) { 231 | state_ = nodes_.top().obj_node ? State::wait_key : State::wait_element; 232 | } 233 | return true; 234 | } 235 | 236 | bool StartArray() { 237 | if (State::wait_start_sequence != state_ && State::wait_value != state_ && 238 | State::wait_element != state_) 239 | return false; 240 | 241 | parsing::sequence_pusher_interface* interface = nullptr; 242 | if (nodes_.empty()) { 243 | interface = createRootSequence(root_); 244 | } else if (nodes_.top().obj_node) { 245 | interface = nodes_.top().obj_node->createChildSequence(current_key_); 246 | } else if (nodes_.top().array_node) { 247 | interface = nodes_.top().array_node->appendChildSequence(); 248 | } 249 | 250 | if (interface) { 251 | state_ = State::wait_element; 252 | nodes_.emplace(nullptr, interface); 253 | return true; 254 | } 255 | 256 | return false; 257 | } 258 | 259 | bool EndArray(SizeType) { 260 | if (State::wait_element != state_ && State::wait_end_sequence != state_) 261 | return false; 262 | nodes_.pop(); 263 | if (!nodes_.empty()) { 264 | state_ = nodes_.top().obj_node ? State::wait_key : State::wait_element; 265 | } 266 | return true; 267 | } 268 | }; 269 | 270 | template 271 | reader_handler> 272 | make_reader_handler(RootType& root) { 273 | return reader_handler>(root); 274 | } 275 | 276 | template 277 | reader_handler make_reader_handler(RootType& root) { 278 | return reader_handler(root); 279 | } 280 | 281 | } // namespace rapidjson 282 | } // namespace extensions 283 | } // namespace named_types 284 | -------------------------------------------------------------------------------- /includes/named_types/extensions/type_traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "named_types/named_tuple.hpp" 10 | #include "named_types/rt_named_tuple.hpp" 11 | 12 | namespace named_types { 13 | 14 | template 15 | struct is_nullable 16 | : std::integral_constant::value || 18 | std::is_assignable::value> { 19 | }; 20 | 21 | template 22 | struct is_char : std::integral_constant< 23 | bool, 24 | std::is_same>::value || 25 | std::is_same>::value || 26 | std::is_same>::value || 27 | std::is_same>::value> {}; 28 | 29 | // is_basic_string 30 | 31 | template 32 | struct is_std_basic_string : std::integral_constant {}; 33 | 34 | template 35 | struct is_std_basic_string> 36 | : std::integral_constant {}; 37 | 38 | // is_raw_string 39 | 40 | template 41 | struct is_raw_string : std::integral_constant {}; 42 | 43 | template 44 | struct is_raw_string 45 | : std::integral_constant::value> {}; 46 | 47 | template 48 | struct is_raw_string 49 | : std::integral_constant::value> {}; 50 | 51 | // is_sequence_container 52 | 53 | template 54 | struct is_sequence_container : std::integral_constant {}; 55 | 56 | template 57 | struct is_sequence_container> 58 | : std::integral_constant {}; 59 | 60 | template 61 | struct is_sequence_container> 62 | : std::integral_constant {}; 63 | 64 | // is_associative_container 65 | 66 | template 67 | struct is_associative_container : std::integral_constant {}; 68 | 69 | template 70 | struct is_associative_container> 71 | : std::integral_constant {}; 72 | 73 | template 74 | struct is_associative_container> 75 | : std::integral_constant {}; 76 | 77 | // is_named_tuple 78 | 79 | template 80 | struct is_named_tuple : std::integral_constant {}; 81 | 82 | template 83 | struct is_named_tuple> 84 | : std::integral_constant {}; 85 | 86 | // is_unique_ptr 87 | 88 | template 89 | struct is_unique_ptr : std::integral_constant {}; 90 | 91 | template 92 | struct is_unique_ptr> : std::integral_constant { 93 | }; 94 | 95 | template 96 | struct is_convertible 97 | : std::integral_constant::value && 99 | is_std_basic_string::value) || 100 | (std::is_arithmetic::value && 101 | std::is_arithmetic::value) || 102 | (is_std_basic_string::value && 103 | std::is_arithmetic::value) || 104 | (is_raw_string::value && 105 | std::is_arithmetic::value) || 106 | std::is_assignable::value> {}; 107 | 108 | template 109 | struct is_static_cast_assignable 110 | : std::integral_constant< 111 | bool, 112 | std::is_arithmetic::value && 113 | std::is_arithmetic::value && 114 | !std::is_assignable:: 116 | value> //&& !std::is_convertible::value; 117 | {}; 118 | 119 | template 120 | struct tuple_member_assignable 121 | : std::integral_constant< 122 | bool, 123 | std::is_assignable, 124 | Source>::value> {}; 125 | 126 | template 127 | struct tuple_member_convertible 128 | : std::integral_constant< 129 | bool, 130 | std::is_convertible>::value && 132 | !std::is_assignable, 133 | Source>::value> {}; 134 | 135 | template 136 | struct tuple_member_static_cast_assignable 137 | : std::integral_constant< 138 | bool, 139 | is_static_cast_assignable, 140 | Source>::value> {}; 141 | 142 | template 143 | struct tuple_member_not_assignable 144 | : std::integral_constant< 145 | bool, 146 | !tuple_member_assignable::value && 147 | !tuple_member_convertible::value && 148 | !tuple_member_static_cast_assignable:: 149 | value> {}; 150 | 151 | template 152 | struct is_sub_object 153 | : std::integral_constant::value || 155 | is_associative_container::value> {}; 156 | 157 | template 158 | struct is_sub_element 159 | : std::integral_constant::value || 161 | is_sequence_container::value || 162 | is_associative_container::value> {}; 163 | 164 | // is_tuple 165 | template struct is_tuple : std::integral_constant {}; 166 | template 167 | struct is_tuple> : std::integral_constant {}; 168 | template 169 | struct is_tuple> : std::integral_constant {}; 170 | 171 | // is_array 172 | template struct is_array : std::integral_constant {}; 173 | template 174 | struct is_array> : std::integral_constant {}; 175 | 176 | // array to tuple 177 | template struct array_to_tuple; 178 | template 179 | struct __array_to_tuple_impl; 180 | template 181 | struct __array_to_tuple_impl> { 182 | template using expand_element = T; 183 | using type = std::tuple...>; 184 | }; 185 | 186 | template struct array_to_tuple> { 187 | using l_value_reference_forwarded_type = typename __array_to_tuple_impl>::type; 188 | using const_l_value_reference_forwarded_type = typename __array_to_tuple_impl>::type; 189 | using r_value_reference_forwarded_type = typename __array_to_tuple_impl>::type; 190 | 191 | private: 192 | template static l_value_reference_forwarded_type forward_impl(std::array& value, std::index_sequence) { 193 | return l_value_reference_forwarded_type(value[Indexes]... ); 194 | } 195 | template static constexpr const_l_value_reference_forwarded_type forward_impl(std::array const& value, std::index_sequence) { 196 | return const_l_value_reference_forwarded_type(value[Indexes]...); 197 | } 198 | template static constexpr r_value_reference_forwarded_type forward_impl(std::array&& value, std::index_sequence) { 199 | return r_value_reference_forwarded_type(std::move(value[Indexes])... ); 200 | } 201 | public: 202 | using type = 203 | typename __array_to_tuple_impl>::type; 204 | 205 | static constexpr l_value_reference_forwarded_type forward(std::array& value) { 206 | return forward_impl(value, std::make_index_sequence()); 207 | } 208 | static constexpr const_l_value_reference_forwarded_type forward(std::array const& value) { 209 | return forward_impl(value, std::make_index_sequence()); 210 | } 211 | static constexpr l_value_reference_forwarded_type forward(std::array&& value) { 212 | return forward_impl(std::move(value), std::make_index_sequence()); 213 | } 214 | }; 215 | 216 | template using array_to_tuple_t = typename array_to_tuple::type; 217 | 218 | template struct tuple_cat_type; 219 | 220 | template struct tuple_cat_type { 221 | using type = typename tuple_cat_type::type>::type; 222 | }; 223 | 224 | template struct tuple_cat_type, std::tuple> { 225 | using type = std::tuple; 226 | }; 227 | 228 | template struct tuple_cat_type> { 229 | using type = std::tuple; 230 | }; 231 | 232 | template <> struct tuple_cat_type<> { 233 | using type = std::tuple<>; 234 | }; 235 | 236 | // Forward as concatenated tuple 237 | template 238 | inline constexpr auto forward_as_reference_tuple(T const& value) 239 | -> std::enable_if_t::value && !is_array::value, std::tuple> { 240 | return std::tuple(value); 241 | } 242 | 243 | template 244 | inline constexpr auto forward_as_reference_tuple(std::tuple const& value, 245 | std::index_sequence) 246 | -> decltype(std::tuple_cat( 247 | forward_as_reference_tuple(std::get(value))...)); 248 | 249 | template 250 | inline constexpr auto forward_as_reference_tuple(std::tuple const& value) 251 | -> decltype(forward_as_reference_tuple(value, 252 | std::index_sequence_for())); 253 | 254 | template 255 | inline constexpr auto forward_as_reference_tuple(std::array const& value, 256 | std::index_sequence) 257 | -> decltype(std::tuple_cat(forward_as_reference_tuple(value[Indexes])...)); 258 | // -> decltype( 259 | // std::tuple_cat(forward_as_reference_tuple(value[Indexes])...)); 260 | 261 | template 262 | inline constexpr auto forward_as_reference_tuple(std::array const& value) 263 | -> decltype(forward_as_reference_tuple(value, std::make_index_sequence())); 264 | /*template 265 | inline auto forward_as_reference_tuple(std::array const& value) 266 | -> decltype(forward_as_reference_tuple(typename array_to_tuple>::const_l_value_reference_forwarded_type));*/ 267 | 268 | template 269 | inline constexpr auto forward_as_reference_tuple(std::tuple const& value, 270 | std::index_sequence) 271 | -> decltype(std::tuple_cat( 272 | forward_as_reference_tuple(std::get(value))...)) { 273 | return std::tuple_cat( 274 | forward_as_reference_tuple(std::get(value))...); 275 | } 276 | 277 | template 278 | inline constexpr auto forward_as_reference_tuple(std::tuple const& value) 279 | -> decltype(forward_as_reference_tuple( 280 | value, std::index_sequence_for())) { 281 | return forward_as_reference_tuple(value, std::index_sequence_for()); 282 | } 283 | 284 | template 285 | inline constexpr auto forward_as_reference_tuple(std::array const& value, 286 | std::index_sequence) 287 | -> decltype(std::tuple_cat(forward_as_reference_tuple(value[Indexes])...)) 288 | { 289 | return std::tuple_cat(forward_as_reference_tuple(value[Indexes])...); 290 | } 291 | // -> decltype(std::tuple_cat(forward_as_reference_tuple(value[Indexes])...)) { 292 | // return std::tuple_cat(forward_as_reference_tuple(value[Indexes])...); 293 | //} 294 | 295 | template 296 | inline constexpr auto forward_as_reference_tuple(std::array const& value) 297 | -> decltype(forward_as_reference_tuple(value, std::make_index_sequence())) { 298 | return forward_as_reference_tuple(value, std::make_index_sequence()); 299 | } 300 | 301 | /*template 302 | inline auto forward_as_reference_tuple(std::array const& value) 303 | -> decltype(forward_as_reference_tuple(typename array_to_tuple>::const_l_value_reference_forwarded_type)) { 304 | return forward_as_reference_tuple(array_to_tuple>::forward(value)); 305 | }*/ 306 | 307 | } // namespace named_types 308 | -------------------------------------------------------------------------------- /includes/named_types/literals/integral_string_literal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "string_literal.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | namespace named_types { 8 | 9 | namespace arithmetic { 10 | 11 | 12 | template constexpr T pow(T value, size_t power) { 13 | static_assert(std::is_unsigned::value,"Type used must be unsigned"); 14 | T current_value = 1; 15 | for (size_t index = 0; index < power; ++index) 16 | current_value *= value; 17 | return current_value; 18 | } 19 | 20 | template constexpr size_t max_pow_holdable(T base, T value) { 21 | static_assert(std::is_unsigned::value,"Type used must be unsigned"); 22 | T current_value = value; 23 | size_t current_pow = 0; 24 | while (base <= current_value) { 25 | current_value /= base; 26 | ++current_pow; 27 | } 28 | 29 | // Did we miss by one click ? 30 | return current_pow; 31 | } 32 | 33 | } // namespace arithmetic 34 | 35 | 36 | /** 37 | * This class represents 38 | */ 39 | template class integral_string_format { 40 | // Compute size storable - init part 41 | static constexpr size_t max_size_storable() { 42 | return arithmetic::max_pow_holdable(sizeof ... (charset), std::numeric_limits::max()); 43 | } 44 | 45 | # ifndef _MSC_VER 46 | template static constexpr size_t index_of(Char const (&input)[Size], size_t index, Char value) { 47 | return (Size <= index) ? Size : ((input[index] == value) ? index : index_of(input,index+1,value)); 48 | } 49 | # else 50 | // MSVC does not support arrays in constexpr 51 | static constexpr size_t index_of(Char value, size_t index, size_t size) { 52 | return size; 53 | } 54 | 55 | template static constexpr size_t index_of(Char value, size_t index, size_t size, Head current, Tail ... tail) { 56 | return (index < size && value == current) ? index : index_of(value,index+1,size, tail...); 57 | } 58 | # endif 59 | 60 | // Returns the index of the given char into the charset 61 | static constexpr size_t index_of(Char value) { 62 | # ifndef _MSC_VER 63 | return index_of({charset...},0u,value); 64 | # else 65 | // MSVC does not support arrays in constexpr 66 | return index_of(value, 0u, sizeof ... (charset), charset ...); 67 | # endif 68 | } 69 | 70 | // Return true if the given char is included in the charset 71 | static constexpr bool contains(Char value) { 72 | return index_of(value) < sizeof ... (charset); 73 | } 74 | 75 | static constexpr Storage encode_impl(Char const* input, size_t current_index, size_t input_size) { 76 | size_t value = 0; 77 | for (size_t index = 0; index < input_size; ++index) { 78 | value += index_of(input[index])*arithmetic::pow(sizeof ... (charset), index); 79 | } 80 | return value; 81 | } 82 | 83 | static constexpr size_t decode_size(Storage input) { 84 | size_t index = 0; 85 | for(;arithmetic::pow(sizeof ... (charset),index) < input; ++index); 86 | return index; 87 | } 88 | 89 | # ifndef _MSC_VER 90 | template static constexpr Char char_at_impl(Char const (&input)[Size], size_t index) { 91 | return index < Size ? input[index] : 0u; 92 | } 93 | # else 94 | // MSVC does not support arrays in constexpr 95 | static constexpr Char char_at_impl(size_t current_index, size_t index) { 96 | return 0u; 97 | } 98 | 99 | template static constexpr Char char_at_impl(size_t current_index, size_t index, Head current, Tail ... tail) { 100 | return current_index == index ? current : char_at_impl(current_index+1u, index, tail...); 101 | } 102 | # endif 103 | 104 | // Returns the char at position "index" in the charset 105 | static constexpr Char char_at(size_t index) { 106 | # ifndef _MSC_VER 107 | return char_at_impl({charset...},index); 108 | # else 109 | // MSVC does not support arrays in constexpr 110 | return char_at_impl(0u, index, charset...); 111 | # endif 112 | } 113 | 114 | // Returns the charset index of the char encoded at pose "index" in the input encoded string 115 | static constexpr size_t decode_char_index_at(Storage input, size_t index) { 116 | return 0u < input ? ((input-1u) / arithmetic::pow(sizeof ... (charset),index)) % sizeof ... (charset): sizeof ... (charset); 117 | } 118 | 119 | // Returns the char encoded at position "index" in the input encoded string 120 | static constexpr Char decode_char_at(Storage input, size_t index) { 121 | return char_at(decode_char_index_at(input,index)); 122 | } 123 | 124 | template struct decode_impl; 125 | template struct decode_impl,value> { 126 | using type = string_literal; 127 | }; 128 | 129 | public: 130 | using string_literal_type = string_literal; 131 | 132 | # ifdef _MSC_VER 133 | # pragma warning(disable:4307) 134 | # endif 135 | static constexpr size_t max_length_value = max_size_storable(); 136 | # ifdef _MSC_VER 137 | # pragma warning(default:4307) 138 | # endif 139 | 140 | // Encodes a string 141 | # ifndef _MSC_VER 142 | template static constexpr Storage encode(Char const (&input)[Size]) { 143 | return encode(input,Size-1); // Be careful to exclude '\0' 144 | } 145 | # endif 146 | 147 | static constexpr Storage encode(Char const* input, size_t input_size) { 148 | return 0u == input_size ? 0u : encode_impl(input,0,input_size)+1; 149 | } 150 | 151 | static constexpr Storage encode(Char const* input) { 152 | return encode(input, const_size(input)); 153 | } 154 | 155 | // Decode an encoded string 156 | template struct decode { 157 | using type = typename decode_impl, value>::type; 158 | }; 159 | }; 160 | 161 | // Providing built-in charsets 162 | template using basic_charset = integral_string_format; 163 | template using basic_lowcase_charset = integral_string_format; 164 | template using ascii_charset = integral_string_format; 171 | 172 | // Providing standard compliant formats 173 | using basic_charset_format = basic_charset; 174 | using basic_lowcase_charset_format = basic_lowcase_charset; 175 | using ascii_charset_format = ascii_charset; 176 | 177 | }; // namespace named_types 178 | -------------------------------------------------------------------------------- /includes/named_types/literals/string_literal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "string_literal.hpp" 5 | 6 | namespace named_types { 7 | 8 | template 9 | unsigned long long constexpr const_size(Char const* input) { 10 | return *input ? 1llu + const_size(input + 1llu) : 0llu; 11 | } 12 | 13 | template 14 | unsigned long long constexpr const_hash(Char const* input) { 15 | return *input 16 | ? static_cast(*input) + 17 | 33llu * const_hash(input + 1llu) 18 | : 5381llu; 19 | } 20 | 21 | #ifndef _MSC_VER 22 | template 23 | unsigned long long constexpr array_const_hash(Char const (&input)[Size]) { 24 | return const_hash(input); 25 | } 26 | #else 27 | // MSVC does not support arrays in constexpr 28 | unsigned long long constexpr array_const_hash() { return 5381llu; } 29 | 30 | template 31 | unsigned long long constexpr array_const_hash(Head current, Tail... tail) { 32 | return 0u != current 33 | ? static_cast(current) + 34 | 33llu * array_const_hash(tail...) 35 | : 5381llu; 36 | } 37 | #endif 38 | 39 | template struct string_literal { 40 | static const char data[sizeof...(chars)+1u]; 41 | static const size_t data_size = sizeof...(chars); 42 | #ifndef _MSC_VER 43 | static const unsigned long long hash_value = 44 | array_const_hash({chars..., '\0'}); 45 | #else 46 | #pragma warning(disable : 4307) 47 | static const unsigned long long hash_value = array_const_hash(chars..., '\0'); 48 | #pragma warning(default : 4307) 49 | #endif 50 | 51 | constexpr string_literal() = default; 52 | constexpr char const* str() const { return data; } 53 | constexpr size_t size() const { return sizeof...(chars); } 54 | constexpr char operator[](size_t index) const { return data[index]; } 55 | 56 | // printf mappings 57 | // stdio includes are user's responsibility 58 | template static int printf(Args&&... args) { 59 | return ::printf(data, std::forward(args)...); 60 | } 61 | 62 | template static int sprintf(char* buffer, Args&&... args) { 63 | return ::sprintf(buffer, data, std::forward(args)...); 64 | } 65 | 66 | template 67 | static int snprintf(char* buffer, int buffer_size, Args&&... args) { 68 | return ::snprintf(buffer, buffer_size, data, std::forward(args)...); 69 | } 70 | }; 71 | 72 | template 73 | const char string_literal::data[sizeof...(chars)+1u] = {chars..., 74 | '\0'}; 75 | 76 | // concatenate 77 | 78 | template struct concatenate; 79 | template 80 | struct concatenate { 81 | using type = typename concatenate< 82 | Head, 83 | typename concatenate::type>::type; 84 | }; 85 | 86 | template 87 | struct concatenate, 88 | string_literal> { 89 | using type = string_literal; 90 | }; 91 | 92 | template 93 | struct concatenate> { 94 | using type = string_literal; 95 | }; 96 | 97 | template using concatenate_t = typename concatenate::type; 98 | 99 | // join 100 | 101 | template struct join; 102 | template 108 | struct join { 109 | using type = typename join< 110 | CharT, 111 | Glue, 112 | Head, 113 | typename join::type>::type; 114 | }; 115 | 116 | template 117 | struct join, 120 | string_literal> { 121 | using type = string_literal; 122 | }; 123 | 124 | template 125 | struct join> { 126 | using type = string_literal; 127 | }; 128 | 129 | template 130 | using join_t = typename join::type; 131 | 132 | // repeat 133 | 134 | template struct repeat_string; 135 | 136 | template 137 | struct repeat_string<0u, string_literal> { 138 | using type = string_literal; 139 | }; 140 | 141 | template 142 | struct repeat_string> { 143 | using type = concatenate_t < string_literal, 144 | typename repeat_string>::type>; 145 | }; 146 | 147 | template 148 | using repeat_string_t = typename repeat_string::type; 149 | 150 | // join_repeat 151 | 152 | template struct join_repeat_string; 153 | 154 | 155 | template 156 | struct join_repeat_string<0u, CharT, Glue, string_literal> { 157 | using type = string_literal; 158 | }; 159 | 160 | template 161 | struct join_repeat_string<1u, CharT, Glue, string_literal> { 162 | using type = string_literal; 163 | }; 164 | 165 | template 166 | struct join_repeat_string> { 167 | using type = concatenate_t , 168 | typename join_repeat_string>::type>; 169 | }; 170 | 171 | template 172 | using join_repeat_string_t = typename join_repeat_string::type; 173 | 174 | } // namespace string_literal 175 | -------------------------------------------------------------------------------- /includes/named_types/named_tag.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "literals/string_literal.hpp" 3 | #include 4 | #include 5 | 6 | namespace named_types { 7 | 8 | template struct __ntag_notation {}; 9 | template struct __ntag_notation { 10 | using type = Spec(Arg); 11 | }; 12 | 13 | template using __ntag_notation_t = typename __ntag_notation::type; 14 | 15 | // Traits for compile time name extraction 16 | 17 | template class has_user_defined_name { 18 | template static auto test(int) -> decltype(TT::classname); 19 | // Unfortunately, MSVC doest not implement expression SFINAE 20 | #ifndef _MSC_VER 21 | template static auto test(int) -> decltype(TT::name); 22 | template static auto test(int) -> decltype(TT::classname()); 23 | template static auto test(int) -> decltype(TT::name()); 24 | #endif // _MSC_VER 25 | template static auto test(...) -> void; 26 | 27 | public: 28 | static constexpr bool value = 29 | std::is_same(0)), char const*>::value; 30 | }; 31 | 32 | template class constexpr_type_name { 33 | template 34 | static inline constexpr auto extract(int) -> decltype(TT::classname) { 35 | return TT::classname; 36 | } 37 | // Unfortunately, MSVC doest not implement expression SFINAE 38 | #ifndef _MSC_VER 39 | template 40 | static inline constexpr auto extract(int) -> decltype(TT::name) { 41 | return TT::name; 42 | } 43 | template 44 | static inline constexpr auto extract(int) -> decltype(TT::classname()) { 45 | return TT::classname(); 46 | } 47 | template 48 | static inline constexpr auto extract(int) -> decltype(TT::name()) { 49 | return TT::name(); 50 | } 51 | #endif // _MSC_VER 52 | public: 53 | static char const* value; 54 | static constexpr char const* str() { return extract(); }; 55 | }; 56 | 57 | template 58 | char const* 59 | constexpr_type_name::value = constexpr_type_name::extract(); 60 | 61 | //// Name extractors specified to work with string literals 62 | template 63 | class has_user_defined_name> { 64 | public: 65 | static constexpr bool value = true; 66 | }; 67 | 68 | template 69 | class constexpr_type_name> { 70 | public: 71 | using type = string_literal; 72 | static char const* value; 73 | static constexpr char const* str() { 74 | return string_literal().str(); 75 | }; 76 | }; 77 | 78 | template 79 | char const* constexpr_type_name>::value = 80 | string_literal::data; 81 | 82 | template 83 | using constexpr_type_name_t = typename constexpr_type_name::type; 84 | 85 | // Private types 86 | 87 | template class __attribute_const_reference_holder; 88 | template class __attribute_reference_holder; 89 | template class __attribute_value_holder; 90 | 91 | // Tag, shared by every one 92 | 93 | template struct named_tag; 94 | template class named_attribute_holder; 95 | 96 | // Specific types : named_tuple 97 | 98 | template struct named_tuple; 99 | template struct __ntuple_tag_spec; 100 | template struct __ntuple_tag_elem; 101 | 102 | // Tag 103 | 104 | template struct named_tag : std::tag::basic_tag { 105 | private: 106 | template struct unnested_ { using type = named_tag; }; 107 | template struct unnested_> { 108 | using type = named_tag; 109 | }; 110 | template struct unnested_value_ { using type = T; }; 111 | template struct unnested_value_> { 112 | using type = T; 113 | }; 114 | 115 | public: 116 | using type = typename unnested_::type; 117 | using value_type = typename unnested_value_::type; 118 | using tag_func_notation = __ntag_notation_t; 119 | constexpr named_tag() = default; 120 | 121 | // Attribute holder generation 122 | 123 | template 124 | __attribute_const_reference_holder operator=(T const& value) { 125 | return __attribute_const_reference_holder(value); 126 | } 127 | 128 | template 129 | __attribute_reference_holder operator=(T& value) { 130 | return __attribute_reference_holder(value); 131 | } 132 | 133 | template 134 | __attribute_value_holder operator=(T&& value) { 135 | return __attribute_value_holder(std::move(value)); 136 | } 137 | 138 | // Specific behavior : named_tuple 139 | 140 | template 141 | inline constexpr decltype(auto) 142 | operator()(named_tuple const& input) const { 143 | return std::get(input); 144 | } 145 | 146 | template 147 | inline constexpr decltype(auto) 148 | operator()(named_tuple& input) const { 149 | return std::get(input); 150 | } 151 | 152 | template 153 | inline constexpr decltype(auto) 154 | operator()(named_tuple&& input) const { 155 | return std::get(std::move(input)); 156 | } 157 | }; 158 | 159 | // Attribute holders 160 | 161 | template class __attribute_const_reference_holder { 162 | Value const& value_; 163 | 164 | public: 165 | using tag_type = Tag; 166 | using value_type = Value; 167 | using tag_func_notation = 168 | __ntag_notation_t::type(value_type)>; 169 | __attribute_const_reference_holder(Value const& input) 170 | : value_(input) {} 171 | __attribute_const_reference_holder( 172 | __attribute_const_reference_holder const&) = delete; 173 | __attribute_const_reference_holder(__attribute_const_reference_holder&&) = 174 | default; 175 | __attribute_const_reference_holder& 176 | operator=(__attribute_const_reference_holder const&) = delete; 177 | __attribute_const_reference_holder& 178 | operator=(__attribute_const_reference_holder&&) = default; 179 | Value const& get() { return value_; } 180 | }; 181 | 182 | template class __attribute_reference_holder { 183 | Value& value_; 184 | 185 | public: 186 | using tag_type = Tag; 187 | using value_type = Value; 188 | using tag_func_notation = 189 | __ntag_notation_t::type(value_type)>; 190 | __attribute_reference_holder(Value& input) 191 | : value_(input) {} 192 | __attribute_reference_holder(__attribute_reference_holder const&) = delete; 193 | __attribute_reference_holder(__attribute_reference_holder&&) = default; 194 | __attribute_reference_holder& 195 | operator=(__attribute_reference_holder const&) = delete; 196 | __attribute_reference_holder& 197 | operator=(__attribute_reference_holder&&) = default; 198 | Value& get() { return value_; } 199 | }; 200 | 201 | template class __attribute_value_holder { 202 | Value&& value_; 203 | 204 | public: 205 | using tag_type = Tag; 206 | using value_type = Value; 207 | using tag_func_notation = 208 | __ntag_notation_t::type(value_type)>; 209 | __attribute_value_holder(Value&& input) 210 | : value_(std::move(input)) {} 211 | __attribute_value_holder(__attribute_value_holder const&) = delete; 212 | __attribute_value_holder(__attribute_value_holder&&) = default; 213 | __attribute_value_holder& operator=(__attribute_value_holder const&) = delete; 214 | __attribute_value_holder& operator=(__attribute_value_holder&&) = default; 215 | Value get() { return std::move(value_); } 216 | }; 217 | 218 | template 219 | inline decltype(auto) 220 | __attribute_holder_get(AttributeHolder&& attribute_holder) { 221 | return std::move(attribute_holder).get(); 222 | } 223 | 224 | // get 225 | 226 | template decltype(auto) get(Tagged&& input) { 227 | return std::get::type>(std::forward(input)); 228 | }; 229 | 230 | } // namespace named_types 231 | -------------------------------------------------------------------------------- /includes/named_types/named_tuple.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "named_tag.hpp" 6 | 7 | namespace named_types { 8 | 9 | template struct __ntuple_tag_spec {}; 10 | template struct __ntuple_tag_spec { 11 | using type = typename named_tag::type; 12 | }; 13 | template 14 | using __ntuple_tag_spec_t = typename __ntuple_tag_spec::type; 15 | 16 | template struct __ntuple_tag_elem {}; 17 | template struct __ntuple_tag_elem { 18 | using type = Arg; 19 | }; 20 | template 21 | using __ntuple_tag_elem_t = typename __ntuple_tag_elem::type; 22 | 23 | template struct __ntuple_tag_notation {}; 24 | template struct __ntuple_tag_notation { 25 | using type = typename named_tag::type(Arg); 26 | }; 27 | template 28 | using __ntuple_tag_notation_t = typename __ntuple_tag_notation::type; 29 | 30 | template 31 | struct named_tuple : public std::tagged_tuple<__ntuple_tag_notation_t...> 32 | // struct named_tuple : std::tagged_tuple< Types ... 33 | { 34 | // Type aliases 35 | using tuple_type = std::tuple<__ntuple_tag_elem_t...>; 36 | using tagged_type = std::tagged_tuple<__ntuple_tag_notation_t...>; 37 | using std::tagged_tuple<__ntuple_tag_notation_t...>::tagged_tuple; 38 | 39 | // Static data 40 | 41 | static constexpr size_t size = sizeof...(Types); 42 | 43 | // Constructors 44 | 45 | constexpr named_tuple() = default; 46 | constexpr named_tuple(named_tuple&&) = default; 47 | constexpr named_tuple(const named_tuple&) = default; 48 | named_tuple& operator=(named_tuple&&) = default; 49 | named_tuple& operator=(const named_tuple&) = default; 50 | 51 | private: 52 | template using Named = typename named_tag::type; 53 | template 54 | using TypeAt = typename Tup::template type_at>::raw_type; 55 | template 56 | using LooseTypeAt = 57 | typename Tup::template permissive_type_at>::raw_type; 58 | template struct tag_assignable_from { 59 | constexpr static bool const value = 60 | ((ForeignTuple::template has_tag>::value) && 61 | std::is_convertible, 62 | TypeAt>::value); 63 | }; 64 | template struct tag_not_assignable_from { 65 | constexpr static bool const value = 66 | !(ForeignTuple::template has_tag>::value); 67 | }; 68 | 69 | template 70 | inline std::enable_if_t::value, Value> 71 | ctor_assign_from(ForeignTuple const& from) { 72 | return std::get>(from); 73 | } 74 | 75 | template 76 | inline typename std::enable_if_t< 77 | tag_not_assignable_from::value, 78 | Value> 79 | ctor_assign_from(ForeignTuple const& from) { 80 | return {}; 81 | } 82 | 83 | template 84 | inline std::enable_if_t::value, int> 85 | assign_from(ForeignTuple const& from) { 86 | this->template get() = std::get>(from); 87 | return {}; 88 | } 89 | 90 | template 91 | inline std::enable_if_t::value, 92 | int> 93 | assign_from(ForeignTuple const& from) { 94 | return {}; 95 | } 96 | 97 | template 98 | inline std::enable_if_t::value, Value> 99 | ctor_move_from(ForeignTuple&& from) { 100 | return std::get>(std::move(from)); 101 | } 102 | 103 | template 104 | inline std::enable_if_t::value, 105 | Value> 106 | ctor_move_from(ForeignTuple&& from) { 107 | return {}; 108 | } 109 | 110 | template 111 | inline std::enable_if_t::value, int> 112 | move_from(ForeignTuple&& from) { 113 | this->template get() = std::get>(std::move(from)); 114 | return {}; 115 | } 116 | 117 | template 118 | inline std::enable_if_t::value, 119 | int> 120 | move_from(ForeignTuple&& from) { 121 | return {}; 122 | } 123 | 124 | public: 125 | template 126 | named_tuple(named_tuple const& other) 127 | : tagged_type(ctor_assign_from<__ntuple_tag_spec_t, 128 | __ntuple_tag_elem_t>(other)...) {} 129 | 130 | template 131 | named_tuple& operator=(named_tuple const& other) { 132 | int dummy[]{ 133 | assign_from<__ntuple_tag_spec_t, __ntuple_tag_elem_t>( 134 | other)...}; 135 | return *this; 136 | } 137 | 138 | template 139 | named_tuple(named_tuple&& other) 140 | : tagged_type( 141 | ctor_move_from<__ntuple_tag_spec_t, 142 | __ntuple_tag_elem_t>(std::move(other))...) {} 143 | 144 | template 145 | named_tuple& operator=(named_tuple&& other) { 146 | int dummy[]{ 147 | move_from<__ntuple_tag_spec_t, __ntuple_tag_elem_t>( 148 | std::move(other))...}; 149 | return *this; 150 | } 151 | 152 | // Member function get 153 | 154 | template inline constexpr decltype(auto) get() const & { 155 | return std::get::type>(*this); 156 | }; 157 | 158 | template inline decltype(auto) get() & { 159 | return std::get::type>(*this); 160 | }; 161 | 162 | template inline decltype(auto) get() && { 163 | return std::get::type>(std::move(*this)); 164 | }; 165 | 166 | // Member operator [] 167 | 168 | template 169 | inline decltype(auto) operator[](named_tag const&)& { 170 | return std::get< 171 | named_tuple::template tag_index::type>::value>( 172 | *this); 173 | } 174 | 175 | template 176 | inline constexpr decltype(auto) operator[](named_tag const&) const & { 177 | return std::get< 178 | named_tuple::template tag_index::type>::value>( 179 | *this); 180 | } 181 | 182 | template 183 | inline decltype(auto) operator[](named_tag const&)&& { 184 | return std::get< 185 | named_tuple::template tag_index::type>::value>( 186 | std::move(*this)); 187 | } 188 | }; 189 | 190 | // make_named_tuple 191 | 192 | template 193 | inline constexpr decltype(auto) make_named_tuple(Types&&... args) { 194 | return named_tuple( 195 | std::move(args).get()...); 196 | } 197 | 198 | // for_each 199 | 200 | template 201 | inline constexpr void for_each(Func&& f, named_tuple const& in) { 202 | using swallow = int[]; 203 | (void)swallow{ 204 | int{}, 205 | (f(__ntuple_tag_spec_t{}, get<__ntuple_tag_spec_t>(in)), 206 | int{})...}; 207 | } 208 | 209 | // apply : should be replaceable by std::experimental::apply 210 | 211 | template 212 | inline constexpr auto apply(Func&& f, named_tuple const& in) -> decltype(auto) { 213 | return f(get<__ntuple_tag_spec_t>(in)...); 214 | } 215 | 216 | } // namespace named_types 217 | 218 | // Standard specialization 219 | 220 | namespace std { 221 | template 222 | struct tuple_element> { 223 | using type = 224 | tuple_element_t...>>; 225 | }; 226 | } // namespace std 227 | -------------------------------------------------------------------------------- /includes/named_types/rt_named_tag.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "named_tag.hpp" 4 | 5 | namespace named_types { 6 | // Named extraction for runtime default naming 7 | template class type_name { 8 | template 9 | static inline auto extract(int) -> decltype(TT::classname) { 10 | return TT::classname; 11 | } 12 | #ifndef _MSC_VER 13 | template static inline auto extract(int) -> decltype(TT::name) { 14 | return TT::name; 15 | } 16 | template 17 | static inline auto extract(int) -> decltype(TT::classname()) { 18 | return TT::classname(); 19 | } 20 | template 21 | static inline auto extract(int) -> decltype(TT::name()) { 22 | return TT::name(); 23 | } 24 | template static inline auto extract(...) -> char const * { 25 | return typeid(TT).name(); 26 | } 27 | #endif // _MSC_VER 28 | public: 29 | static char const* value; 30 | }; 31 | template 32 | char const* type_name::value = type_name::extract(0); 33 | 34 | // Name extractors specified to work with string literals 35 | //#ifndef _MSC_VER 36 | template class type_name> { 37 | public: 38 | static char const* value; 39 | }; 40 | template 41 | char const* type_name>::value = 42 | string_literal::data; 43 | //#endif // _MSC_VER 44 | 45 | // Default base class for runtime views 46 | struct base_const_rt_view { 47 | virtual size_t index_of(std::type_info const& tag_id) const = 0; 48 | virtual size_t index_of(std::string const& name) const = 0; 49 | virtual std::type_info const& typeid_at(size_t index) const = 0; 50 | virtual std::type_info const& typeid_at(std::string const& name) const = 0; 51 | virtual void const* retrieve_raw(size_t index) const = 0; 52 | virtual void const* retrieve_raw(std::string const& name) const = 0; 53 | 54 | template inline T const* retrieve(size_t index) const { 55 | return (typeid(T) == typeid_at(index) 56 | ? reinterpret_cast(retrieve_raw(index)) 57 | : nullptr); 58 | } 59 | 60 | template 61 | inline T const* retrieve(std::string const& name) const { 62 | size_t index = index_of(name); 63 | return retrieve(index); 64 | } 65 | }; 66 | template struct const_rt_view_impl; 67 | 68 | struct base_rt_view : public base_const_rt_view { 69 | virtual void* retrieve_raw(size_t index) = 0; 70 | virtual void* retrieve_raw(std::string const& name) = 0; 71 | 72 | template inline T* retrieve(size_t index) { 73 | return (typeid(T) == typeid_at(index) 74 | ? reinterpret_cast(retrieve_raw(index)) 75 | : nullptr); 76 | } 77 | 78 | template inline T* retrieve(std::string const& name) { 79 | size_t index = index_of(name); 80 | return retrieve(index); 81 | } 82 | }; 83 | template struct rt_view_impl; 84 | 85 | // template using rt_view_reference = std::cond 86 | template decltype(auto) make_rt_view(T const& arg) { 87 | return const_rt_view_impl(arg); 88 | } 89 | 90 | template decltype(auto) make_rt_view(T& arg) { 91 | return rt_view_impl(arg); 92 | } 93 | 94 | template 95 | using const_rt_view = const_rt_view_impl; 96 | template using rt_view = rt_view_impl; 97 | 98 | } // namespace named_types 99 | -------------------------------------------------------------------------------- /includes/named_types/rt_named_tuple.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "named_tuple.hpp" 3 | #include "rt_named_tag.hpp" 4 | #include 5 | #include 6 | 7 | namespace named_types { 8 | 9 | template 10 | struct const_rt_view_impl> : public Parent { 11 | protected: 12 | using value_type = named_tuple const; 13 | static const std::array 14 | tag_typeinfos; 15 | static const std::array 16 | value_typeinfos; 17 | static const std::array attributes; 18 | static const size_t size = sizeof...(Types); 19 | 20 | // Pointers are not const to profit to the non version inheriting from it 21 | std::array pointers_; 22 | 23 | public: 24 | const_rt_view_impl(named_tuple const& viewed) 25 | : pointers_{const_cast<__ntuple_tag_elem_t*>( 26 | &std::get<__ntuple_tag_spec_t>(viewed))...} {} 27 | 28 | virtual size_t index_of(std::type_info const& tag_id) const { 29 | auto matching_attribute_iterator = 30 | std::find(begin(tag_typeinfos), end(tag_typeinfos), &tag_id); 31 | return ( 32 | end(tag_typeinfos) != matching_attribute_iterator 33 | ? std::distance(begin(tag_typeinfos), matching_attribute_iterator) 34 | : size); 35 | } 36 | 37 | virtual size_t index_of(std::string const& name) const { 38 | auto matching_attribute_iterator = 39 | std::find(begin(attributes), end(attributes), name); 40 | return (end(attributes) != matching_attribute_iterator 41 | ? std::distance(begin(attributes), matching_attribute_iterator) 42 | : size); 43 | } 44 | 45 | virtual std::type_info const& typeid_at(size_t index) const { 46 | return (index < size ? *value_typeinfos[index] : typeid(void)); 47 | } 48 | 49 | virtual std::type_info const& typeid_at(std::string const& name) const { 50 | auto matching_attribute_iterator = 51 | std::find(begin(attributes), end(attributes), name); 52 | return (end(attributes) != matching_attribute_iterator 53 | ? *value_typeinfos[std::distance(begin(attributes), 54 | matching_attribute_iterator)] 55 | : typeid(void)); 56 | } 57 | 58 | virtual void const* retrieve_raw(size_t index) const { 59 | return (index < size ? pointers_[index] : nullptr); 60 | } 61 | 62 | virtual void const* retrieve_raw(std::string const& name) const { 63 | auto matching_attribute_iterator = 64 | std::find(begin(attributes), end(attributes), name); 65 | return (end(attributes) != matching_attribute_iterator 66 | ? pointers_[std::distance(begin(attributes), 67 | matching_attribute_iterator)] 68 | : nullptr); 69 | } 70 | }; 71 | 72 | template 73 | std::array const 74 | const_rt_view_impl>::tag_typeinfos = { 75 | {&typeid(typename __ntuple_tag_spec_t::type)...}}; 76 | 77 | template 78 | std::array const 79 | const_rt_view_impl>::value_typeinfos = { 80 | {&typeid(__ntuple_tag_elem_t)...}}; 81 | 82 | template 83 | std::array const 84 | const_rt_view_impl>::attributes = { 85 | {std::string(type_name< 86 | typename __ntuple_tag_spec_t::value_type>::value)...}}; 87 | 88 | // Non-const version 89 | template 90 | struct rt_view_impl> 91 | : public const_rt_view_impl> { 92 | using const_rt_view_type = 93 | const_rt_view_impl>; 94 | 95 | public: 96 | rt_view_impl(named_tuple& viewed) 97 | : const_rt_view_impl>(viewed){}; 98 | 99 | virtual void* retrieve_raw(size_t index) { 100 | return (index < const_rt_view_type::size 101 | ? const_rt_view_type::pointers_[index] 102 | : nullptr); 103 | } 104 | 105 | virtual void* retrieve_raw(std::string const& name) { 106 | auto matching_attribute_iterator = 107 | std::find(begin(const_rt_view_type::attributes), 108 | end(const_rt_view_type::attributes), name); 109 | return (end(const_rt_view_type::attributes) != matching_attribute_iterator 110 | ? const_rt_view_type::pointers_[std::distance( 111 | begin(const_rt_view_type::attributes), 112 | matching_attribute_iterator)] 113 | : nullptr); 114 | } 115 | }; 116 | 117 | } // namespace named_types 118 | -------------------------------------------------------------------------------- /includes/std/experimental/tagged.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // This file is based on the work of Eric Niebler's work for the range library 3 | // 4 | // Most of the code has bee copied from https://github.com/ericniebler/stl2. 5 | // 6 | // There are no API breakage over Eric's code, but there is a few additions 7 | // to add raw templating features, particularly the indexed_tagged template 8 | // which enables the user to use the mapping between a Tag and a Type where 9 | // applicable. This is the case for tagged_tuple, tagged_variants. 10 | // 11 | // The indexed_tagged is a key feature to implement the named_tuple of 12 | // this project. 13 | // 14 | // 15 | 16 | #ifndef SDT_EXPERIMENTAL_TAGGED_HEADER 17 | #define SDT_EXPERIMENTAL_TAGGED_HEADER 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace std { 25 | template struct tagged; 26 | template 27 | struct tuple_size> : tuple_size {}; 28 | template 29 | struct tuple_element> : tuple_element {}; 30 | 31 | struct __getters { 32 | // private: 33 | template friend struct tagged; 34 | template struct collect_; 35 | 36 | template struct tag_getter_ { 37 | using type = typename Tag::template getter; 38 | }; 39 | 40 | template 41 | struct collect_, Tags...> 42 | : public tag_getter_::type... { 43 | collect_() = default; 44 | collect_(const collect_&) = default; 45 | collect_& operator=(const collect_&) = default; 46 | 47 | private: 48 | template friend struct tagged; 49 | ~collect_() = default; 50 | }; 51 | 52 | template 53 | using collect = collect_, Tags...>; 54 | }; 55 | 56 | template 57 | struct tagged : Base, __getters::collect, Tags...> { 58 | using Base::Base; 59 | tagged() = default; 60 | tagged(tagged&&) = default; 61 | tagged(const tagged&) = default; 62 | tagged& operator=(tagged&&) = default; 63 | tagged& operator=(const tagged&) = default; 64 | 65 | template // requires Constructible() 66 | tagged(tagged&& that) 67 | : Base(static_cast(that)) {} 68 | 69 | template // requires Constructible() 70 | tagged(tagged const& that) 71 | : Base(static_cast(that)) {} 72 | 73 | template // requires Assignable() 74 | tagged& operator=(tagged&& that) { 75 | static_cast(*this) = static_cast(that); 76 | return *this; 77 | } 78 | 79 | template // requires Assignable() 80 | tagged& operator=(const tagged& that) { 81 | static_cast(*this) = static_cast(that); 82 | return *this; 83 | } 84 | 85 | template // requires Assignable() && !Same, 86 | // tagged>() 87 | tagged& operator=(U&& u) { 88 | static_cast(*this) = std::forward(u); 89 | return *this; 90 | } 91 | }; 92 | 93 | template struct __tag_spec {}; 94 | template struct __tag_spec { 95 | using type = Spec; 96 | }; 97 | template using __tag_spec_t = typename __tag_spec::type; 98 | template struct __tag_elem {}; 99 | template struct __tag_elem { 100 | using type = Arg; 101 | }; 102 | template using __tag_elem_t = typename __tag_elem::type; 103 | 104 | template struct indexed_tagged; 105 | 106 | struct __indexes { 107 | // private: 108 | template friend struct indexed_tagged; 109 | 110 | template struct collect_; 111 | 112 | template struct tag_indexer_ { 113 | constexpr tag_indexer_() = default; 114 | using type = Arg; 115 | using raw_type = remove_cv_t>; 116 | using tag_type = Tag; 117 | using tag_index = integral_constant; 118 | }; 119 | 120 | template 121 | struct collect_, Types...> 122 | : tag_indexer_<__tag_spec_t, 123 | __tag_elem_t, 124 | Is>... { 125 | constexpr collect_(){}; 126 | ~collect_() = default; 127 | constexpr collect_(const collect_&) = default; 128 | collect_& operator=(const collect_&) = default; 129 | 130 | template 131 | struct tag_index 132 | : decltype(collect_::template get_tag_index(collect_())) {}; 133 | 134 | template 135 | struct type_at 136 | : decltype(collect_::template get_tag_indexer(collect_())) {}; 137 | 138 | template 139 | struct permissive_type_at 140 | : decltype( 141 | collect_::template permissive_get_tag_indexer(collect_())) { 142 | }; 143 | 144 | template 145 | struct has_tag 146 | : integral_constant(collect_()) < sizeof...(Types))> {}; 149 | 150 | private: 151 | template 152 | static constexpr typename tag_indexer_::tag_index 153 | get_tag_index(tag_indexer_ const&) { 154 | return {}; 155 | } 156 | 157 | template 158 | static constexpr typename tag_indexer_::tag_index 159 | permissive_get_tag_index(tag_indexer_ const&) { 160 | return {}; 161 | } 162 | 163 | template 164 | static constexpr typename tag_indexer_:: 165 | tag_index permissive_get_tag_index(...) { 166 | return {}; 167 | } 168 | 169 | template 170 | static constexpr size_t 171 | permissive_get_tag_index_value(tag_indexer_ const&) { 172 | return tag_indexer_::tag_index::value; 173 | } 174 | 175 | template 176 | static constexpr size_t permissive_get_tag_index_value(...) { 177 | return -1; 178 | } 179 | 180 | template 181 | static constexpr tag_indexer_ 182 | get_tag_indexer(tag_indexer_ const&) { 183 | return {}; 184 | } 185 | 186 | template 187 | static constexpr tag_indexer_ 188 | permissive_get_tag_indexer(tag_indexer_ const&) { 189 | return {}; 190 | } 191 | 192 | template 193 | static constexpr tag_indexer_ 194 | permissive_get_tag_indexer(...) { 195 | return {}; 196 | } 197 | 198 | template friend struct indexed_tagged; 199 | }; 200 | 201 | template 202 | using collect = 203 | collect_, Types...>; 204 | }; 205 | 206 | template 207 | struct indexed_tagged 208 | : tagged...>, 209 | __indexes::collect, Types...> { 210 | using tagged...>::tagged; 211 | }; 212 | 213 | template 214 | using tagged_pair = 215 | tagged, __tag_elem_t>, 216 | __tag_spec_t, 217 | __tag_spec_t>; 218 | 219 | template 220 | using __tagged_tuple = 221 | indexed_tagged::type ... >, Types...>; 222 | 223 | /** 224 | * Making tagged_tuple a new type is mandatory to make 225 | * std::get resolve correclty 226 | */ 227 | template struct tagged_tuple : __tagged_tuple { 228 | using __tagged_tuple::__tagged_tuple; 229 | }; 230 | 231 | template 232 | typename tagged_tuple::template type_at::raw_type const& 233 | get(tagged_tuple const& input) { 234 | return get::template tag_index::value>(input); 235 | }; 236 | 237 | template 238 | typename tagged_tuple::template type_at::raw_type& 239 | get(tagged_tuple& input) { 240 | return get::template tag_index::value>(input); 241 | }; 242 | 243 | template 244 | typename tagged_tuple::template type_at::raw_type&& 245 | get(tagged_tuple&& input) { 246 | return move(get::template tag_index::value>( 247 | std::forward>(input))); 248 | }; 249 | 250 | namespace tag { 251 | // The basic_tag does not offer access by mmeber but can be used in other 252 | // contexts 253 | struct basic_tag { 254 | // Should be private dut is doent work with clang 3.5 255 | template struct getter { 256 | using type_self = getter; 257 | getter() = default; 258 | getter(const getter&) = default; 259 | getter& operator=(const getter&) = default; 260 | ~getter() = default; 261 | 262 | private: 263 | friend struct __getters; 264 | }; 265 | 266 | friend struct __getters; 267 | }; 268 | } 269 | } 270 | 271 | #endif // SDT_EXPERIMENTAL_TAGGED_HEADER 272 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | formats: 2 | - none 3 | 4 | python: 5 | version: 3 6 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CheckCXXCompilerFlag) 2 | include(CheckCXXSourceCompiles) 3 | Find_Package(Threads REQUIRED) 4 | Find_Package(rapidjson) 5 | 6 | include_directories( 7 | ${PROJECT_SOURCE_DIR}/includes/ 8 | ${PROJECT_SOURCE_DIR}/test/ 9 | ${PROJECT_BINARY_DIR}/includes/ 10 | ${PROJECT_BINARY_DIR}/test/ 11 | ${GTEST_INCLUDE_DIRS} 12 | ) 13 | 14 | # Compilation test for string literal operator template 15 | check_cxx_source_compiles(" 16 | template struct string_literal {}; 17 | template constexpr string_literal operator \"\"_t () { return {}; } 18 | int main(){return 0;}" compiles_string_literal_operator_template) 19 | if (${compiles_string_literal_operator_template}) 20 | message("-- Support for string literal operator template FOUND.") 21 | else() 22 | unset(compiles_string_literal_operator_template CACHE) 23 | message(WARNING 24 | "Support for string literal operator template NOT FOUND\n" 25 | "Some are features disabled.\n" 26 | "MSVC is known not to support it.\n") 27 | endif () 28 | 29 | add_custom_target(build-test) 30 | 31 | # "nt" stands for "named tuple" 32 | add_library(test-main test-main.cc) 33 | target_link_libraries(test-main catch) 34 | 35 | function(add_nt_test name) 36 | if("${ARGV1}" STREQUAL "GT") 37 | add_executable(${name} ${name}.cc ${HEADER_FILES}) 38 | target_link_libraries(${name} ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} test-main catch) 39 | project_add_test(${name} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name}) 40 | else() 41 | add_executable(${name} ${name}.cc ${HEADER_FILES}) 42 | target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) 43 | project_add_test(${name} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name}) 44 | endif() 45 | endfunction() 46 | 47 | #add_nt_test(unit_tests GT) 48 | add_nt_test(named_tuple_tests GT) 49 | add_nt_test(named_tuple_extensions_tests GT) 50 | add_nt_test(demo2) 51 | add_nt_test(demo3) 52 | add_nt_test(demo5) 53 | add_nt_test(demo6) 54 | 55 | # Tests with string literal operator 56 | if (${compiles_string_literal_operator_template}) 57 | add_nt_test(named_tuple_tests_cpp1z GT) 58 | add_nt_test(demo1) 59 | add_nt_test(demo4) 60 | endif() 61 | 62 | # Rapidjson extension 63 | if (${RAPIDJSON_FOUND}) 64 | include_directories(${RAPIDJSON_INCLUDE_DIRS}) 65 | add_nt_test(named_tuple_rapidjson_tests GT) 66 | endif() 67 | 68 | # Compile examples 69 | add_subdirectory(examples) 70 | -------------------------------------------------------------------------------- /test/cmake/Findrapidjson.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011 Milo Yip (miloyip@gmail.com) 2 | # Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com) 3 | # Distributed under the MIT License (see license.txt file) 4 | 5 | # ----------------------------------------------------------------------------------- 6 | # 7 | # Finds the rapidjson library 8 | # 9 | # ----------------------------------------------------------------------------------- 10 | # 11 | # Variables used by this module, they can change the default behaviour. 12 | # Those variables need to be either set before calling find_package 13 | # or exported as environment variables before running CMake: 14 | # 15 | # RAPIDJSON_INCLUDEDIR - Set custom include path, useful when rapidjson headers are 16 | # outside system paths 17 | # RAPIDJSON_USE_SSE2 - Configure rapidjson to take advantage of SSE2 capabilities 18 | # RAPIDJSON_USE_SSE42 - Configure rapidjson to take advantage of SSE4.2 capabilities 19 | # 20 | # ----------------------------------------------------------------------------------- 21 | # 22 | # Variables defined by this module: 23 | # 24 | # RAPIDJSON_FOUND - True if rapidjson was found 25 | # RAPIDJSON_INCLUDE_DIRS - Path to rapidjson include directory 26 | # RAPIDJSON_CXX_FLAGS - Extra C++ flags required for compilation with rapidjson 27 | # 28 | # ----------------------------------------------------------------------------------- 29 | # 30 | # Example usage: 31 | # 32 | # set(RAPIDJSON_USE_SSE2 ON) 33 | # set(RAPIDJSON_INCLUDEDIR "/opt/github.com/rjeczalik/rapidjson/include") 34 | # 35 | # find_package(rapidjson REQUIRED) 36 | # 37 | # include_directories("${RAPIDJSON_INCLUDE_DIRS}") 38 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}") 39 | # add_executable(foo foo.cc) 40 | # 41 | # ----------------------------------------------------------------------------------- 42 | 43 | foreach(opt RAPIDJSON_INCLUDEDIR RAPIDJSON_USE_SSE2 RAPIDJSON_USE_SSE42) 44 | if(${opt} AND DEFINED ENV{${opt}} AND NOT ${opt} STREQUAL "$ENV{${opt}}") 45 | message(WARNING "Conflicting ${opt} values: ignoring environment variable and using CMake cache entry.") 46 | elseif(DEFINED ENV{${opt}} AND NOT ${opt}) 47 | set(${opt} "$ENV{${opt}}") 48 | endif() 49 | endforeach() 50 | 51 | find_path( 52 | RAPIDJSON_INCLUDE_DIRS 53 | NAMES rapidjson/rapidjson.h 54 | PATHS ${RAPIDJSON_INCLUDEDIR} 55 | DOC "Include directory for the rapidjson library." 56 | ) 57 | 58 | mark_as_advanced(RAPIDJSON_INCLUDE_DIRS) 59 | 60 | if(RAPIDJSON_INCLUDE_DIRS) 61 | set(RAPIDJSON_FOUND TRUE) 62 | endif() 63 | 64 | mark_as_advanced(RAPIDJSON_FOUND) 65 | 66 | if(RAPIDJSON_USE_SSE42) 67 | set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE42") 68 | if(MSVC) 69 | set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE4.2") 70 | else() 71 | set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse4.2") 72 | endif() 73 | else() 74 | if(RAPIDJSON_USE_SSE2) 75 | set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE2") 76 | if(MSVC) 77 | set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE2") 78 | else() 79 | set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse2") 80 | endif() 81 | endif() 82 | endif() 83 | 84 | mark_as_advanced(RAPIDJSON_CXX_FLAGS) 85 | 86 | if(RAPIDJSON_FOUND) 87 | if(NOT rapidjson_FIND_QUIETLY) 88 | message(STATUS "Found rapidjson header files in ${RAPIDJSON_INCLUDE_DIRS}") 89 | if(DEFINED RAPIDJSON_CXX_FLAGS) 90 | message(STATUS "Found rapidjson C++ extra compilation flags: ${RAPIDJSON_CXX_FLAGS}") 91 | endif() 92 | endif() 93 | elseif(rapidjson_FIND_REQUIRED) 94 | message(FATAL_ERROR "Could not find rapidjson") 95 | else() 96 | message(STATUS "Optional package rapidjson was not found") 97 | endif() 98 | -------------------------------------------------------------------------------- /test/demo1.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace named_types; 7 | namespace { 8 | template constexpr named_tag> operator ""_t () { return {}; } 9 | } 10 | 11 | int main() { 12 | auto test = make_named_tuple( 13 | "nom"_t = std::string("Roger") 14 | , "age"_t = 47 15 | , "taille"_t = 1.92 16 | , "liste"_t = std::vector({1,2,3}) 17 | ); 18 | 19 | std::cout 20 | << "nom"_t(test) << "\n" 21 | << "age"_t(test) << "\n" 22 | << "taille"_t(test) << "\n" 23 | << "liste"_t(test).size() << std::endl; 24 | 25 | std::get(test) = "Marcel"; 26 | ++std::get<1>(test); 27 | "taille"_t(test) = 1.93; 28 | 29 | std::cout 30 | << std::get<0>(test) << "\n" 31 | << std::get<1>(test) << "\n" 32 | << std::get<2>(test) << "\n" 33 | << std::get<3>(test).size() << std::endl; 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /test/demo2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace { 7 | using named_types::named_tag; 8 | using named_types::make_named_tuple; 9 | template named_tag _() { return {}; } 10 | template auto _(Tuple&& in) -> decltype(_()(in)) { return _()(in); } 11 | 12 | struct name; 13 | struct age; 14 | struct taille; 15 | struct liste; 16 | } 17 | 18 | int main() { 19 | 20 | auto test = make_named_tuple( 21 | _() = std::string("Roger") 22 | , _() = 47 23 | , _() = 1.92 24 | , _() = std::vector({1,2,3}) 25 | ); 26 | 27 | std::cout 28 | << _(test) << "\n" 29 | << _(test) << "\n" 30 | << _(test) << "\n" 31 | << _(test).size() << std::endl; 32 | 33 | _(test) = "Marcel"; 34 | ++std::get<1>(test); 35 | std::get>(test) = 1.93; 36 | 37 | std::cout 38 | << std::get<0>(test) << "\n" 39 | << std::get<1>(test) << "\n" 40 | << std::get<2>(test) << "\n" 41 | << std::get<3>(test).size() << std::endl; 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /test/demo3.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace named_types; 8 | namespace { 9 | size_t constexpr operator "" _h(const char* c, size_t s) { return const_hash(c); } 10 | 11 | template 12 | constexpr named_tag> at() { return {}; } 13 | 14 | template constexpr decltype(auto) 15 | at(Tuple&& in) { return at()(std::forward(in)); } 16 | } 17 | 18 | int main() { 19 | auto test = make_named_tuple( 20 | at<"name"_h>() = std::string("Roger") 21 | , at<"age"_h>() = 47 22 | , at<"size"_h>() = 1.92 23 | , at<"list"_h>() = std::vector {1,2,3} 24 | ); 25 | 26 | std::cout 27 | << at<"name"_h>(test) << "\n" 28 | << at<"age"_h>(test) << "\n" 29 | << at<"size"_h>(test) << "\n" 30 | << at<"list"_h>(test).size() 31 | << std::endl; 32 | 33 | std::get())>(test) = "Marcel"; 34 | ++std::get<1>(test); 35 | at<"size"_h>(test) = 1.93; 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /test/demo4.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace named_types; 9 | namespace { 10 | template named_tag _() { return {}; } 11 | template auto _(Tuple&& in) -> decltype(_()(in)) { 12 | return _()(in); 13 | } 14 | template 15 | constexpr named_tag> operator""_t() { 16 | return {}; 17 | } 18 | struct host; 19 | struct port; 20 | 21 | size_t constexpr operator"" _s(const char* c, size_t s) { 22 | return basic_lowcase_charset_format::encode(c, s); 23 | } 24 | 25 | template 26 | constexpr named_tag::type> 27 | at() { 28 | return {}; 29 | } 30 | 31 | template constexpr decltype(auto) at(Tuple&& in) { 32 | return at()(std::forward(in)); 33 | } 34 | } 35 | 36 | template class Serializer { 37 | std::ostringstream& output_; 38 | 39 | public: 40 | Serializer(std::ostringstream& output) 41 | : output_(output) {} 42 | 43 | template 44 | void operator()(Tag const&, Type const& value) { 45 | output_ << ((0 < Tuple::template tag_index::value) ? "," : "") << '"' 46 | << typename Tag::value_type().str() << "\":\"" << value << "\""; 47 | } 48 | 49 | void stream(Tuple const& t) { 50 | output_ << '{'; 51 | for_each(*this,t); 52 | output_ << '}'; 53 | } 54 | }; 55 | 56 | template std::string Serialize(Tuple const& t) { 57 | std::ostringstream output; 58 | Serializer(output).stream(t); 59 | return output.str(); 60 | } 61 | 62 | // Templated version allows default values 63 | template void configure(T&& values) { 64 | // Default values 65 | auto conf = 66 | make_named_tuple(_() = std::string("defaulthost"), _() = 80); 67 | // Inject values 68 | conf = values; 69 | std::cout << "Host " << _(conf) << " on port " << _(conf) << "\n"; 70 | } 71 | 72 | // Non-templated version limits bloating 73 | void start(named_tuple const& conf) { 74 | std::cout << "Host " << _(conf) << " on port " << _(conf) << "\n"; 75 | } 76 | 77 | int main() { 78 | auto test = make_named_tuple(at<"name"_s>() = std::string("Roger"), 79 | at<"lastname"_s>() = std::string("Lefouard"), 80 | at<"age"_s>() = 45, 81 | at<"size"_s>() = 1.92f); 82 | 83 | std::cout << Serialize(test) << std::endl; 84 | 85 | configure(make_named_tuple(_() = std::string("mywebsite"))); 86 | configure(make_named_tuple(_() = 441u)); 87 | 88 | start(make_named_tuple(_() = std::string("mywebsite"))); 89 | start(make_named_tuple(_() = 441u)); 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /test/demo5.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace named_types; 8 | namespace { 9 | size_t constexpr operator "" _h(const char* c, size_t s) { return const_hash(c); } 10 | template constexpr named_tag> at() { return {}; } 11 | template constexpr decltype(auto) at(Tuple&& in) { return at()(std::forward(in)); } 12 | } 13 | 14 | int main() { 15 | auto test = make_named_tuple( 16 | at<"name"_h>() = std::string("Roger") 17 | , at<"age"_h>() = 47 18 | , at<"size"_h>() = 1.92 19 | , at<"list"_h>() = std::vector {1,2,3} 20 | ); 21 | 22 | std::cout 23 | << at<"name"_h>(test) << "\n" 24 | << at<"age"_h>(test) << "\n" 25 | << at<"size"_h>(test) << "\n" 26 | << at<"list"_h>(test).size() 27 | << std::endl; 28 | 29 | std::get())>(test) = "Marcel"; 30 | ++std::get<1>(test); 31 | at<"size"_h>(test) = 1.93; 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/demo6.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace { 12 | using named_types::named_tag; 13 | using named_types::named_tuple; 14 | using named_types::make_named_tuple; 15 | using named_types::constexpr_type_name; 16 | using named_types::concatenate; 17 | 18 | size_t constexpr operator"" _s(const char* c, size_t s) { 19 | return named_types::basic_lowcase_charset_format::encode(c, s); 20 | } 21 | 22 | template 23 | using decodestr = 24 | typename named_types::basic_lowcase_charset_format::decode::type; 25 | 26 | // A more simple version could be written without concatenation of chunks 27 | // MSVC doest not support variadic chunks well 28 | 29 | // Alias is used for declaration 30 | template 31 | using attr = named_tag, 32 | decodestr, 33 | decodestr>::type>; 34 | 35 | // First function creates tags 36 | template 37 | constexpr attr at() { 38 | return {}; 39 | } 40 | 41 | // Second fonction creates accessors : precedence in the template list prevents 42 | // from using default values or variadic fuckers 43 | template 44 | constexpr decltype(auto) at(Tuple&& in) { 45 | return at()(std::forward(in)); 46 | } 47 | template 48 | constexpr decltype(auto) at(Tuple&& in) { 49 | return at()(std::forward(in)); 50 | } 51 | template constexpr decltype(auto) at(Tuple&& in) { 52 | return at()(std::forward(in)); 53 | } 54 | 55 | // Json simple serializer 56 | template class JsonSerializer { 57 | std::ostringstream& output_; 58 | 59 | public: 60 | JsonSerializer(std::ostringstream& output) 61 | : output_(output) {} 62 | 63 | template 64 | void stream_push(named_tuple const& value) { 65 | JsonSerializer>(output_).stream(value); 66 | } 67 | template void stream_push(std::vector const& v) { 68 | output_ << '['; 69 | for (auto it = begin(v); it != end(v); ++it) { 70 | if (begin(v) != it) 71 | output_ << ','; 72 | stream_push(*it); 73 | } 74 | output_ << ']'; 75 | } 76 | void stream_push(std::string const& value) { output_ << '"' << value << '"'; } 77 | void stream_push(int value) { output_ << value; } 78 | void stream_push(size_t value) { output_ << value; } 79 | void stream_push(double value) { output_ << value; } 80 | void stream_push(bool value) { output_ << value; } 81 | 82 | template 83 | void operator()(Tag const&, Type const& value) { 84 | output_ << ((0 < Tuple::template tag_index::value) ? "," : "") << '"' 85 | << constexpr_type_name::value << "\":"; 86 | stream_push(value); 87 | } 88 | 89 | void stream(Tuple const& t) { 90 | output_ << std::boolalpha << '{'; 91 | for_each(*this,t); 92 | output_ << '}'; 93 | } 94 | }; 95 | 96 | template std::string JsonSerialize(Tuple const& t) { 97 | std::ostringstream output; 98 | JsonSerializer(output).stream(t); 99 | return output.str(); 100 | } 101 | } 102 | 103 | int main() { 104 | // Init with json like notation 105 | using Child = named_tuple), size_t(attr<"age"_s>)>; 106 | auto test = make_named_tuple(at<"name"_s>() = std::string("Marcel"), 107 | at<"age"_s>() = 57, 108 | at<"size"_s>() = 1.92, 109 | at<"children"_s>() = std::vector{ 110 | Child{"Martine", 3u}, Child{"Marceau", 8u}}, 111 | at<"atmost12char"_s, "perchunk"_s>() = true); 112 | 113 | std::cout << JsonSerialize(test) << std::endl; 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /test/demo7.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace named_types; 10 | namespace { 11 | size_t constexpr operator"" _s(const char* c, size_t s) { 12 | return named_types::basic_lowcase_charset_format::encode(c, s); 13 | } 14 | template 15 | using attr = named_tag< 16 | typename named_types::basic_lowcase_charset_format::decode::type>; 17 | 18 | template 19 | builder{template T* operator()(U && ... args){ 20 | return new T(std::forward(args)...); 21 | } 22 | } 23 | ; 24 | 25 | template 26 | using attr = named_tag::type>; 27 | 28 | template struct factory; 29 | 30 | template 31 | struct factory 32 | : public const_rt_view> {}; 33 | } 34 | 35 | int main() { 36 | auto test = make_named_tuple(at<"name"_h>() = std::string("Roger"), 37 | at<"age"_h>() = 47, 38 | at<"size"_h>() = 1.92, 39 | at<"list"_h>() = std::vector{1, 2, 3}); 40 | 41 | std::cout << at<"name"_h>(test) << "\n" << at<"age"_h>(test) << "\n" 42 | << at<"size"_h>(test) << "\n" << at<"list"_h>(test).size() 43 | << std::endl; 44 | 45 | std::get())>(test) = "Marcel"; 46 | ++std::get<1>(test); 47 | at<"size"_h>(test) = 1.93; 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /test/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | function(add_example name) 2 | add_executable(${name} ${name}.cc ${HEADER_FILES}) 3 | target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) 4 | project_add_test(${name} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name}) 5 | endfunction() 6 | 7 | add_example(factory) 8 | -------------------------------------------------------------------------------- /test/examples/factory.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace { 12 | size_t constexpr operator "" _s(const char* c, size_t s) { return named_types::basic_lowcase_charset_format::encode(c,s); } 13 | template using attr = named_types::named_tag::type>; 14 | }; 15 | 16 | struct Message { 17 | bool by_move_; 18 | std::string name_; 19 | 20 | Message(std::string&& name) : by_move_(true), name_(std::move(name)) {} 21 | Message(std::string const& name) : by_move_(false), name_(name) {}; 22 | virtual ~Message() = default; 23 | virtual std::string print() const = 0; 24 | }; 25 | 26 | struct MessageOk : Message { 27 | using Message::Message; 28 | std::string print() const override { 29 | std::ostringstream result; 30 | result << "OK " << name_; 31 | return result.str(); 32 | } 33 | }; 34 | 35 | struct MessageError : Message { 36 | using Message::Message; 37 | std::string print() const override { 38 | std::ostringstream result; 39 | result << "ERROR " << name_; 40 | return result.str(); 41 | } 42 | }; 43 | 44 | int main() { 45 | named_types::extensions::factory), MessageError(attr<"error"_s>)> my_factory; 46 | 47 | std::unique_ptr message(my_factory.create("ok","yeah")); 48 | std::cout << message->print() << std::endl; 49 | 50 | std::string nope("nope"); 51 | message.reset(my_factory.create("error",nope)); 52 | std::cout << message->print() << std::endl; 53 | } 54 | -------------------------------------------------------------------------------- /test/named_tuple_extensions_tests.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "catch.hpp" 15 | 16 | namespace { 17 | size_t constexpr operator"" _s(const char* c, size_t s) { 18 | return named_types::basic_lowcase_charset_format::encode(c, s); 19 | } 20 | template 21 | using attr = named_types::named_tag< 22 | typename named_types::basic_lowcase_charset_format::decode::type>; 23 | 24 | using name = attr<"name"_s>; 25 | using age = attr<"age"_s>; 26 | using size = attr<"size"_s>; 27 | using children = attr<"children"_s>; 28 | using child1 = attr<"child1"_s>; 29 | using matrix = attr<"matrix"_s>; 30 | using miles = attr<"miles"_s>; 31 | using list = attr<"list"_s>; 32 | using func = attr<"func"_s>; 33 | }; 34 | 35 | // Testing the factory 36 | 37 | struct Message { 38 | bool by_move_; 39 | std::string name_; 40 | 41 | Message(std::string&& name) 42 | : by_move_(true) 43 | , name_(std::move(name)) {} 44 | Message(std::string const& name) 45 | : by_move_(false) 46 | , name_(name){}; 47 | virtual ~Message() = default; 48 | virtual std::string print() const = 0; 49 | }; 50 | 51 | struct MessageOk : Message { 52 | using Message::Message; 53 | std::string print() const override { 54 | std::ostringstream result; 55 | result << "OK " << name_; 56 | return result.str(); 57 | } 58 | }; 59 | struct MessageError : Message { 60 | using Message::Message; 61 | std::string print() const override { 62 | std::ostringstream result; 63 | result << "ERROR " << name_; 64 | return result.str(); 65 | } 66 | }; 67 | TEST_CASE("Traits1", "[Traits1]") { 68 | CHECK(( 69 | std::is_same, 70 | named_types::array_to_tuple_t>>::value)); 71 | } 72 | 73 | TEST_CASE("Factory1", "[Factory1]") { 74 | using namespace named_types; 75 | using namespace named_types::extensions; 76 | 77 | extensions::factory), 79 | MessageError(attr<"error"_s>)> my_factory; 80 | 81 | std::unique_ptr message(my_factory.create("ok", "yeah")); 82 | REQUIRE(static_cast(message)); 83 | CHECK(message->by_move_); 84 | CHECK("OK yeah" == message->print()); 85 | 86 | std::string nope("nope"); 87 | message.reset(my_factory.create("error", nope)); 88 | REQUIRE(static_cast(message)); 89 | CHECK_FALSE(message->by_move_); 90 | CHECK("ERROR nope" == message->print()); 91 | } 92 | 93 | TEST_CASE("ParsersTools1", "[ParsersTools1]") { 94 | using namespace named_types; 95 | using namespace named_types::extensions::parsing; 96 | 97 | CHECK(is_nullable::value); 98 | CHECK(is_nullable>::value); 99 | CHECK_FALSE(is_nullable::value); 100 | 101 | CHECK_FALSE(is_std_basic_string::value); 102 | CHECK(is_std_basic_string::value); 103 | CHECK(is_std_basic_string::value); 104 | 105 | CHECK("3" == (lexical_cast(3))); 106 | CHECK(1u == (lexical_cast(1.f))); 107 | CHECK(23 == (lexical_cast(std::string("23")))); 108 | CHECK(23 == (lexical_cast("23"))); 109 | } 110 | -------------------------------------------------------------------------------- /test/named_tuple_rapidjson_tests.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "catch.hpp" 13 | 14 | namespace { 15 | size_t constexpr operator"" _s(const char* c, size_t s) { 16 | return named_types::basic_lowcase_charset_format::encode(c, s); 17 | } 18 | template 19 | using attr = named_types::named_tag< 20 | typename named_types::basic_lowcase_charset_format::decode::type>; 21 | 22 | using name = attr<"name"_s>; 23 | using age = attr<"age"_s>; 24 | using size = attr<"size"_s>; 25 | using children = attr<"children"_s>; 26 | using child1 = attr<"child1"_s>; 27 | using matrix = attr<"matrix"_s>; 28 | using miles = attr<"miles"_s>; 29 | using list = attr<"list"_s>; 30 | using func = attr<"func"_s>; 31 | }; 32 | 33 | // Testing the factory 34 | TEST_CASE("RapidJson1", "[RapidJson1]") { 35 | // using namespace named_types::extensions::parsing; 36 | // using namespace named_types; 37 | using named_types::extensions::rapidjson::make_reader_handler; 38 | 39 | using Tuple = named_types::named_tuple(list), 43 | std::function(func)>; 44 | 45 | std::string input = R"json({"age":57,"name":"Marcelo","size":1.8})json"; 46 | Tuple output{"Roger", 52, 1.9, {}, nullptr}; 47 | // Tuple output { "Roger", 52, 1.9, {} }; 48 | auto handler = make_reader_handler(output); 49 | 50 | ::rapidjson::Reader reader; 51 | ::rapidjson::StringStream ss(input.c_str()); 52 | CHECK(reader.Parse(ss, handler)); 53 | CHECK("Marcelo" == named_types::get(output)); 54 | CHECK(57 == named_types::get(output)); 55 | } 56 | 57 | TEST_CASE("RapidJson2", "[RapidJson2]") { 58 | // using namespace named_types::extensions::parsing; 59 | using namespace named_types; 60 | using named_types::extensions::rapidjson::make_reader_handler; 61 | 62 | using MyTuple = named_tuple< 63 | std::string(name), 64 | int(age), 65 | double(size), 66 | named_tuple(child1), 67 | std::vector>(children), 68 | std::vector(miles), 69 | std::vector>(matrix)>; 70 | 71 | MyTuple t1; 72 | std::string input1 = R"json({"age":57,"name":"Marcelo","size":1.8,")json" 73 | R"json(child1":{"name":"Coucou","age":3},"children")json" 74 | R"json(:[{"name":"Albertine","age":4}],"miles":[1,)json" 75 | R"json(2,3],"matrix":[[1,2],[3,4]]})json"; 76 | auto handler = make_reader_handler(t1); 77 | ::rapidjson::Reader reader; 78 | ::rapidjson::StringStream ss(input1.c_str()); 79 | CHECK(reader.Parse(ss, handler)); 80 | CHECK(3 == t1.get().get()); 81 | CHECK("Albertine" == t1.get()[0].get()); 82 | CHECK(4 == t1[children()][0][age()]); 83 | CHECK(4 == t1.get()[1][1]); 84 | } 85 | 86 | TEST_CASE("RapidJson3", "[RapidJson3]") { 87 | using namespace named_types; 88 | using named_types::extensions::rapidjson::make_reader_handler; 89 | 90 | using MyTuple = 91 | named_tuple>(children)>; 95 | 96 | MyTuple t1; 97 | std::string input1 = R"json({"age":57,"name":"Marcelo","size":1.8,")json" 98 | R"json(children":{"Albertine":{"age":4},"Rupert":{")json" 99 | R"json(age":5}}})json"; 100 | auto handler = make_reader_handler(t1); 101 | ::rapidjson::Reader reader; 102 | ::rapidjson::StringStream ss(input1.c_str()); 103 | CHECK(reader.Parse(ss, handler)); 104 | CHECK(4 == t1.get()["Albertine"].get()); 105 | } 106 | 107 | TEST_CASE("RapidJson4", "[RapidJson4]") { 108 | using namespace named_types; 109 | using named_types::extensions::rapidjson::make_reader_handler; 110 | 111 | using MyTuple = named_tuple; 112 | 113 | std::vector data; 114 | std::string input1 = 115 | R"json([{"name":"Robert","age":48},{"age":57,"name":"Marcelo"}])json"; 116 | auto handler = make_reader_handler(data); 117 | ::rapidjson::Reader reader; 118 | ::rapidjson::StringStream ss(input1.c_str()); 119 | CHECK(reader.Parse(ss, handler)); 120 | CHECK("Marcelo" == data[1].get()); 121 | } 122 | -------------------------------------------------------------------------------- /test/named_tuple_tests.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "catch.hpp" 12 | 13 | using namespace named_types; 14 | 15 | namespace { 16 | struct name {}; 17 | struct age { 18 | inline static char const* name() { return "age4"; } 19 | }; 20 | struct taille; 21 | struct size; 22 | struct liste; 23 | struct func; 24 | struct birthday; // Not used, for failure tests 25 | struct surname; 26 | 27 | 28 | size_t constexpr operator "" _s(const char* c, size_t s) { return named_types::basic_lowcase_charset_format::encode(c,s); } 29 | template using attr = named_types::named_tag::type>; 30 | } 31 | 32 | struct serializer_01 { 33 | std::ostringstream output; 34 | 35 | template 36 | void operator()(Tag const&, Type const& value) { 37 | output << '"' << value << "\";"; 38 | } 39 | 40 | std::string result() { return output.str(); }; 41 | }; 42 | 43 | template std::string func_apply_01(Tuple const& t) { 44 | serializer_01 instance; 45 | for_each(instance, t); 46 | return instance.result(); 47 | } 48 | 49 | 50 | static named_tag name_key; 51 | struct func_to_apply_01 { 52 | template size_t operator() (T&& ... args) const { return sizeof ... (T); } 53 | }; 54 | 55 | TEST_CASE("UnitTests","[all]") { 56 | named_tuple(liste), 60 | std::function(func)> test{ 61 | "Roger", 47, 1.92, {1, 2, 3}, [](int a) { return a * a; }}; 62 | 63 | 64 | SECTION("Construction1") { 65 | CHECK(std::string("Roger") == std::get<0>(test)); 66 | CHECK(std::string("Roger") == std::get>(test)); 67 | CHECK(std::string("Roger") == named_types::get(test)); 68 | CHECK(std::string("Roger") == named_types::get>(test)); 69 | CHECK(std::string("Roger") == test.get()); 70 | CHECK(std::string("Roger") == test.get>()); 71 | CHECK(std::string("Roger") == test[name_key]); 72 | CHECK(std::string("Roger") == name_key(test)); 73 | } 74 | 75 | SECTION("Traits1") { 76 | using TupleType = decltype(test); 77 | CHECK(TupleType::has_tag>::value); 78 | CHECK_FALSE(TupleType::has_tag>::value); 79 | } 80 | 81 | SECTION("MakeTuple1") { 82 | auto t = make_named_tuple(name_key = std::string("Roger")); 83 | CHECK(std::string("Roger") == t[name_key]); 84 | } 85 | 86 | SECTION("Promotion1") { 87 | named_tag name_k; 88 | named_tag size_k; 89 | named_tag surname_k; 90 | named_tag bday_k; 91 | 92 | auto t1 = make_named_tuple(name_k = std::string("Roger"), 93 | surname_k = std::string("LeGros"), 94 | size_k = 3u); 95 | 96 | auto t2 = make_named_tuple( 97 | size_k = 4u, name_k = std::string("Marcel"), bday_k = 1e6); 98 | 99 | decltype(t1) t3(t2); // Copy 100 | CHECK(std::string("Marcel") == t3[name_k]); 101 | CHECK(4u == t3[size_k]); 102 | 103 | decltype(t1) t4(std::move(t2)); // Move 104 | CHECK(std::string("Marcel") == t4[name_k]); 105 | CHECK(std::string("Marcel") != t2[name_k]); 106 | CHECK(4u == t4[size_k]); 107 | } 108 | 109 | SECTION("Injection1") { 110 | named_tag name_k; 111 | named_tag size_k; 112 | named_tag surname_k; 113 | named_tag bday_k; 114 | 115 | auto t1 = make_named_tuple(name_k = std::string("Roger"), 116 | surname_k = std::string("LeGros"), 117 | size_k = 3u); 118 | 119 | auto t2 = make_named_tuple( 120 | size_k = 4u, name_k = std::string("Marcel"), bday_k = 1e6); 121 | 122 | t1 = t2; // Copy 123 | CHECK(std::string("Marcel") == t1[name_k]); 124 | CHECK(std::string("LeGros") == t1[surname_k]); 125 | CHECK(4u == t1[size_k]); 126 | 127 | t1[name_k] = "Robert"; 128 | CHECK(std::string("Robert") == t1[name_k]); 129 | 130 | t2 = std::move(t1); // Move 131 | CHECK(std::string("Robert") == t2[name_k]); 132 | CHECK(std::string("Robert") != t1[name_k]); 133 | CHECK(std::string("LeGros") == t1[surname_k]); 134 | CHECK(4u == t1[size_k]); 135 | } 136 | 137 | SECTION("TaggedTuple") { 138 | struct name : std::tag::basic_tag {}; 139 | struct size : std::tag::basic_tag {}; 140 | struct yo : std::tag::basic_tag {}; 141 | using T1 = std::tagged_tuple; 142 | T1 t{"Roger", 3, {}}; 143 | 144 | CHECK(0 == T1::tag_index::value); 145 | CHECK(std::string("Roger") == std::get::value>(t)); 146 | CHECK(std::string("Roger") == std::get(t)); 147 | 148 | CHECK(1 == T1::tag_index::value); 149 | CHECK(3 == std::get::value>(t)); 150 | CHECK(3 == std::get(t)); 151 | 152 | auto t2 = t; 153 | CHECK(3 == std::get(t2)); 154 | } 155 | 156 | SECTION("ConstexprStrings1") { 157 | CHECK(193488139 == 158 | (std::integral_constant< 159 | size_t, 160 | string_literal::hash_value>::value)); 161 | CHECK(193488139 == 162 | (std::integral_constant::value)); 163 | CHECK( 164 | 1u == 165 | (std::integral_constant(2, 0)>::value)); 166 | CHECK( 167 | 2u == 168 | (std::integral_constant(2, 1)>::value)); 169 | CHECK( 170 | 4u == 171 | (std::integral_constant(2, 2)>::value)); 172 | 173 | CHECK( 174 | 31u == 175 | (std::integral_constant:: 177 | max_length_value>::value)); 178 | CHECK(12u == 179 | (std::integral_constant< 180 | size_t, 181 | basic_lowcase_charset_format::max_length_value>::value)); 182 | CHECK(10u == 183 | (std::integral_constant< 184 | size_t, 185 | basic_charset_format::max_length_value>::value)); 186 | CHECK( 187 | 9u == 188 | (std::integral_constant::value)); 190 | 191 | constexpr uint64_t const str_test1 = 192 | std::integral_constant::value; 194 | CHECK( 195 | 6u == 196 | (std::integral_constant< 197 | size_t, 198 | basic_lowcase_charset_format::decode::type().size()>::value)); 199 | CHECK(std::string("coucou") == 200 | std::string(basic_lowcase_charset_format::decode::type().str())); 201 | 202 | constexpr uint64_t const str_test2 = std::integral_constant< 203 | uint64_t, 204 | basic_lowcase_charset_format::encode("aaaaaaaaaaaa")>::value; 205 | CHECK(12u == 206 | (std::integral_constant::type().size()>::value)); 209 | CHECK(std::string("aaaaaaaaaaaa") == 210 | std::string( 211 | basic_lowcase_charset_format::decode::type().str())); 212 | 213 | constexpr uint64_t const str_test3 = std::integral_constant< 214 | uint64_t, 215 | basic_lowcase_charset_format::encode("------------")>::value; 216 | CHECK(12u == 217 | (std::integral_constant::type().size()>::value)); 220 | CHECK(std::string("------------") == 221 | std::string( 222 | basic_lowcase_charset_format::decode::type().str())); 223 | 224 | constexpr uint64_t const str_test4 = 225 | std::integral_constant::value; 227 | CHECK(0u == 228 | (std::integral_constant::type().size()>::value)); 231 | CHECK(std::string("") == 232 | std::string( 233 | basic_lowcase_charset_format::decode::type().str())); 234 | 235 | constexpr uint64_t const str_test5 = 236 | std::integral_constant::value; 238 | CHECK( 239 | 9 == 240 | (std::integral_constant< 241 | size_t, 242 | ascii_charset_format::decode::type().size()>::value)); 243 | CHECK(std::string("Yeah@1!?$") == 244 | std::string(ascii_charset_format::decode::type().str())); 245 | 246 | constexpr uint64_t const str_test6 = 247 | std::integral_constant::value; 249 | CHECK( 250 | 10 == 251 | (std::integral_constant< 252 | size_t, 253 | ascii_charset_format::decode::type().size()>::value)); 254 | CHECK(std::string("I_love_YOU") == 255 | std::string(basic_charset_format::decode::type().str())); 256 | 257 | CHECK( 258 | std::string("abcdefg") == 259 | std::string(concatenate, 260 | string_literal, 261 | string_literal>::type().str())); 262 | } 263 | 264 | SECTION("ConstexprStrings2") { 265 | using Str1 = string_literal; 266 | using Str2 = string_literal; 267 | using Str3 = string_literal; 268 | 269 | CHECK(std::string("Roger") == (join::type::data)); 270 | CHECK(std::string("Roger,Marcel") == (join::type::data)); 271 | CHECK(std::string("Roger,Marcel,Pastis") == (join::type::data)); 272 | 273 | CHECK(std::string("") == (repeat_string<0,Str1>::type::data)); 274 | CHECK(std::string("Roger") == (repeat_string<1,Str1>::type::data)); 275 | CHECK(std::string("RogerRoger") == (repeat_string<2,Str1>::type::data)); 276 | CHECK(std::string("RogerRogerRoger") == (repeat_string<3,Str1>::type::data)); 277 | 278 | CHECK(std::string("") == (join_repeat_string<0,char,',',Str1>::type::data)); 279 | CHECK(std::string("Roger") == (join_repeat_string<1,char,',',Str1>::type::data)); 280 | CHECK(std::string("Roger,Roger") == (join_repeat_string<2,char,',',Str1>::type::data)); 281 | CHECK(std::string("Roger,Roger,Roger") == (join_repeat_string<3,char,',',Str1>::type::data)); 282 | } 283 | 284 | SECTION("RuntimeView1") { 285 | attr<"name"_s> name_k; 286 | attr<"size"_s> size_k; 287 | attr<"surname"_s> surname_k; 288 | attr<"birthday"_s> bday_k; 289 | 290 | auto t1 = make_named_tuple(name_k = std::string("Roger"), 291 | surname_k = std::string("LeGros"), 292 | size_k = 3u); 293 | 294 | decltype(t1) const& t1_const = t1; 295 | 296 | auto const_view1 = make_rt_view(t1_const); 297 | CHECK(0 == const_view1.index_of(typeid(attr<"name"_s>))); 298 | CHECK(1 == const_view1.index_of(typeid(attr<"surname"_s>))); 299 | CHECK(2 == const_view1.index_of(typeid(attr<"size"_s>))); 300 | 301 | void const * raw_ptr = const_view1.retrieve_raw("surname"); 302 | REQUIRE(raw_ptr != nullptr); 303 | CHECK("LeGros" == *reinterpret_cast(raw_ptr)); 304 | } 305 | 306 | SECTION("ForEach1") { 307 | attr<"name"_s> name_k; 308 | attr<"size"_s> size_k; 309 | attr<"surname"_s> surname_k; 310 | 311 | auto t1 = make_named_tuple(name_k = std::string("Roger"), 312 | surname_k = std::string("Marcel"), 313 | size_k = 3u); 314 | std::string serialized = func_apply_01(t1); 315 | CHECK("\"Roger\";\"Marcel\";\"3\";" == serialized); 316 | 317 | auto t2 = make_named_tuple(); 318 | serialized = func_apply_01(t2); 319 | CHECK("" == serialized); 320 | 321 | auto t3 = make_named_tuple(name_k = std::string("Roger")); 322 | serialized = func_apply_01(t3); 323 | CHECK("\"Roger\";" == serialized); 324 | } 325 | 326 | 327 | SECTION("Apply1") { 328 | attr<"name"_s> name_k; 329 | attr<"size"_s> size_k; 330 | attr<"surname"_s> surname_k; 331 | 332 | auto t1 = make_named_tuple(name_k = std::string("Roger"), 333 | surname_k = std::string("Marcel"), 334 | size_k = 3u); 335 | 336 | CHECK(3u == (apply(func_to_apply_01(),t1))); 337 | auto t2 = make_named_tuple(); 338 | CHECK(0u == (apply(func_to_apply_01(),t2))); 339 | auto t3 = make_named_tuple(name_k = std::string("Roger")); 340 | CHECK(1u == (apply(func_to_apply_01(),t3))); 341 | } 342 | 343 | SECTION("LiteralPrintfFamily1") { 344 | std::array buffer; 345 | string_literal::sprintf(buffer.data(), "Hello Marcello"); 346 | CHECK("Hello Marcello" == std::string(buffer.data())); 347 | string_literal::snprintf(buffer.data(), buffer.size(), "Hello Roberta"); 348 | CHECK("Hello Roberta" == std::string(buffer.data())); 349 | } 350 | 351 | } 352 | -------------------------------------------------------------------------------- /test/named_tuple_tests_cpp1z.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "catch.hpp" 10 | 11 | using namespace named_types; 12 | namespace { 13 | template 14 | constexpr named_tag> operator""_t() { 15 | return {}; 16 | } 17 | } 18 | 19 | namespace { 20 | struct name { 21 | // static char const* name() { return "name"; } 22 | }; 23 | struct age { 24 | // static constexpr char const * classname = "age1"; 25 | // static constexpr char const * name = "age2"; 26 | // inline static char const* classname() { return "age3"; } 27 | inline static char const* name() { return "age4"; } 28 | }; 29 | struct taille; 30 | struct size; 31 | struct liste; 32 | struct func; 33 | struct birthday; // Not used, for failure tests 34 | struct surname; 35 | } 36 | 37 | struct serializer_01 { 38 | std::ostringstream output; 39 | 40 | template 41 | void operator()(Tag const&, Type const& value) { 42 | output << '"' << value << "\";"; 43 | } 44 | 45 | std::string result() { return output.str(); }; 46 | }; 47 | 48 | template std::string func_apply_01(Tuple const& t) { 49 | serializer_01 instance; 50 | for_each(instance, t); 51 | return instance.result(); 52 | } 53 | 54 | TEST_CASE("UnitTests_cpp1z","[all]") { 55 | named_tuple(liste), 59 | std::function(func)> test{ 60 | "Roger", 47, 1.92, {1, 2, 3}, [](int a) { return a * a; }}; 61 | 62 | static named_tag name_key; 63 | 64 | SECTION("Literal1") { 65 | named_tuple t{ 66 | "Roger", 4}; 67 | 68 | decltype("name"_t) name_key; 69 | 70 | CHECK(std::string("Roger") == std::get<0>(test)); 71 | CHECK(std::string("Roger") == t["name"_t]); 72 | CHECK(std::string("Roger") == "name"_t(t)); 73 | CHECK(std::string("Roger") == std::get(t)); 74 | CHECK(std::string("Roger") == named_types::get(t)); 75 | CHECK(std::string("Roger") == t.get()); 76 | } 77 | 78 | SECTION("MakeTuple2") { 79 | std::string surname = "Marcel"; 80 | 81 | auto t1 = make_named_tuple("name"_t = std::string("Roger"), 82 | "surname"_t = surname, 83 | "size"_t = 3u, 84 | "objects"_t = std::vector({1, 2, 3})); 85 | 86 | CHECK(std::string("Roger") == t1["name"_t]); 87 | CHECK(3u == t1["size"_t]); 88 | CHECK(3u == t1["objects"_t].size()); 89 | CHECK(std::string("Marcel") == surname); 90 | } 91 | 92 | 93 | SECTION("Apply1") { 94 | auto t1 = make_named_tuple("name"_t = std::string("Roger"), 95 | "surname"_t = std::string("Marcel"), 96 | "size"_t = 3u); 97 | std::string serialized = func_apply_01(t1); 98 | CHECK("\"Roger\";\"Marcel\";\"3\";" == serialized); 99 | 100 | auto t2 = make_named_tuple(); 101 | serialized = func_apply_01(t2); 102 | CHECK("" == serialized); 103 | 104 | auto t3 = make_named_tuple("name"_t = std::string("Roger")); 105 | serialized = func_apply_01(t3); 106 | CHECK("\"Roger\";" == serialized); 107 | 108 | // std::cout << type_name::value << "\n"; 109 | // std::cout << type_name::value << "\n"; 110 | // std::cout << type_name::value << 111 | // "\n"; 112 | } 113 | 114 | SECTION("RuntimeView1") { 115 | auto t1 = make_named_tuple("name"_t = std::string("Roger"), 116 | "surname"_t = std::string("Marcel"), 117 | "size"_t = 3u); 118 | 119 | const_rt_view rt_view_impl(t1); 120 | base_const_rt_view& view = rt_view_impl; 121 | 122 | std::string const* value = nullptr; 123 | // value = 124 | 125 | CHECK(typeid(std::string) == view.typeid_at(0)); 126 | CHECK(typeid(void) == view.typeid_at(4)); 127 | CHECK(typeid(std::string) == view.typeid_at("surname")); 128 | CHECK(typeid(void) == view.typeid_at("toutnu")); 129 | 130 | value = view.retrieve(0); 131 | CHECK(nullptr != value); 132 | CHECK(std::string("Roger") == *value); 133 | 134 | value = view.retrieve("surname"); 135 | CHECK(nullptr != value); 136 | CHECK(std::string("Marcel") == *value); 137 | 138 | value = view.retrieve("toutnu"); 139 | CHECK(nullptr == value); 140 | 141 | auto value_bad1 = view.retrieve>("name"); 142 | CHECK(nullptr == value); 143 | 144 | // for(size_t i = 0; i < 3; ++i) 145 | // std::cout << const_rt_view::attributes[i] 146 | // << std::endl; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /test/test-main.cc: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | --------------------------------------------------------------------------------