├── .clang-format ├── .cleantype.json ├── .gitignore ├── .gitmodules ├── .travis.yml ├── AUTHORS ├── CMakeLists.txt ├── LICENSE.md ├── Makefile ├── README.md ├── TODO.md ├── appveyor.yml ├── binder ├── Readme.md └── environment.yml ├── cmake └── cmake_init │ ├── AUTHORS │ ├── ClangTidy.cmake │ ├── CompileOptions.cmake │ ├── ComponentInstall.cmake │ ├── Coverage.cmake │ ├── Cppcheck.cmake │ ├── Custom.cmake │ ├── Findclang_tidy.cmake │ ├── Findcppcheck.cmake │ ├── Findgcov.cmake │ ├── Findlcov.cmake │ ├── Gcov.cmake │ ├── GenerateTemplateExportHeader.cmake │ ├── HealthCheck.cmake │ ├── LICENSE │ └── README.md ├── conanfile.txt ├── demos ├── .gitignore ├── asciinema_casts │ ├── demo_cling.cast │ └── demo_compiler_error.cast ├── demo_cling.cpp ├── demo_compiler_decipher.cpp ├── demo_simple.cpp ├── im_not_a_touch_typist.py └── include │ ├── cleantype │ ├── fplus │ ├── meta │ └── range ├── include_all_in_one ├── include │ └── cleantype │ │ └── cleantype.hpp └── make_all_in_one.py ├── notebooks └── cleantype │ ├── .gitignore │ ├── build_ct_tools.cpp │ ├── cleantype-range-v3.ipynb │ ├── cleantype.ipynb │ ├── demos │ ├── examples │ ├── cleantype_examples_utils.h │ ├── quick_demo.ipynb │ ├── test_compile.py │ ├── types_variations.hpp │ ├── typesetting_pointless_holy_war.ipynb │ └── zoo_type_qualifiers.ipynb │ ├── include │ ├── boost │ ├── cleantype │ ├── fplus │ ├── meta │ ├── nlohmann │ └── range │ ├── include_all_in_one │ └── resources ├── resources ├── cleantype_logo.png ├── cleantype_logo_2.png ├── cleantype_logo_small.jpg ├── cleantype_logo_small.png ├── gitpod.jpg └── gitpod.png ├── scripts ├── build │ ├── cmake_all_options.sh │ ├── cmake_ninja.sh │ ├── cmake_ninja_all_options.sh │ ├── cmake_win.bat │ └── ln_compile_commands.sh ├── docker_build │ └── ubuntu18 │ │ ├── Dockerfile │ │ ├── docker_attach.sh │ │ ├── docker_create_image.sh │ │ ├── docker_start.sh │ │ └── install_scripts │ │ ├── customize_env.sh │ │ ├── install_base.sh │ │ ├── install_clang.sh │ │ └── install_miniconda.sh └── docker_cling │ ├── Dockerfile │ ├── docker_create_image.sh │ ├── docker_login.sh │ ├── docker_run_notebook.sh │ └── install_scripts │ ├── conda_opencv.sh │ ├── conda_xeus_cling.sh │ ├── create_notebook_launcher.sh │ ├── customize_env.sh │ ├── install_base.sh │ └── install_miniconda.sh ├── src ├── include │ └── cleantype │ │ ├── cleantype.hpp │ │ ├── cleantype_compiler_typename.hpp │ │ ├── cleantype_configuration.hpp │ │ └── details │ │ ├── cleantype_clean.hpp │ │ ├── cleantype_clean_impl.hpp │ │ ├── cleantype_configuration_json.hpp │ │ ├── cleantype_eastconst.hpp │ │ ├── cleantype_format.hpp │ │ ├── cleantype_fp │ │ ├── Readme.md │ │ ├── fp_base.hpp │ │ ├── fp_interact.hpp │ │ ├── fp_show.hpp │ │ └── fp_tree.hpp │ │ ├── cleantype_full.hpp │ │ ├── cleantype_holder.hpp │ │ ├── cleantype_invoke_result.hpp │ │ ├── cleantype_lambda.hpp │ │ ├── cleantype_lambda_parse.hpp │ │ ├── cleantype_parse.hpp │ │ ├── filesystem.hpp │ │ ├── hana_type_name │ │ ├── Readme.md │ │ ├── tests │ │ │ ├── CMakeLists.txt │ │ │ └── type_name_stringliteral_test.cpp │ │ ├── type_name_compiler_capabilities.hpp │ │ ├── type_name_pretty_function.hpp │ │ └── type_name_stringliteral.hpp │ │ ├── invoke_result_polyfill.hpp │ │ └── stringutils.hpp ├── tests │ ├── CMakeLists.txt │ ├── cleantype_clean_test.cpp │ ├── cleantype_compiler_typename_test.cpp │ ├── cleantype_config.test.cpp │ ├── cleantype_eastconst_test.cpp │ ├── cleantype_full_test.cpp │ ├── cleantype_invoke_result_test.cpp │ ├── cleantype_lambda_parse_test.cpp │ ├── cleantype_test_indent.cpp │ ├── debug_utilities.hpp │ ├── lambda_generic_test.cpp │ ├── lambda_test.cpp │ ├── test_main.cpp │ └── test_pack_sizeof.cpp └── tools │ └── ct_compiler_decipher │ ├── CMakeLists.txt │ ├── ct_compiler_decipher.cpp │ └── example │ └── ct_compiler_decipher_example.cpp └── third_party └── include ├── doctest.h └── nlohmann └── json.hpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: true 6 | AlignEscapedNewlinesLeft: true 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | AllowAllParametersOfDeclarationOnNextLine: true 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AlwaysBreakAfterDefinitionReturnType: false 16 | AlwaysBreakTemplateDeclarations: true 17 | AlwaysBreakBeforeMultilineStrings: true 18 | BreakBeforeBinaryOperators: None 19 | BreakBeforeTernaryOperators: true 20 | BreakConstructorInitializersBeforeComma: false 21 | BinPackParameters: false 22 | BinPackArguments: false 23 | ColumnLimit: 100 24 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 25 | ConstructorInitializerIndentWidth: 4 26 | DerivePointerAlignment: false 27 | ExperimentalAutoDetectBinPacking: false 28 | IndentCaseLabels: true 29 | IndentWrappedFunctionNames: false 30 | IndentFunctionDeclarationAfterType: false 31 | MaxEmptyLinesToKeep: 1 32 | KeepEmptyLinesAtTheStartOfBlocks: false 33 | NamespaceIndentation: All 34 | ObjCBlockIndentWidth: 2 35 | ObjCSpaceAfterProperty: false 36 | ObjCSpaceBeforeProtocolList: false 37 | PenaltyBreakBeforeFirstCallParameter: 1 38 | PenaltyBreakComment: 300 39 | PenaltyBreakString: 1000 40 | PenaltyBreakFirstLessLess: 120 41 | PenaltyExcessCharacter: 1000000 42 | PenaltyReturnTypeOnItsOwnLine: 200 43 | PointerAlignment: Middle 44 | SpacesBeforeTrailingComments: 2 45 | Cpp11BracedListStyle: true 46 | Standard: Auto 47 | IndentWidth: 4 48 | TabWidth: 8 49 | UseTab: Never 50 | BreakBeforeBraces: Allman 51 | SpacesInParentheses: false 52 | SpacesInSquareBrackets: false 53 | SpacesInAngles: false 54 | SpaceInEmptyParentheses: false 55 | SpacesInCStyleCastParentheses: false 56 | SpaceAfterCStyleCast: false 57 | SpacesInContainerLiterals: true 58 | SpaceBeforeAssignmentOperators: true 59 | ContinuationIndentWidth: 4 60 | CommentPragmas: '^ IWYU pragma:' 61 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, ForEachSide, ForEachActivisu8Camera, ForEachViewType ] 62 | SpaceBeforeParens: ControlStatements 63 | DisableFormat: false 64 | ... 65 | -------------------------------------------------------------------------------- /.cleantype.json: -------------------------------------------------------------------------------- 1 | { 2 | "force_east_const_": true, 3 | "indent_depth_limit": 3, 4 | "replacements_after_undesirable_node_extractions": { 5 | "basic_string<_CharT, _Traits, _Allocator>": "std::string", 6 | "std::basic_string": "std::string" 7 | }, 8 | "suppress_custom_": [ 9 | " __ptr64" 10 | ], 11 | "suppress_extra_namespaces_": [ 12 | "::__1", 13 | "::__cxx11" 14 | ], 15 | "suppress_extract_struct_class_": [ 16 | "class ", 17 | "struct " 18 | ], 19 | "undesirable_type_nodes_": [ 20 | "std::char_traits", 21 | "std::allocator", 22 | "std::less" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /.idea/ 3 | /.vscode/ 4 | /cmake-build-debug/ 5 | /compile_commands.json 6 | /build-gcc 7 | /hana_play 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "FunctionalPlus"] 2 | path = third_party/tests_thirdparty/FunctionalPlus 3 | url = https://github.com/Dobiasd/FunctionalPlus.git 4 | [submodule "third_party/hana"] 5 | path = third_party/tests_thirdparty/hana 6 | url = https://github.com/pthom/hana.git 7 | [submodule "third_party/tests/range-v3"] 8 | path = third_party/tests_thirdparty/range-v3 9 | url = https://github.com/ericniebler/range-v3.git 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # We don't care about the language here, except that setting 2 | # language: cpp will override our CC and CXX env variables below 3 | # and we do not want that ! 4 | language: Ruby 5 | 6 | dist: trusty 7 | sudo: required 8 | 9 | addons: 10 | apt: 11 | packages: 12 | - python3-pip 13 | 14 | matrix: 15 | include: 16 | ############## 17 | # GCC 18 | ############## 19 | - os: linux 20 | compiler: gcc 21 | env: GCC_VERSION=8 22 | - CC=gcc-8 23 | - CXX=g++-8 24 | - CXX_STANDARD=14 25 | addons: 26 | apt: 27 | sources: ['ubuntu-toolchain-r-test'] 28 | packages: ['g++-8'] 29 | - os: linux 30 | compiler: gcc 31 | env: GCC_VERSION=8 32 | - CC=gcc-8 33 | - CXX=g++-8 34 | - CXX_STANDARD=17 35 | addons: 36 | apt: 37 | sources: ['ubuntu-toolchain-r-test'] 38 | packages: ['g++-8'] 39 | - os: linux 40 | compiler: gcc 41 | env: GCC_VERSION=7 42 | - CC=gcc-7 43 | - CXX=g++-7 44 | - CXX_STANDARD=14 45 | addons: 46 | apt: 47 | sources: ['ubuntu-toolchain-r-test'] 48 | packages: ['g++-7'] 49 | - os: linux 50 | compiler: gcc 51 | env: GCC_VERSION=7 52 | - CC=gcc-7 53 | - CXX=g++-7 54 | - CXX_STANDARD=17 55 | addons: 56 | apt: 57 | sources: ['ubuntu-toolchain-r-test'] 58 | packages: ['g++-7'] 59 | - os: linux 60 | compiler: gcc 61 | env: GCC_VERSION=6 62 | - CC=gcc-6 63 | - CXX=g++-6 64 | - CXX_STANDARD=14 65 | addons: 66 | apt: 67 | sources: ['ubuntu-toolchain-r-test'] 68 | packages: ['g++-6'] 69 | - os: linux 70 | compiler: gcc 71 | env: GCC_VERSION=5 72 | - CC=gcc-5 73 | - CXX=g++-5 74 | - CXX_STANDARD=14 75 | addons: 76 | apt: 77 | sources: ['ubuntu-toolchain-r-test'] 78 | packages: ['g++-5'] 79 | 80 | ############## 81 | # CLANG 82 | ############## 83 | - os: linux 84 | compiler: clang 85 | env: CLANG_VERSION=7 86 | - CC=clang-7 87 | - CXX=clang++-7 88 | - CXX_STANDARD=14 89 | addons: 90 | apt: 91 | sources: ['llvm-toolchain-trusty', 'llvm-toolchain-trusty-7', 'ubuntu-toolchain-r-test'] 92 | packages: ['clang-7', 'libc++-7-dev', 'libc++abi-7-dev'] 93 | - os: linux 94 | compiler: clang 95 | env: CLANG_VERSION=6.0 96 | - CC=clang-6.0 97 | - CXX=clang++-6.0 98 | - CXX_STANDARD=14 99 | addons: 100 | apt: 101 | sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0'] 102 | packages: ['clang-6.0', 'g++-6'] 103 | - os: linux 104 | compiler: clang 105 | env: CLANG_VERSION=7 106 | - CC=clang-7 107 | - CXX=clang++-7 108 | - CXX_STANDARD=17 109 | addons: 110 | apt: 111 | sources: ['llvm-toolchain-trusty', 'llvm-toolchain-trusty-7', 'ubuntu-toolchain-r-test'] 112 | packages: ['clang-7', 'libc++-7-dev', 'libc++abi-7-dev'] 113 | 114 | ############## 115 | # OSX / APPLECLANG 116 | ############## 117 | - os: osx 118 | osx_image: xcode10 119 | env: 120 | - CXX=clang 121 | - OSX=1 122 | - CXX_STANDARD=17 123 | - os: osx 124 | osx_image: xcode10 125 | env: 126 | - CXX=clang 127 | - OSX=1 128 | - CXX_STANDARD=14 129 | - os: osx 130 | osx_image: xcode9.4 131 | env: 132 | - CXX=clang 133 | - OSX=1 134 | - CXX_STANDARD=14 135 | 136 | 137 | before_install: 138 | - echo "Before install" 139 | - | 140 | git submodule init 141 | git submodule update 142 | # - | 143 | # if [ "$LIBCXX" == "On" ]; then 144 | # ./cmake/install_libcxx.sh 145 | # export CXXFLAGS="-stdlib=libc++" 146 | # fi 147 | - | 148 | if [ "${CLANG_VERSION}" == "7" ]; then 149 | export CXXFLAGS="-stdlib=libc++" 150 | fi 151 | - | 152 | sudo pip install conan --upgrade 153 | conan user 154 | 155 | 156 | install: 157 | - mkdir -p build && cd build 158 | - conan install .. 159 | 160 | script: 161 | - which $CXX 162 | - $CXX --version 163 | - cmake --version 164 | - cmake .. -DCLEANTYPE_ALL_OPTIONS=ON -DCLEANTYPE_CXX_STANDARD=${CXX_STANDARD} -DCMAKE_INSTALL_PREFIX=$(pwd)/install 165 | - cmake --build . --config Release -- -j4 166 | - ctest -C Release --output-on-failure 167 | - cmake --build . --target install 168 | - export PATH=$PATH:$(pwd)/install/bin 169 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Pascal Thomet 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.8.1) 2 | 3 | project(cleantype) 4 | 5 | option(CLEANTYPE_BUILD_TESTS "Build tests." ON) 6 | option(CLEANTYPE_USE_CONAN "Find deps (Boost) using conan." OFF) 7 | option(CLEANTYPE_BUILD_TOOLS "Build tools (ct_compiler_decipher)." ON) 8 | set(CLEANTYPE_CXX_STANDARD 14 CACHE STRING "Select CXX standard (14 or 17)") 9 | option(CLEANTYPE_ALL_OPTIONS "Use conan / build tests / build compile time" OFF) 10 | 11 | set(CMAKE_CXX_STANDARD ${CLEANTYPE_CXX_STANDARD}) 12 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | set(CMAKE_CXX_EXTENSIONS OFF) 14 | 15 | if (CLEANTYPE_ALL_OPTIONS) 16 | set(CLEANTYPE_BUILD_TESTS ON) 17 | set(CLEANTYPE_USE_CONAN ON) 18 | set(CLEANTYPE_BUILD_TOOLS ON) 19 | endif() 20 | 21 | enable_testing() 22 | 23 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 24 | 25 | if (CLEANTYPE_USE_CONAN) 26 | include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) 27 | conan_basic_setup(TARGETS) 28 | endif() 29 | 30 | 31 | find_program(CCACHE_FOUND ccache) 32 | if(CCACHE_FOUND) 33 | message("ccache found -> using it") 34 | set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) 35 | set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) 36 | endif(CCACHE_FOUND) 37 | 38 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 39 | set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR} ${CMAKE_MODULE_PATH}) 40 | 41 | function(clean_type_set_target_option target) 42 | if (MSVC) 43 | target_compile_options(${target} PRIVATE /std:c++latest) 44 | target_compile_definitions(${target} PRIVATE 45 | -D_SILENCE_CXX17_IS_LITERAL_TYPE_DEPRECATION_WARNING 46 | -D_SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING 47 | ) 48 | endif() 49 | target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/src/include) 50 | target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/third_party/tests_thirdparty/FunctionalPlus/include) 51 | target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/third_party/tests_thirdparty/hana/include) 52 | target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/third_party/include) 53 | target_compile_definitions(${target} PRIVATE -DCLEANTYPE_USE_NLOHMANN_JSON) 54 | if (APPLE) 55 | target_link_libraries(${target} PRIVATE c++) 56 | endif() 57 | if (UNIX) 58 | target_link_libraries(${target} PRIVATE stdc++ m) 59 | endif() 60 | endfunction() 61 | 62 | if (CLEANTYPE_BUILD_TESTS) 63 | add_subdirectory(src/tests) 64 | add_subdirectory(src/include/cleantype/details/hana_type_name/tests) 65 | endif() 66 | 67 | if (CLEANTYPE_BUILD_TOOLS) 68 | add_subdirectory(src/tools/ct_compiler_decipher) 69 | endif() 70 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This Makefile is intentionally simple and incomplete 2 | # It is provided as a quick way to build ct_compiler_decipher 3 | # Prefer to use cmake in development mode. 4 | 5 | all: ct_compiler_decipher 6 | 7 | ct_compiler_decipher: src/tools/ct_compiler_decipher/ct_compiler_decipher.cpp 8 | $(CXX) -Isrc/include --std=c++14 src/tools/ct_compiler_decipher/ct_compiler_decipher.cpp -o ct_compiler_decipher 9 | 10 | clean: 11 | rm ct_compiler_decipher 12 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | * [X] Cleanup 2 | * [X] Indent : no \n before < 3 | * [X] Link article / REPL C++ 4 | * [X] Patience for interactive demo 5 | * [X] Shorten article so that manual is reached 6 | * [X] Demo indent / no indent 7 | * [X] Proof read & classify code 8 | * [X] Doc inside cleantype.hpp (missing invoke, etc) 9 | * [X] debug.hpp / json.hpp 10 | * [X] Configuration via pref file ? 11 | * [X] third parties cleanup 12 | * [X] Continuous Integration : C++14 & C++17 13 | * [X] Doc 14 | * [X] Doc reorder 15 | * [X] Doc : example hana static string + example type 16 | * [X] State alpha -> apha / beta 17 | * [X] Change link "Note: this library is heavily tested" 18 | * [X] Layout doc : Table of Content? 19 | * [X] Add example with range v3 (no submodule : checkout via notebook) 20 | * [X] Better doc / config 21 | 22 | * [X] Range-v3 & indent: 23 | * [X] auto-indent clean 24 | * [X] pref / start auto indent 25 | * [X] doc / range-v3 & indent 26 | 27 | * invoke_result : 28 | * [X] remove cleantype_function.hpp 29 | * [X] polyfill invoke_result 30 | * [N] invoke_result_clean / invoke_result_full 31 | * [X] CT_invoke_result_fn, CT_invoke_result_fn_template 32 | * [X] improve invoke_result on functions ant templated functions 33 | * [X] Doc (separate page ?) 34 | 35 | * [X] type_name_s : 36 | * [X] hana 37 | * [X] pas de doctest, main only 38 | * [X] pas de format 39 | * [X] test / regex 40 | * [X] recup test dans full_s 41 | * [-] PR hana_pr_typename 42 | * [X] Types multiples par wrap dans Template Holder ? 43 | * [X] full_s : compile time tests 44 | * [X] west_const -> east_const 45 | * [X] suppr typename, replace by type_name_s 46 | * [X] retest lambda and 4 params types (was an issue, should not be anymore) : see cleantype_full_multiple_fromvalues 47 | * [X] Change macro names 48 | * [X] clean : check issues with multiple types (why parameter packs...) 49 | * [X] impl_clean_several_types -> publier dans API (et renommer) 50 | * [X] Compile time types log 51 | * [X] CMake / detection boost 52 | * [X] Header separe pour inclusion hana 53 | * [X] interact / clean 54 | * [X] prog version inline 55 | * [X] command line options / clean 56 | 57 | * [X] Notebook Doc 58 | * [X] decipherer build tool 59 | * [X] decipherer 60 | * [X] check status / references & update accordingly 61 | * [X] doc / build and usage decipherer 62 | 63 | * [X] Compiler log decipherer 64 | * [X] clang 65 | * [X] msvc 66 | * [X] gcc 67 | * [X] interact progressive ou utiliser tee ? 68 | 69 | * [X] east const 70 | 71 | * [X] Check references: (same, and for compile time) 72 | * [X] boost::hana::experimental::type_name 73 | * [X] ctti : Compile Time Type Information for C++ 74 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | 3 | 4 | branches: 5 | only: 6 | - master 7 | clone_folder: c:\projects\cleantype 8 | image: 9 | # - Visual Studio 2015 10 | - Visual Studio 2017 11 | configuration: 12 | - Release 13 | # - Debug 14 | platform: 15 | - x64 16 | environment: 17 | matrix: 18 | - arch: Win64 19 | # - arch: #does not work, Release|x64 not a valid target 20 | matrix: 21 | fast_finish: true 22 | 23 | # skip unsupported combinations 24 | init: 25 | - set arch= 26 | - if "%arch%"=="Win64" ( set arch= Win64) 27 | - echo %arch% 28 | - echo %APPVEYOR_BUILD_WORKER_IMAGE% 29 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( set generator="Visual Studio 15 2017%arch%" ) 30 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" ( set generator="Visual Studio 14 2015%arch%" ) 31 | - echo %generator% 32 | 33 | before_build: 34 | - cmd: |- 35 | echo "Downloading conan..." 36 | set PATH=%PATH%;%PYTHON%/Scripts/ 37 | pip.exe install conan 38 | conan user 39 | conan --version 40 | git submodule init 41 | git submodule update 42 | 43 | build_script: 44 | - cmd: |- 45 | mkdir build 46 | cd build 47 | conan install .. --build=missing 48 | cmake --version 49 | cmake .. -DCLEANTYPE_ALL_OPTIONS=ON -G %generator% -DCMAKE_INSTALL_PREFIX=c:/projects/cleantype/install 50 | cmake --build . --target ALL_BUILD --config Release 51 | cmake --build . --target install --config Release 52 | set PATH=%PATH%;c:/projects/cleantype/install/bin 53 | 54 | test_script: 55 | - ps: cd c:\projects\cleantype\build 56 | - ctest -C Release --output-on-failure 57 | 58 | only_commits: 59 | files: 60 | - CMakeLists.txt 61 | - appveyor.yml 62 | - src/ 63 | - cmake/ 64 | -------------------------------------------------------------------------------- /binder/Readme.md: -------------------------------------------------------------------------------- 1 | Configs for mybinder.org 2 | 3 | 4 | cf 5 | https://mybinder.readthedocs.io/en/latest/using.html#preparing-a-repository-for-binder 6 | and 7 | https://conda.io/docs/user-guide/tasks/manage-environments.html#creating-an-environment-file-manually 8 | -------------------------------------------------------------------------------- /binder/environment.yml: -------------------------------------------------------------------------------- 1 | name: cling 2 | channels: 3 | - QuantStack 4 | - conda-forge 5 | dependencies: 6 | - jupyter 7 | - opencv 8 | - xeus-cling=0.4.10=he860b03_1000 9 | - rise 10 | -------------------------------------------------------------------------------- /cmake/cmake_init/AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | Stefan Buschmann 3 | Daniel Limberger 4 | Willy Scheibel 5 | 6 | Thanks to all Contributors -------------------------------------------------------------------------------- /cmake/cmake_init/ClangTidy.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Function to register a target for clang-tidy 3 | function(perform_clang_tidy check_target target) 4 | set(includes "$") 5 | 6 | add_custom_target( 7 | ${check_target} 8 | COMMAND 9 | ${clang_tidy_EXECUTABLE} 10 | -p\t${PROJECT_BINARY_DIR} 11 | ${ARGN} 12 | -checks=* 13 | "$<$>:--\t$<$:-I$>>" 14 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 15 | ) 16 | 17 | set_target_properties(${check_target} 18 | PROPERTIES 19 | FOLDER "Maintenance" 20 | EXCLUDE_FROM_DEFAULT_BUILD 1 21 | ) 22 | 23 | add_dependencies(${check_target} ${target}) 24 | endfunction() 25 | -------------------------------------------------------------------------------- /cmake/cmake_init/CompileOptions.cmake: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Platform and architecture setup 4 | # 5 | 6 | # Get upper case system name 7 | string(TOUPPER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME_UPPER) 8 | 9 | # Determine architecture (32/64 bit) 10 | set(X64 OFF) 11 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 12 | set(X64 ON) 13 | endif() 14 | 15 | 16 | # 17 | # Project options 18 | # 19 | 20 | set(DEFAULT_PROJECT_OPTIONS 21 | DEBUG_POSTFIX "d" 22 | CXX_STANDARD 11 # Not available before CMake 3.1; see below for manual command line argument addition 23 | LINKER_LANGUAGE "CXX" 24 | POSITION_INDEPENDENT_CODE ON 25 | CXX_VISIBILITY_PRESET "hidden" 26 | CXX_EXTENSIONS Off 27 | ) 28 | 29 | 30 | # 31 | # Include directories 32 | # 33 | 34 | set(DEFAULT_INCLUDE_DIRECTORIES) 35 | 36 | 37 | # 38 | # Libraries 39 | # 40 | 41 | set(DEFAULT_LIBRARIES) 42 | 43 | 44 | # 45 | # Compile definitions 46 | # 47 | 48 | set(DEFAULT_COMPILE_DEFINITIONS 49 | SYSTEM_${SYSTEM_NAME_UPPER} 50 | ) 51 | 52 | # MSVC compiler options 53 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") 54 | set(DEFAULT_COMPILE_DEFINITIONS ${DEFAULT_COMPILE_DEFINITIONS} 55 | _SCL_SECURE_NO_WARNINGS # Calling any one of the potentially unsafe methods in the Standard C++ Library 56 | _CRT_SECURE_NO_WARNINGS # Calling any one of the potentially unsafe methods in the CRT Library 57 | ) 58 | endif () 59 | 60 | 61 | # 62 | # Compile options 63 | # 64 | 65 | set(DEFAULT_COMPILE_OPTIONS) 66 | 67 | # MSVC compiler options 68 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") 69 | set(DEFAULT_COMPILE_OPTIONS ${DEFAULT_COMPILE_OPTIONS} 70 | /MP # -> build with multiple processes 71 | /W4 # -> warning level 4 72 | # /WX # -> treat warnings as errors 73 | 74 | /wd4251 # -> disable warning: 'identifier': class 'type' needs to have dll-interface to be used by clients of class 'type2' 75 | /wd4592 # -> disable warning: 'identifier': symbol will be dynamically initialized (implementation limitation) 76 | # /wd4201 # -> disable warning: nonstandard extension used: nameless struct/union (caused by GLM) 77 | # /wd4127 # -> disable warning: conditional expression is constant (caused by Qt) 78 | 79 | #$<$: 80 | #/RTCc # -> value is assigned to a smaller data type and results in a data loss 81 | #> 82 | 83 | $<$: 84 | /Gw # -> whole program global optimization 85 | /GS- # -> buffer security check: no 86 | /GL # -> whole program optimization: enable link-time code generation (disables Zi) 87 | /GF # -> enable string pooling 88 | > 89 | 90 | # No manual c++11 enable for MSVC as all supported MSVC versions for cmake-init have C++11 implicitly enabled (MSVC >=2013) 91 | ) 92 | endif () 93 | 94 | # GCC and Clang compiler options 95 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 96 | set(DEFAULT_COMPILE_OPTIONS ${DEFAULT_COMPILE_OPTIONS} 97 | -Wall 98 | -Wextra 99 | -Wunused 100 | 101 | -Wreorder 102 | -Wignored-qualifiers 103 | -Wmissing-braces 104 | -Wreturn-type 105 | -Wswitch 106 | -Wswitch-default 107 | -Wuninitialized 108 | -Wmissing-field-initializers 109 | 110 | $<$: 111 | -Wmaybe-uninitialized 112 | 113 | $<$,4.8>: 114 | -Wpedantic 115 | 116 | -Wreturn-local-addr 117 | > 118 | > 119 | 120 | $<$: 121 | -Wpedantic 122 | 123 | # -Wreturn-stack-address # gives false positives 124 | > 125 | 126 | $<$: 127 | -pthread 128 | > 129 | 130 | # Required for CMake < 3.1; should be removed if minimum required CMake version is raised. 131 | $<$: 132 | -std=c++11 133 | > 134 | 135 | $<$: 136 | -fprofile-arcs 137 | -ftest-coverage 138 | > 139 | ) 140 | endif () 141 | 142 | 143 | # 144 | # Linker options 145 | # 146 | 147 | set(DEFAULT_LINKER_OPTIONS) 148 | 149 | # Use pthreads on mingw and linux 150 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR "${CMAKE_SYSTEM_NAME}" MATCHES "Linux") 151 | set(DEFAULT_LINKER_OPTIONS 152 | ${DEFAULT_LINKER_OPTIONS} 153 | -pthread 154 | ) 155 | 156 | if (${OPTION_COVERAGE_ENABLED}) 157 | set(DEFAULT_LINKER_OPTIONS 158 | ${DEFAULT_LINKER_OPTIONS} 159 | -fprofile-arcs 160 | -ftest-coverage 161 | ) 162 | endif () 163 | endif() 164 | -------------------------------------------------------------------------------- /cmake/cmake_init/ComponentInstall.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Execute cmake_install.cmake wrapper that allows to pass both DESTDIR and COMPONENT environment variable 3 | 4 | execute_process( 5 | COMMAND ${CMAKE_COMMAND} -DCOMPONENT=$ENV{COMPONENT} -P cmake_install.cmake 6 | ) 7 | -------------------------------------------------------------------------------- /cmake/cmake_init/Coverage.cmake: -------------------------------------------------------------------------------- 1 | 2 | include(${CMAKE_CURRENT_LIST_DIR}/Gcov.cmake) 3 | 4 | set(OPTION_COVERAGE_ENABLED OFF) 5 | 6 | set(LCOV_EXCLUDE_COVERAGE 7 | ${LCOV_EXCLUDE_COVERAGE} 8 | "\"*/googletest/*\"" 9 | "\"*v1*\"" 10 | "\"/usr/*\"" 11 | ) 12 | 13 | # Function to register a target for enabled coverage report 14 | function(generate_coverage_report target) 15 | if(NOT TARGET coverage) 16 | add_custom_target(coverage) 17 | 18 | set_target_properties(coverage 19 | PROPERTIES 20 | FOLDER "Maintenance" 21 | EXCLUDE_FROM_DEFAULT_BUILD 1 22 | ) 23 | endif() 24 | 25 | if (${OPTION_COVERAGE_ENABLED}) 26 | generate_lcov_report(coverage-${target} ${target} ${ARGN}) 27 | add_dependencies(coverage coverage-${target}) 28 | endif() 29 | endfunction() 30 | 31 | # Enable or disable coverage 32 | function(enable_coverage status) 33 | if(NOT ${status}) 34 | set(OPTION_COVERAGE_ENABLED ${status} PARENT_SCOPE) 35 | message(STATUS "Coverage lcov skipped: Manually disabled") 36 | 37 | return() 38 | endif() 39 | 40 | find_package(lcov) 41 | 42 | if(NOT lcov_FOUND) 43 | set(OPTION_COVERAGE_ENABLED OFF PARENT_SCOPE) 44 | message(STATUS "Coverage lcov skipped: lcov not found") 45 | 46 | return() 47 | endif() 48 | 49 | set(OPTION_COVERAGE_ENABLED ${status} PARENT_SCOPE) 50 | message(STATUS "Coverage report enabled") 51 | endfunction() 52 | -------------------------------------------------------------------------------- /cmake/cmake_init/Cppcheck.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Function to register a target for cppcheck 3 | function(perform_cppcheck check_target target) 4 | set(includes "$") 5 | 6 | add_custom_target( 7 | ${check_target} 8 | COMMAND 9 | ${cppcheck_EXECUTABLE} 10 | "$<$:-I$>" 11 | --enable=all 12 | --std=c++11 13 | --verbose 14 | --suppress=missingIncludeSystem 15 | ${ARGN} 16 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 17 | ) 18 | 19 | set_target_properties(${check_target} 20 | PROPERTIES 21 | FOLDER "Maintenance" 22 | EXCLUDE_FROM_DEFAULT_BUILD 1 23 | ) 24 | 25 | add_dependencies(${check_target} ${target}) 26 | endfunction() 27 | -------------------------------------------------------------------------------- /cmake/cmake_init/Custom.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Set policy if policy is available 3 | function(set_policy POL VAL) 4 | 5 | if(POLICY ${POL}) 6 | cmake_policy(SET ${POL} ${VAL}) 7 | endif() 8 | 9 | endfunction(set_policy) 10 | 11 | 12 | # Define function "source_group_by_path with three mandatory arguments (PARENT_PATH, REGEX, GROUP, ...) 13 | # to group source files in folders (e.g. for MSVC solutions). 14 | # 15 | # Example: 16 | # source_group_by_path("${CMAKE_CURRENT_SOURCE_DIR}/src" "\\\\.h$|\\\\.inl$|\\\\.cpp$|\\\\.c$|\\\\.ui$|\\\\.qrc$" "Source Files" ${sources}) 17 | function(source_group_by_path PARENT_PATH REGEX GROUP) 18 | 19 | foreach (FILENAME ${ARGN}) 20 | 21 | get_filename_component(FILEPATH "${FILENAME}" REALPATH) 22 | file(RELATIVE_PATH FILEPATH ${PARENT_PATH} ${FILEPATH}) 23 | get_filename_component(FILEPATH "${FILEPATH}" DIRECTORY) 24 | 25 | string(REPLACE "/" "\\" FILEPATH "${FILEPATH}") 26 | 27 | source_group("${GROUP}\\${FILEPATH}" REGULAR_EXPRESSION "${REGEX}" FILES ${FILENAME}) 28 | 29 | endforeach() 30 | 31 | endfunction(source_group_by_path) 32 | 33 | 34 | # Function that extract entries matching a given regex from a list. 35 | # ${OUTPUT} will store the list of matching filenames. 36 | function(list_extract OUTPUT REGEX) 37 | 38 | foreach(FILENAME ${ARGN}) 39 | if(${FILENAME} MATCHES "${REGEX}") 40 | list(APPEND ${OUTPUT} ${FILENAME}) 41 | endif() 42 | endforeach() 43 | 44 | set(${OUTPUT} ${${OUTPUT}} PARENT_SCOPE) 45 | 46 | endfunction(list_extract) 47 | -------------------------------------------------------------------------------- /cmake/cmake_init/Findclang_tidy.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Findclang_tidy results: 3 | # clang_tidy_FOUND 4 | # clang_tidy_EXECUTABLE 5 | 6 | include(FindPackageHandleStandardArgs) 7 | 8 | find_program(clang_tidy_EXECUTABLE 9 | NAMES 10 | clang-tidy-3.5 11 | clang-tidy-3.6 12 | clang-tidy-3.7 13 | clang-tidy-3.8 14 | clang-tidy-3.9 15 | clang-tidy-4.0 16 | clang-tidy 17 | PATHS 18 | "${CLANG_TIDY_DIR}" 19 | ) 20 | 21 | find_package_handle_standard_args(clang_tidy 22 | FOUND_VAR 23 | clang_tidy_FOUND 24 | REQUIRED_VARS 25 | clang_tidy_EXECUTABLE 26 | ) 27 | 28 | mark_as_advanced(clang_tidy_EXECUTABLE) -------------------------------------------------------------------------------- /cmake/cmake_init/Findcppcheck.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Findcppcheck results: 3 | # cppcheck_FOUND 4 | # cppcheck_EXECUTABLE 5 | 6 | include(FindPackageHandleStandardArgs) 7 | 8 | # work around CMP0053, see http://public.kitware.com/pipermail/cmake/2014-November/059117.html 9 | set(PROGRAMFILES_x86_ENV "PROGRAMFILES(x86)") 10 | 11 | find_program(cppcheck_EXECUTABLE 12 | NAMES 13 | cppcheck 14 | PATHS 15 | "${CPPCHECK_DIR}" 16 | "$ENV{CPPCHECK_DIR}" 17 | "$ENV{PROGRAMFILES}/Cppcheck" 18 | "$ENV{${PROGRAMFILES_x86_ENV}}/Cppcheck" 19 | ) 20 | 21 | find_package_handle_standard_args(cppcheck 22 | FOUND_VAR 23 | cppcheck_FOUND 24 | REQUIRED_VARS 25 | cppcheck_EXECUTABLE 26 | ) 27 | 28 | mark_as_advanced(cppcheck_EXECUTABLE) 29 | -------------------------------------------------------------------------------- /cmake/cmake_init/Findgcov.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Findgcov results: 3 | # gcov_FOUND 4 | # gcov_EXECUTABLE 5 | 6 | include(FindPackageHandleStandardArgs) 7 | 8 | # work around CMP0053, see http://public.kitware.com/pipermail/cmake/2014-November/059117.html 9 | set(PROGRAMFILES_x86_ENV "PROGRAMFILES(x86)") 10 | 11 | find_program(gcov_EXECUTABLE 12 | NAMES 13 | gcov 14 | PATHS 15 | "${GCOV_DIR}" 16 | "$ENV{GCOV_DIR}" 17 | "$ENV{PROGRAMFILES}/gcov" 18 | "$ENV{${PROGRAMFILES_x86_ENV}}/gcov" 19 | ) 20 | 21 | find_package_handle_standard_args(gcov 22 | FOUND_VAR 23 | gcov_FOUND 24 | REQUIRED_VARS 25 | gcov_EXECUTABLE 26 | ) 27 | 28 | mark_as_advanced(gcov_EXECUTABLE) 29 | -------------------------------------------------------------------------------- /cmake/cmake_init/Findlcov.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Findlcov results: 3 | # lcov_FOUND 4 | # lcov_EXECUTABLE 5 | 6 | include(FindPackageHandleStandardArgs) 7 | 8 | # work around CMP0053, see http://public.kitware.com/pipermail/cmake/2014-November/059117.html 9 | set(PROGRAMFILES_x86_ENV "PROGRAMFILES(x86)") 10 | 11 | find_program(lcov_EXECUTABLE 12 | NAMES 13 | lcov 14 | PATHS 15 | "${LCOV_DIR}" 16 | "$ENV{LCOV_DIR}" 17 | "$ENV{PROGRAMFILES}/lcov" 18 | "$ENV{${PROGRAMFILES_x86_ENV}}/lcov" 19 | ) 20 | 21 | find_program(genhtml_EXECUTABLE 22 | NAMES 23 | genhtml 24 | PATHS 25 | "${LCOV_DIR}" 26 | "$ENV{LCOV_DIR}" 27 | "$ENV{PROGRAMFILES}/lcov" 28 | "$ENV{${PROGRAMFILES_x86_ENV}}/lcov" 29 | ) 30 | 31 | find_package_handle_standard_args(lcov 32 | FOUND_VAR 33 | lcov_FOUND 34 | REQUIRED_VARS 35 | lcov_EXECUTABLE 36 | genhtml_EXECUTABLE 37 | ) 38 | 39 | mark_as_advanced( 40 | lcov_EXECUTABLE 41 | genhtml_EXECUTABLE 42 | ) 43 | -------------------------------------------------------------------------------- /cmake/cmake_init/Gcov.cmake: -------------------------------------------------------------------------------- 1 | 2 | #mkdir build/coverage 3 | #lcov -d build/source/tests/fiblib-test/CMakeFiles/fiblib-test.dir -c -o build/coverage/fiblib-test.info 4 | #genhtml -o build/coverage/html build/coverage/fiblib-test.info 5 | 6 | set(LCOV_EXCLUDE_COVERAGE) 7 | 8 | # Function to register a target for coverage 9 | function(generate_lcov_report coverage_target target) 10 | if(NOT TARGET coverage-init) 11 | add_custom_target( 12 | coverage-zero 13 | COMMAND 14 | ${lcov_EXECUTABLE} 15 | --zerocounters 16 | --base-directory ${CMAKE_BINARY_DIR} 17 | --directory ${CMAKE_SOURCE_DIR} 18 | -q 19 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 20 | ) 21 | 22 | add_custom_target( 23 | coverage-init 24 | COMMAND 25 | ${lcov_EXECUTABLE} 26 | --no-external 27 | --capture 28 | --initial 29 | --base-directory ${CMAKE_BINARY_DIR} 30 | --directory ${CMAKE_SOURCE_DIR} 31 | --output-file ${CMAKE_BINARY_DIR}/coverage-base.info 32 | -q 33 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 34 | BYPRODUCTS ${CMAKE_BINARY_DIR}/coverage-base.info 35 | ) 36 | 37 | add_custom_target( 38 | coverage-info 39 | COMMAND 40 | ${lcov_EXECUTABLE} 41 | --capture 42 | --no-external 43 | --base-directory ${CMAKE_BINARY_DIR} 44 | --directory ${CMAKE_SOURCE_DIR} 45 | --output-file ${CMAKE_BINARY_DIR}/coverage-captured.info 46 | -q 47 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 48 | BYPRODUCTS ${CMAKE_BINARY_DIR}/coverage-captured.info 49 | ) 50 | 51 | add_custom_target( 52 | coverage-merge 53 | COMMAND 54 | ${lcov_EXECUTABLE} 55 | --add-tracefile ${CMAKE_BINARY_DIR}/coverage-base.info 56 | --add-tracefile ${CMAKE_BINARY_DIR}/coverage-captured.info 57 | --output-file ${CMAKE_BINARY_DIR}/coverage-merged.info 58 | -q 59 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 60 | BYPRODUCTS ${CMAKE_BINARY_DIR}/coverage-merged.info 61 | ) 62 | 63 | add_custom_target( 64 | coverage-filter 65 | COMMAND 66 | ${lcov_EXECUTABLE} 67 | --base-directory ${CMAKE_BINARY_DIR} 68 | --directory ${CMAKE_SOURCE_DIR} 69 | --remove ${CMAKE_BINARY_DIR}/coverage-merged.info 70 | ${LCOV_EXCLUDE_COVERAGE} 71 | --output-file ${CMAKE_BINARY_DIR}/coverage-filtered.info 72 | -q 73 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 74 | BYPRODUCTS ${CMAKE_BINARY_DIR}/coverage-filtered.info 75 | ) 76 | 77 | add_custom_target( 78 | coverage-report 79 | COMMAND 80 | ${genhtml_EXECUTABLE} 81 | --output-directory ${CMAKE_BINARY_DIR}/coverage 82 | --title "${META_PROJECT_NAME} Test Coverage" 83 | --num-spaces 4 84 | ${CMAKE_BINARY_DIR}/coverage-filtered.info 85 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 86 | DEPENDS ${CMAKE_BINARY_DIR}/coverage-filtered.info 87 | ) 88 | 89 | add_dependencies(coverage-init coverage-zero) 90 | #add_dependencies(coverage-info coverage-init) 91 | add_dependencies(coverage-merge coverage-info) 92 | add_dependencies(coverage-filter coverage-merge) 93 | add_dependencies(coverage-report coverage-filter) 94 | add_dependencies(coverage coverage-report) 95 | endif() 96 | 97 | add_custom_target(${coverage_target} 98 | COMMAND $ 99 | ) 100 | 101 | add_dependencies(coverage-info ${coverage_target}) 102 | add_dependencies(${coverage_target} coverage-init) 103 | 104 | endfunction() 105 | -------------------------------------------------------------------------------- /cmake/cmake_init/GenerateTemplateExportHeader.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Creates an export header similar to generate_export_header, but for templates. 3 | # The main difference is that for MSVC, templates must not get exported. 4 | # When the file ${export_file} is included in source code, the macro ${target_id}_TEMPLATE_API 5 | # may get used to define public visibility for templates on GCC and Clang platforms. 6 | function(generate_template_export_header target target_id export_file) 7 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") 8 | configure_file(${PROJECT_SOURCE_DIR}/source/codegeneration/template_msvc_api.h.in ${CMAKE_CURRENT_BINARY_DIR}/${export_file}) 9 | else() 10 | configure_file(${PROJECT_SOURCE_DIR}/source/codegeneration/template_api.h.in ${CMAKE_CURRENT_BINARY_DIR}/${export_file}) 11 | endif() 12 | endfunction() 13 | -------------------------------------------------------------------------------- /cmake/cmake_init/HealthCheck.cmake: -------------------------------------------------------------------------------- 1 | 2 | include(${CMAKE_CURRENT_LIST_DIR}/Cppcheck.cmake) 3 | include(${CMAKE_CURRENT_LIST_DIR}/ClangTidy.cmake) 4 | 5 | set(OPTION_CPPCHECK_ENABLED Off) 6 | set(OPTION_CLANG_TIDY_ENABLED Off) 7 | 8 | # Function to register a target for enabled health checks 9 | function(perform_health_checks target) 10 | if(NOT TARGET check-all) 11 | add_custom_target(check-all) 12 | 13 | set_target_properties(check-all 14 | PROPERTIES 15 | FOLDER "Maintenance" 16 | EXCLUDE_FROM_DEFAULT_BUILD 1 17 | ) 18 | endif() 19 | 20 | add_custom_target(check-${target}) 21 | 22 | set_target_properties(check-${target} 23 | PROPERTIES 24 | FOLDER "Maintenance" 25 | EXCLUDE_FROM_DEFAULT_BUILD 1 26 | ) 27 | 28 | if (OPTION_CPPCHECK_ENABLED) 29 | perform_cppcheck(cppcheck-${target} ${target} ${ARGN}) 30 | add_dependencies(check-${target} cppcheck-${target}) 31 | endif() 32 | 33 | if (OPTION_CLANG_TIDY_ENABLED) 34 | perform_clang_tidy(clang-tidy-${target} ${target} ${ARGN}) 35 | add_dependencies(check-${target} clang-tidy-${target}) 36 | endif() 37 | 38 | add_dependencies(check-all check-${target}) 39 | endfunction() 40 | 41 | # Enable or disable cppcheck for health checks 42 | function(enable_cppcheck status) 43 | if(NOT ${status}) 44 | set(OPTION_CPPCHECK_ENABLED ${status} PARENT_SCOPE) 45 | message(STATUS "Check cppcheck skipped: Manually disabled") 46 | 47 | return() 48 | endif() 49 | 50 | find_package(cppcheck) 51 | 52 | if(NOT cppcheck_FOUND) 53 | set(OPTION_CPPCHECK_ENABLED Off PARENT_SCOPE) 54 | message(STATUS "Check cppcheck skipped: cppcheck not found") 55 | 56 | return() 57 | endif() 58 | 59 | set(OPTION_CPPCHECK_ENABLED ${status} PARENT_SCOPE) 60 | message(STATUS "Check cppcheck") 61 | endfunction() 62 | 63 | # Enable or disable clang-tidy for health checks 64 | function(enable_clang_tidy status) 65 | if(NOT ${status}) 66 | set(OPTION_CLANG_TIDY_ENABLED ${status} PARENT_SCOPE) 67 | message(STATUS "Check clang-tidy skipped: Manually disabled") 68 | 69 | return() 70 | endif() 71 | 72 | find_package(clang_tidy) 73 | 74 | if(NOT clang_tidy_FOUND) 75 | set(OPTION_CLANG_TIDY_ENABLED Off PARENT_SCOPE) 76 | message(STATUS "Check clang-tidy skipped: clang-tidy not found") 77 | 78 | return() 79 | endif() 80 | 81 | set(OPTION_CLANG_TIDY_ENABLED ${status} PARENT_SCOPE) 82 | message(STATUS "Check clang-tidy") 83 | 84 | set(CMAKE_EXPORT_COMPILE_COMMANDS On PARENT_SCOPE) 85 | endfunction() 86 | 87 | # Configure cmake target to check for cmake-init template 88 | function(add_check_template_target current_template_sha) 89 | add_custom_target( 90 | check-template 91 | COMMAND ${CMAKE_COMMAND} 92 | -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} 93 | -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR} 94 | -DAPPLIED_CMAKE_INIT_SHA=${current_template_sha} 95 | -P ${PROJECT_SOURCE_DIR}/cmake/CheckTemplate.cmake 96 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 97 | ) 98 | 99 | set_target_properties(check-template 100 | PROPERTIES 101 | FOLDER "Maintenance" 102 | EXCLUDE_FROM_DEFAULT_BUILD 1 103 | ) 104 | endfunction() -------------------------------------------------------------------------------- /cmake/cmake_init/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2012-2015 Computer Graphics Systems Group at the Hasso-Plattner-Institute, Germany. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /cmake/cmake_init/README.md: -------------------------------------------------------------------------------- 1 | These script are part of [cmake-init](https://github.com/cginternals/cmake-init) 2 | 3 | See [LICENSE](LICENSE) and [AUTHORS](AUTHORS). 4 | -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | boost/1.68.0@conan/stable 3 | 4 | [generators] 5 | cmake 6 | 7 | [options] 8 | -------------------------------------------------------------------------------- /demos/.gitignore: -------------------------------------------------------------------------------- 1 | ct_compiler_decipher 2 | demo_simple 3 | -------------------------------------------------------------------------------- /demos/demo_cling.cpp: -------------------------------------------------------------------------------- 1 | // This is the source code for the main "video" (asciinema) demo 2 | // The video was created using the following commands: 3 | // > asciinema rec demo_cling.cast 4 | // > python im_not_a_touch_typist.py demo_cling.cpp | tee /dev/tty | cling --std=c++14 5 | // > Ctrl-D 6 | #pragma cling add_include_path("./include") 7 | #include 8 | 9 | 10 | // CleanType (https://github.com/pthom/cleantype) 11 | // Readable C++ type introspection 12 | 13 | // This demo uses cling, a fully compliant C++14 REPL, and asciinema, a terminal session recorder. 14 | // You can pause at any time, and copy-paste samples from it. 15 | 16 | #include 17 | 18 | // The dumbest logger in the west... 19 | #define LOG(...) std::cout << __VA_ARGS__ << "\n"; 20 | 21 | // First, let's define a variable for demonstration purpose 22 | std::set my_set { "Hello", "There"}; 23 | 24 | // let's ask CleanType to give us the type of "my_set" 25 | // cleantype::full will return the *full* type info 26 | LOG( cleantype::full(my_set) ); 27 | 28 | 29 | // Ouch, that was barely readable! 30 | // cleantype::clean will return a *readable* type 31 | LOG( cleantype::clean(my_set) ); 32 | 33 | // Let's now show the content of "my_set" together with its type 34 | LOG( cleantype::show_details(my_set) ); 35 | 36 | 37 | // Yes, but what about lambdas? Could you guess the signature of the lambda below? 38 | auto lambda_example = []() { 39 | // when C++ meets js... 40 | return +!!""; // See https://blog.knatten.org/2018/10/12/1662 41 | }; 42 | 43 | // cleantype::lambda_clean returns the signature of lambda functions 44 | LOG( cleantype::lambda_clean(lambda_example) ); 45 | 46 | 47 | 48 | // Ok, maybe this was too easy. Let's try with a generic lambda! 49 | auto add = [](auto a, auto b) { 50 | return a + b; 51 | }; 52 | 53 | // Now, can we see its signature? 54 | // Yes, we just need to specify the input argument types. 55 | LOG( cleantype::lambda_clean(add) ); 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | // Can CleanType understand some more complex libraries 64 | // like range-v3 where most variables, functions and lambdas are of type "auto"? 65 | // Well... yes! 66 | 67 | #include 68 | 69 | using namespace ranges; 70 | 71 | auto square_yield_fn(int x) { 72 | return ranges::yield(x * x); 73 | } 74 | auto squares_view = view::for_each(view::ints(1), square_yield_fn); 75 | 76 | // What is the type of squares_view? 77 | // Let's see... 78 | LOG( cleantype::clean(squares_view) ); 79 | 80 | // Let's make it more complex yet: 81 | auto squares_take_10 = squares_view | view::take(10); 82 | 83 | // As you will see below, CleanType can indent the types 84 | // when they get more complex! 85 | 86 | LOG( cleantype::clean(squares_take_10) ); 87 | 88 | 89 | 90 | // Thanks for watching! 91 | 92 | 93 | 94 | 95 | 96 | .q -------------------------------------------------------------------------------- /demos/demo_compiler_decipher.cpp: -------------------------------------------------------------------------------- 1 | 2 | // This demo showcases how ct_compiler_decipher can 3 | // make the compiler output more readable. 4 | // 5 | // 1. First compile ct_compiler_decipher: 6 | // > g++ -Iinclude -std=c++14 ../src/tools/ct_compiler_decipher/ct_compiler_decipher.cpp -o ct_compiler_decipher 7 | // 8 | // 2. Try to compile this file (it will fail, this is intentional) 9 | // > g++ -std=c++14 -Iinclude demo_compiler_decipher.cpp 2>&1 | less 10 | // The error will resemble this: 11 | // demo_compiler_decipher.cpp:21:23: error: no match for ‘operator+’ 12 | // (operand types are ‘const std::set >’ and ‘int’) 13 | // 14 | // 3. Compile this file, and pipe the compiler output to ct_compiler_decipher 15 | // > g++ -std=c++14 -Iinclude demo_compiler_decipher.cpp 2>&1 | ./ct_compiler_decipher | less 16 | // The error will resemble this: 17 | // demo_compiler_decipher.cpp:21:23: error: no match for ‘operator+’ 18 | // (operand types are ‘const std::set ’ and ‘int’) 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | int main() { 27 | std::vector> v; 28 | std::transform( 29 | v.begin(), v.end(), 30 | v.begin(), 31 | [](const auto & xs) { 32 | return xs + 1; // ouch, error here! 33 | } 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /demos/demo_simple.cpp: -------------------------------------------------------------------------------- 1 | // Compile with 2 | // cd demos/ 3 | // g++ -std=c++14 -Iinclude demo_simple.cpp -o demo_simple 4 | // 5 | // Edit and compile this file without installing anything at 6 | // https://gitpod.io/#https://github.com/pthom/cleantype/blob/master/demos/demo_simple.cpp 7 | // 8 | #include 9 | #include 10 | #include 11 | 12 | #define LOG(...) std::cout << __VA_ARGS__ << "\n"; 13 | 14 | void demo() 15 | { 16 | // First, let's define a variable for demonstration purpose 17 | std::set my_set { "Hello", "There"}; 18 | 19 | // let's ask CleanType to give us the type of "my_set" 20 | // cleantype::full will return the *full* type info 21 | LOG( cleantype::full(my_set) ); 22 | // outputs: 23 | // std::set, std::allocator>, std::less, std::allocator>>, std::allocator, std::allocator>>> & 24 | 25 | // Ouch, that was barely readable! 26 | // cleantype::clean will return a *readable* type 27 | LOG( cleantype::clean(my_set) ); 28 | // outputs: 29 | // std::set & 30 | 31 | // Let's now show the content of "my_set" together with its type 32 | LOG( cleantype::show_details(my_set) ); 33 | // outputs: 34 | // std::set & = [Hello, There] 35 | 36 | 37 | // Yes, but what about lambdas? Could you guess the signature of the lambda below? 38 | auto lambda_example = []() { 39 | // when C++ meets js... 40 | return +!!""; // See https://blog.knatten.org/2018/10/12/1662 41 | }; 42 | 43 | // cleantype::lambda_clean returns the signature of lambda functions 44 | LOG( cleantype::lambda_clean(lambda_example) ); 45 | // outputs: 46 | // lambda: () -> int 47 | 48 | // Ok, maybe this was too easy. Let's try with a generic lambda! 49 | auto add = [](auto a, auto b) { 50 | return a + b; 51 | }; 52 | 53 | // Now, can we see its signature? 54 | // Yes, we just need to specify the input argument types. 55 | LOG( cleantype::lambda_clean(add) ); 56 | // outputs: 57 | // lambda: (std::string, char) -> std::string 58 | } 59 | 60 | 61 | // Can CleanType understand some more complex libraries 62 | // like range-v3 where most variables, functions and lambdas are of type "auto"? 63 | // Well... yes! 64 | 65 | #include 66 | 67 | using namespace ranges; 68 | 69 | auto square_yield_fn(int x) { 70 | return ranges::yield(x * x); 71 | } 72 | 73 | void demo_ranges() 74 | { 75 | auto squares_view = view::for_each(view::ints(1), square_yield_fn); 76 | 77 | // What is the type of squares_view? 78 | // Let's see... 79 | LOG( cleantype::clean(squares_view) ); 80 | // outputs: 81 | // ranges::v3::join_view, ranges::v3::single_view(*)(int)>, void> & 82 | 83 | // Let's make it more complex yet: 84 | auto squares_take_10 = squares_view | view::take(10); 85 | 86 | // As you will see below, CleanType can indent the types 87 | // when they get more complex! 88 | LOG( cleantype::clean(squares_take_10) ); 89 | // outputs: 90 | // ranges::v3::detail::take_exactly_view_< 91 | // ranges::v3::join_view< 92 | // ranges::v3::transform_view< 93 | // ranges::v3::iota_view< 94 | // int, 95 | // void 96 | // >, 97 | // ranges::v3::single_view< 98 | // int 99 | // > (*)(int) 100 | // >, 101 | // void 102 | // >, 103 | // false 104 | // > & 105 | } 106 | 107 | int main() 108 | { 109 | demo(); 110 | demo_ranges(); 111 | } -------------------------------------------------------------------------------- /demos/im_not_a_touch_typist.py: -------------------------------------------------------------------------------- 1 | # python im_not_a_touch_typist demo_cling.cpp | tee /dev/tty | cling --std=c++14 2 | 3 | import sys 4 | import time 5 | import subprocess 6 | 7 | def send_letter(letter): 8 | sys.stdout.write(letter) 9 | sys.stdout.flush() 10 | 11 | def write_line(line): 12 | delay_letter = 0.040 13 | delay_line = 0.5 14 | for c in line: 15 | send_letter(c) 16 | time.sleep(delay_letter) 17 | time.sleep(delay_line) 18 | send_letter("\n") 19 | 20 | def simulate_keypresses(content): 21 | lines = content.split("\n") 22 | for line in lines: 23 | write_line(line) 24 | 25 | 26 | if __name__ == "__main__": 27 | filename = sys.argv[1] 28 | with open(filename, "r") as f: 29 | content = f.read() 30 | simulate_keypresses(content) 31 | -------------------------------------------------------------------------------- /demos/include/cleantype: -------------------------------------------------------------------------------- 1 | ../../include_all_in_one/include/cleantype -------------------------------------------------------------------------------- /demos/include/fplus: -------------------------------------------------------------------------------- 1 | ../../third_party/tests_thirdparty/FunctionalPlus/include/fplus -------------------------------------------------------------------------------- /demos/include/meta: -------------------------------------------------------------------------------- 1 | ../../third_party/tests_thirdparty/range-v3/include/meta -------------------------------------------------------------------------------- /demos/include/range: -------------------------------------------------------------------------------- 1 | ../../third_party/tests_thirdparty/range-v3/include/range -------------------------------------------------------------------------------- /include_all_in_one/make_all_in_one.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python3 2 | 3 | import os 4 | import sys 5 | import typing 6 | 7 | THIS_SCRIPT_DIR = sys.path[0] 8 | INCLUDE_DIR = THIS_SCRIPT_DIR + "/../src/include/cleantype/" 9 | ALL_IN_ONE_FILE = THIS_SCRIPT_DIR + "/include/cleantype/cleantype.hpp" 10 | 11 | MAIN_TITLE = """ 12 | // CleanType : amalgamated version 13 | // 14 | // This file is part of CleanType: Clean Types for C++ 15 | // Copyright Pascal Thomet - 2018 16 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 17 | """ 18 | 19 | TITLE = """ 20 | ////////////////////////////////////////// 21 | //// Header: HEADER_FILE 22 | ////////////////////////////////////////// 23 | """ 24 | 25 | FileName = typing.NewType("Filename", str) 26 | FileContent = typing.NewType("FileContent", str) 27 | CodeLine = typing.NewType("CodeLine", str) 28 | 29 | 30 | def read_file(file: FileName) -> FileContent: 31 | with open(file, "r") as f: 32 | r = f.read() 33 | return r 34 | 35 | 36 | def get_included_file(codeline: CodeLine) -> typing.Optional[FileName]: 37 | search = "#include FileContent: 47 | if header_file in already_processed_headers: 48 | return "" 49 | already_processed_headers.append(header_file) 50 | dst_file_content = TITLE.replace("HEADER_FILE", header_file) 51 | original_file_content = read_file(INCLUDE_DIR + header_file) 52 | for line in original_file_content.split("\n"): 53 | included_file = get_included_file(line) 54 | if included_file is not None: 55 | dst_file_content = dst_file_content + \ 56 | process_header_file(included_file, already_processed_headers) 57 | else: 58 | if "#pragma once" not in line: 59 | dst_file_content = dst_file_content + line + "\n" 60 | return dst_file_content 61 | 62 | def make_all_in_one() -> str: 63 | c = process_header_file("cleantype.hpp") 64 | c = "#pragma once\n" + MAIN_TITLE + c 65 | return c 66 | 67 | 68 | if __name__ == "__main__": 69 | content = make_all_in_one() 70 | # print(make_all_in_one()) 71 | with open(ALL_IN_ONE_FILE, "w") as f: 72 | f.write(content) 73 | print("{} was created".format(ALL_IN_ONE_FILE)) 74 | -------------------------------------------------------------------------------- /notebooks/cleantype/.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | build/ 3 | code.cpp 4 | -------------------------------------------------------------------------------- /notebooks/cleantype/build_ct_tools.cpp: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | inline void exec(const std::string & cmd) 16 | { 17 | std::string cmd_r = cmd + " 2>&1"; 18 | std::cout << cmd_r << std::endl; 19 | std::array buffer; 20 | std::unique_ptr pipe(popen(cmd_r.c_str(), "r"), pclose); 21 | if (!pipe) 22 | throw std::runtime_error("popen() failed!"); 23 | while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) 24 | std::cout << buffer.data(); 25 | } 26 | 27 | 28 | inline std::string getcurrendir() 29 | { 30 | char temp[1024]; 31 | return ( getcwd(temp, sizeof(temp)) ? std::string( temp ) : std::string("") ); 32 | } 33 | 34 | 35 | inline void add_path_to_env(const std::string & path) 36 | { 37 | std::string env_path = getenv("PATH"); 38 | env_path = env_path + ":" + path; 39 | setenv("PATH", env_path.c_str(), 1); 40 | } 41 | 42 | 43 | inline void save_temp_code(const std::string & code) 44 | { 45 | std::ofstream ofs; 46 | ofs.open("code.cpp"); 47 | ofs << code; 48 | } 49 | 50 | 51 | inline void compile_code(const std::string & code) 52 | { 53 | save_temp_code(code); 54 | std::string command = "clang++ --std=c++14 -c code.cpp -Iinclude -o a.out 2>&1"; 55 | exec(command); 56 | } 57 | 58 | inline void compile_code__extract(const std::string & code) 59 | { 60 | save_temp_code(code); 61 | std::string command = "clang++ --std=c++14 -c code.cpp -Iinclude -o a.out 2>&1 | head -5"; 62 | exec(command); 63 | } 64 | 65 | 66 | inline void compile_code_decipher(const std::string & code) 67 | { 68 | save_temp_code(code); 69 | std::string command = "clang++ --std=c++14 -c code.cpp -Iinclude -o a.out 2>&1 | ct_compiler_decipher"; 70 | exec(command); 71 | } 72 | 73 | inline void compile_code_decipher__extract(const std::string & code) 74 | { 75 | save_temp_code(code); 76 | std::string command = "clang++ --std=c++14 -c code.cpp -Iinclude -o a.out 2>&1 | ct_compiler_decipher | head -5"; 77 | exec(command); 78 | } 79 | 80 | 81 | inline void make_ct_compiler_decipher() 82 | { 83 | auto this_dir = getcurrendir(); 84 | chdir("../.."); 85 | unlink("ct_compiler_decipher"); 86 | exec("make"); 87 | add_path_to_env(this_dir + "/../.."); 88 | chdir(this_dir.c_str()); 89 | } -------------------------------------------------------------------------------- /notebooks/cleantype/cleantype-range-v3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Decipher range-v3 auto types" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "[range-v3](https://github.com/ericniebler/range-v3) is a library which contains the current state of the ranges proposal that will be included in C++ 20.\n", 15 | "It allows very expressive code. However, the design of the library is based on a complex collection of types, so that most of the functions and variables can only be noted as `auto`. \n", 16 | "\n", 17 | "`cleantype` can help in deciphering what's going on with the types with range-v3: \n", 18 | "\n", 19 | "First, we include cleantype and the range-v3 library" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 1, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "#pragma cling add_include_path(\"./include\")\n", 29 | "#include \n", 30 | "#include \n", 31 | "\n", 32 | "#define run__show(...) \\\n", 33 | "{ \\\n", 34 | " std::cout << #__VA_ARGS__ << \"\\n\"; \\\n", 35 | " std::cout << __VA_ARGS__ << \"\\n\\n\"; \\\n", 36 | "}\n", 37 | "using namespace ranges;" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "Then we set the indent depth limit to 2, because indenting will make the types much easier to read, since `range-v3` uses long and deep nested types. " 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 2, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "cleantype::CleanConfiguration::GlobalConfig().indent_depth_limit = 2;" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "### Example of a view that return square numbers" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "Let's define a function that yields using `ranges::yield` and, then let's identify its return type." 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 3, 73 | "metadata": {}, 74 | "outputs": [ 75 | { 76 | "name": "stdout", 77 | "output_type": "stream", 78 | "text": [ 79 | "CT_type_fn(square_yield_fn, int)\n", 80 | "ranges::v3::single_view\n", 81 | "\n" 82 | ] 83 | } 84 | ], 85 | "source": [ 86 | "auto square_yield_fn(int x) {\n", 87 | " return ranges::yield(x * x);\n", 88 | "}\n", 89 | "run__show( CT_type_fn(square_yield_fn, int) );" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "Now, let's define a view that transform ints into squares. This view is lazy, and unlimited (it never ends). We then identify its type:" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 4, 102 | "metadata": {}, 103 | "outputs": [ 104 | { 105 | "name": "stdout", 106 | "output_type": "stream", 107 | "text": [ 108 | "cleantype::clean(squares_view_fn)\n", 109 | "ranges::v3::join_view\n", 110 | "<\n", 111 | " ranges::v3::transform_view\n", 112 | " <\n", 113 | " ranges::v3::iota_view\n", 114 | " <\n", 115 | " int,\n", 116 | " void\n", 117 | " >,\n", 118 | " ranges::v3::single_view\n", 119 | " <\n", 120 | " int\n", 121 | " > (*)(int)\n", 122 | " >,\n", 123 | " void\n", 124 | "> &\n", 125 | "\n" 126 | ] 127 | } 128 | ], 129 | "source": [ 130 | "auto squares_view_fn = view::for_each(view::ints(1), square_yield_fn);\n", 131 | "run__show( cleantype::clean(squares_view_fn) );" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 5, 137 | "metadata": {}, 138 | "outputs": [ 139 | { 140 | "name": "stdout", 141 | "output_type": "stream", 142 | "text": [ 143 | "cleantype::clean(squares_fn_take_10)\n", 144 | "ranges::v3::detail::take_exactly_view_\n", 145 | "<\n", 146 | " ranges::v3::join_view\n", 147 | " <\n", 148 | " ranges::v3::transform_view\n", 149 | " <\n", 150 | " ranges::v3::iota_view\n", 151 | " <\n", 152 | " int,\n", 153 | " void\n", 154 | " >,\n", 155 | " ranges::v3::single_view\n", 156 | " <\n", 157 | " int\n", 158 | " > (*)(int)\n", 159 | " >,\n", 160 | " void\n", 161 | " >,\n", 162 | " false\n", 163 | "> &\n", 164 | "\n" 165 | ] 166 | } 167 | ], 168 | "source": [ 169 | "auto squares_fn_take_10 = squares_view_fn | view::take(10);\n", 170 | "run__show( cleantype::clean(squares_fn_take_10) );" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "### Example with range-v3 and lambdas:" 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": {}, 183 | "source": [ 184 | "Since lambda are actually anonymous structs, cleantype cannot disclose the signature of the inner lambda of a view that is contructed using a lambda. " 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": 6, 190 | "metadata": {}, 191 | "outputs": [ 192 | { 193 | "name": "stdout", 194 | "output_type": "stream", 195 | "text": [ 196 | "cleantype::lambda_clean(square_yield_lambda)\n", 197 | "lambda: (int) -> ranges::v3::single_view\n", 198 | "\n", 199 | "cleantype::clean(squares_view_lambda)\n", 200 | "ranges::v3::join_view\n", 201 | "<\n", 202 | " ranges::v3::transform_view\n", 203 | " <\n", 204 | " ranges::v3::iota_view\n", 205 | " <\n", 206 | " int,\n", 207 | " void\n", 208 | " >,\n", 209 | " (lambda at input_line_14:5:32)\n", 210 | " >,\n", 211 | " void\n", 212 | "> &\n", 213 | "\n" 214 | ] 215 | } 216 | ], 217 | "source": [ 218 | "{\n", 219 | " using namespace ranges;\n", 220 | " \n", 221 | " auto square_yield_lambda = [](int x) {\n", 222 | " return yield(x * x);\n", 223 | " };\n", 224 | " run__show( cleantype::lambda_clean(square_yield_lambda) );\n", 225 | " auto squares_view_lambda = view::for_each(view::ints(1), square_yield_lambda);\n", 226 | " run__show( cleantype::clean(squares_view_lambda) );\n", 227 | "}" 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "metadata": {}, 233 | "source": [ 234 | "In an ideal world, I would be interesting to be able to display the view type as below (but I'm afraid that the code in order to get to this might be intractable).\n", 235 | "\n", 236 | "````\n", 237 | "ranges::v3::join_view\n", 238 | "<\n", 239 | " ranges::v3::transform_view\n", 240 | " <\n", 241 | " ranges::v3::iota_view\n", 242 | " <\n", 243 | " int,\n", 244 | " void\n", 245 | " >,\n", 246 | " lambda: (int) -> ranges::v3::single_view\n", 247 | " >,\n", 248 | " void\n", 249 | "> &\n", 250 | "````" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "Thus, it is advised to prefer \"auto return functions\" to lambdas when using range-v3 with cleantype." 258 | ] 259 | } 260 | ], 261 | "metadata": { 262 | "kernelspec": { 263 | "display_name": "C++17", 264 | "language": "C++17", 265 | "name": "xeus-cling-cpp17" 266 | }, 267 | "language_info": { 268 | "codemirror_mode": "text/x-c++src", 269 | "file_extension": ".cpp", 270 | "mimetype": "text/x-c++src", 271 | "name": "c++", 272 | "version": "-std=c++17" 273 | } 274 | }, 275 | "nbformat": 4, 276 | "nbformat_minor": 2 277 | } 278 | -------------------------------------------------------------------------------- /notebooks/cleantype/demos: -------------------------------------------------------------------------------- 1 | ../../demos -------------------------------------------------------------------------------- /notebooks/cleantype/examples/cleantype_examples_utils.h: -------------------------------------------------------------------------------- 1 | // Special macro to change the include path (this is required for the binder demo) 2 | #pragma cling add_include_path("../include") 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // This macro is used later in this manual in order to display commands and their results 12 | #define run_show(...) \ 13 | { \ 14 | std::cout << #__VA_ARGS__ << "\n"; \ 15 | std::cout << __VA_ARGS__ << "\n\n"; \ 16 | } 17 | 18 | std::string int_to_roman(int value) 19 | { 20 | // clang-format off 21 | std::vector> roman 22 | { 23 | { 1000, "M" },{ 900, "CM" }, 24 | { 500, "D" },{ 400, "CD" }, 25 | { 100, "C" },{ 90, "XC" }, 26 | { 50, "L" },{ 40, "XL" }, 27 | { 10, "X" },{ 9, "IX" }, 28 | { 5, "V" },{ 4, "IV" }, 29 | { 1, "I" } 30 | }; 31 | // clang-format on 32 | std::string result; 33 | for (auto const & kv : roman) 34 | { 35 | while (value >= kv.first) 36 | { 37 | result += kv.second; 38 | value -= kv.first; 39 | } 40 | } 41 | return result; 42 | } 43 | 44 | std::string int_to_string(int value) 45 | { 46 | std::stringstream ss; 47 | ss << value; 48 | return ss.str(); 49 | } 50 | -------------------------------------------------------------------------------- /notebooks/cleantype/examples/quick_demo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "#include \"cleantype_examples_utils.h\"" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 2, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "namespace\n", 19 | "{\n", 20 | " std::string enclose_string(const std::string & s)\n", 21 | " {\n", 22 | " using namespace std::string_literals;\n", 23 | " return \"\\\"\"s + s + \"\\\"\"s;\n", 24 | " }\n", 25 | "\n", 26 | " std::array int_to_strings(int value)\n", 27 | " {\n", 28 | " return {enclose_string(int_to_string(value)), enclose_string(int_to_roman(value))};\n", 29 | " }\n", 30 | "} // namespace" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 3, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "auto make_cache_int_strings = [](int limit) {\n", 40 | " auto numbers = fplus::numbers(1, limit + 1);\n", 41 | " auto strs = fplus::transform([](int x) { return int_to_strings(x); }, numbers);\n", 42 | " return fplus::create_map(numbers, strs);\n", 43 | "};;" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 4, 49 | "metadata": {}, 50 | "outputs": [ 51 | { 52 | "name": "stdout", 53 | "output_type": "stream", 54 | "text": [ 55 | "cleantype::lambda_clean(make_cache_int_strings)\n", 56 | "lambda: (int) -> std::map\n", 57 | "<\n", 58 | " int,\n", 59 | " std::array\n", 60 | " <\n", 61 | " std::string,\n", 62 | " 2\n", 63 | " >\n", 64 | ">\n", 65 | "\n" 66 | ] 67 | } 68 | ], 69 | "source": [ 70 | "cleantype::set_indent_depth_limit(1);\n", 71 | "run_show( cleantype::lambda_clean(make_cache_int_strings) );" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 5, 77 | "metadata": {}, 78 | "outputs": [ 79 | { 80 | "name": "stdout", 81 | "output_type": "stream", 82 | "text": [ 83 | "CT_show_details(five_numbers)\n", 84 | "[std::map\n", 85 | "<\n", 86 | " int,\n", 87 | " std::array\n", 88 | " <\n", 89 | " std::string,\n", 90 | " 2\n", 91 | " >\n", 92 | ">] five_numbers = [(1, [\"1\", \"I\"]), (2, [\"2\", \"II\"]), (3, [\"3\", \"III\"]), (4, [\"4\", \"IV\"]), (5, [\"5\", \"V\"])]\n", 93 | "\n" 94 | ] 95 | } 96 | ], 97 | "source": [ 98 | "auto five_numbers = make_cache_int_strings(5);\n", 99 | "run_show( CT_show_details(five_numbers) );" 100 | ] 101 | } 102 | ], 103 | "metadata": { 104 | "kernelspec": { 105 | "display_name": "C++17", 106 | "language": "C++17", 107 | "name": "xeus-cling-cpp17" 108 | }, 109 | "language_info": { 110 | "codemirror_mode": "text/x-c++src", 111 | "file_extension": ".cpp", 112 | "mimetype": "text/x-c++src", 113 | "name": "c++", 114 | "version": "-std=c++17" 115 | } 116 | }, 117 | "nbformat": 4, 118 | "nbformat_minor": 2 119 | } 120 | -------------------------------------------------------------------------------- /notebooks/cleantype/examples/test_compile.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | 5 | def c(command: str, cwd: str = None) -> str: 6 | r = subprocess.run(command, cwd=cwd, shell=True, 7 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 8 | out = r.stdout.decode("utf-8") 9 | print(out) 10 | 11 | 12 | code = """ 13 | #include 14 | int main() { 15 | } 16 | """ 17 | 18 | 19 | def compile_code(code): 20 | with open("f.cpp", "w") as f: 21 | f.write(code) 22 | c("clang --std=c++14 -c f.cpp -o a.out -v") 23 | 24 | 25 | compile_code(code) 26 | 27 | # ==> 28 | # In file included from /srv/conda/lib/clang/5.0.0/include/limits.h:37: 29 | # /usr/include/limits.h:145:5: error: function-like macro '__GLIBC_USE' is not defined 30 | # #if __GLIBC_US 31 | 32 | # cf https://github.com/QuantStack/xeus-cling/issues/194 33 | # However, it works if I install xtl=0.5.2. 34 | # The only difference seems to be the version of zeu-cling, 35 | # so it's broken with xeus-cling=0.4.10=he860b03_1001 but works with xeus-cling=0.4.10=he860b03_1000 36 | # https://github.com/conda-forge/clangdev-feedstock/pull/45 37 | -------------------------------------------------------------------------------- /notebooks/cleantype/examples/zoo_type_qualifiers.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# The zoo of type qualifiers\n", 8 | "\n", 9 | "`cleantype`handles quite well `const`, `volatile`, references (`&`), rvalue references (`&&`), and pointers (`*`). See below a demonstration " 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "// Special macro to change the include path (this is required for the binder demo)\n", 19 | "#pragma cling add_include_path(\"../include\")\n", 20 | "#include \n", 21 | "\n", 22 | "#define run_show(...) \\\n", 23 | "{ \\\n", 24 | " std::cout << #__VA_ARGS__ << \"\\n\"; \\\n", 25 | " std::cout << __VA_ARGS__ << \"\\n\\n\"; \\\n", 26 | "}" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "auto foo = [](auto && x) {\n", 36 | " run_show( CT_cleantype_clean(x) );\n", 37 | " run_show( cleantype::clean() );\n", 38 | "};;\n", 39 | "\n", 40 | "#define test_call_foo(var, title) \\\n", 41 | " std::cout << \" *********** \" << title << \" ***********\\n\"; \\\n", 42 | " std::cout << \"Bare variable (before the call)\\n\"; \\\n", 43 | " run_show( cleantype::clean() );\\\n", 44 | " run_show( CT_cleantype_clean(var) );\\\n", 45 | " std::cout << \"Now inside foo (pass by universal reference)\\n\"; \\\n", 46 | " foo(var);" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 3, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "name": "stdout", 56 | "output_type": "stream", 57 | "text": [ 58 | " *********** Calling with an int lvalue (transformed to a ref by the call) ***********\n", 59 | "Bare variable (before the call)\n", 60 | "cleantype::clean()\n", 61 | "int\n", 62 | "\n", 63 | "CT_cleantype_clean(a)\n", 64 | "int\n", 65 | "\n", 66 | "Now inside foo (pass by universal reference)\n", 67 | "CT_cleantype_clean(x)\n", 68 | "int &\n", 69 | "\n", 70 | "cleantype::clean()\n", 71 | "int &\n", 72 | "\n", 73 | " *********** Calling with a const lvalue reference ***********\n", 74 | "Bare variable (before the call)\n", 75 | "cleantype::clean()\n", 76 | "const int &\n", 77 | "\n", 78 | "CT_cleantype_clean(b)\n", 79 | "const int &\n", 80 | "\n", 81 | "Now inside foo (pass by universal reference)\n", 82 | "CT_cleantype_clean(x)\n", 83 | "const int &\n", 84 | "\n", 85 | "cleantype::clean()\n", 86 | "const int &\n", 87 | "\n", 88 | " *********** Calling with an rvalue reference ***********\n", 89 | "Bare variable (before the call)\n", 90 | "cleantype::clean()\n", 91 | "int\n", 92 | "\n", 93 | "CT_cleantype_clean(42)\n", 94 | "int\n", 95 | "\n", 96 | "Now inside foo (pass by universal reference)\n", 97 | "CT_cleantype_clean(x)\n", 98 | "int &&\n", 99 | "\n", 100 | "cleantype::clean()\n", 101 | "int &&\n", 102 | "\n", 103 | " *********** Calling with a const pointer ***********\n", 104 | "Bare variable (before the call)\n", 105 | "cleantype::clean()\n", 106 | "int * const\n", 107 | "\n", 108 | "CT_cleantype_clean(c)\n", 109 | "int * const\n", 110 | "\n", 111 | "Now inside foo (pass by universal reference)\n", 112 | "CT_cleantype_clean(x)\n", 113 | "int * const &\n", 114 | "\n", 115 | "cleantype::clean()\n", 116 | "int * const &\n", 117 | "\n", 118 | " *********** Calling with a pointer to const ***********\n", 119 | "Bare variable (before the call)\n", 120 | "cleantype::clean()\n", 121 | "const int *\n", 122 | "\n", 123 | "CT_cleantype_clean(d)\n", 124 | "const int *\n", 125 | "\n", 126 | "Now inside foo (pass by universal reference)\n", 127 | "CT_cleantype_clean(x)\n", 128 | "const int * &\n", 129 | "\n", 130 | "cleantype::clean()\n", 131 | "const int * &\n", 132 | "\n", 133 | " *********** Calling with a volatile int ***********\n", 134 | "Bare variable (before the call)\n", 135 | "cleantype::clean()\n", 136 | "volatile int\n", 137 | "\n", 138 | "CT_cleantype_clean(vol)\n", 139 | "volatile int\n", 140 | "\n", 141 | "Now inside foo (pass by universal reference)\n", 142 | "CT_cleantype_clean(x)\n", 143 | "volatile int &\n", 144 | "\n", 145 | "cleantype::clean()\n", 146 | "volatile int &\n", 147 | "\n", 148 | " *********** Calling with a const ***********\n", 149 | "Bare variable (before the call)\n", 150 | "cleantype::clean()\n", 151 | "const int\n", 152 | "\n", 153 | "CT_cleantype_clean(e)\n", 154 | "const int\n", 155 | "\n", 156 | "Now inside foo (pass by universal reference)\n", 157 | "CT_cleantype_clean(x)\n", 158 | "const int &\n", 159 | "\n", 160 | "cleantype::clean()\n", 161 | "const int &\n", 162 | "\n" 163 | ] 164 | } 165 | ], 166 | "source": [ 167 | "{\n", 168 | " int a = 5; \n", 169 | " test_call_foo(a, \"Calling with an int lvalue (transformed to a ref by the call)\");\n", 170 | " \n", 171 | " int const & b = a; \n", 172 | " test_call_foo(b, \"Calling with a const lvalue reference\");\n", 173 | " \n", 174 | " test_call_foo(42, \"Calling with an rvalue reference\");\n", 175 | " \n", 176 | " int * const c = &a;\n", 177 | " test_call_foo(c, \"Calling with a const pointer\");\n", 178 | "\n", 179 | " int const * d = &a;\n", 180 | " test_call_foo(d, \"Calling with a pointer to const\");\n", 181 | "\n", 182 | " int volatile vol = 42;\n", 183 | " test_call_foo(vol, \"Calling with a volatile int\");\n", 184 | " \n", 185 | " int const e = 5; \n", 186 | " test_call_foo(e, \"Calling with a const\");\n", 187 | "\n", 188 | "}" 189 | ] 190 | } 191 | ], 192 | "metadata": { 193 | "kernelspec": { 194 | "display_name": "C++14", 195 | "language": "C++14", 196 | "name": "xeus-cling-cpp14" 197 | }, 198 | "language_info": { 199 | "codemirror_mode": "text/x-c++src", 200 | "file_extension": ".cpp", 201 | "mimetype": "text/x-c++src", 202 | "name": "c++", 203 | "version": "-std=c++14" 204 | } 205 | }, 206 | "nbformat": 4, 207 | "nbformat_minor": 2 208 | } 209 | -------------------------------------------------------------------------------- /notebooks/cleantype/include/boost: -------------------------------------------------------------------------------- 1 | ../../../third_party/tests_thirdparty/hana/include/boost -------------------------------------------------------------------------------- /notebooks/cleantype/include/cleantype: -------------------------------------------------------------------------------- 1 | ../../../src/include/cleantype -------------------------------------------------------------------------------- /notebooks/cleantype/include/fplus: -------------------------------------------------------------------------------- 1 | ../../../third_party/tests_thirdparty/FunctionalPlus/include/fplus -------------------------------------------------------------------------------- /notebooks/cleantype/include/meta: -------------------------------------------------------------------------------- 1 | ../../../third_party/tests_thirdparty/range-v3/include/meta -------------------------------------------------------------------------------- /notebooks/cleantype/include/nlohmann: -------------------------------------------------------------------------------- 1 | ../../../third_party/include/nlohmann -------------------------------------------------------------------------------- /notebooks/cleantype/include/range: -------------------------------------------------------------------------------- 1 | ../../../third_party/tests_thirdparty/range-v3/include/range -------------------------------------------------------------------------------- /notebooks/cleantype/include_all_in_one: -------------------------------------------------------------------------------- 1 | ../../include_all_in_one -------------------------------------------------------------------------------- /notebooks/cleantype/resources: -------------------------------------------------------------------------------- 1 | ../../resources -------------------------------------------------------------------------------- /resources/cleantype_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pthom/cleantype/d95221b1bc8e2df7af77b54b833025fde64de049/resources/cleantype_logo.png -------------------------------------------------------------------------------- /resources/cleantype_logo_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pthom/cleantype/d95221b1bc8e2df7af77b54b833025fde64de049/resources/cleantype_logo_2.png -------------------------------------------------------------------------------- /resources/cleantype_logo_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pthom/cleantype/d95221b1bc8e2df7af77b54b833025fde64de049/resources/cleantype_logo_small.jpg -------------------------------------------------------------------------------- /resources/cleantype_logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pthom/cleantype/d95221b1bc8e2df7af77b54b833025fde64de049/resources/cleantype_logo_small.png -------------------------------------------------------------------------------- /resources/gitpod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pthom/cleantype/d95221b1bc8e2df7af77b54b833025fde64de049/resources/gitpod.jpg -------------------------------------------------------------------------------- /resources/gitpod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pthom/cleantype/d95221b1bc8e2df7af77b54b833025fde64de049/resources/gitpod.png -------------------------------------------------------------------------------- /scripts/build/cmake_all_options.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(readlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | src_dir=$DIR/../.. 3 | 4 | cmake $src_dir -DCLEANTYPE_ALL_OPTIONS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 5 | -------------------------------------------------------------------------------- /scripts/build/cmake_ninja.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(readlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | src_dir=$DIR/../.. 3 | 4 | cmake $src_dir -GNinja 5 | -------------------------------------------------------------------------------- /scripts/build/cmake_ninja_all_options.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(readlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | src_dir=$DIR/../.. 3 | cmake $src_dir -GNinja -DCLEANTYPE_ALL_OPTIONS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 4 | -------------------------------------------------------------------------------- /scripts/build/cmake_win.bat: -------------------------------------------------------------------------------- 1 | set THIS_DIR=%~dp0 2 | set SOURCE_DIR=%~dp0\..\.. 3 | cmake %SOURCE_DIR% -DCLEANTYPE_ALL_OPTIONS=ON -G"Visual Studio 15 2017 Win64" 4 | -------------------------------------------------------------------------------- /scripts/build/ln_compile_commands.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(readlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | src_dir=$DIR/../.. 3 | build_dir=$(pwd) 4 | 5 | cd $src_dir 6 | if [ ! -L compile_commands.json ]; then 7 | ln -s $build_dir/compile_commands.json . 8 | fi 9 | -------------------------------------------------------------------------------- /scripts/docker_build/ubuntu18/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN apt-get update 3 | 4 | ARG install_scripts=/install_scripts 5 | 6 | ADD install_scripts/install_base.sh $install_scripts/install_base.sh 7 | RUN $install_scripts/install_base.sh 8 | 9 | ADD install_scripts/customize_env.sh $install_scripts/customize_env.sh 10 | RUN $install_scripts/customize_env.sh 11 | 12 | ADD install_scripts/install_miniconda.sh $install_scripts/install_miniconda.sh 13 | RUN $install_scripts/install_miniconda.sh 14 | 15 | RUN /srv/conda/bin/pip install --upgrade pip && /srv/conda/bin/pip install conan 16 | 17 | ADD install_scripts/install_clang.sh $install_scripts/install_clang.sh 18 | RUN $install_scripts/install_clang.sh 19 | 20 | WORKDIR /sources_docker 21 | -------------------------------------------------------------------------------- /scripts/docker_build/ubuntu18/docker_attach.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(greadlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | docker start u18builder && docker attach u18builder 3 | -------------------------------------------------------------------------------- /scripts/docker_build/ubuntu18/docker_create_image.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(greadlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | docker build $DIR -t u18build 3 | -------------------------------------------------------------------------------- /scripts/docker_build/ubuntu18/docker_start.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(greadlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | docker run \ 3 | --name u18builder -it -v $DIR/../../..:/sources_docker \ 4 | --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --security-opt apparmor=unconfined \ 5 | u18build \ 6 | /bin/zsh 7 | -------------------------------------------------------------------------------- /scripts/docker_build/ubuntu18/install_scripts/customize_env.sh: -------------------------------------------------------------------------------- 1 | 2 | # Prompt with a [DOCKER] prefix 3 | echo " 4 | export PROMPT='[DOCKER]\${ret_status} %{\$fg[cyan]%}%~%{\$reset_color%} > ' 5 | " >> /root/.zshrc 6 | # 7 | echo "export LC_ALL=C.UTF-8" >> /root/.zshrc 8 | echo "export LC_ALL=C.UTF-8" >> /root/.bashrc 9 | echo "export LANG=C.UTF-8" >> /root/.zshrc 10 | echo "export LANG=C.UTF-8" >> /root/.bashrc 11 | -------------------------------------------------------------------------------- /scripts/docker_build/ubuntu18/install_scripts/install_base.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | apt-get install -y build-essential python3 python3-pip zsh curl wget cmake ninja-build git tree htop nano vim 4 | 5 | # install zsh & oh-my-zsh (so that we have nice colors) 6 | apt-get install -y zsh wget git 7 | wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | zsh || true 8 | -------------------------------------------------------------------------------- /scripts/docker_build/ubuntu18/install_scripts/install_clang.sh: -------------------------------------------------------------------------------- 1 | # cf http://apt.llvm.org/ 2 | set -e 3 | 4 | apt-get update 5 | apt-get -y install python3-software-properties 6 | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - 7 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" >> /etc/apt/sources.list 8 | echo "deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" >> /etc/apt/sources.list 9 | tail /etc/apt/sources.list 10 | apt-get update 11 | apt-get install -y clang-7 lldb-7 lld-7 12 | -------------------------------------------------------------------------------- /scripts/docker_build/ubuntu18/install_scripts/install_miniconda.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | # install miniconda 3 | mkdir -p $install_scripts 4 | curl https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o $install_scripts/miniconda-install.sh 5 | chmod +x $install_scripts/miniconda-install.sh 6 | $install_scripts/miniconda-install.sh -b 7 | 8 | # symlink /srv/conda required for path compatibility with mybinder.org 9 | mkdir -p /srv && ln -s /root/miniconda3 /srv/conda 10 | 11 | # add /srv/conda/bin to the path 12 | echo "export PATH=\$PATH:/srv/conda/bin" >> /root/.bashrc 13 | echo "export PATH=\$PATH:/srv/conda/bin" >> /root/.zshrc 14 | -------------------------------------------------------------------------------- /scripts/docker_cling/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN apt-get update 3 | 4 | ARG install_scripts=/install_scripts 5 | 6 | ADD install_scripts/install_base.sh $install_scripts/install_base.sh 7 | RUN $install_scripts/install_base.sh 8 | 9 | ADD install_scripts/install_miniconda.sh $install_scripts/install_miniconda.sh 10 | RUN $install_scripts/install_miniconda.sh 11 | 12 | ADD install_scripts/conda_xeus_cling.sh $install_scripts/conda_xeus_cling.sh 13 | RUN $install_scripts/conda_xeus_cling.sh 14 | 15 | ADD install_scripts/conda_opencv.sh $install_scripts/conda_opencv.sh 16 | RUN $install_scripts/conda_opencv.sh 17 | 18 | ADD install_scripts/customize_env.sh $install_scripts/customize_env.sh 19 | RUN $install_scripts/customize_env.sh 20 | 21 | ADD install_scripts/create_notebook_launcher.sh $install_scripts/create_notebook_launcher.sh 22 | RUN $install_scripts/create_notebook_launcher.sh 23 | 24 | RUN /srv/conda/bin/conda install -y -c conda-forge rise 25 | 26 | WORKDIR /sources_docker 27 | -------------------------------------------------------------------------------- /scripts/docker_cling/docker_create_image.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(greadlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | docker build $DIR -t cling_xeus 3 | -------------------------------------------------------------------------------- /scripts/docker_cling/docker_login.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(greadlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | # docker run --rm -it -v $DIR/..:/sources_docker cling_xeus /bin/zsh 3 | 4 | docker run --rm -it -p 5900:5900 -v $DIR/../..:/sources_docker cling_xeus /bin/zsh 5 | -------------------------------------------------------------------------------- /scripts/docker_cling/docker_run_notebook.sh: -------------------------------------------------------------------------------- 1 | DIR="$(dirname "$(greadlink -f "$0")")" # readlink on linux (brew install coreutils on mac) 2 | # open http://localhost:8888 3 | docker run --rm -it -p 8888:8888 -v $DIR/../..:/sources_docker cling_xeus /bin/bash -c "cd /sources_docker && /usr/local/bin/jnote" 4 | -------------------------------------------------------------------------------- /scripts/docker_cling/install_scripts/conda_opencv.sh: -------------------------------------------------------------------------------- 1 | # install opencv via conda 2 | /srv/conda/bin/conda install opencv 3 | -------------------------------------------------------------------------------- /scripts/docker_cling/install_scripts/conda_xeus_cling.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | export PATH=$PATH:/srv/conda/bin 3 | # install jupyter & xeus.cling 4 | conda install jupyter 5 | conda install -c QuantStack -c conda-forge xeus-cling 6 | -------------------------------------------------------------------------------- /scripts/docker_cling/install_scripts/create_notebook_launcher.sh: -------------------------------------------------------------------------------- 1 | # jnote = alias to run jupyter notebook with correct settings 2 | echo " 3 | #\!/bin/bash 4 | export PATH=\$PATH:/srv/conda/bin 5 | jupyter-notebook --allow-root --no-browser --ip 0.0.0.0 --NotebookApp.token='' --NotebookApp.password='' 6 | " >> /usr/local/bin/jnote 7 | 8 | chmod +x /usr/local/bin/jnote 9 | -------------------------------------------------------------------------------- /scripts/docker_cling/install_scripts/customize_env.sh: -------------------------------------------------------------------------------- 1 | 2 | # Prompt with a [DOCKER] prefix 3 | echo " 4 | export PROMPT='[DOCKER]\${ret_status} %{\$fg[cyan]%}%~%{\$reset_color%} > ' 5 | " >> /root/.zshrc 6 | # 7 | echo "export LC_ALL=C.UTF-8" >> /root/.zshrc 8 | echo "export LC_ALL=C.UTF-8" >> /root/.bashrc 9 | echo "export LANG=C.UTF-8" >> /root/.zshrc 10 | echo "export LANG=C.UTF-8" >> /root/.bashrc 11 | -------------------------------------------------------------------------------- /scripts/docker_cling/install_scripts/install_base.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | apt-get install -y build-essential python3 python3-pip zsh curl wget cmake ninja-build git tree htop nano vim 4 | 5 | # install zsh & oh-my-zsh (so that we have nice colors) 6 | apt-get install -y zsh wget git 7 | wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | zsh || true 8 | -------------------------------------------------------------------------------- /scripts/docker_cling/install_scripts/install_miniconda.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | # install miniconda 3 | mkdir -p $install_scripts 4 | curl https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o $install_scripts/miniconda-install.sh 5 | chmod +x $install_scripts/miniconda-install.sh 6 | $install_scripts/miniconda-install.sh -b 7 | 8 | # symlink /srv/conda required for path compatibility with mybinder.org 9 | mkdir -p /srv && ln -s /root/miniconda3 /srv/conda 10 | 11 | # add /srv/conda/bin to the path 12 | echo "export PATH=\$PATH:/srv/conda/bin" >> /root/.bashrc 13 | echo "export PATH=\$PATH:/srv/conda/bin" >> /root/.zshrc 14 | -------------------------------------------------------------------------------- /src/include/cleantype/cleantype_compiler_typename.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #if defined(_HANA_TN_CAN_CONSTEXPR) 10 | 11 | #include 12 | #include 13 | 14 | namespace cleantype 15 | { 16 | namespace compile_time_internal 17 | { 18 | template 19 | auto type_name_impl(std::index_sequence) 20 | { 21 | constexpr auto name = 22 | boost::hana::experimental::type_name_details::type_name_impl_stringliteral(); 23 | return boost::hana::string<*(name.ptr + i)...>{}; 24 | } 25 | } // namespace compile_time_internal 26 | 27 | template 28 | auto full_compiletime() 29 | { 30 | constexpr auto name = 31 | boost::hana::experimental::type_name_details::type_name_impl_stringliteral(); 32 | return compile_time_internal::type_name_impl(std::make_index_sequence{}); 33 | } 34 | } // namespace cleantype 35 | 36 | #endif // #if defined(_HANA_TN_CAN_CONSTEXPR) 37 | -------------------------------------------------------------------------------- /src/include/cleantype/cleantype_configuration.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // In order to configure the behavior of clean types : 13 | // 14 | // * Duplicate the file .cleantype.json at the root of the cleantype repository, 15 | // and save this file in anywhere in the hierarchy of the parent directories 16 | // of the execution directory. 17 | // * Edit this file as a normal json file (you can use also use an online editor like 18 | // https://jsoneditoronline.org/) 19 | // * #define CLEANTYPE_USE_NLOHMANN_JSON before including this file and 20 | // add the include path to nlohmann/json.hpp) 21 | 22 | namespace cleantype 23 | { 24 | struct CleanConfiguration; 25 | namespace internal 26 | { 27 | CleanConfiguration ImplGlobalConfig(); 28 | } // namespace internal 29 | 30 | struct CleanConfiguration 31 | { 32 | std::vector suppress_extra_namespaces_ = {"::__1", "::__cxx11"}; 33 | 34 | // unnecessary class, struct given by msvc 35 | std::vector suppress_extract_struct_class_ = {"class ", "struct "}; 36 | 37 | // add your custom suppressions here 38 | std::vector suppress_custom_ = {" __ptr64"}; 39 | 40 | // these node are suppressed after parse of the template tree of a type 41 | std::vector undesirable_type_nodes_ = { 42 | "std::char_traits", "std::allocator", "std::less"}; 43 | 44 | std::map replacements_after_undesirable_node_extractions = { 45 | {"std::basic_string", "std::string"}, 46 | {"basic_string<_CharT, _Traits, _Allocator>", "std::string"}}; 47 | 48 | // set this to true in order to force the results to be east const 49 | // this is experimental, and can fail 50 | bool force_east_const_ = false; 51 | 52 | // * any type with a depth <= indent_depth_limit 53 | // will be presented on a single line 54 | // * any type with a depth > indent_depth_limit 55 | // will be presented on several indented lines 56 | // set indent_depth_limit = 0 to disable indentation 57 | std::size_t indent_depth_limit = 3; 58 | 59 | inline static CleanConfiguration & GlobalConfig() 60 | { 61 | thread_local CleanConfiguration gCleanConfiguration = internal::ImplGlobalConfig(); 62 | return gCleanConfiguration; 63 | } 64 | 65 | inline static CleanConfiguration _EmptyConfig() 66 | { 67 | CleanConfiguration r; 68 | r.suppress_extra_namespaces_ = {}; 69 | r.suppress_extract_struct_class_ = {}; 70 | r.suppress_custom_ = {}; 71 | r.undesirable_type_nodes_ = {}; 72 | r.replacements_after_undesirable_node_extractions = {}; 73 | r.force_east_const_ = false; 74 | r.indent_depth_limit = 0; 75 | return r; 76 | } 77 | }; 78 | 79 | inline bool force_east_const() { return CleanConfiguration::GlobalConfig().force_east_const_; } 80 | inline void set_force_east_const(bool v) 81 | { 82 | CleanConfiguration::GlobalConfig().force_east_const_ = v; 83 | } 84 | 85 | inline std::size_t indent_depth_limit() 86 | { 87 | return CleanConfiguration::GlobalConfig().indent_depth_limit; 88 | } 89 | inline void set_indent_depth_limit(std::size_t v) 90 | { 91 | CleanConfiguration::GlobalConfig().indent_depth_limit = v; 92 | } 93 | 94 | } // namespace cleantype 95 | 96 | #include 97 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_clean.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace cleantype 11 | { 12 | inline std::string clean_typestring(const std::string & type_names) 13 | { 14 | return internal::impl_clean(type_names); 15 | } 16 | 17 | inline std::string indent_type_tree(const std::string & type_names) 18 | { 19 | return internal::impl_indent_type_tree(type_names); 20 | } 21 | 22 | template 23 | std::string clean() 24 | { 25 | return clean_typestring(internal::impl_full()); 26 | } 27 | 28 | template 29 | std::string clean(T &&... v) 30 | { 31 | return clean(); 32 | } 33 | 34 | template 35 | std::string show_details(T && v) 36 | { 37 | return clean() + " = " + cleantype_fp::show(v); 38 | } 39 | 40 | } // namespace cleantype 41 | 42 | #define CT_cleantype_clean(var) cleantype::clean() 43 | 44 | #define CT_show_details(var) \ 45 | std::string("[") + CT_cleantype_clean(var) + "] " + #var + " = " + cleantype_fp::show(var) 46 | 47 | #define CT_show_details_cont(var) \ 48 | std::string("[") + CT_cleantype_clean(var) + "] " + #var + " = " + cleantype_fp::show_cont(var) 49 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_clean_impl.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace cleantype 16 | { 17 | namespace internal 18 | { 19 | inline code_pair_tree filter_undesirable_type_nodes(code_pair_tree const & xs) 20 | { 21 | std::function is_node_desirable = 22 | [](const code_pair & code_pair) { 23 | const std::vector undesirable_nodes = 24 | cleantype::CleanConfiguration::GlobalConfig().undesirable_type_nodes_; 25 | bool found = std::find(undesirable_nodes.begin(), 26 | undesirable_nodes.end(), 27 | cleantype_fp::trim(' ', code_pair.lhs)) != 28 | undesirable_nodes.end(); 29 | return !found; 30 | }; 31 | 32 | auto xss = cleantype_fp_tree::tree_keep_if(is_node_desirable, xs); 33 | return xss; 34 | } 35 | 36 | inline std::string perform_suppressions(std::string const & typ_name, 37 | std::vector const & suppressions) 38 | { 39 | std::string result = typ_name; 40 | for (const auto & v : suppressions) 41 | result = cleantype_fp::replace_tokens(v, std::string(""), result); 42 | return result; 43 | } 44 | 45 | inline std::string perform_replacements( 46 | std::string const & typ_name, std::map const & replacements) 47 | { 48 | std::string result = typ_name; 49 | for (const auto & kv : replacements) 50 | result = cleantype_fp::replace_tokens(kv.first, kv.second, result); 51 | return result; 52 | } 53 | 54 | inline std::string remove_extra_namespaces(std::string const & typ_name) 55 | { 56 | return perform_suppressions( 57 | typ_name, cleantype::CleanConfiguration::GlobalConfig().suppress_extra_namespaces_); 58 | } 59 | 60 | inline std::string remove_struct_class(std::string const & typ_name) 61 | { 62 | return perform_suppressions( 63 | typ_name, 64 | cleantype::CleanConfiguration::GlobalConfig().suppress_extract_struct_class_); 65 | } 66 | 67 | inline std::string remove_custom(std::string const & typ_name) 68 | { 69 | return perform_suppressions( 70 | typ_name, cleantype::CleanConfiguration::GlobalConfig().suppress_custom_); 71 | } 72 | 73 | inline std::string perform_std_replacements(std::string const & typ_name) 74 | { 75 | return perform_replacements(typ_name, 76 | cleantype::CleanConfiguration::GlobalConfig() 77 | .replacements_after_undesirable_node_extractions); 78 | } 79 | 80 | inline void trim_spaces_inplace(code_pair & xs_io) 81 | { 82 | xs_io.lhs = cleantype_fp::trim(' ', xs_io.lhs); 83 | xs_io.rhs = cleantype_fp::trim(' ', xs_io.rhs); 84 | } 85 | 86 | inline std::string impl_clean_one_type(std::string const & typ_name) 87 | { 88 | std::string typ_namecleaned = remove_struct_class(remove_extra_namespaces(typ_name)); 89 | typ_namecleaned = remove_custom(typ_namecleaned); 90 | 91 | code_pair_tree template_tree = parse_template_tree(typ_namecleaned); 92 | cleantype_fp_tree::tree_transform_leafs_depth_first_inplace(trim_spaces_inplace, 93 | template_tree); 94 | code_pair_tree template_tree_filtered = filter_undesirable_type_nodes(template_tree); 95 | std::string template_tree_filtered_str = 96 | code_pair_tree_to_string(template_tree_filtered); 97 | 98 | std::string final_type = perform_std_replacements(template_tree_filtered_str); 99 | final_type = format_whitespace(final_type); 100 | return final_type; 101 | } 102 | 103 | inline std::string impl_indent_type_tree(const std::string & type_names) 104 | { 105 | std::string types_with_holder = add_type_holder_str(type_names); 106 | code_pair_tree template_tree = parse_template_tree(types_with_holder); 107 | std::string types_with_holder_indented = 108 | cleantype_fp_tree::show_tree_lhs_rhs(template_tree, 109 | make_template_tree_separators(), 110 | make_template_show_tree_options_with_indent()); 111 | 112 | // now, types_with_holder_indented is like this: 113 | // 114 | // cleantype::internal::TupleTypeHolder< 115 | // Foo< 116 | // int, 117 | // char 118 | // > 119 | // > 120 | // 121 | // --> we remove the lines [0, last] 122 | // then we remove the first indentation level 123 | auto remove_indented_tuple_holder = [](const std::string & type_str) { 124 | std::vector lines = stringutils::split_string(type_str, '\n'); 125 | assert(lines.size() >= 3); 126 | std::vector filtered_lines(lines.begin() + 1, lines.end() - 1); 127 | std::vector unindented_lines = cleantype_fp::transform( 128 | [](const std::string & s) { return stringutils::remove_start(s, " "); }, 129 | filtered_lines); 130 | std::string joined_lines = cleantype_fp::join(std::string("\n"), unindented_lines); 131 | return joined_lines; 132 | }; 133 | return remove_indented_tuple_holder(types_with_holder_indented); 134 | } 135 | 136 | inline std::string impl_clean_several_types(std::string const & type_names) 137 | { 138 | std::string types_with_holder = add_type_holder_str(type_names); 139 | std::string types_clean_with_holder = impl_clean_one_type(types_with_holder); 140 | return remove_type_holder_str(types_clean_with_holder); 141 | } 142 | 143 | inline std::string impl_indent_if_neeeded(std::string const & type_names) 144 | { 145 | std::size_t indent_depth_limit = 146 | cleantype::CleanConfiguration::GlobalConfig().indent_depth_limit; 147 | if (indent_depth_limit == 0) 148 | return type_names; 149 | std::string types_with_holder = add_type_holder_str(type_names); 150 | code_pair_tree template_tree = parse_template_tree(types_with_holder); 151 | std::size_t depth = cleantype_fp_tree::tree_depth(template_tree); 152 | if (depth > indent_depth_limit + 1) 153 | return impl_indent_type_tree(type_names); 154 | else 155 | return type_names; 156 | } 157 | 158 | inline std::string impl_clean(std::string const & type_names) 159 | { 160 | std::string cleaned = impl_clean_several_types(type_names); 161 | std::string indented = impl_indent_if_neeeded(cleaned); 162 | return indented; 163 | } 164 | 165 | } // namespace internal 166 | 167 | } // namespace cleantype 168 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_configuration_json.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | 5 | #pragma once 6 | #include 7 | #include 8 | 9 | #ifndef CLEANTYPE_USE_NLOHMANN_JSON 10 | namespace cleantype { 11 | namespace internal { 12 | inline CleanConfiguration ImplGlobalConfig() { return cleantype::CleanConfiguration(); } 13 | } 14 | } 15 | #else 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | #include 25 | 26 | namespace cleantype 27 | { 28 | 29 | inline void to_json(nlohmann::json & j, const cleantype::CleanConfiguration & c) 30 | { 31 | j = nlohmann::json{{"suppress_extra_namespaces_", c.suppress_extra_namespaces_}, 32 | {"suppress_extract_struct_class_", c.suppress_extract_struct_class_}, 33 | {"suppress_custom_", c.suppress_custom_}, 34 | {"undesirable_type_nodes_", c.undesirable_type_nodes_}, 35 | {"replacements_after_undesirable_node_extractions", 36 | c.replacements_after_undesirable_node_extractions}, 37 | {"force_east_const_", c.force_east_const_}, 38 | {"indent_depth_limit", c.indent_depth_limit}}; 39 | } 40 | 41 | inline void from_json(const nlohmann::json & j, cleantype::CleanConfiguration & c) 42 | { 43 | c = cleantype::CleanConfiguration::_EmptyConfig(); 44 | j.at("suppress_extra_namespaces_").get_to(c.suppress_extra_namespaces_); 45 | j.at("suppress_extract_struct_class_").get_to(c.suppress_extract_struct_class_); 46 | j.at("suppress_custom_").get_to(c.suppress_custom_); 47 | j.at("undesirable_type_nodes_").get_to(c.undesirable_type_nodes_); 48 | j.at("replacements_after_undesirable_node_extractions") 49 | .get_to(c.replacements_after_undesirable_node_extractions); 50 | j.at("force_east_const_").get_to(c.force_east_const_); 51 | j.at("indent_depth_limit").get_to(c.indent_depth_limit); 52 | } 53 | 54 | namespace internal 55 | { 56 | static std::string CleanConfigurationExample = R"( 57 | { 58 | "force_east_const_": true, 59 | "indent_depth_limit": 3, 60 | "replacements_after_undesirable_node_extractions": { 61 | "basic_string<_CharT, _Traits, _Allocator>": "std::string", 62 | "std::basic_string": "std::string" 63 | }, 64 | "suppress_custom_": [ 65 | " __ptr64" 66 | ], 67 | "suppress_extra_namespaces_": [ 68 | "::__1", 69 | "::__cxx11" 70 | ], 71 | "suppress_extract_struct_class_": [ 72 | "class ", 73 | "struct " 74 | ], 75 | "undesirable_type_nodes_": [ 76 | "std::char_traits", 77 | "std::allocator", 78 | "std::less" 79 | ] 80 | } 81 | )"; 82 | 83 | 84 | inline CleanConfiguration ImplGlobalConfig() 85 | { 86 | std::vector parent_dirs = cleantype::filesystem::parent_directories(); 87 | for (const std::string & dir : parent_dirs) 88 | { 89 | std::string pref_file = dir + "/.cleantype.json"; 90 | if (cleantype::filesystem::file_exists(pref_file)) 91 | { 92 | std::ifstream is(pref_file); 93 | nlohmann::json json_data; 94 | is >> json_data; 95 | cleantype::CleanConfiguration config = 96 | json_data.get(); 97 | return config; 98 | } 99 | } 100 | return cleantype::CleanConfiguration(); 101 | } 102 | } // namespace internal 103 | 104 | } // namespace cleantype 105 | 106 | #endif // #ifndef CLEANTYPE_USE_NLOHMANN_JSON 107 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_eastconst.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace cleantype 11 | { 12 | namespace internal 13 | { 14 | std::vector split_types(std::string const & type_names); 15 | 16 | inline std::string apply_east_const_one_type(std::string const & type_name) 17 | { 18 | // Note : this implementation is by no means neither complete nor foolproof 19 | // It expects types that were preprocessed as inputs (spaces before * and &, etc.) 20 | // For a more complete implementation, maybe a BNF grammar parsing would be required 21 | // 22 | // By default, this transformation is not applied : it is only for the unit tests 23 | // consistency accross platforms. I am not an east-const zealot. 24 | namespace stringutils = cleantype::stringutils; 25 | 26 | if (type_name.empty()) 27 | return ""; 28 | if (stringutils::ends_with(type_name, "const") && 29 | (!stringutils::starts_with(type_name, "const "))) 30 | return type_name; 31 | 32 | // const T * const => T const * const 33 | if (stringutils::starts_ends_with(type_name, "const ", " * const")) 34 | { 35 | auto r = stringutils::remove_start_end(type_name, "const ", " * const"); 36 | r = r + " const * const"; 37 | return r; 38 | } 39 | 40 | // const T * const & => T const * const & 41 | if (stringutils::starts_ends_with(type_name, "const ", " * const &")) 42 | { 43 | auto r = stringutils::remove_start_end(type_name, "const ", " * const &"); 44 | r = r + " const * const &"; 45 | return r; 46 | } 47 | 48 | // const T * & => T const * & 49 | if (stringutils::starts_ends_with(type_name, "const ", " * &")) 50 | { 51 | auto r = stringutils::remove_start_end(type_name, "const ", " * &"); 52 | r = r + " const * &"; 53 | return r; 54 | } 55 | 56 | // const T & => T const & 57 | if (stringutils::starts_ends_with(type_name, "const ", " &")) 58 | { 59 | auto r = stringutils::remove_start_end(type_name, "const ", " &"); 60 | r = r + " const &"; 61 | return r; 62 | } 63 | 64 | // const T * => T const * 65 | if (stringutils::starts_ends_with(type_name, "const ", " *")) 66 | { 67 | auto r = stringutils::remove_start_end(type_name, "const ", " *"); 68 | r = r + " const *"; 69 | return r; 70 | } 71 | 72 | // const * T => T const * 73 | if (stringutils::starts_with(type_name, "const * ")) 74 | { 75 | auto r = stringutils::remove_start(type_name, "const * "); 76 | r = r + " const *"; 77 | return r; 78 | } 79 | 80 | // const T => T const 81 | if (stringutils::starts_with(type_name, "const ")) 82 | { 83 | auto r = stringutils::remove_start(type_name, "const "); 84 | r = r + " const"; 85 | return r; 86 | } 87 | 88 | return type_name; 89 | } 90 | 91 | } // namespace internal 92 | 93 | inline std::string apply_east_const_typelist(std::string const & type_names) 94 | { 95 | std::vector types = internal::split_types(type_names); 96 | types = cleantype_fp::transform(internal::apply_east_const_one_type, types); 97 | std::string r = cleantype_fp::join(std::string(", "), types); 98 | return r; 99 | } 100 | 101 | } // namespace cleantype 102 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_format.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cleantype 10 | { 11 | namespace internal 12 | { 13 | // r = stringutils::replace_tokens("__cdecl ", "", r); 14 | // r = stringutils::replace_tokens("struct ", "", r); 15 | // r = stringutils::replace_tokens("class ", "", r); 16 | 17 | inline std::string format_whitespace(const std::string & str_type) 18 | { 19 | std::string r = str_type; 20 | r = stringutils::replace_tokens("\t", " ", r); 21 | r = stringutils::replace_tokens("\r\n", " ", r); 22 | r = stringutils::replace_tokens("\n", " ", r); 23 | r = stringutils::replace_tokens(" ", " ", r); 24 | r = stringutils::replace_tokens(" ", " ", r); 25 | r = stringutils::replace_tokens(" ", " ", r); 26 | r = stringutils::insert_spaces_after(',', r); 27 | r = stringutils::insert_spaces_before_after('&', r); 28 | r = stringutils::insert_spaces_before_after('*', r); 29 | r = stringutils::remove_spaces_before_after(')', r); 30 | r = stringutils::remove_spaces_before_after('(', r); 31 | r = stringutils::remove_spaces_before('>', r); 32 | r = stringutils::remove_spaces_after('<', r); 33 | r = stringutils::remove_spaces_after('[', r); 34 | r = stringutils::remove_spaces_before(']', r); 35 | r = stringutils::insert_spaces_before('[', r); 36 | r = stringutils::insert_spaces_after(']', r); 37 | r = stringutils::replace_tokens("*&", "* &", r); 38 | r = stringutils::replace_tokens("&*", "& *", r); 39 | r = stringutils::replace_tokens("& &", "&&", r); 40 | r = stringutils::replace_tokens("[ ]", "[]", r); 41 | r = stringutils::replace_tokens(" ,", ",", r); 42 | r = stringutils::replace_tokens("* *", "**", r); 43 | r = cleantype_fp::trim(' ', r); 44 | return r; 45 | } 46 | 47 | } // namespace internal 48 | 49 | } // namespace cleantype 50 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_fp/Readme.md: -------------------------------------------------------------------------------- 1 | # cleantype_fp: Functional programming style utilities used by cleantype 2 | 3 | * fp_base.hpp is inspired by FunctionalPlus (https://github.com/Dobiasd/FunctionalPlus), 4 | a higly recommendable functional programing library for C++ 5 | * fp_show.hpp contains the machinery in order to show the content of variables 6 | and containers 7 | * fp_tree.hpp contains functions that parse and manipulate trees in a functional way (this is the basis 8 | of the type parsing in this project) 9 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_fp/fp_base.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | 5 | // These functions are inspired by (FunctionalPlus)[https://github.com/Dobiasd/FunctionalPlus], 6 | // a Functional Programming Library for C++, which I highly recommend. 7 | // See fplus its api search site (a la Haskell): http://www.editgym.com/fplus-api-search/ 8 | // and see demo at 9 | // https://code-ballads.net/generated-notebooks/cpp/repl_cling/markdown/#A-REPL-session-of-C++-functional-programming,-using-fplus 10 | 11 | // Note: These versions are intentionally simplified and not completely generic. 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace cleantype_fp 25 | { 26 | inline std::string repeat(std::size_t n, const std::string & xs) 27 | { 28 | std::string xss; 29 | for (std::size_t i = 0; i < n; i++) 30 | xss += xs; 31 | return xss; 32 | } 33 | 34 | template 35 | std::vector transform(F f, const std::vector & xs) 36 | { 37 | std::vector out; 38 | for (const auto & x : xs) 39 | out.push_back(f(x)); 40 | return out; 41 | } 42 | 43 | template 44 | std::vector keep_if(F f, const std::vector & xs) 45 | { 46 | std::vector out; 47 | for (const auto & v : xs) 48 | { 49 | if (f(v)) 50 | out.push_back(v); 51 | } 52 | return out; 53 | } 54 | 55 | inline std::string join(std::string const & separator, const std::vector & xs) 56 | { 57 | std::string out; 58 | for (size_t idx = 0; idx < xs.size(); idx++) 59 | { 60 | out += xs[idx]; 61 | if (idx < xs.size() - 1) 62 | out += separator; 63 | } 64 | return out; 65 | } 66 | 67 | inline std::string join(std::string const & separator, const std::deque & xs) 68 | { 69 | std::string out; 70 | for (size_t idx = 0; idx < xs.size(); idx++) 71 | { 72 | out += xs[idx]; 73 | if (idx < xs.size() - 1) 74 | out += separator; 75 | } 76 | return out; 77 | } 78 | 79 | template 80 | std::vector trim(const T & trim_what, const std::vector & xs) 81 | { 82 | bool stop = false; 83 | std::vector out; 84 | for (const auto & v : xs) 85 | { 86 | if (stop) 87 | out.push_back(v); 88 | else if (v != trim_what) 89 | { 90 | out.push_back(v); 91 | stop = true; 92 | } 93 | } 94 | while ((!out.empty()) && (out.back() == trim_what)) 95 | out.pop_back(); 96 | return out; 97 | } 98 | 99 | inline std::string trim(const char & trim_what, std::string const & xs) 100 | { 101 | bool stop = false; 102 | std::string out; 103 | for (const auto & v : xs) 104 | { 105 | if (stop) 106 | out.push_back(v); 107 | else if (v != trim_what) 108 | { 109 | out.push_back(v); 110 | stop = true; 111 | } 112 | } 113 | while ((!out.empty()) && (out.back() == trim_what)) 114 | out.pop_back(); 115 | return out; 116 | } 117 | 118 | inline std::string trim_whitespace(std::string const & s) 119 | { 120 | std::string r = trim(' ', s); 121 | r = trim('\t', r); 122 | r = trim('\n', r); 123 | return r; 124 | } 125 | 126 | inline std::string replace_tokens(const std::string & from, 127 | const std::string & to, 128 | const std::string & xs) 129 | { 130 | if (from.empty()) 131 | return xs; 132 | std::string out = xs; 133 | size_t start_pos = 0; 134 | while ((start_pos = out.find(from, start_pos)) != std::string::npos) 135 | { 136 | out.replace(start_pos, from.length(), to); 137 | start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' 138 | } 139 | return out; 140 | } 141 | 142 | template 143 | std::vector keep_if(Pred pred, std::vector && xs) 144 | { 145 | std::vector r; 146 | for (const auto & v : xs) 147 | if (pred(v)) 148 | r.push_back(v); 149 | return r; 150 | } 151 | 152 | template 153 | std::vector numbers(const T start, const T end) 154 | { 155 | std::vector r; 156 | T v = start; 157 | while (v < end) 158 | r.push_back(v++); 159 | return r; 160 | } 161 | 162 | template 163 | std::vector numbers(const T end) 164 | { 165 | return numbers(static_cast(0), end); 166 | } 167 | 168 | template 169 | std::vector> zip(const std::vector & xs, const std::vector & ys) 170 | { 171 | std::vector> r; 172 | 173 | auto len = std::min(xs.size(), ys.size()); 174 | for (std::size_t idx = 0; idx < len; idx++) 175 | { 176 | r.push_back({xs[idx], ys[idx]}); 177 | } 178 | return r; 179 | } 180 | 181 | template 182 | std::pair, std::vector> unzip(const std::vector> & xs) 183 | { 184 | std::pair, std::vector> r; 185 | for (const auto & v : xs) 186 | { 187 | r.first.push_back(v.first); 188 | r.second.push_back(v.second); 189 | } 190 | return r; 191 | } 192 | 193 | inline std::string to_upper_case(const std::string & xs) 194 | { 195 | std::string r = xs; 196 | std::transform(r.begin(), r.end(), r.begin(), ::toupper); 197 | return r; 198 | } 199 | 200 | inline std::string to_lower_case(const std::string & xs) 201 | { 202 | std::string r = xs; 203 | std::transform(r.begin(), r.end(), r.begin(), ::tolower); 204 | return r; 205 | } 206 | 207 | template 208 | T maximum(const std::vector & xs) 209 | { 210 | assert(!xs.empty()); 211 | T max = xs[0]; 212 | for (const auto & v : xs) 213 | if (v > max) 214 | max = v; 215 | return max; 216 | } 217 | 218 | template 219 | std::vector reverse(const std::vector & xs) 220 | { 221 | std::vector r; 222 | for (std::size_t i = xs.size(); i > 0; i--) 223 | r.push_back(xs[i - 1]); 224 | return r; 225 | } 226 | 227 | } // namespace cleantype_fp 228 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_fp/fp_interact.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | 10 | namespace cleantype_fp_interact 11 | { 12 | template 13 | std::function interact(F f) 14 | { 15 | return [f]() -> void { 16 | std::cout << f(std::string(std::istreambuf_iterator(std::cin.rdbuf()), 17 | std::istreambuf_iterator())); 18 | }; 19 | } 20 | 21 | template 22 | std::function interact_by_line(F f, InputStream & is, OutputStream & os) 23 | { 24 | return [f, &is, &os]() -> void { 25 | std::string line; 26 | while (!is.eof()) 27 | { 28 | std::getline(is, line); 29 | std::string out = f(line); 30 | os << out << "\n"; 31 | } 32 | }; 33 | } 34 | 35 | template 36 | std::function interact_by_line(F f) 37 | { 38 | return interact_by_line(f, std::cin, std::cout); 39 | } 40 | 41 | } // namespace cleantype_fp_interact 42 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_fp/fp_show.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | 5 | // These functions are inspired by 6 | // (FunctionalPlus)[https://github.com/Dobiasd/FunctionalPlus], a Functional 7 | // Programming Library for C++, which I highly recommend. 8 | // 9 | // See its api search site (a la Haskell): 10 | // http://www.editgym.com/fplus-api-search/ and see demo at 11 | // https://code-ballads.net/generated-notebooks/cpp/repl_cling/markdown/#A-REPL-session-of-C++-functional-programming,-using-fplus 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace cleantype_fp 24 | { 25 | template 26 | std::string show(const T & v) 27 | { 28 | std::stringstream ss; 29 | ss << v; 30 | return ss.str(); 31 | } 32 | inline std::string show(const bool & v) { return v ? "true" : "false"; } 33 | inline std::string show(const char * xs) { return std::string(xs); } 34 | 35 | template 36 | std::string show_cont(T & xs); 37 | 38 | } // namespace cleantype_fp 39 | 40 | // Below : overload for common containers 41 | // (tuple is not yet included) 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | namespace cleantype_fp 57 | { 58 | template 59 | std::string show(const std::array & v) 60 | { 61 | return show_cont(v); 62 | } 63 | template 64 | std::string show(const std::vector & v) 65 | { 66 | return show_cont(v); 67 | } 68 | template 69 | std::string show(const std::deque & v) 70 | { 71 | return show_cont(v); 72 | } 73 | template 74 | std::string show(const std::map & v) 75 | { 76 | return show_cont(v); 77 | } 78 | 79 | template 80 | std::string show(const std::forward_list & v) 81 | { 82 | return cleantype_fp::show_cont(v); 83 | } 84 | template 85 | std::string show(const std::list & v) 86 | { 87 | return cleantype_fp::show_cont(v); 88 | } 89 | template 90 | std::string show(const std::stack & v) 91 | { 92 | return cleantype_fp::show_cont(v); 93 | } 94 | template 95 | std::string show(const std::queue & v) 96 | { 97 | return cleantype_fp::show_cont(v); 98 | } 99 | template 100 | std::string show(const std::priority_queue & v) 101 | { 102 | return cleantype_fp::show_cont(v); 103 | } 104 | 105 | template 106 | std::string show(const std::set & v) 107 | { 108 | return cleantype_fp::show_cont(v); 109 | } 110 | template 111 | std::string show(const std::multiset & v) 112 | { 113 | return cleantype_fp::show_cont(v); 114 | } 115 | 116 | template 117 | std::string show(const std::multimap & v) 118 | { 119 | return cleantype_fp::show_cont(v); 120 | } 121 | 122 | template 123 | std::string show(const std::unordered_set & v) 124 | { 125 | return cleantype_fp::show_cont(v); 126 | } 127 | template 128 | std::string show(const std::unordered_multiset & v) 129 | { 130 | return cleantype_fp::show_cont(v); 131 | } 132 | template 133 | std::string show(const std::unordered_map & v) 134 | { 135 | return cleantype_fp::show_cont(v); 136 | } 137 | template 138 | std::string show(const std::unordered_multimap & v) 139 | { 140 | return cleantype_fp::show_cont(v); 141 | } 142 | 143 | template 144 | std::string show(const std::pair & xs) 145 | { 146 | return std::string("(") + show(xs.first) + ", " + show(xs.second) + ")"; 147 | } 148 | 149 | template 150 | std::string show_cont(T & xs) 151 | { 152 | std::vector strs; 153 | for (const auto & x : xs) 154 | strs.push_back(cleantype_fp::show(x)); 155 | 156 | return std::string("[") + cleantype_fp::join(", ", strs) + "]"; 157 | } 158 | 159 | } // namespace cleantype_fp 160 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_full.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #ifndef _MSC_VER 9 | #include 10 | #endif 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace cleantype 24 | { 25 | using stringliteral = boost::hana::experimental::type_name_details::stringliteral; 26 | namespace internal 27 | { 28 | template 29 | constexpr stringliteral _impl_typeid_hana_literal() 30 | { 31 | return boost::hana::experimental::type_name_details::type_name_impl_stringliteral(); 32 | } 33 | 34 | template 35 | std::string _impl_typeid_hana() 36 | { 37 | return boost::hana::experimental::type_name_details::stringliteral_to_string( 38 | _impl_typeid_hana_literal()); 39 | } 40 | 41 | template 42 | constexpr stringliteral _impl_typeid_hana_inside_holder() 43 | { 44 | return boost::hana::experimental::type_name_details::type_name_impl_stringliteral< 45 | TupleTypeHolder>(); 46 | } 47 | 48 | template 49 | stringliteral impl_typeid() 50 | { 51 | return _impl_typeid_hana_inside_holder(); 52 | } 53 | 54 | template 55 | std::string impl_full() 56 | { 57 | stringliteral type_sl_in_tupletypeholder = impl_typeid(); 58 | std::string type_in_tupletypeholder = 59 | boost::hana::experimental::type_name_details::stringliteral_to_string( 60 | type_sl_in_tupletypeholder); 61 | 62 | std::string type_definition = remove_type_holder_str(type_in_tupletypeholder); 63 | 64 | std::string formatted = cleantype::internal::format_whitespace(type_definition); 65 | 66 | if (CleanConfiguration::GlobalConfig().force_east_const_) 67 | formatted = cleantype::apply_east_const_typelist(formatted); 68 | 69 | return formatted; 70 | } 71 | } // namespace internal 72 | 73 | template 74 | std::string full() 75 | { 76 | return internal::impl_full(); 77 | } 78 | 79 | template 80 | std::string full(T &&... v) 81 | { 82 | return full(); 83 | } 84 | 85 | template 86 | std::string show_details_full(T && v) 87 | { 88 | return std::string("[") + full() + "]" + " = " + cleantype_fp::show(v); 89 | } 90 | 91 | } // namespace cleantype 92 | 93 | #define CT_cleantype_full(var) cleantype::full() 94 | 95 | #define CT_show_details_full(var) \ 96 | std::string("[") + CT_cleantype_full(var) + "] " + #var + " = " + cleantype_fp::show(var) 97 | 98 | #define CT_show_details_full_cont(var) \ 99 | std::string("[") + CT_cleantype_full(var) + "] " + #var + " = " + cleantype_fp::show_cont(var) 100 | 101 | #define CT_compiler_log_var_type(var) \ 102 | { \ 103 | var.IntentionalError = 42; \ 104 | } 105 | #define CT_compiler_log_type(T) \ 106 | { \ 107 | T::IntentionalError = 42; \ 108 | } 109 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_holder.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cleantype 10 | { 11 | namespace internal 12 | { 13 | // Trick in order to avoid having to deal the tedious syntax of parameter packs 14 | template 15 | struct TupleTypeHolder 16 | { 17 | }; 18 | 19 | inline std::string add_type_holder_str(const std::string & type_names) 20 | { 21 | #ifdef _MSC_VER 22 | const std::string start = "struct cleantype::internal::TupleTypeHolder<"; 23 | #else 24 | const std::string start = "cleantype::internal::TupleTypeHolder<"; 25 | #endif 26 | const std::string end = ">"; 27 | return start + type_names + end; 28 | } 29 | 30 | inline std::string remove_type_holder_str(const std::string & types_inside_holder) 31 | { 32 | std::string r = types_inside_holder; 33 | if (stringutils::starts_with(r, "struct cleantype::internal::TupleTypeHolder<")) 34 | r = stringutils::remove_start(r, "struct cleantype::internal::TupleTypeHolder<"); 35 | if (stringutils::starts_with(r, "cleantype::internal::TupleTypeHolder<")) 36 | r = stringutils::remove_start(r, "cleantype::internal::TupleTypeHolder<"); 37 | if (stringutils::ends_with(r, ">")) 38 | r = stringutils::remove_end(r, ">"); 39 | return r; 40 | } 41 | 42 | // splits a string containings a list of comma separated types into 43 | // a vector of types 44 | // example : 45 | // split_types("int, map") => ["int", "map"] 46 | inline std::vector split_types(std::string const & type_names) 47 | { 48 | std::vector result; 49 | // counts < and > occurrences 50 | int count = 0; 51 | std::string current; 52 | for (const auto c : type_names) 53 | { 54 | if (c == '<') 55 | ++count; 56 | if (c == '>') 57 | --count; 58 | if ((c == ',') && (count == 0)) 59 | { 60 | result.push_back(cleantype_fp::trim(' ', current)); 61 | current = ""; 62 | } 63 | else 64 | { 65 | current += c; 66 | } 67 | } 68 | result.push_back(cleantype_fp::trim(' ', current)); 69 | return result; 70 | } 71 | 72 | } // namespace internal 73 | } // namespace cleantype -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_invoke_result.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace cleantype 11 | { 12 | #if __cplusplus < 201703L 13 | template 14 | struct invoke_result : detail::invoke_result 15 | { 16 | }; 17 | #else 18 | template 19 | struct invoke_result : std::invoke_result 20 | { 21 | }; 22 | #endif 23 | 24 | template 25 | using invoke_result_t = typename invoke_result::type; 26 | } // namespace cleantype 27 | 28 | #define CT_invoke_result_fn(f, ...) cleantype::invoke_result::type 29 | 30 | #define CT_invoke_result_fn_template(f, ...) \ 31 | cleantype::invoke_result), __VA_ARGS__>::type 32 | 33 | #define CT_type_fn(f, ...) cleantype::clean() 34 | #define CT_type_fn_full(f, ...) cleantype::full() 35 | 36 | #define CT_type_fn_template(f, ...) cleantype::clean() 37 | #define CT_type_fn_template_full(f, ...) \ 38 | cleantype::full() 39 | 40 | #ifdef _MSC_VER 41 | // under MSVC 2017, std::invoke_result fails with template functions 42 | // See 43 | // https://stackoverflow.com/questions/54111146/invoke-result-for-template-function-with-auto-return-type-and-msvc-2017 44 | // You need to call CT_invoke_result_fn_template_memoize before calling CT_invoke_result_fn_template 45 | // in order to help the compiler 46 | #define CT_invoke_result_fn_template_memoize(f, ...) \ 47 | { \ 48 | auto _ = f<__VA_ARGS__>; \ 49 | (void)_; \ 50 | } 51 | #endif 52 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_lambda.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cleantype 10 | { 11 | namespace internal 12 | { 13 | template 14 | std::string lambda_memfn_type(Lambda fn) 15 | { 16 | #ifdef _MSC_VER 17 | auto as_ptr = &Lambda::operator(); 18 | #else 19 | auto as_ptr = &Lambda::template operator(); 20 | #endif 21 | auto as_mem_fn = std::mem_fn(as_ptr); 22 | std::string mem_fn_type = cleantype::internal::_impl_typeid_hana(); 23 | 24 | return mem_fn_type; 25 | } 26 | 27 | template 28 | std::string lambda_memfn_type(Lambda fn) 29 | { 30 | auto as_ptr = &Lambda::operator(); // if you have an error here, your lambda is generic! Add template params for its input types! 31 | auto as_mem_fn = std::mem_fn(as_ptr); 32 | std::string mem_fn_type = cleantype::internal::_impl_typeid_hana(); 33 | return mem_fn_type; 34 | } 35 | 36 | } // namespace internal 37 | 38 | ////////////////////////////// 39 | // Start of public API 40 | ////////////////////////////// 41 | 42 | // * `cleantype::lambda_clean(Lambda fn)` is a function that 43 | // will return a string containing 44 | // the readable signature of a lambda 45 | // 46 | // In the case of a generic lambda, you will need to specify the type of the auto parameters: 47 | // Example: 48 | // auto f = [](auto x, auto y) { return x + y; }; 49 | // std::cout << cleantype::lambda_clean(f) << std::endl; 50 | // ==> lambda: (int, char) -> int 51 | template 52 | std::string lambda_clean(Lambda fn) 53 | { 54 | // return cleantype::lambda(fn, true); // Won't compile : clang gives up here 55 | bool flag_clean = true; 56 | std::string memfn_type = cleantype::internal::lambda_memfn_type(fn); 57 | std::string final_type = 58 | cleantype::internal::_mem_fn_to_lambda_type(memfn_type, flag_clean); 59 | return final_type; 60 | } 61 | 62 | // * `cleantype::lambda_clean(Lambda fn)` is a function that 63 | // will return a string containing 64 | // the full signature of a lambda 65 | // In the case of a generic lambda, you will need to specify the type of the auto parameters 66 | // (see lambda_clean doc for an example) 67 | template 68 | std::string lambda_full(Lambda fn) 69 | { 70 | // return cleantype::lambda(fn, false); // Won't compile : clang gives up here 71 | bool flag_clean = false; 72 | std::string memfn_type = cleantype::internal::lambda_memfn_type(fn); 73 | std::string final_type = 74 | cleantype::internal::_mem_fn_to_lambda_type(memfn_type, flag_clean); 75 | return final_type; 76 | } 77 | 78 | // * `cleantype::lambda(Lambda fn, bool flag_clean)` is a 79 | // function that will return 80 | // a string containing the signature of a lambda. 81 | // flag_clean controls wether the signature is cleaned or not. 82 | // 83 | // In the case of a generic lambda, you will need to specify the type of the auto parameters: 84 | // Example: 85 | // auto f = [](auto x, auto y) { return x + y; }; 86 | // std::cout << cleantype::lambda(f, true) << std::endl; 87 | // ==> lambda: (int, char) -> int 88 | template 89 | std::string lambda(Lambda fn, bool flag_clean) 90 | { 91 | std::string memfn_type = cleantype::internal::lambda_memfn_type(fn); 92 | std::string final_type = 93 | cleantype::internal::_mem_fn_to_lambda_type(memfn_type, flag_clean); 94 | return final_type; 95 | } 96 | 97 | } // namespace cleantype 98 | 99 | #define CT_show_details_lambda(f) std::string("[") + cleantype::lambda_clean(f) + "] " + #f 100 | #define CT_show_details_lambda_full(f) std::string("[") + cleantype::lambda_full(f) + "] " + #f 101 | 102 | // CT_type_lambda_generic_fromparams_ 103 | #define CT_type_lambda_generic_fromparams_1(fn, arg1) cleantype::lambda_clean(fn) 104 | #define CT_type_lambda_generic_fromparams_2(fn, arg1, arg2) \ 105 | cleantype::lambda_clean(fn) 106 | #define CT_type_lambda_generic_fromparams_3(fn, arg1, arg2, arg3) \ 107 | cleantype::lambda_clean(fn) 108 | #define CT_type_lambda_generic_fromparams_4(fn, arg1, arg2, arg3, arg4) \ 109 | cleantype::lambda_clean(fn) 110 | #define CT_type_lambda_generic_fromparams_5(fn, arg1, arg2, arg3, arg4, arg5) \ 111 | cleantype::lambda_clean(fn) 116 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_lambda_parse.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace cleantype 11 | { 12 | namespace internal 13 | { 14 | inline std::string remove_outer_parenthesis(std::string const & s) 15 | { 16 | assert(s.size() >= 2); 17 | assert(s.front() == '('); 18 | assert(s.back() == ')'); 19 | std::string result(s.begin() + 1, s.end() - 1); 20 | return result; 21 | } 22 | 23 | struct extract_parenthesis_content_at_end_result 24 | { 25 | std::string remaining_at_start; 26 | std::string parenthesis_content; 27 | bool success; 28 | 29 | static extract_parenthesis_content_at_end_result error() 30 | { 31 | extract_parenthesis_content_at_end_result r; 32 | r.success = false; 33 | return r; 34 | } 35 | }; 36 | 37 | // Example : 38 | // "ABC(DEF)(GHI)KLM" 39 | // Returns { remaining_at_start = "ABC", parenthesis_content="GHI", success = true } 40 | inline extract_parenthesis_content_at_end_result extract_parenthesis_content_at_end( 41 | std::string const & str) 42 | { 43 | if (str.empty()) 44 | { 45 | std::cerr << "extract_parenthesis_content_at_end_result : error (empty input)" 46 | << std::endl; 47 | return extract_parenthesis_content_at_end_result::error(); 48 | } 49 | 50 | extract_parenthesis_content_at_end_result result; 51 | 52 | std::string s = str; 53 | 54 | while (s.back() != ')') 55 | { 56 | s.pop_back(); 57 | if (s.empty()) 58 | { 59 | std::cerr 60 | << "extract_parenthesis_content_at_end_result: error (missing last ')' )" 61 | << std::endl; 62 | return extract_parenthesis_content_at_end_result::error(); 63 | } 64 | } 65 | 66 | std::vector content; 67 | int nb_parenthesis = 1; 68 | content.push_back(')'); 69 | s.pop_back(); 70 | while (nb_parenthesis > 0) 71 | { 72 | char c = s.back(); 73 | content.push_back(c); 74 | if (c == ')') 75 | nb_parenthesis++; 76 | if (c == '(') 77 | nb_parenthesis--; 78 | s.pop_back(); 79 | if (s.empty()) 80 | { 81 | std::cerr << "extract_parenthesis_content_at_end_result: error (non zero count " 82 | "of '()' )" 83 | << std::endl; 84 | return extract_parenthesis_content_at_end_result::error(); 85 | } 86 | } 87 | std::reverse(content.begin(), content.end()); 88 | for (auto c : content) 89 | result.parenthesis_content += c; 90 | 91 | result.parenthesis_content = remove_outer_parenthesis(result.parenthesis_content); 92 | result.remaining_at_start = s; 93 | result.success = true; 94 | return result; 95 | } 96 | 97 | inline std::string _remove_mem_fn_surround(std::string const & mem_fn_type) 98 | { 99 | std::string result = mem_fn_type; 100 | // Suppress mem_fn< at the start 101 | size_t idx1 = result.find('<'); 102 | if (idx1 == std::string::npos) 103 | return "Error, can not find first '<' in mem_fn_type: " + mem_fn_type; 104 | result = result.substr(idx1 + 1); 105 | 106 | // Suppress all after the last ')' 107 | size_t idx2 = result.rfind(')'); 108 | if (idx1 == std::string::npos) 109 | return "Error, can not find last '>' in mem_fn_type: " + mem_fn_type; 110 | result = result.substr(0, idx2 + 1); 111 | 112 | return result; 113 | } 114 | 115 | inline std::string _mem_fn_to_lambda_type(std::string const & mem_fn_type, 116 | bool clean_params) 117 | { 118 | // Examples of possible inputs: 119 | 120 | // auto f = [&c](int a, int b) -> double { return a + b + c; }; 121 | // MSVC : class std::_Mem_fn::*)(int,int)const > clang: 123 | // std::__1::__mem_fn MSVC : double (__thiscall 125 | // ::*)(int,int)const 126 | 127 | // auto f = [](int a, int b) { return std::pair(a, b); }; 128 | // clang: std::__1::__mem_fn 129 | // (cleantype::_DOCTEST_ANON_FUNC_2()::$_1::*)(int, int) const> clang: 130 | // std::__1::pair (cleantype::_DOCTEST_ANON_FUNC_2()::$_1::*)(int, int) const 131 | 132 | const std::string lambda_full_type = _remove_mem_fn_surround(mem_fn_type); 133 | // std::cout << lambda_full_type << std::endl; 134 | std::string params_str, return_str_with_leading_garbage; 135 | { 136 | // lambda params are at the end between parenthesis 137 | auto params_r = extract_parenthesis_content_at_end(lambda_full_type); 138 | if (!params_r.success) 139 | std::cerr << "_mem_fn_to_lambda_type : error parsing mem_fn_type --> " 140 | << mem_fn_type << std::endl; 141 | params_str = params_r.parenthesis_content; 142 | return_str_with_leading_garbage = params_r.remaining_at_start; 143 | } 144 | 145 | // Separate params and clean them, then join them 146 | const std::string params_cleaned = [&]() { 147 | auto params_list = split_types(params_str); 148 | if (clean_params) 149 | params_list = cleantype_fp::transform(impl_clean, params_list); 150 | std::string params_joined = cleantype_fp::join(std::string(", "), params_list); 151 | if (params_joined == "void") 152 | params_joined = ""; 153 | if (cleantype::CleanConfiguration::GlobalConfig().force_east_const_) 154 | params_joined = cleantype::apply_east_const_typelist(params_joined); 155 | return params_joined; 156 | }(); 157 | 158 | // garbage between the parentheses before (lambda anonymous name) 159 | std::string return_str; 160 | { 161 | auto garbage_r = 162 | extract_parenthesis_content_at_end(return_str_with_leading_garbage); 163 | if (!garbage_r.success) 164 | std::cerr << "_mem_fn_to_lambda_type : error parsing mem_fn_type --> " 165 | << mem_fn_type << std::endl; 166 | return_str = garbage_r.remaining_at_start; 167 | } 168 | 169 | std::string return_type = clean_params ? impl_clean(return_str) : return_str; 170 | if (cleantype::CleanConfiguration::GlobalConfig().force_east_const_) 171 | return_type = cleantype::apply_east_const_typelist(return_type); 172 | 173 | // std::cout << "params= " << params << '\n'; 174 | // std::cout << "return_type= " << return_type << '\n'; 175 | return std::string("lambda: ") + "(" + params_cleaned + ")" + " -> " + return_type; 176 | } 177 | 178 | } // namespace internal 179 | 180 | } // namespace cleantype 181 | -------------------------------------------------------------------------------- /src/include/cleantype/details/cleantype_parse.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cleantype 10 | { 11 | namespace internal 12 | { 13 | // lhs / rhs explanation : 14 | // for example in "std::vector const &", 15 | // - lhs = "std::vector" 16 | // - rhs = "const &" 17 | // - int is the lhs of a child node 18 | using code_pair = cleantype_fp_tree::lhs_rhs; 19 | using code_pair_tree = cleantype_fp_tree::tree; 20 | 21 | inline cleantype_fp_tree::tree_separators make_template_tree_separators() 22 | { 23 | cleantype_fp_tree::tree_separators sep; 24 | sep.open_child = '<'; 25 | sep.close_child = '>'; 26 | sep.siblings_separator = ','; 27 | return sep; 28 | } 29 | 30 | inline cleantype_fp_tree::show_tree_lhs_rhs_options make_template_show_tree_options_impl( 31 | bool indent) 32 | { 33 | cleantype_fp_tree::show_tree_lhs_rhs_options result; 34 | if (indent) 35 | { 36 | result.children_indent = cleantype_fp_tree::children_indent_t::newline_before_child; 37 | result.siblings_spacing = cleantype_fp_tree::siblings_spacing_t::new_line; 38 | result.indent = " "; 39 | } 40 | else 41 | { 42 | result.children_indent = cleantype_fp_tree::children_indent_t::no_indent; 43 | result.siblings_spacing = cleantype_fp_tree::siblings_spacing_t::space; 44 | result.indent = ""; 45 | } 46 | result.add_space_after_lhs = false; 47 | result.add_space_before_rhs = true; 48 | return result; 49 | } 50 | 51 | inline cleantype_fp_tree::show_tree_lhs_rhs_options 52 | make_template_show_tree_options_no_indent() 53 | { 54 | return make_template_show_tree_options_impl(false); 55 | } 56 | 57 | inline cleantype_fp_tree::show_tree_lhs_rhs_options 58 | make_template_show_tree_options_with_indent() 59 | { 60 | return make_template_show_tree_options_impl(true); 61 | } 62 | 63 | inline code_pair_tree parse_template_tree(std::string const & s) 64 | { 65 | return parse_lhs_rhs_tree(s, make_template_tree_separators(), true); 66 | } 67 | 68 | inline std::string code_pair_tree_to_string(code_pair_tree const & xs) 69 | { 70 | return cleantype_fp_tree::show_tree_lhs_rhs( 71 | xs, make_template_tree_separators(), make_template_show_tree_options_no_indent()); 72 | } 73 | 74 | } // namespace internal 75 | 76 | } // namespace cleantype 77 | -------------------------------------------------------------------------------- /src/include/cleantype/details/filesystem.hpp: -------------------------------------------------------------------------------- 1 | // filesystem polyfills for C++14 (70's style) 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #if defined(__unix__) || defined(__APPLE__) 9 | #include 10 | #include 11 | #endif 12 | #if defined(__unix__) || defined(__APPLE__) 13 | #include 14 | #endif 15 | #ifdef _WIN32 16 | #include 17 | #endif 18 | 19 | namespace cleantype 20 | { 21 | namespace filesystem 22 | { 23 | inline std::string getcwd() 24 | { 25 | #ifdef _WIN32 26 | char * answer = _getcwd(NULL, 0); 27 | #else 28 | #ifdef __APPLE__ 29 | char buffer[PATH_MAX]; 30 | #else 31 | char buffer[MAXPATHLEN]; 32 | #endif 33 | char * answer = ::getcwd(buffer, sizeof(buffer)); 34 | #endif 35 | 36 | std::string s; 37 | if (answer) 38 | s = answer; 39 | return s; 40 | } 41 | 42 | inline std::vector parent_directories() 43 | { 44 | std::string cwd = cleantype::filesystem::getcwd(); 45 | cwd = cleantype_fp::replace_tokens(std::string("\\"), std::string("/"), cwd); 46 | 47 | std::vector folder_elems = stringutils::split_string(cwd, '/'); 48 | 49 | if (folder_elems.empty()) 50 | return {}; 51 | 52 | std::vector parent_dirs; 53 | std::string current = ""; 54 | for (const auto & folder_elem : folder_elems) 55 | { 56 | current = current + folder_elem + "/"; 57 | parent_dirs.push_back(current); 58 | } 59 | 60 | parent_dirs = cleantype_fp::reverse(parent_dirs); 61 | return parent_dirs; 62 | } 63 | 64 | inline bool file_exists(const std::string & filename) 65 | { 66 | struct stat buffer; 67 | return (stat(filename.c_str(), &buffer) == 0); 68 | } 69 | 70 | inline std::string read_istream(std::istream & is) 71 | { 72 | std::stringstream ss; 73 | std::string line; 74 | while (!is.eof()) 75 | { 76 | std::getline(is, line); 77 | ss << line << "\n"; 78 | } 79 | return ss.str(); 80 | } 81 | 82 | inline std::string read_file(const std::string & filename) 83 | { 84 | std::ifstream is(filename); 85 | return read_istream(is); 86 | } 87 | } // namespace filesystem 88 | } -------------------------------------------------------------------------------- /src/include/cleantype/details/hana_type_name/Readme.md: -------------------------------------------------------------------------------- 1 | This folder contains is a proposed extension to [Boost.Hana](http://boostorg.github.io/hana/)'s 2 | [experimental type_name](http://boostorg.github.io/hana/group__group-experimental.html#gaf14876d1f1a3c42ce7a0243d7b263bec). 3 | 4 | The original version was limited to clang. 5 | This proposed extension adds support for MSVC (constexpr, i.e at compile time), 6 | and for GCC (runtime only). 7 | 8 | See PR https://github.com/boostorg/hana/pull/432 which originates from the author of this project (Pascal Thomet). 9 | -------------------------------------------------------------------------------- /src/include/cleantype/details/hana_type_name/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(type_name_stringliteral_test type_name_stringliteral_test.cpp) 2 | clean_type_set_target_option(type_name_stringliteral_test) 3 | -------------------------------------------------------------------------------- /src/include/cleantype/details/hana_type_name/tests/type_name_stringliteral_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace type_name_details = boost::hana::experimental::type_name_details; 10 | 11 | #ifdef _HANA_TN_CAN_CONSTEXPR 12 | #define RUN_ONE_TYPE_TEST_COMPILE_TIME(type_definition, type_string_literal) \ 13 | { \ 14 | constexpr auto computed = \ 15 | type_name_details::type_name_impl_stringliteral(); \ 16 | static_assert(type_name_details::stringliteral_equal_sz(computed, type_string_literal), \ 17 | "RUN_ONE_TYPE_TEST_COMPILE_TIME error"); \ 18 | } 19 | #else 20 | #define RUN_ONE_TYPE_TEST_COMPILE_TIME(type_definition, type_string_literal) 21 | #endif 22 | 23 | template 24 | struct Template 25 | { 26 | }; 27 | 28 | template 29 | void check_matches(std::string const & re) 30 | { 31 | type_name_details::stringliteral name_cs = type_name_details::type_name_impl_stringliteral(); 32 | std::string name = type_name_details::stringliteral_to_string(name_cs); 33 | std::regex regex{re}; 34 | if (!std::regex_match(name, regex)) 35 | { 36 | std::cerr << "type name '" << name << "' does not match regex '" << re << "'" << std::endl; 37 | std::abort(); 38 | } 39 | } 40 | 41 | void compile_time_tests() 42 | { 43 | RUN_ONE_TYPE_TEST_COMPILE_TIME(void, "void"); 44 | RUN_ONE_TYPE_TEST_COMPILE_TIME(char, "char"); 45 | 46 | // __PRETTY_FUNCTION__ seems to favor west-const (this is true for MSVC, GCC and Clang) 47 | // on the contrary, typeid().name() is strictly east const accross all compilers 48 | // (Does this really need to be tested ?) 49 | RUN_ONE_TYPE_TEST_COMPILE_TIME(const char, "const char"); 50 | RUN_ONE_TYPE_TEST_COMPILE_TIME(char const, "const char"); 51 | } 52 | 53 | void rumtime_regex_tests() 54 | { 55 | // Make sure we get something reasonable 56 | check_matches("int const|const int"); 57 | check_matches(R"(int\s*&)"); 58 | check_matches(R"(const\s+int\s*&|int\s+const\s*&)"); 59 | check_matches(R"(int\s*\(\s*&\s*\)\s*\[\s*\])"); 60 | check_matches(R"(int\s*\(\s*&\s*\)\s*\[\s*10\s*\])"); 61 | check_matches>( 62 | R"((struct )?Template<\s*void\s*,\s*(char const|const char)\s*\*\s*>)"); 63 | check_matches(R"(void\s*\((__cdecl)?\s*\*\s*\)\s*\(\s*int\s*\))"); 64 | } 65 | 66 | int main() 67 | { 68 | compile_time_tests(); 69 | rumtime_regex_tests(); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /src/include/cleantype/details/hana_type_name/type_name_compiler_capabilities.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | @file 3 | Defines `boost::hana::experimental::type_name`. 4 | @copyright Louis Dionne 2013-2017 5 | Distributed under the Boost Software License, Version 1.0. 6 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | */ 8 | 9 | /* 10 | This folder contains is a proposed extension 11 | to [Boost.Hana](http://boostorg.github.io/hana/)'s[experimental type_name] 12 | 13 | The original version was experimental, and limited to Clang. 14 | This version: 15 | * adds complete support for MSVC 16 | * adds partial support for GCC (runtime only) 17 | * offers compiler capabilities detection 18 | * runs out of the box with or without boost 19 | 20 | This extension is being studied : 21 | see PR https://github.com/boostorg/hana/pull/432 22 | which originates from the author of this project (Pascal Thomet). 23 | */ 24 | 25 | #ifndef BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_COMPILER_CAPABILITIES_HPP 26 | #define BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_COMPILER_CAPABILITIES_HPP 27 | 28 | // only clang and MSVC support constexpr __PRETTY_FUNCTION__, gcc does not 29 | #if defined(__clang__) || defined(_MSC_VER) 30 | #define _HANA_TN_CAN_CONSTEXPR 31 | #endif 32 | 33 | // in constexpr mode, strlen is equivalent to sizeof() - 1 34 | #ifdef _HANA_TN_CAN_CONSTEXPR 35 | #define _HANA_TN_CONSTEXPR_IF_POSSIBLE constexpr 36 | #define _HANA_SIZEOF_OR_STRLEN(var) sizeof(var) - 1 37 | #else 38 | #include // this include is not needed in constexpr mode, save compilation time 39 | #define _HANA_TN_CONSTEXPR_IF_POSSIBLE 40 | #define _HANA_SIZEOF_OR_STRLEN(var) strlen(var) 41 | #endif 42 | 43 | #endif // !BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_COMPILER_CAPABILITIES_HPP 44 | -------------------------------------------------------------------------------- /src/include/cleantype/details/hana_type_name/type_name_pretty_function.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | @file 3 | Defines `boost::hana::experimental::type_name`. 4 | @copyright Louis Dionne 2013-2017 5 | Distributed under the Boost Software License, Version 1.0. 6 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | */ 8 | 9 | /* 10 | This folder contains is a proposed extension 11 | to [Boost.Hana](http://boostorg.github.io/hana/)'s[experimental type_name] 12 | 13 | The original version was experimental, and limited to Clang. 14 | This version: 15 | * adds complete support for MSVC 16 | * adds partial support for GCC (runtime only) 17 | * offers compiler capabilities detection 18 | * runs out of the box with or without boost 19 | 20 | This extension is being studied : 21 | see PR https://github.com/boostorg/hana/pull/432 22 | which originates from the author of this project (Pascal Thomet). 23 | */ 24 | 25 | #ifndef BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_PRERRY_FUNCTION_HPP 26 | #define BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_PRERRY_FUNCTION_HPP 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef _MSC_VER 33 | #define _HANA_TN__PRETTY_FUNCTION__ __FUNCSIG__ 34 | #else 35 | #define _HANA_TN__PRETTY_FUNCTION__ __PRETTY_FUNCTION__ 36 | #endif 37 | 38 | #if defined(__clang__) 39 | #define _HANA_TN_PRETTY_FUNCTION_TYPE_PREFIX \ 40 | "boost::hana::experimental::type_name_details::stringliteral " \ 41 | "boost::hana::experimental::type_name_details::type_name_impl_stringliteral() [T = " 42 | #define _HANA_TN_PRETTY_FUNCTION_TYPE_SUFFIX "]" 43 | #elif defined(_MSC_VER) 44 | #define _HANA_TN_PRETTY_FUNCTION_TYPE_PREFIX \ 45 | "struct boost::hana::experimental::type_name_details::stringliteral __cdecl " \ 46 | "boost::hana::experimental::type_name_details::type_name_impl_stringliteral<" 47 | #define _HANA_TN_PRETTY_FUNCTION_TYPE_SUFFIX ">(void)" 48 | #elif defined(__GNUC__) || defined(__GNUG__) 49 | #define _HANA_TN_PRETTY_FUNCTION_TYPE_PREFIX \ 50 | "constexpr boost::hana::experimental::type_name_details::stringliteral " \ 51 | "boost::hana::experimental::type_name_details::type_name_impl_stringliteral() [with T = " 52 | #define _HANA_TN_PRETTY_FUNCTION_TYPE_SUFFIX "]" 53 | #else 54 | #error "No support for this compiler." 55 | #endif 56 | 57 | namespace boost 58 | { 59 | namespace hana 60 | { 61 | namespace experimental 62 | { 63 | namespace type_name_details 64 | { 65 | template 66 | constexpr stringliteral type_name_impl_stringliteral() 67 | { 68 | _HANA_TN_CONSTEXPR_IF_POSSIBLE char const * pretty_function = 69 | _HANA_TN__PRETTY_FUNCTION__; 70 | _HANA_TN_CONSTEXPR_IF_POSSIBLE std::size_t total_size = 71 | _HANA_SIZEOF_OR_STRLEN(_HANA_TN__PRETTY_FUNCTION__); 72 | _HANA_TN_CONSTEXPR_IF_POSSIBLE std::size_t prefix_size = 73 | _HANA_SIZEOF_OR_STRLEN(_HANA_TN_PRETTY_FUNCTION_TYPE_PREFIX); 74 | _HANA_TN_CONSTEXPR_IF_POSSIBLE std::size_t suffix_size = 75 | _HANA_SIZEOF_OR_STRLEN(_HANA_TN_PRETTY_FUNCTION_TYPE_SUFFIX); 76 | return {pretty_function + prefix_size, total_size - prefix_size - suffix_size}; 77 | // return {pretty_function, total_size}; 78 | } 79 | } // end namespace type_name_details 80 | 81 | } // namespace experimental 82 | } // namespace hana 83 | } // namespace boost 84 | 85 | #endif // !BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_PRERRY_FUNCTION_HPP 86 | -------------------------------------------------------------------------------- /src/include/cleantype/details/hana_type_name/type_name_stringliteral.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | @file 3 | Defines `boost::hana::experimental::type_name`. 4 | @copyright Louis Dionne 2013-2017 5 | Distributed under the Boost Software License, Version 1.0. 6 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | */ 8 | 9 | /* 10 | This folder contains is a proposed extension 11 | to [Boost.Hana](http://boostorg.github.io/hana/)'s[experimental type_name] 12 | 13 | The original version was experimental, and limited to Clang. 14 | This version: 15 | * adds complete support for MSVC 16 | * adds partial support for GCC (runtime only) 17 | * offers compiler capabilities detection 18 | * runs out of the box with or without boost 19 | 20 | This extension is being studied : 21 | see PR https://github.com/boostorg/hana/pull/432 22 | which originates from the author of this project (Pascal Thomet). 23 | */ 24 | 25 | #ifndef BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_CSTRING_HPP 26 | #define BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_CSTRING_HPP 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace boost 34 | { 35 | namespace hana 36 | { 37 | namespace experimental 38 | { 39 | namespace type_name_details 40 | { 41 | struct stringliteral 42 | { 43 | char const * ptr; 44 | std::size_t length; 45 | }; 46 | 47 | #define _HANA_TN_MAKE_STRINGLITERAL(str_literal) \ 48 | stringliteral \ 49 | { \ 50 | str_literal, _HANA_SIZEOF_OR_STRLEN(str_literal); 51 | 52 | inline constexpr std::size_t constexpr_strlen(char const * s) 53 | { 54 | std::size_t r = 0; 55 | while (*s++ != '\0') 56 | r++; 57 | return r; 58 | } 59 | 60 | inline constexpr bool stringliteral_equal(stringliteral const & cs1, 61 | stringliteral const & cs2) 62 | { 63 | if (cs1.length != cs2.length) 64 | return false; 65 | 66 | std::size_t idx = 0; 67 | do 68 | { 69 | char c1 = cs1.ptr[idx]; 70 | char c2 = cs2.ptr[idx]; 71 | if (c1 != c2) 72 | return false; 73 | idx++; 74 | } while (idx < cs1.length); 75 | return true; 76 | } 77 | 78 | inline constexpr bool stringliteral_equal_sz(stringliteral const & cs1, 79 | char const * literal) 80 | { 81 | stringliteral cs2{literal, constexpr_strlen(literal)}; 82 | return stringliteral_equal(cs1, cs2); 83 | } 84 | 85 | inline std::string stringliteral_to_string(stringliteral const & cs) 86 | { 87 | return std::string(cs.ptr, cs.length); 88 | } 89 | 90 | } // namespace type_name_details 91 | } // namespace experimental 92 | } // namespace hana 93 | } // namespace boost 94 | 95 | #endif // !BOOST_HANA_EXPERIMENTAL_DETAIL_TYPE_NAME_CSTRING_HPP 96 | -------------------------------------------------------------------------------- /src/include/cleantype/details/invoke_result_polyfill.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | // From https://en.cppreference.com/w/cpp/types/result_of 3 | 4 | namespace cleantype 5 | { 6 | #if __cplusplus < 201703L 7 | namespace detail 8 | { 9 | template 10 | struct is_reference_wrapper : std::false_type 11 | { 12 | }; 13 | template 14 | struct is_reference_wrapper> : std::true_type 15 | { 16 | }; 17 | 18 | template 19 | struct invoke_impl 20 | { 21 | template 22 | static auto call(F && f, Args &&... args) 23 | -> decltype(std::forward(f)(std::forward(args)...)); 24 | }; 25 | 26 | template 27 | struct invoke_impl 28 | { 29 | template ::type, 31 | class = typename std::enable_if::value>::type> 32 | static auto get(T && t) -> T &&; 33 | 34 | template ::type, 36 | class = typename std::enable_if::value>::type> 37 | static auto get(T && t) -> decltype(t.get()); 38 | 39 | template ::type, 41 | class = typename std::enable_if::value>::type, 42 | class = typename std::enable_if::value>::type> 43 | static auto get(T && t) -> decltype(*std::forward(t)); 44 | 45 | template ::value>::type> 49 | static auto call(MT1 B::*pmf, T && t, Args &&... args) 50 | -> decltype((invoke_impl::get(std::forward(t)).* 51 | pmf)(std::forward(args)...)); 52 | 53 | template 54 | static auto call(MT B::*pmd, T && t) 55 | -> decltype(invoke_impl::get(std::forward(t)).*pmd); 56 | }; 57 | 58 | template ::type> 59 | auto INVOKE(F && f, Args &&... args) 60 | -> decltype(invoke_impl::call(std::forward(f), std::forward(args)...)); 61 | 62 | } // namespace detail 63 | 64 | // Conforming C++14 implementation (is also a valid C++11 implementation): 65 | namespace detail 66 | { 67 | template 68 | struct invoke_result 69 | { 70 | }; 71 | template 72 | struct invoke_result(), std::declval()...))), 74 | F, 75 | Args...> 76 | { 77 | using type = decltype(detail::INVOKE(std::declval(), std::declval()...)); 78 | }; 79 | } // namespace detail 80 | #endif 81 | 82 | } // namespace cleantype -------------------------------------------------------------------------------- /src/include/cleantype/details/stringutils.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace cleantype 12 | { 13 | namespace stringutils 14 | { 15 | inline std::string remove_spaces_before(const char token, std::string const & str) 16 | { 17 | std::string result; 18 | bool space_before = false; 19 | for (auto c : str) 20 | { 21 | if ((c == token) && space_before) 22 | { 23 | result.pop_back(); 24 | } 25 | result = result + c; 26 | 27 | if (c == ' ') 28 | space_before = true; 29 | else 30 | space_before = false; 31 | } 32 | return result; 33 | } 34 | 35 | inline std::string remove_spaces_after(const char token, std::string const & str) 36 | { 37 | std::string result; 38 | bool token_before = false; 39 | for (auto c : str) 40 | { 41 | result = result + c; 42 | if ((c == ' ') && token_before) 43 | result.pop_back(); 44 | 45 | if (c == token) 46 | token_before = true; 47 | else 48 | token_before = false; 49 | } 50 | return result; 51 | } 52 | 53 | inline std::string remove_spaces_before_after(const char token, std::string const & str) 54 | { 55 | std::string result; 56 | result = remove_spaces_before(token, remove_spaces_after(token, str)); 57 | return result; 58 | } 59 | 60 | inline std::string insert_spaces_before(const char token, std::string const & str) 61 | { 62 | std::string result; 63 | bool space_or_same_token_before = true; 64 | for (auto c : str) 65 | { 66 | if ((c == token) && !(space_or_same_token_before)) 67 | result = result + " "; 68 | result = result + c; 69 | if ((c == ' ') || (c == token)) 70 | space_or_same_token_before = true; 71 | else 72 | space_or_same_token_before = false; 73 | } 74 | return result; 75 | } 76 | 77 | inline std::string insert_spaces_after(const char token, std::string const & str) 78 | { 79 | std::string result; 80 | bool token_before = false; 81 | for (auto c : str) 82 | { 83 | if (token_before && (c != ' ')) 84 | result = result + ' '; 85 | result = result + c; 86 | token_before = (c == token); 87 | } 88 | return result; 89 | } 90 | 91 | inline std::string insert_spaces_before_after(const char token, std::string const & str) 92 | { 93 | std::string result = insert_spaces_before(token, str); 94 | result = insert_spaces_after(token, result); 95 | return result; 96 | } 97 | 98 | inline std::string replace_tokens(std::string const & from, 99 | const std::string & to, 100 | std::string const & xs) 101 | { 102 | if (from.empty()) 103 | return xs; 104 | std::string out = xs; 105 | std::size_t start_pos = 0; 106 | while ((start_pos = out.find(from, start_pos)) != std::string::npos) 107 | { 108 | out.replace(start_pos, from.length(), to); 109 | start_pos += 110 | to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' 111 | } 112 | return out; 113 | } 114 | 115 | inline bool ends_with(std::string const & value, std::string const & ending) 116 | { 117 | if (ending.size() > value.size()) 118 | return false; 119 | return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); 120 | } 121 | 122 | inline bool starts_with(std::string const & value, std::string const & start) 123 | { 124 | return (value.find(start) == 0); 125 | } 126 | 127 | inline bool starts_ends_with(std::string const & value, 128 | std::string const & start, 129 | std::string const & end) 130 | { 131 | return (starts_with(value, start) && ends_with(value, end)); 132 | } 133 | 134 | inline std::string remove_end(std::string const & value, std::string const & ending) 135 | { 136 | assert(ends_with(value, ending)); 137 | std::string r = value.substr(0, value.size() - ending.size()); 138 | return r; 139 | } 140 | 141 | inline std::string remove_start(std::string const & value, std::string const & start) 142 | { 143 | assert(starts_with(value, start)); 144 | std::string r = value.substr(start.size(), value.size() - start.size()); 145 | return r; 146 | } 147 | 148 | inline std::string remove_start_end(std::string const & value, 149 | std::string const & start, 150 | std::string const & end) 151 | { 152 | std::string r = remove_start(value, start); 153 | r = remove_end(r, end); 154 | return r; 155 | } 156 | 157 | inline std::vector split_string(std::string const & s, char delimiter) 158 | { 159 | std::vector tokens; 160 | std::string token; 161 | std::istringstream tokenStream(s); 162 | while (std::getline(tokenStream, token, delimiter)) 163 | tokens.push_back(token); 164 | return tokens; 165 | } 166 | 167 | } // namespace stringutils 168 | } // namespace cleantype 169 | -------------------------------------------------------------------------------- /src/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | function(add_main_tests) 2 | file(GLOB_RECURSE cpp_files ${CMAKE_SOURCE_DIR}/src/tests/*.cpp) 3 | file(GLOB_RECURSE hpp_files ${CMAKE_SOURCE_DIR}/src/include/cleantype/*.hpp) 4 | 5 | set(files ${cpp_files} ${hpp_files}) 6 | 7 | set(doctest_INCLUDES ${CMAKE_SOURCE_DIR}/third_party/doctest/doctest) 8 | set(rangev3_INCLUDES ${CMAKE_SOURCE_DIR}/third_party/tests/range-v3/include) 9 | 10 | add_executable(cleantype_test ${files}) 11 | target_include_directories(cleantype_test PRIVATE ${doctest_INCLUDES} ${rangev3_INCLUDES}) 12 | clean_type_set_target_option(cleantype_test) 13 | source_group(TREE ${CMAKE_SOURCE_DIR}/src/include/ FILES ${hpp_files}) 14 | source_group(TREE ${CMAKE_SOURCE_DIR}/src/tests/ FILES ${cpp_files}) 15 | 16 | add_test(NAME cleantype_test COMMAND cleantype_test) 17 | endfunction() 18 | 19 | add_main_tests() 20 | -------------------------------------------------------------------------------- /src/tests/cleantype_clean_test.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #include "debug_utilities.hpp" 5 | #include "doctest.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | TEST_CASE("CT_show_details") 12 | { 13 | { 14 | int a = 1; 15 | REQUIRE_EQ(CT_show_details(a), "[int] a = 1"); 16 | } 17 | { 18 | std::string s("hello"); 19 | REQUIRE_EQ(CT_show_details(s), "[std::string] s = hello"); 20 | } 21 | { 22 | std::vector v{{1, 2, 3, 4, 5}}; 23 | REQUIRE_EQ(CT_show_details_cont(v), "[std::vector] v = [1, 2, 3, 4, 5]"); 24 | } 25 | { 26 | std::map v{{{"a", 1}, {"b", 2}, {"c", 3}}}; 27 | auto t = CT_show_details_cont(v); 28 | REQUIRE_EQ(CT_show_details_cont(v), 29 | "[std::map] v = [(a, 1), (b, 2), (c, 3)]"); 30 | } 31 | { 32 | std::vector v{{{"a"}, {"b"}, {"c"}}}; 33 | REQUIRE_EQ(CT_show_details(v), "[std::vector] v = [a, b, c]"); 34 | } 35 | { 36 | std::set v{{{"a"}, {"b"}, {"c"}}}; 37 | REQUIRE_EQ(CT_show_details(v), "[std::set] v = [a, b, c]"); 38 | } 39 | } 40 | 41 | template 42 | auto make_test_string_transform(Transform f) 43 | { 44 | return [f](std::string const & input, std::string const & expected_output) { 45 | std::string computed_output = f(input); 46 | if (computed_output != expected_output) 47 | std::cout << "Mince"; 48 | REQUIRE_EQ(computed_output, expected_output); 49 | }; 50 | } 51 | 52 | TEST_CASE("clean_from_values") 53 | { 54 | int a = 3; 55 | int const & b = a; 56 | int const * const c = &a; 57 | char d = 42; 58 | std::vector ee; 59 | const auto & e = ee; 60 | auto computed = cleantype::clean(a, b, c, d, e); 61 | auto expected = std::string( 62 | "int &, int const &, int const * const &, char &, std::vector const &"); 63 | REQUIRE_EQ(computed, expected); 64 | } 65 | 66 | TEST_CASE("clean_typename_from_string") 67 | { 68 | auto make_one_test = make_test_string_transform(cleantype::clean_typestring); 69 | make_one_test(" int ", "int"); 70 | make_one_test("int&", "int &"); 71 | make_one_test("int&&", "int &&"); 72 | make_one_test("std::pair ", "std::pair"); 73 | make_one_test("std::pair ", "std::pair"); 74 | make_one_test("std::pair < std::vector< std::string,int > >", 75 | "std::pair>"); 76 | make_one_test("std::pair < std::vector< std::string > >", 77 | "std::pair>"); 78 | make_one_test("std::__1::basic_string const &", "std::string const &"); 79 | make_one_test("int&", "int &"); 80 | make_one_test("std::string const&", "std::string const &"); 81 | make_one_test( 82 | "class std::basic_string,class std::allocator > " 83 | "const &", 84 | "std::string const &"); 85 | make_one_test("class std::vector > const&", 86 | "std::vector const &"); 87 | } 88 | 89 | void compare_type_full_to_repr(std::string const & type_full, std::string const & expected_repr) 90 | { 91 | std::string type_clean = cleantype::clean_typestring(type_full); 92 | std::string type_west = cleantype::apply_east_const_typelist(type_clean); 93 | std::string expected_repr2 = 94 | cleantype_fp::replace_tokens(std::string(" COMMA "), std::string(", "), expected_repr); 95 | if (type_west != expected_repr2) 96 | std::cout << "Ah"; 97 | REQUIRE_EQ(type_west, expected_repr2); 98 | } 99 | 100 | template 101 | void impl_test_clean_type(std::string const & expectedRepr, T value) 102 | { 103 | std::string type_full = CT_cleantype_full(value); 104 | compare_type_full_to_repr(type_full, expectedRepr); 105 | } 106 | 107 | #define test_clean_type__defaultcontructible(type_definition) \ 108 | { \ 109 | type_definition value = type_definition(); \ 110 | impl_test_clean_type(#type_definition, value); \ 111 | impl_test_clean_type(#type_definition " const &", value); \ 112 | } 113 | 114 | #define COMMA , 115 | 116 | TEST_CASE("clean_typename_from_type") 117 | { 118 | test_clean_type__defaultcontructible(int); 119 | test_clean_type__defaultcontructible(std::vector); 120 | test_clean_type__defaultcontructible(std::pair); 121 | test_clean_type__defaultcontructible( 122 | std::deque>>); 123 | test_clean_type__defaultcontructible(std::set); 124 | test_clean_type__defaultcontructible(std::list); 125 | } 126 | 127 | TEST_CASE("clean_pack") 128 | { 129 | REQUIRE_EQ(cleantype::clean(), "std::string"); 130 | REQUIRE_EQ(cleantype::clean>(), "std::string, std::vector"); 131 | REQUIRE_EQ(cleantype::clean &, int const &, int &&>(), 132 | "std::string, std::vector const &, int const &, int &&"); 133 | } 134 | 135 | TEST_CASE("clean_multiple_args") 136 | { 137 | REQUIRE_EQ(cleantype::clean(std::string("ah"), 1), "std::string, int"); 138 | std::vector v; 139 | REQUIRE_EQ(cleantype::clean(std::string("ah"), &v, 1), "std::string, std::vector *, int"); 140 | } 141 | 142 | TEST_CASE("impl_clean") 143 | { 144 | std::string typ_name = 145 | "std::__1::map>, std::__1::less, " 146 | "std::__1::allocator>>>>"; 148 | std::string type_cleaned = cleantype::clean_typestring(typ_name); 149 | std::string expected = "std::map>"; 150 | REQUIRE_EQ(type_cleaned, expected); 151 | } -------------------------------------------------------------------------------- /src/tests/cleantype_compiler_typename_test.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #include "debug_utilities.hpp" 5 | #include "doctest.h" 6 | #include 7 | #include 8 | 9 | #ifdef _HANA_TN_CAN_CONSTEXPR 10 | 11 | TEST_CASE("cleantype_compiler_typename_test") 12 | { 13 | auto int_type = cleantype::full_compiletime(); 14 | #ifndef _MSC_VER // Visual studio will replace chars by ints... 15 | REQUIRE_EQ(cleantype::full(int_type), "boost::hana::string<'i', 'n', 't'> &"); 16 | #endif 17 | 18 | // Note : there are lots of other tests inside 19 | // src/include/cleantype/details/hana_type_name/tests/type_name_stringliteral_test.cpp 20 | } 21 | 22 | #endif // #ifdef _HANA_TN_CAN_CONSTEXPR 23 | -------------------------------------------------------------------------------- /src/tests/cleantype_config.test.cpp: -------------------------------------------------------------------------------- 1 | #include "doctest.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | TEST_CASE("CleanConfiguration_string_serialize") 8 | { 9 | using namespace nlohmann; 10 | cleantype::CleanConfiguration config_current = cleantype::CleanConfiguration::GlobalConfig(); 11 | json json_data_current = config_current; 12 | 13 | std::string str_example = cleantype::internal::CleanConfigurationExample; 14 | json json_data_example = json::parse(str_example); 15 | 16 | REQUIRE_EQ(json_data_current, json_data_example); 17 | 18 | cleantype::CleanConfiguration config_example = 19 | json_data_example.get(); 20 | REQUIRE_EQ(config_current.suppress_extra_namespaces_, 21 | config_example.suppress_extra_namespaces_); 22 | } 23 | -------------------------------------------------------------------------------- /src/tests/cleantype_eastconst_test.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #include "debug_utilities.hpp" 5 | #include "doctest.h" 6 | #include 7 | 8 | #ifdef _WIN32 9 | #include 10 | #endif 11 | 12 | template 13 | auto make_test_string_transform(Transform f) 14 | { 15 | return [f](std::string const & input, std::string const & expected_output) { 16 | std::string computed_output = f(input); 17 | if (computed_output != expected_output) 18 | DEBUGBREAK; 19 | REQUIRE_EQ(computed_output, expected_output); 20 | }; 21 | } 22 | 23 | TEST_CASE("apply_east_const_typelist") 24 | { 25 | auto make_one_test = make_test_string_transform(cleantype::apply_east_const_typelist); 26 | 27 | // T => T 28 | make_one_test("T", "T"); 29 | // T * => T * 30 | make_one_test("T *", "T *"); 31 | make_one_test("T * &", "T * &"); 32 | 33 | // const T => T const 34 | make_one_test("T const", "T const"); 35 | make_one_test("const T", "T const"); 36 | 37 | // const T & => T const & 38 | make_one_test("T const &", "T const &"); 39 | make_one_test("const T &", "T const &"); 40 | 41 | // const * T => T const * 42 | make_one_test("T const *", "T const *"); 43 | make_one_test("const T *", "T const *"); 44 | 45 | // const T * const => T const * const 46 | make_one_test("T const * const", "T const * const"); 47 | make_one_test("const T * const", "T const * const"); 48 | 49 | // const T * & => T const * & 50 | make_one_test("T const * &", "T const * &"); 51 | make_one_test("const T * &", "T const * &"); 52 | 53 | // const T * const & => T const * const & 54 | make_one_test("const int * const &", "int const * const &"); 55 | } 56 | -------------------------------------------------------------------------------- /src/tests/cleantype_invoke_result_test.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #include "doctest.h" 5 | #include 6 | #include 7 | #include 8 | 9 | auto add_auto_fn(int a, int b) { return a + b; } 10 | 11 | template 12 | auto add_auto_template_fn(U a, V b) 13 | { 14 | return a + b; 15 | } 16 | 17 | int fortytwo(int a, int b) { return a + 42; } 18 | 19 | struct my_functor 20 | { 21 | auto operator()(int a) { return a + 42; } 22 | }; 23 | 24 | TEST_CASE("test_invoke_result") 25 | { 26 | { 27 | // For functions, use < decltype(&f), Args... > 28 | using T = cleantype::invoke_result::type; 29 | static_assert(std::is_same::value, ""); 30 | using U = cleantype::invoke_result_t; 31 | static_assert(std::is_same::value, ""); 32 | } 33 | { 34 | // For auto functions, use < decltype(&f), Args... > 35 | using T = cleantype::invoke_result::type; 36 | static_assert(std::is_same::value, ""); 37 | using U = cleantype::invoke_result_t; 38 | static_assert(std::is_same::value, ""); 39 | } 40 | { 41 | // For templated auto functions: use < decltype(&f), Args... > 42 | // this does *not* work under MSVC, because of a compiler bug (solved in MSVC 2019) 43 | // See 44 | // https://stackoverflow.com/questions/54111146/invoke-result-for-template-function-with-auto-return-type-and-msvc-2017 45 | #ifndef _MSC_VER 46 | using T = cleantype:: 47 | invoke_result), int, double>::type; 48 | static_assert(std::is_same::value, ""); 49 | using U = 50 | cleantype::invoke_result_t), int, double>; 51 | static_assert(std::is_same::value, ""); 52 | #endif 53 | } 54 | { 55 | // For simple lambdas: use < decltype(lambda), Args... > 56 | auto simple_lambda = [](int a) { return a + 42; }; 57 | using T = cleantype::invoke_result::type; 58 | static_assert(std::is_same::value, ""); 59 | using U = cleantype::invoke_result_t; 60 | static_assert(std::is_same::value, ""); 61 | } 62 | { 63 | // For generic lambdas: use < decltype(lambda), Args... > 64 | auto generic_lambda = [](auto a) { return a + 42; }; 65 | using T = cleantype::invoke_result::type; 66 | static_assert(std::is_same::value, ""); 67 | using U = cleantype::invoke_result_t; 68 | static_assert(std::is_same::value, ""); 69 | } 70 | { 71 | // For functors: use < functor, Args... > 72 | using T = cleantype::invoke_result::type; 73 | static_assert(std::is_same::value, ""); 74 | using U = cleantype::invoke_result_t; 75 | static_assert(std::is_same::value, ""); 76 | } 77 | } 78 | 79 | TEST_CASE("test_invoke_result_FN") 80 | { 81 | { 82 | // For functions and auto function: use CT_invoke_result_fn(f, Args...) 83 | using T = CT_invoke_result_fn(fortytwo, int, int); 84 | static_assert(std::is_same::value, ""); 85 | 86 | REQUIRE_EQ(CT_type_fn(fortytwo, int, int), "int"); 87 | } 88 | #ifndef _MSC_VER 89 | { 90 | // For templated auto functions: use CT_invoke_result_fn_template(f, Args...) 91 | using T = CT_invoke_result_fn_template(add_auto_template_fn, int, double); 92 | static_assert(std::is_same::value, ""); 93 | 94 | REQUIRE_EQ(CT_type_fn_template(add_auto_template_fn, int, double), "double"); 95 | } 96 | #else 97 | { 98 | // For templated auto functions under MSVC: 99 | // use CT_invoke_result_fn_template(f, Args...) 100 | // you will need to "help" the compiler before, by calling 101 | // CT_invoke_result_fn_template_memoize 102 | CT_invoke_result_fn_template_memoize(add_auto_template_fn, int, double); 103 | using T = CT_invoke_result_fn_template(add_auto_template_fn, int, double); 104 | static_assert(std::is_same::value, ""); 105 | } 106 | #endif 107 | } 108 | -------------------------------------------------------------------------------- /src/tests/cleantype_lambda_parse_test.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #include "debug_utilities.hpp" 5 | #include "doctest.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | TEST_CASE("split_types") 12 | { 13 | using namespace cleantype::internal; 14 | { 15 | std::string params_str("int, string"); 16 | auto params = split_types(params_str); 17 | std::vector expected{{"int"}, {"string"}}; 18 | REQUIRE_EQ(params, expected); 19 | } 20 | { 21 | std::string params_str( 22 | "int, std::__1::basic_string, " 23 | "std::__1::allocator >, double"); 24 | auto params = split_types(params_str); 25 | std::vector expected{ 26 | {"int"}, 27 | {"std::__1::basic_string, std::__1::allocator " 28 | ">"}, 29 | {"double"}, 30 | }; 31 | REQUIRE_EQ(params, expected); 32 | } 33 | { 34 | std::string params_str(""); 35 | auto params = split_types(params_str); 36 | std::vector expected{""}; 37 | REQUIRE_EQ(params, expected); 38 | } 39 | { 40 | std::string params_str("int"); 41 | auto params = split_types(params_str); 42 | std::vector expected{"int"}; 43 | REQUIRE_EQ(params, expected); 44 | } 45 | { 46 | std::string params_str( 47 | "std::__1::basic_string const &, std::__1::basic_string const &"); 48 | auto params = split_types(params_str); 49 | params = cleantype_fp::transform(cleantype::internal::impl_clean_one_type, params); 50 | std::vector expected{"std::string const &", "std::string const &"}; 51 | REQUIRE_EQ(params, expected); 52 | } 53 | } 54 | 55 | TEST_CASE("extract_parenthesis_content_at_end") 56 | { 57 | std::string input = "ABC(DEF)(GHI)KLM"; 58 | auto r = cleantype::internal::extract_parenthesis_content_at_end(input); 59 | REQUIRE_EQ(r.parenthesis_content, "GHI"); 60 | REQUIRE_EQ(r.remaining_at_start, "ABC(DEF)"); 61 | REQUIRE(r.success); 62 | } 63 | 64 | TEST_CASE("_mem_fn_to_lambda_type") 65 | { 66 | { 67 | std::string memfn_type = 68 | "class std::_Mem_fn (__thiscall " 69 | "::*)(int,int)const >"; 70 | std::string expected = "lambda: (int, int) -> std::pair"; 71 | auto computed = cleantype::internal::_mem_fn_to_lambda_type(memfn_type, true); 72 | REQUIRE_EQ(computed, expected); 73 | } 74 | { 75 | std::string memfn_type = 76 | "std::__1::__mem_fn>, " 78 | "std::__1::less, std::__1::allocator>>>>(_DOCTEST_ANON_FUNC_2()::$_5:: *)(int)const>"; 81 | std::string expected = "lambda: (int) -> std::map>"; 82 | auto computed = cleantype::internal::_mem_fn_to_lambda_type(memfn_type, true); 83 | REQUIRE_EQ(computed, expected); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/tests/cleantype_test_indent.cpp: -------------------------------------------------------------------------------- 1 | #include "doctest.h" 2 | #include 3 | 4 | template 5 | struct Foo 6 | { 7 | }; 8 | 9 | TEST_CASE("indent") 10 | { 11 | { 12 | std::string s("int"); 13 | auto indented = cleantype::indent_type_tree(s); 14 | std::string expected = "int"; 15 | REQUIRE_EQ(indented, expected); 16 | } 17 | 18 | { 19 | std::string s("Foo"); 20 | auto indented = cleantype::indent_type_tree(s); 21 | std::string expected = R"(Foo< 22 | int 23 | >)"; 24 | REQUIRE_EQ(indented, expected); 25 | } 26 | 27 | { 28 | std::string s("Foo"); 29 | auto indented = cleantype::indent_type_tree(s); 30 | std::string expected = R"(Foo< 31 | int, 32 | char 33 | >)"; 34 | REQUIRE_EQ(indented, expected); 35 | } 36 | 37 | { 38 | std::string s("Foo< int, Foo>>"); 39 | auto indented = cleantype::indent_type_tree(s); 40 | std::string expected = R"(Foo< 41 | int, 42 | Foo< 43 | int, 44 | Foo< 45 | std::string, 46 | int 47 | > 48 | > 49 | >)"; 50 | REQUIRE_EQ(indented, expected); 51 | } 52 | 53 | { 54 | std::string s("std::deque>>"); 55 | cleantype::CleanConfiguration::GlobalConfig().indent_depth_limit = 3; 56 | std::string expected("std::deque>>"); 57 | auto indented = cleantype::internal::impl_indent_if_neeeded(s); 58 | REQUIRE_EQ(indented, expected); 59 | } 60 | { 61 | std::string s("std::deque>>"); 62 | std::size_t old_limit = cleantype::CleanConfiguration::GlobalConfig().indent_depth_limit; 63 | cleantype::CleanConfiguration::GlobalConfig().indent_depth_limit = 2; 64 | std::string expected = R"(std::deque< 65 | std::pair< 66 | std::string, 67 | std::map< 68 | int, 69 | int 70 | > 71 | > 72 | >)"; 73 | auto indented = cleantype::internal::impl_indent_if_neeeded(s); 74 | REQUIRE_EQ(indented, expected); 75 | cleantype::CleanConfiguration::GlobalConfig().indent_depth_limit = old_limit; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/tests/debug_utilities.hpp: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #define DEBUGBREAK DebugBreak(); 3 | #else 4 | #include 5 | #define DEBUGBREAK raise(SIGINT); 6 | #endif 7 | 8 | #define LOG(...) std::cout << __VA_ARGS__ << "\n"; 9 | #define LOG_EXPRESSION(...) std::cout << #__VA_ARGS__ << "\n" << __VA_ARGS__ << "\n"; 10 | -------------------------------------------------------------------------------- /src/tests/lambda_generic_test.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #include "doctest.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | TEST_CASE("lambda_generic_clean") 11 | { 12 | { 13 | auto f = [](auto i) { return 2 * i; }; 14 | REQUIRE_EQ(cleantype::lambda_clean(f), "lambda: (int) -> int"); 15 | } 16 | { 17 | auto f = [](auto b) { 18 | std::vector range = fplus::numbers(0, b); 19 | return fplus::pairs_to_map_grouped(fplus::overlapping_pairs_cyclic(range)); 20 | }; 21 | REQUIRE_EQ(cleantype::lambda_clean(f), 22 | "lambda: (int) -> std::map>"); 23 | } 24 | { 25 | auto f = [](auto a, auto b) { return a + b; }; 26 | REQUIRE_EQ(cleantype::lambda_clean(f), "lambda: (int, char) -> int"); 27 | } 28 | } 29 | 30 | TEST_CASE("lambda_generic_1_to_5_params") 31 | { 32 | { 33 | auto f = [](auto i) { return 2 * i; }; 34 | REQUIRE_EQ(CT_type_lambda_generic_fromparams_1(f, 1), "lambda: (int) -> int"); 35 | } 36 | { 37 | auto f = [](auto i, auto j) { return 2 * i + j; }; 38 | REQUIRE_EQ(CT_type_lambda_generic_fromparams_2(f, 1, 1), "lambda: (int, int) -> int"); 39 | } 40 | { 41 | auto f = [](auto i, auto j, auto k) { return 2 * i + j + 3 * k; }; 42 | REQUIRE_EQ(CT_type_lambda_generic_fromparams_3(f, 1, 1, 1), 43 | "lambda: (int, int, int) -> int"); 44 | } 45 | } 46 | 47 | auto lambda_std = [](int a) { return a * a; }; 48 | auto lambda_generic = [](int a) { return a * 2; }; 49 | auto lambda_composed = fplus::fwd::compose(lambda_std, lambda_generic); 50 | 51 | TEST_CASE("lambda_generic_composition") 52 | { 53 | { 54 | REQUIRE_EQ(CT_type_lambda_generic_fromparams_1(lambda_composed, 1), 55 | "lambda: (int &&) -> int"); 56 | } 57 | { 58 | auto local_lambda_std = [](auto a) { return a * a; }; 59 | auto local_lambda_generic = [](auto a) { return a * 2; }; 60 | auto local_lambda_composed = fplus::fwd::compose(local_lambda_std, local_lambda_generic); 61 | REQUIRE_EQ(CT_type_lambda_generic_fromparams_1(local_lambda_composed, 1), 62 | "lambda: (int &&) -> int"); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/tests/lambda_test.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #include "debug_utilities.hpp" 5 | #include "doctest.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef _WIN32 13 | #include 14 | #endif // _WIN32 15 | 16 | template 17 | void test_one_lambda(Lambda f, std::string const & expected_type) 18 | { 19 | const std::string computed_type = CT_show_details_lambda(f); 20 | if (computed_type != expected_type) 21 | DEBUGBREAK; 22 | REQUIRE_EQ(computed_type, expected_type); 23 | } 24 | 25 | #define CT_show_details_lambda2(f) std::string("[") + cleantype::lambda_clean(f) + "] " + #f 26 | 27 | TEST_CASE("log_type_lambda_clean") 28 | { 29 | { 30 | auto f = []() { std::cout << "Hello"; }; 31 | REQUIRE_EQ(CT_show_details_lambda(f), "[lambda: () -> void] f"); 32 | } 33 | { 34 | auto f = []() { return 42u; }; 35 | auto s = CT_show_details_lambda(f); 36 | test_one_lambda(f, "[lambda: () -> unsigned int] f"); 37 | } 38 | { 39 | int c = 5; 40 | auto f = [&c](int a, int b) -> double { return a + b + c; }; 41 | test_one_lambda(f, "[lambda: (int, int) -> double] f"); 42 | } 43 | { 44 | auto f = [](std::string const & a, std::string const & b) -> std::string const { 45 | return a + b; 46 | }; 47 | test_one_lambda( 48 | f, "[lambda: (std::string const &, std::string const &) -> std::string const] f"); 49 | } 50 | { 51 | int c = 5; 52 | auto f = [](int a, int b) { 53 | return std::pair(a + b, cos(a + static_cast(b))); 54 | }; 55 | test_one_lambda(f, "[lambda: (int, int) -> std::pair] f"); 56 | } 57 | { 58 | std::string prefix = "a-"; 59 | auto f = [&prefix](std::string const & s) { return prefix + s; }; 60 | test_one_lambda(f, "[lambda: (std::string const &) -> std::string] f"); 61 | } 62 | } 63 | 64 | TEST_CASE("lambda_generic_or_not") 65 | { 66 | { 67 | auto lambda = [](auto v) { return v + 42; }; 68 | REQUIRE_EQ(cleantype::lambda_full(lambda), "lambda: (int) -> int"); 69 | } 70 | { 71 | auto lambda = [](int v) { return v + 42; }; 72 | REQUIRE_EQ(cleantype::lambda_full(lambda), "lambda: (int) -> int"); 73 | } 74 | } 75 | 76 | TEST_CASE("lambda_clean_flag") 77 | { 78 | { 79 | auto make_repeat_vector = [](auto v, unsigned int nb) { 80 | std::vector r; 81 | for (std::size_t i = 0; i < nb; i++) 82 | r.push_back(v); 83 | return r; 84 | }; 85 | REQUIRE_EQ(cleantype::lambda(make_repeat_vector, true), 86 | "lambda: (std::string, unsigned int) -> std::vector"); 87 | 88 | std::string full_type = cleantype::lambda(make_repeat_vector, false); 89 | // This test is disabled : it is very much compiler and stdlib dependant ! 90 | // REQUIRE_EQ( 91 | // full_type, 92 | // "lambda: (std::__1::basic_string, unsigned int) -> 93 | // std::__1::vector, 94 | // std::__1::allocator > >"); 95 | } 96 | } -------------------------------------------------------------------------------- /src/tests/test_main.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of cleantype: Clean Types for C++ 2 | // Copyright Pascal Thomet - 2018 3 | // Distributed under the Boost Software License, Version 1.0. (see LICENSE.md) 4 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 5 | #include "doctest.h" 6 | #include 7 | 8 | struct ForceEastConst 9 | { 10 | ForceEastConst() { cleantype::CleanConfiguration::GlobalConfig().force_east_const_ = true; } 11 | }; 12 | 13 | ForceEastConst forceEastConst; 14 | -------------------------------------------------------------------------------- /src/tests/test_pack_sizeof.cpp: -------------------------------------------------------------------------------- 1 | // Based on the number of args in the parameter 2 | // packs, the return type will be *different* 3 | // (using these macros for clarity) 4 | #define EMPTY_ARGS 42u 5 | #define NONEMPTY_ARGS false 6 | 7 | /////////////////////////////////////// 8 | // C++ 17 version, using constexpr if => disabled (this project is C++14 compatible) 9 | /////////////////////////////////////// 10 | /* 11 | template 12 | constexpr auto one_cpp17() 13 | { 14 | if constexpr((sizeof...(Args) > 0)) 15 | return NONEMPTY_ARGS; 16 | else 17 | return EMPTY_ARGS; 18 | } 19 | 20 | template 21 | constexpr auto two_cpp17(T t) 22 | { 23 | if constexpr((sizeof...(Args) > 0)) 24 | return NONEMPTY_ARGS; 25 | else 26 | return EMPTY_ARGS; 27 | } 28 | 29 | void test_cpp17() 30 | { 31 | static_assert( one_cpp17() == NONEMPTY_ARGS, "" ); 32 | static_assert( one_cpp17<>() == EMPTY_ARGS, "" ); 33 | static_assert( one_cpp17() == EMPTY_ARGS, "" ); 34 | 35 | static_assert( two_cpp17(42) == EMPTY_ARGS, "" ); 36 | static_assert( two_cpp17<>(42) == EMPTY_ARGS, "" ); 37 | static_assert( two_cpp17(42) == NONEMPTY_ARGS, "" ); 38 | 39 | // Yikes ! when using only one arg (supposedly T), sizeof...(Args) is still > 0 !!! 40 | // => As as consequence, the static_assert below passes: 41 | // static_assert( two_cpp17(42) == NONEMPTY_ARGS, "" ); 42 | // Although, I would have thought otherwise, i.e this : 43 | // static_assert( two_cpp17(42) == EMPTY_ARGS, "" ); 44 | } 45 | */ 46 | 47 | /////////////////////////////////////// 48 | // C++ 14 version, using overloads 49 | /////////////////////////////////////// 50 | template 51 | constexpr auto one_cpp14() 52 | { 53 | return NONEMPTY_ARGS; 54 | } 55 | 56 | template <> 57 | constexpr auto one_cpp14() 58 | { 59 | return EMPTY_ARGS; 60 | } 61 | 62 | // template 63 | // template 64 | template 65 | constexpr auto two_cpp14(T t) 66 | { 67 | return NONEMPTY_ARGS; 68 | } 69 | 70 | template 71 | constexpr auto two_cpp14(T t) 72 | { 73 | return EMPTY_ARGS; 74 | } 75 | 76 | void test_cpp14() 77 | { 78 | static_assert(one_cpp14() == NONEMPTY_ARGS, ""); 79 | static_assert(one_cpp14<>() == EMPTY_ARGS, ""); 80 | static_assert(one_cpp14() == EMPTY_ARGS, ""); 81 | 82 | static_assert(two_cpp14(42) == EMPTY_ARGS, ""); 83 | static_assert(two_cpp14<>(42) == EMPTY_ARGS, ""); 84 | static_assert(two_cpp14(42) == EMPTY_ARGS, ""); 85 | static_assert(two_cpp14(42) == NONEMPTY_ARGS, ""); 86 | static_assert(two_cpp14(42) == NONEMPTY_ARGS, ""); 87 | } 88 | -------------------------------------------------------------------------------- /src/tools/ct_compiler_decipher/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(ct_compiler_decipher ct_compiler_decipher.cpp) 2 | clean_type_set_target_option(ct_compiler_decipher) 3 | install(TARGETS ct_compiler_decipher DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) 4 | 5 | if (NOT MSVC) # ct_compiler_decipher_example contains intentional bugs for demo purposes, but msvc considers them as build failure 6 | add_executable(ct_compiler_decipher_example EXCLUDE_FROM_ALL example/ct_compiler_decipher_example.cpp) 7 | clean_type_set_target_option(ct_compiler_decipher_example) 8 | endif() 9 | -------------------------------------------------------------------------------- /src/tools/ct_compiler_decipher/ct_compiler_decipher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct template_count 6 | { 7 | int nb_open_close = 0; 8 | int nb_remaining_open = 0; 9 | }; 10 | 11 | template_count count_templates(const std::string & compiler_line) 12 | { 13 | template_count r; 14 | for (auto c : compiler_line) 15 | { 16 | if (c == '<') 17 | { 18 | r.nb_open_close++; 19 | r.nb_remaining_open++; 20 | } 21 | if (c == '>') 22 | { 23 | r.nb_open_close++; 24 | r.nb_remaining_open--; 25 | } 26 | } 27 | return r; 28 | } 29 | 30 | bool need_decipher_line(const std::string & compiler_line) 31 | { 32 | auto r = count_templates(compiler_line); 33 | 34 | if (r.nb_remaining_open != 0) 35 | return false; 36 | return (r.nb_open_close >= 2); 37 | } 38 | 39 | std::string msvc_remove_false_open_template(const std::string & compiler_line) 40 | { 41 | #ifdef _MSC_VER 42 | // msvc compile lines start with a false opening template (">") => we skip it 43 | // example : 44 | // 1>F:\dvp\OpenSource\type_name\src\include\cleantype/details/cleantype_fp/fp_base.hpp(38): ... 45 | 46 | auto idx = compiler_line.find(">"); 47 | if ((idx != std::string::npos) && (idx < 5)) 48 | { 49 | std::string cut = compiler_line.substr(idx + 1, compiler_line.size() - idx); 50 | return cut; 51 | } 52 | 53 | return compiler_line; 54 | #else 55 | return compiler_line; 56 | #endif 57 | } 58 | 59 | std::string decipher_line(const std::string & compiler_line) 60 | { 61 | std::string compiler_line_cut = msvc_remove_false_open_template(compiler_line); 62 | bool needs_decipher = need_decipher_line(compiler_line_cut); 63 | if (needs_decipher) 64 | // return std::string("PROCESSED\n") + cleantype::clean_typestring(compiler_line_cut) + 65 | // "\n\n"; 66 | return cleantype::clean_typestring(compiler_line_cut); 67 | else 68 | // return std::string("BARE\n") + compiler_line + "\n\n"; 69 | return compiler_line; 70 | } 71 | 72 | int main() 73 | { 74 | auto prog = cleantype_fp_interact::interact_by_line(decipher_line); 75 | 76 | // Debug version 77 | //{ 78 | // std::string error_log = R"( 79 | // )"; 80 | // std::istringstream is(error_log); 81 | // auto prog = cleantype_fp::interact_by_line(decipher_line, is, std::cout); 82 | //} 83 | 84 | prog(); 85 | } 86 | -------------------------------------------------------------------------------- /src/tools/ct_compiler_decipher/example/ct_compiler_decipher_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Intentionally bad code, in order to get the compiler to spit 7 | // incomprehensible template errors 8 | 9 | auto my_spurious_lambda = [](int a, int b) { 10 | std::map r1; 11 | std::vector r2; 12 | for (std::size_t i = 0; i < b; i++) 13 | r2.push_back(r1); 14 | auto add_one = [](auto x) { return x + 1; }; 15 | auto r3 = fplus::transform(add_one, r2); 16 | return r3; 17 | }; 18 | 19 | int main() { auto v = my_spurious_lambda(1, 3); } 20 | --------------------------------------------------------------------------------