├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CMakeLists.txt ├── ChangeLog ├── LICENSE ├── README.md ├── include └── strong_type │ ├── affine_point.hpp │ ├── arithmetic.hpp │ ├── bicrementable.hpp │ ├── bitarithmetic.hpp │ ├── boolean.hpp │ ├── convertible_to.hpp │ ├── decrementable.hpp │ ├── difference.hpp │ ├── equality.hpp │ ├── equality_with.hpp │ ├── formattable.hpp │ ├── hashable.hpp │ ├── implicitly_convertible_to.hpp │ ├── incrementable.hpp │ ├── indexed.hpp │ ├── invocable.hpp │ ├── iostreamable.hpp │ ├── istreamable.hpp │ ├── iterator.hpp │ ├── ordered.hpp │ ├── ordered_with.hpp │ ├── ostreamable.hpp │ ├── pointer.hpp │ ├── range.hpp │ ├── regular.hpp │ ├── scalable_with.hpp │ ├── semiregular.hpp │ ├── strong_ordering.hpp │ ├── strong_type.hpp │ ├── type.hpp │ └── unique.hpp ├── strong_type-config.cmake └── test ├── CMakeLists.txt ├── catch2.hpp ├── empty.cpp ├── test.cpp ├── test_affine_point.cpp ├── test_arithmetic.cpp ├── test_bicrementable.cpp ├── test_bitarithmetic.cpp ├── test_boolean.cpp ├── test_convertible_to.cpp ├── test_decrementable.cpp ├── test_difference.cpp ├── test_equality.cpp ├── test_equality_with.cpp ├── test_fmt.cpp ├── test_fmt10 └── CMakeLists.txt ├── test_fmt11 └── CMakeLists.txt ├── test_fmt8 └── CMakeLists.txt ├── test_fmt9 └── CMakeLists.txt ├── test_hashable.cpp ├── test_implicitly_convertible_to.cpp ├── test_incrementable.cpp ├── test_indexed.cpp ├── test_invocable.cpp ├── test_iostreamable.cpp ├── test_istreamable.cpp ├── test_iterator.cpp ├── test_main.cpp ├── test_ordered.cpp ├── test_ordered_with.cpp ├── test_ostreamable.cpp ├── test_pointer.cpp ├── test_range.cpp ├── test_regular.cpp ├── test_scalable_with.cpp ├── test_semiregular.cpp ├── test_type.cpp ├── test_unique.cpp └── test_utils.hpp /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build_linux: 7 | runs-on: ubuntu-20.04 8 | container: { image: "ghcr.io/rollbear/${{matrix.config.container}}", options: "--security-opt seccomp=unconfined" } 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | config: 13 | - { cxx: clang++-15, std: 14, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:15" } 14 | - { cxx: clang++-15, std: 17, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:15" } 15 | - { cxx: clang++-15, std: 20, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:15" } 16 | - { cxx: clang++-15, std: 14, container: "clang:15" } 17 | - { cxx: clang++-15, std: 17, container: "clang:15" } 18 | - { cxx: clang++-15, std: 20, container: "clang:15" } 19 | - { cxx: clang++-16, std: 14, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:16" } 20 | - { cxx: clang++-16, std: 17, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:16" } 21 | - { cxx: clang++-16, std: 20, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:16" } 22 | - { cxx: clang++-16, std: 23, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:16" } 23 | - { cxx: clang++-16, std: 14, container: "clang:16" } 24 | - { cxx: clang++-16, std: 17, container: "clang:16" } 25 | - { cxx: clang++-16, std: 20, container: "clang:16" } 26 | - { cxx: clang++-16, std: 23, container: "clang:16" } 27 | - { cxx: clang++-17, std: 14, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:17" } 28 | - { cxx: clang++-17, std: 17, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:17" } 29 | - { cxx: clang++-17, std: 20, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:17" } 30 | - { cxx: clang++-17, std: 23, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:17" } 31 | - { cxx: clang++-17, std: 14, container: "clang:17" } 32 | - { cxx: clang++-17, std: 17, container: "clang:17" } 33 | - { cxx: clang++-17, std: 20, container: "clang:17" } 34 | - { cxx: clang++-17, std: 23, container: "clang:17" } 35 | - { cxx: g++-13, std: 14, container: "gcc:13" } 36 | - { cxx: g++-13, std: 17, container: "gcc:13" } 37 | - { cxx: g++-13, std: 20, container: "gcc:13" } 38 | - { cxx: g++-12, std: 14, container: "gcc:12" } 39 | - { cxx: g++-12, std: 17, container: "gcc:12" } 40 | - { cxx: g++-12, std: 20, container: "gcc:12" } 41 | 42 | - { cxx: clang++-14, std: 14, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:14" } 43 | - { cxx: clang++-14, std: 17, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:14" } 44 | - { cxx: clang++-14, std: 20, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:14" } 45 | - { cxx: clang++-14, std: 14, container: "clang:14" } 46 | - { cxx: clang++-14, std: 17, container: "clang:14" } 47 | - { cxx: clang++-14, std: 20, container: "clang:14" } 48 | 49 | - { cxx: clang++-13, std: 14, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:13" } 50 | - { cxx: clang++-13, std: 17, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:13" } 51 | - { cxx: clang++-13, std: 20, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:13" } 52 | - { cxx: clang++-13, std: 14, container: "clang:13" } 53 | - { cxx: clang++-13, std: 17, container: "clang:13" } 54 | - { cxx: clang++-13, std: 20, container: "clang:13" } 55 | 56 | - { cxx: clang++-12, std: 14, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:12" } 57 | - { cxx: clang++-12, std: 17, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:12" } 58 | - { cxx: clang++-12, std: 20, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:12" } 59 | - { cxx: clang++-12, std: 14, container: "clang:12" } 60 | - { cxx: clang++-12, std: 17, container: "clang:12" } 61 | - { cxx: clang++-12, std: 20, container: "clang:12" } 62 | 63 | - { cxx: clang++-11, std: 14, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:11" } 64 | - { cxx: clang++-11, std: 17, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:11" } 65 | - { cxx: clang++-11, std: 20, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:11" } 66 | - { cxx: clang++-11, std: 14, container: "clang:11" } 67 | - { cxx: clang++-11, std: 17, container: "clang:11" } 68 | - { cxx: clang++-11, std: 20, container: "clang:11" } 69 | 70 | - { cxx: clang++-10, std: 14, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:10" } 71 | - { cxx: clang++-10, std: 17, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:10" } 72 | - { cxx: clang++-10, std: 20, stdlib: "libc++", linker: "-fuse-ld=gold -lc++abi", container: "clang:10" } 73 | - { cxx: clang++-10, std: 14, container: "clang:10" } 74 | - { cxx: clang++-10, std: 17, container: "clang:10" } 75 | - { cxx: clang++-10, std: 20, container: "clang:10" } 76 | - { cxx: g++-10, std: 14, container: "gcc:10" } 77 | - { cxx: g++-10, std: 17, container: "gcc:10" } 78 | - { cxx: g++-10, std: 20, container: "gcc:10" } 79 | - { cxx: clang++-9, std: 14, container: "clang:9" } 80 | - { cxx: clang++-9, std: 17, container: "clang:9" } 81 | - { cxx: g++-9, std: 14, container: "gcc:9" } 82 | - { cxx: g++-9, std: 17, container: "gcc:9" } 83 | - { cxx: clang++-8, std: 14, container: "clang:8" } 84 | - { cxx: clang++-8, std: 17, container: "clang:8" } 85 | - { cxx: g++-8, std: 14, container: "gcc:8" } 86 | - { cxx: g++-8, std: 17, container: "gcc:8" } 87 | - { cxx: g++-7, std: 14, container: "gcc:7" } 88 | - { cxx: g++-7, std: 17, container: "gcc:7" } 89 | 90 | name: "Linux ${{matrix.config.cxx}} C++${{matrix.config.std}} ${{matrix.config.stdlib}}" 91 | steps: 92 | - uses: actions/checkout@v4 93 | 94 | 95 | - name: "setup" 96 | shell: bash 97 | run: | 98 | STDLIB="" 99 | if [ -n "${{matrix.config.stdlib}}" ] 100 | then 101 | STDLIB="-stdlib=libc++" 102 | fi 103 | LIBRARY_PREFIX="/usr/local/lib/c++${{matrix.config.std}}${{matrix.config.stdlib}}" 104 | cmake \ 105 | -S . \ 106 | -B build \ 107 | -DCMAKE_CXX_COMPILER=${{matrix.config.cxx}} \ 108 | -DCMAKE_CXX_STANDARD=${{matrix.config.std}} \ 109 | -DCMAKE_CXX_FLAGS="${STDLIB} -Wall -Wextra -Wconversion -pedantic -Werror --coverage" \ 110 | -DCMAKE_PREFIX_PATH="${LIBRARY_PREFIX}" \ 111 | -DCMAKE_VERBOSE_MAKEFILE=yes \ 112 | -DSTRONG_TYPE_UNIT_TEST=yes \ 113 | -DCMAKE_BUILD_TYPE=Debug 114 | - name: "build" 115 | run: | 116 | cmake --build build -t self_test test_fmt8 test_fmt9 test_fmt10 test_fmt11 117 | 118 | - name: "test" 119 | run: | 120 | ./build/test/self_test -s && \ 121 | ./build/test/test_fmt8/test_fmt8 -s && \ 122 | ./build/test/test_fmt9/test_fmt9 -s && \ 123 | ./build/test/test_fmt10/test_fmt10 -s && \ 124 | ./build/test/test_fmt11/test_fmt11 -s 125 | 126 | - name: "collect coverage" 127 | run: | 128 | COV=`echo ${{matrix.config.cxx}} | grep -q clang && echo "llvm-cov gcov"|| echo gcov` 129 | ${COV} -abcfup `find . -name "test*.gcno"` 130 | ls *.gcov| grep -v 'include#strong_type'|xargs rm 131 | find . -name "test*.gcno" | xargs rm 132 | 133 | - name: "upload coverage" 134 | uses: codecov/codecov-action@v4 135 | with: 136 | name: "Linux ${{matrix.config.cxx}} C++${{matrix.config.std}} ${{matrix.config.stdlib}}" 137 | fail_ci_if_error: false 138 | token: ${{ secrets.CODECOV_TOKEN }} 139 | verbose: true 140 | 141 | build_windows: 142 | runs-on: windows-latest 143 | strategy: 144 | fail-fast: false 145 | matrix: 146 | config: 147 | - { std: 14 } 148 | - { std: 17 } 149 | - { std: 20 } 150 | - { std: 20, import_std: "import std" } 151 | - { std: 23 } 152 | - { std: 23, import_std: "import std" } 153 | 154 | name: "Windows C++${{matrix.config.std}} ${{matrix.config.import_std}}" 155 | steps: 156 | - uses: actions/checkout@v4 157 | 158 | - name: Configure MSVC console (Windows) 159 | uses: ilammy/msvc-dev-cmd@v1 160 | 161 | - name: "setup" 162 | shell: bash 163 | run: | 164 | EXTRA_FLAGS="" 165 | if [ -n "${{matrix.config.import_std}}" ] 166 | then 167 | EXTRA_FLAGS="${EXTRA_FLAGS} -DSTRONG_TYPE_IMPORT_STD_LIBRARY=yes" 168 | fi 169 | cmake \ 170 | -S . \ 171 | -B build \ 172 | -DCMAKE_CXX_COMPILER=cl \ 173 | -DCMAKE_C_COMPILER=cl \ 174 | -DCMAKE_CXX_STANDARD=${{matrix.config.std}} \ 175 | -DCMAKE_CXX_FLAGS="'/permissive- /EHsc /W4 /WX'" \ 176 | -DCMAKE_BUILD_TYPE=Debug \ 177 | -DCMAKE_VERBOSE_MAKEFILE=yes \ 178 | -DSTRONG_TYPE_UNIT_TEST=yes \ 179 | ${EXTRA_FLAGS} \ 180 | -G Ninja 181 | 182 | - name: "build" 183 | shell: bash 184 | run: | 185 | cmake --build build --target self_test 186 | 187 | - name: "test" 188 | shell: bash 189 | run: | 190 | ./build/test/self_test.exe -s 191 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | build 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # strong_type C++14/17/20 strong typedef library 3 | # 4 | # Copyright (C) Björn Fahller 5 | # 6 | # Use, modification and distribution is subject to the 7 | # Boost Software License, Version 1.0. (See accompanying 8 | # file LICENSE_1_0.txt or copy at 9 | # http://www.boost.org/LICENSE_1_0.txt) 10 | # 11 | # Project home: https://github.com/rollbear/strong_type 12 | # 13 | 14 | if(STRONG_TYPE_IMPORT_STD_LIBRARY) 15 | cmake_minimum_required(VERSION 3.30) 16 | else() 17 | cmake_minimum_required(VERSION 3.14) 18 | endif() 19 | 20 | if(STRONG_TYPE_IMPORT_STD_LIBRARY) 21 | if("${CMAKE_GENERATOR}" STREQUAL "Visual Studio 17 2022") 22 | # This can be done before or after project() on MSVC 23 | # It works regardless of CMAKE_EXPERIMENTAL_CXX_IMPORT_STD 24 | # cmake -DSTRONG_TYPE_IMPORT_STD_LIBRARY=ON src_path 25 | set(CMAKE_CXX_SCAN_FOR_MODULES ON) 26 | else() 27 | # This needs to be done before selecting the languages so the project() command 28 | # The CMAKE_EXPERIMENTAL_CXX_IMPORT_STD is required 29 | # To build on calng you need a command line that uses Ninja points to a clang compiler and switched to use the clang libc++ not GCCs libstdc++ 30 | # cmake -G Ninja -DCMAKE_CXX_FLAGS=-stdlib=libc++ -DSTRONG_TYPE_IMPORT_STD_LIBRARY=ON -DCMAKE_CXX_COMPILER=/usr/lib/llvm-20/bin/clang++ src_path 31 | set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "0e5b6991-d74f-4b3d-a41c-cf096e0b2508") 32 | set(CMAKE_CXX_MODULE_STD ON) 33 | endif() 34 | 35 | # We could do C++ 26 here as well, all compilers have agreed to support the std module in C++ 20 but CMake does not support that yet 36 | set(CMAKE_CXX_STANDARD 23) 37 | endif() 38 | 39 | project(strong_type) 40 | 41 | include(GNUInstallDirs) 42 | include(CMakePackageConfigHelpers) 43 | 44 | option(STRONG_TYPE_UNIT_TEST "Decide whether to build unit tests or not" OFF) 45 | 46 | set(STRONG_TYPE_VERSION 15) 47 | set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) 48 | set(MASTER_PROJECT OFF) 49 | if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) 50 | set(MASTER_PROJECT ON) 51 | endif() 52 | 53 | if (${STRONG_TYPE_UNIT_TEST}) 54 | add_subdirectory(test) 55 | endif() 56 | 57 | write_basic_package_version_file( 58 | "${CMAKE_CURRENT_BINARY_DIR}/strong_type/strong_type-config-version.cmake" 59 | VERSION ${STRONG_TYPE_VERSION} 60 | COMPATIBILITY AnyNewerVersion 61 | ARCH_INDEPENDENT) 62 | 63 | add_library(strong_type INTERFACE) 64 | add_library(strong_type::strong_type ALIAS strong_type) 65 | 66 | target_include_directories( 67 | strong_type 68 | INTERFACE 69 | $ 70 | ) 71 | 72 | target_include_directories( 73 | strong_type 74 | INTERFACE 75 | $/include> 76 | ) 77 | 78 | install( 79 | TARGETS 80 | strong_type 81 | EXPORT 82 | strong_type-targets 83 | INCLUDES DESTINATION 84 | include 85 | ) 86 | 87 | install( 88 | EXPORT 89 | strong_type-targets 90 | NAMESPACE 91 | strong_type:: 92 | DESTINATION 93 | lib/cmake/strong_type 94 | ) 95 | install( 96 | FILES 97 | strong_type-config.cmake 98 | "${CMAKE_CURRENT_BINARY_DIR}/strong_type/strong_type-config-version.cmake" 99 | DESTINATION 100 | lib/cmake/strong_type 101 | COMPONENT 102 | Devel 103 | ) 104 | 105 | install( 106 | DIRECTORY 107 | "include/strong_type/" 108 | DESTINATION 109 | "${CMAKE_INSTALL_INCLUDEDIR}/strong_type" 110 | ) 111 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | * Support for "import std;" is enabled by defining the macro 2 | STRONG_TYPE_IMPORT_STD_LIBRARY. This has currently only been 3 | tested on MSVC with C++20 and C++23. Other compilers may or 4 | may not work at this point. You can also run the unit-tests 5 | with "import std;" by adding the CMake option 6 | -DSTRONG_TYPE_IMPORT_STD_LIBRARY=yes 7 | 8 | Huge thangs to David Hunter for contributing this addition. 9 | 10 | * Make strong::range work with range types that only has 11 | const_iterator types (e.g. std::set). Thanks David Feltell for 12 | reporting the problem. 13 | 14 | v15 2024-07-07 15 | 16 | * CMake package is now ARCH_INDEPENDENT, as it should be when it's 17 | header only. Thank you Patrick Kappl for submitting the fix. 18 | 19 | * Much reworked strong::range, which is now compatible with 20 | std::ranges. This was primarily sparked by a discussion with 21 | Harald Achitz. Thank you for bringing up the deficiencies. 22 | 23 | v14 2024-03-05 24 | 25 | * Added several missing [[nodiscard]] 26 | 27 | * .begin() and .end() are now constexpr for strong::range types. Thanks 28 | Harald Achitz for reporting the missing specifiers. 29 | 30 | * Added .size() member to strong::range types, if the underlying type 31 | has a .size() member. Thanks Harald Achitz for the suggestion. 32 | 33 | v13 2023-11-29 34 | 35 | * Added static_assert() messages explaining why a modifier cannot be 36 | used with an underlying type. Thank you SilmaliTech for suggesting 37 | the improvement. 38 | 39 | * Added modifier `invocable` for types with operator(). Thank you 40 | Dominic Koepke for the suggestion and the draft implementation. 41 | 42 | v12 2023-07-20 43 | 44 | * Fixed a bug where fmt formatter function was not const, as it must be 45 | per the documentation. Thank you Tim Blechmann for submitting the 46 | fix. 47 | 48 | * Strong types can be weakly_ordered, strongly_ordered and 49 | partially_ordered, using operator <=> in C++20 and later. Huge thanks 50 | to Björn Schäpers and Tim Blechmann for the suggestions, discussions 51 | and infinite patience. 52 | 53 | v11 2023-05-02 54 | 55 | * A strong type can now be used as an NTTP (Non Type Template Parameter) 56 | 57 | using type = strong::type; 58 | 59 | template 60 | struct S { 61 | constexpr operator int() const { return value_of(t);} 62 | }; 63 | 64 | int main() 65 | { 66 | S obj; 67 | return obj; 68 | } 69 | 70 | Thank you Toni Neubert for the implementation. 71 | 72 | v10 2023-02-03 73 | 74 | * Corrected the test for, and use of, concepts when specializing 75 | std::numeric_limits<> for strong::arithmetic types. Thank you 76 | Björn Schäpers for reporting. 77 | 78 | v9 2023-01-23 79 | 80 | * Lowered the minimum required CMake version to 3.7, unless unit-tests 81 | are built. 82 | 83 | * A type predicate strong::type_is_v has been introduced. 84 | It can be used in compile time tests for generic code to ensure that 85 | a strong type has the necessary modifiers. Example: 86 | 87 | using type = strong::type>; 90 | static_assert(strong::type_is_v); 91 | static_assert(strong::type_is_v>); 92 | 93 | Note that for variadic modifiers like strong::ordered_with<>, the 94 | predicate ensures that all types listed in the test are supported, 95 | so in the example above, the test type_is_v> 96 | is true because 'long' is included in the type definition using 97 | ordered_with. 98 | 99 | There's also a type version, to use as 100 | strong::is_type::value; 101 | 102 | * std::numeric_limits is specialized for types using the 103 | strong::arithmetic modifier. 104 | 105 | * Added missing const&& overloads for value_of() 106 | 107 | v8 2023-01-04 108 | 109 | * Split the header file into one file for each modifier. This can 110 | in some cases speed up compilation times considerably. The header 111 | file still includes everything, so 112 | no changes to existing code is necessary. 113 | 114 | * Added new modifier scalable_with. Allows multiplication and 115 | division with each of the types Ts. If the underlying type can be 116 | divided, the result will be the first of the type in Ts. 117 | 118 | * difference types are conditionally ordered, if the underlying type 119 | supports it. Previously they were always ordered, but e.g. a 2D 120 | vector on a plane is a useful difference type, but it is usually 121 | not ordered. This change allows the vector in 2D space to be used 122 | as a difference type. 123 | 124 | * Add Cmake alias target strong_type::strong_type 125 | 126 | * Use the CMake option -DSTRONG_TYPE_UNIT_TEST=yes to build unit tests 127 | 128 | v7 2022-12-22 129 | 130 | * Added missing #include for . Thank you Björn Schäpers 131 | 132 | * Fixed MSVC check (typo) for constexpr. Thank you Sergei Soloviev 133 | 134 | * Builds cleanly with -Wconversion 135 | 136 | * Strengthened the unit test suite and CI build structure 137 | 138 | v6 2022-10-21 139 | 140 | * Added missing strong::is_ostreamable<> predicate needed for fmtlib 9. 141 | Thank you Tim Blechman @timblechmann for submitting the fix. 142 | 143 | v5 2022-10-20 144 | 145 | * Fixed issue #22, a regression with strong::formattable and fmtlib. 146 | A type that is strong::ostreamable can be formatted with fmt. A 147 | type that is both strong::formattable and strong::ostreamable will 148 | use the type's formatter<> when using fmt. The behaviour of 149 | std::format is unchanged. 150 | 151 | * strong::arithmetic no longer specializes std::is_arithmetic<>. Issue 152 | #19. This is expressively disallowed by the standard and is undefined 153 | behaviour. Sorry for this potentially breaking change, but it was 154 | always wrong. 155 | 156 | v4 2021-08-16 157 | 158 | * strong::affine_point can now be defaulted as 159 | strong::affine_point<>, in which case a difference type will be 160 | generated using the same tag as the strong affine point type. 161 | 162 | * operator% is now conditionally supported for arithmetic types, 163 | provided that the underlying type supports the operation. 164 | 165 | * operator% is also conditionally supported for difference types, 166 | difference % difference => underlying type, and 167 | difference % underlying type => difference. 168 | 169 | * strong::difference is now strong::equality comparable in addition 170 | to being strong::ordered 171 | 172 | v3 2021-08-02 173 | 174 | * increment/decrement operators are now hidden friends 175 | 176 | * swap() is now constexpr. Thanks Björn Schäpers @HazardyKnusperkeks 177 | 178 | * operator() is now noexcept if the underlying type has a 179 | noexcept operator (). Thanks Björn Schäpers @HazardyKnusperkeks 180 | 181 | * Fixed bug where clang++ on Windows wrongly used MSVC work-arounds 182 | 183 | * Fixed bug where non-const operator[] returned const& 184 | 185 | * Use github-actions for CI 186 | 187 | v2 2020-07-13 188 | 189 | * Fixed strong::underlying_type for CRTP defined strong type T 190 | 191 | * Added strong::ordered_with for cross-type ordering 192 | relations. 193 | 194 | * Added strong::equality_with for cross-type equality 195 | comparison operators. 196 | 197 | * Added strong::unique modifier for creating move-only types 198 | 199 | v1 2020-07-11 200 | 201 | * Moved to Boost Software License (BSL) 1.0 license 202 | 203 | * Added convertible_to and implicitly_convertible_to 204 | modifiers. 205 | 206 | * Added strong::uninitialized for when you *want* to create a 207 | variable with unitialized value. Unlike the built in types, 208 | this is explicitly visible at the site of use. 209 | 210 | * Moved many namespace scope functions as inline friends to 211 | avoid ADL issues. 212 | 213 | * Added strong::semiregular and strong::regular since they are 214 | such frequently seen good defaults. 215 | 216 | * Many internal improvements and compiler bug work-arounds. 217 | 218 | * Added strong::iterator and strong::range modifiers. 219 | 220 | * More noexcept() specifiers 221 | 222 | * Removed strong::unique and strong::scoped. They are different 223 | beasts that don't feel quite at home here. Thanks Adi Shavit. 224 | 225 | 0.0.1 2017-09-30 226 | 227 | * First announcement 228 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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. 24 | -------------------------------------------------------------------------------- /include/strong_type/affine_point.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_AFFINE_POINT_HPP 15 | #define STRONG_TYPE_AFFINE_POINT_HPP 16 | 17 | #include "difference.hpp" 18 | 19 | namespace strong 20 | { 21 | template 22 | struct affine_point 23 | { 24 | template 25 | class modifier; 26 | }; 27 | 28 | namespace impl 29 | { 30 | template 31 | struct subtractable : std::false_type {}; 32 | 33 | template 34 | struct subtractable() - std::declval())>> 35 | : std::true_type {}; 36 | } 37 | 38 | 39 | template 40 | template 41 | class affine_point::modifier<::strong::type> 42 | { 43 | using type = ::strong::type; 44 | static_assert(impl::subtractable::value, "it must be possible to subtract instances of your underlying type"); 45 | using base_diff_type = decltype(std::declval() - std::declval()); 46 | public: 47 | using difference = std::conditional_t{}, strong::type, D>; 48 | static_assert(std::is_constructible::value, ""); 49 | STRONG_NODISCARD 50 | friend 51 | STRONG_CONSTEXPR 52 | difference 53 | operator-( 54 | const type& lh, 55 | const type& rh) 56 | { 57 | return difference(value_of(lh) - value_of(rh)); 58 | } 59 | 60 | friend 61 | STRONG_CONSTEXPR 62 | type& 63 | operator+=( 64 | type& lh, 65 | const difference& d) 66 | noexcept(noexcept(value_of(lh) += impl::access(d))) 67 | { 68 | value_of(lh) += impl::access(d); 69 | return lh; 70 | } 71 | 72 | friend 73 | STRONG_CONSTEXPR 74 | type& 75 | operator-=( 76 | type& lh, 77 | const difference& d) 78 | noexcept(noexcept(value_of(lh) -= impl::access(d))) 79 | { 80 | value_of(lh) -= impl::access(d); 81 | return lh; 82 | } 83 | 84 | STRONG_NODISCARD 85 | friend 86 | STRONG_CONSTEXPR 87 | type 88 | operator+( 89 | type lh, 90 | const difference& d) 91 | { 92 | return lh += d; 93 | } 94 | 95 | STRONG_NODISCARD 96 | friend 97 | STRONG_CONSTEXPR 98 | type 99 | operator+( 100 | const difference& d, 101 | type rh) 102 | { 103 | return rh+= d; 104 | } 105 | 106 | STRONG_NODISCARD 107 | friend 108 | STRONG_CONSTEXPR 109 | type 110 | operator-( 111 | type lh, 112 | const difference& d) 113 | { 114 | return lh -= d; 115 | } 116 | }; 117 | 118 | } 119 | #endif //STRONG_TYPE_AFFINE_POINT_HPP 120 | -------------------------------------------------------------------------------- /include/strong_type/arithmetic.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_ARITHMETIC_HPP 15 | #define STRONG_TYPE_ARITHMETIC_HPP 16 | 17 | #include "type.hpp" 18 | 19 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 20 | #include 21 | #endif 22 | 23 | namespace strong 24 | { 25 | struct arithmetic { 26 | template 27 | class modifier 28 | { 29 | static_assert(impl::always_false, 30 | "Underlying type must support arithmeric operations"); 31 | }; 32 | }; 33 | 34 | template 35 | class arithmetic::modifier, impl::void_t() * std::declval() - std::declval() / std::declval())>> 36 | { 37 | using type = strong::type; 38 | public: 39 | STRONG_NODISCARD 40 | friend 41 | STRONG_CONSTEXPR 42 | type 43 | operator-( 44 | const type &lh) 45 | { 46 | return type{-value_of(lh)}; 47 | } 48 | 49 | friend 50 | STRONG_CONSTEXPR 51 | type& 52 | operator+=( 53 | type &lh, 54 | const type &rh) 55 | noexcept(noexcept(value_of(lh) += value_of(rh))) 56 | { 57 | value_of(lh) += value_of(rh); 58 | return lh; 59 | } 60 | 61 | friend 62 | STRONG_CONSTEXPR 63 | type& 64 | operator-=( 65 | type &lh, 66 | const type &rh) 67 | noexcept(noexcept(value_of(lh) -= value_of(rh))) 68 | { 69 | value_of(lh) -= value_of(rh); 70 | return lh; 71 | } 72 | 73 | friend 74 | STRONG_CONSTEXPR 75 | type& 76 | operator*=( 77 | type &lh, 78 | const type &rh) 79 | noexcept(noexcept(value_of(lh) *= value_of(rh))) 80 | { 81 | value_of(lh) *= value_of(rh); 82 | return lh; 83 | } 84 | 85 | friend 86 | STRONG_CONSTEXPR 87 | type& 88 | operator/=( 89 | type &lh, 90 | const type &rh) 91 | noexcept(noexcept(value_of(lh) /= value_of(rh))) 92 | { 93 | value_of(lh) /= value_of(rh); 94 | return lh; 95 | } 96 | 97 | template () % std::declval())> 98 | friend 99 | STRONG_CONSTEXPR 100 | type& 101 | operator%=( 102 | type &lh, 103 | const type &rh) 104 | noexcept(noexcept(value_of(lh) %= value_of(rh))) 105 | { 106 | value_of(lh) %= value_of(rh); 107 | return lh; 108 | } 109 | 110 | STRONG_NODISCARD 111 | friend 112 | STRONG_CONSTEXPR 113 | type 114 | operator+( 115 | type lh, 116 | const type &rh) 117 | { 118 | lh += rh; 119 | return lh; 120 | } 121 | 122 | STRONG_NODISCARD 123 | friend 124 | STRONG_CONSTEXPR 125 | type 126 | operator-( 127 | type lh, 128 | const type &rh) 129 | { 130 | lh -= rh; 131 | return lh; 132 | } 133 | 134 | STRONG_NODISCARD 135 | friend 136 | STRONG_CONSTEXPR 137 | type 138 | operator*( 139 | type lh, 140 | const type &rh) 141 | { 142 | lh *= rh; 143 | return lh; 144 | } 145 | 146 | STRONG_NODISCARD 147 | friend 148 | STRONG_CONSTEXPR 149 | type 150 | operator/( 151 | type lh, 152 | const type &rh) 153 | { 154 | lh /= rh; 155 | return lh; 156 | } 157 | 158 | template () % std::declval())> 159 | STRONG_NODISCARD 160 | friend 161 | STRONG_CONSTEXPR 162 | type 163 | operator%( 164 | type lh, 165 | const type &rh) 166 | { 167 | lh %= rh; 168 | return lh; 169 | } 170 | 171 | }; 172 | 173 | } 174 | 175 | template 176 | #if defined(__cpp_concepts) 177 | requires strong::type_is_v, strong::arithmetic> 178 | class std::numeric_limits> 179 | : public std::numeric_limits 180 | #else 181 | class std::numeric_limits> 182 | : public std::conditional< 183 | strong::type_is_v, strong::arithmetic>, 184 | std::numeric_limits, 185 | std::numeric_limits 186 | >::type 187 | #endif 188 | { 189 | using type = strong::type; 190 | public: 191 | STRONG_NODISCARD static constexpr type min() noexcept { return type{std::numeric_limits::min()};} 192 | STRONG_NODISCARD static constexpr type lowest() noexcept { return type{std::numeric_limits::lowest()};} 193 | STRONG_NODISCARD static constexpr type max() noexcept { return type{std::numeric_limits::max()};} 194 | STRONG_NODISCARD static constexpr type epsilon() noexcept { return type{std::numeric_limits::epsilon()};} 195 | STRONG_NODISCARD static constexpr type round_error() noexcept { return type{std::numeric_limits::round_error()};} 196 | STRONG_NODISCARD static constexpr type infinity() noexcept { return type{std::numeric_limits::infinity()};} 197 | STRONG_NODISCARD static constexpr type quiet_NaN() noexcept { return type{std::numeric_limits::quiet_NaN()};} 198 | STRONG_NODISCARD static constexpr type signaling_NaN() noexcept { return type{std::numeric_limits::signaling_NaN()};} 199 | STRONG_NODISCARD static constexpr type denorm_min() noexcept { return type{std::numeric_limits::denorm_min()};} 200 | }; 201 | #endif //STRONG_TYPE_ARITHMETIC_HPP 202 | -------------------------------------------------------------------------------- /include/strong_type/bicrementable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_BICREMENTABLE_HPP 15 | #define STRONG_TYPE_BICREMENTABLE_HPP 16 | 17 | #include "incrementable.hpp" 18 | #include "decrementable.hpp" 19 | 20 | namespace strong 21 | { 22 | struct bicrementable 23 | { 24 | template 25 | class modifier 26 | : public incrementable::modifier 27 | , public decrementable::modifier 28 | { 29 | }; 30 | }; 31 | 32 | } 33 | #endif //STRONG_TYPE_BICREMENTABLE_HPP 34 | -------------------------------------------------------------------------------- /include/strong_type/bitarithmetic.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_BITARITHMETIC_HPP 15 | #define STRONG_TYPE_BITARITHMETIC_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | struct bitarithmetic 22 | { 23 | template 24 | class modifier 25 | { 26 | static_assert(impl::always_false, 27 | "Underlying type must support bitarithmetic operations &, | and ^"); 28 | }; 29 | template 30 | class modifier, impl::void_t() |= std::declval()) &= std::declval()) ^= std::declval())>> 31 | { 32 | using type = strong::type; 33 | public: 34 | friend 35 | STRONG_CONSTEXPR 36 | type& 37 | operator&=( 38 | type &lh, 39 | const type &rh) 40 | noexcept(noexcept(value_of(lh) &= value_of(rh))) 41 | { 42 | value_of(lh) = T(value_of(lh) & value_of(rh)); 43 | return lh; 44 | } 45 | 46 | friend 47 | STRONG_CONSTEXPR 48 | type& 49 | operator|=( 50 | type &lh, 51 | const type &rh) 52 | noexcept(noexcept(value_of(lh) |= value_of(rh))) 53 | { 54 | value_of(lh) = T(value_of(lh) | value_of(rh)); 55 | return lh; 56 | } 57 | 58 | friend 59 | STRONG_CONSTEXPR 60 | type& 61 | operator^=( 62 | type &lh, 63 | const type &rh) 64 | noexcept(noexcept(value_of(lh) ^= value_of(rh))) 65 | { 66 | value_of(lh) = T(value_of(lh) ^ value_of(rh)); 67 | return lh; 68 | } 69 | 70 | template 71 | friend 72 | STRONG_CONSTEXPR 73 | type& 74 | operator<<=( 75 | type &lh, 76 | C c) 77 | noexcept(noexcept(value_of(lh) <<= c)) 78 | { 79 | value_of(lh) = T(value_of(lh) << c); 80 | return lh; 81 | } 82 | 83 | template 84 | friend 85 | STRONG_CONSTEXPR 86 | type& 87 | operator>>=( 88 | type &lh, 89 | C c) 90 | noexcept(noexcept(value_of(lh) >>= c)) 91 | { 92 | value_of(lh) = T(value_of(lh) >> c); 93 | return lh; 94 | } 95 | 96 | STRONG_NODISCARD 97 | friend 98 | STRONG_CONSTEXPR 99 | type 100 | operator~( 101 | const type &lh) 102 | { 103 | auto v = value_of(lh); 104 | return type(T(~v)); 105 | } 106 | 107 | STRONG_NODISCARD 108 | friend 109 | STRONG_CONSTEXPR 110 | type 111 | operator&( 112 | type lh, 113 | const type &rh) 114 | { 115 | lh &= rh; 116 | return lh; 117 | } 118 | 119 | STRONG_NODISCARD 120 | friend 121 | STRONG_CONSTEXPR 122 | type 123 | operator|( 124 | type lh, 125 | const type &rh) 126 | { 127 | lh |= rh; 128 | return lh; 129 | } 130 | 131 | STRONG_NODISCARD 132 | friend 133 | STRONG_CONSTEXPR 134 | type 135 | operator^( 136 | type lh, 137 | const type &rh) 138 | { 139 | lh ^= rh; 140 | return lh; 141 | } 142 | 143 | template 144 | STRONG_NODISCARD 145 | friend 146 | STRONG_CONSTEXPR 147 | type 148 | operator<<( 149 | type lh, 150 | C c) 151 | { 152 | lh <<= c; 153 | return lh; 154 | } 155 | 156 | template 157 | STRONG_NODISCARD 158 | friend 159 | STRONG_CONSTEXPR 160 | type 161 | operator>>( 162 | type lh, 163 | C c) 164 | { 165 | lh >>= c; 166 | return lh; 167 | } 168 | }; 169 | }; 170 | 171 | } 172 | #endif //STRONG_TYPE_BITARITHMETIC_HPP 173 | -------------------------------------------------------------------------------- /include/strong_type/boolean.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_BOOLEAN_HPP 15 | #define STRONG_TYPE_BOOLEAN_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | struct boolean 22 | { 23 | template 24 | class modifier 25 | { 26 | static_assert(impl::always_false, 27 | "Underlying type must be convertible to bool"); 28 | }; 29 | template 30 | class modifier(std::declval>()))>> 31 | { 32 | public: 33 | STRONG_NODISCARD 34 | explicit 35 | STRONG_CONSTEXPR 36 | operator bool() 37 | const 38 | noexcept(noexcept(static_cast(value_of(std::declval())))) 39 | { 40 | const auto& self = static_cast(*this); 41 | return static_cast(value_of(self)); 42 | } 43 | }; 44 | }; 45 | 46 | } 47 | #endif //STRONG_TYPE_BOOLEAN_HPP 48 | -------------------------------------------------------------------------------- /include/strong_type/convertible_to.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_CONVERTIBLE_TO_HPP 15 | #define STRONG_TYPE_CONVERTIBLE_TO_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | namespace impl 22 | { 23 | template 24 | struct converter 25 | { 26 | static_assert(always_false, 27 | "Underlying type must be convertible to target type"); 28 | }; 29 | template 30 | struct converter< 31 | strong::type, 32 | D, 33 | impl::void_t(std::declval()))> 34 | > 35 | { 36 | STRONG_CONSTEXPR explicit operator D() const 37 | noexcept(noexcept(static_cast(std::declval()))) 38 | { 39 | auto& self = static_cast&>(*this); 40 | return static_cast(value_of(self)); 41 | } 42 | }; 43 | 44 | } 45 | 46 | template 47 | struct convertible_to 48 | { 49 | template 50 | struct modifier : impl::converter... 51 | { 52 | }; 53 | }; 54 | 55 | } 56 | #endif //STRONG_TYPE_CONVERTIBLE_TO_HPP 57 | -------------------------------------------------------------------------------- /include/strong_type/decrementable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_DECREMENTABLE_HPP 15 | #define STRONG_TYPE_DECREMENTABLE_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | struct decrementable 22 | { 23 | template 24 | class modifier 25 | { 26 | static_assert(impl::always_false, 27 | "underlying type must be decrementable"); 28 | }; 29 | template 30 | class modifier&>())>> 31 | { 32 | public: 33 | friend 34 | STRONG_CONSTEXPR 35 | T& 36 | operator--(T& t) 37 | noexcept(noexcept(--std::declval().value_of())) 38 | { 39 | --value_of(t); 40 | return t; 41 | } 42 | 43 | friend 44 | STRONG_CONSTEXPR 45 | T 46 | operator--(T& t, int) 47 | { 48 | auto copy = t; 49 | --t; 50 | return copy; 51 | } 52 | }; 53 | }; 54 | 55 | } 56 | #endif //STRONG_TYPE_DECREMENTABLE_HPP 57 | -------------------------------------------------------------------------------- /include/strong_type/difference.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_DIFFERENCE_HPP 15 | #define STRONG_TYPE_DIFFERENCE_HPP 16 | 17 | #include "ordered.hpp" 18 | #include "equality.hpp" 19 | 20 | namespace strong 21 | { 22 | namespace impl 23 | { 24 | struct conditionally_ordered 25 | { 26 | template 27 | class modifier; 28 | }; 29 | template 30 | class conditionally_ordered::modifier<::strong::type> 31 | { 32 | using type = ::strong::type; 33 | public: 34 | template 35 | STRONG_NODISCARD 36 | friend 37 | STRONG_CONSTEXPR 38 | auto 39 | operator<( 40 | const type& lh, 41 | const type& rh) 42 | noexcept(noexcept(std::declval() < std::declval())) 43 | -> decltype(std::declval() < std::declval()) 44 | { 45 | return value_of(lh) < value_of(rh); 46 | } 47 | template 48 | STRONG_NODISCARD 49 | friend 50 | STRONG_CONSTEXPR 51 | auto 52 | operator<=( 53 | const type& lh, 54 | const type& rh) 55 | noexcept(noexcept(std::declval() <= std::declval())) 56 | -> decltype(std::declval() <= std::declval()) 57 | { 58 | return value_of(lh) <= value_of(rh); 59 | } 60 | template 61 | STRONG_NODISCARD 62 | friend 63 | STRONG_CONSTEXPR 64 | auto 65 | operator>( 66 | const type& lh, 67 | const type& rh) 68 | noexcept(noexcept(std::declval() > std::declval())) 69 | -> decltype(std::declval() > std::declval()) 70 | { 71 | return value_of(lh) > value_of(rh); 72 | } 73 | template 74 | STRONG_NODISCARD 75 | friend 76 | STRONG_CONSTEXPR 77 | auto 78 | operator>=( 79 | const type& lh, 80 | const type& rh) 81 | noexcept(noexcept(std::declval() >= std::declval())) 82 | -> decltype(std::declval() >= std::declval()) 83 | { 84 | return value_of(lh) >= value_of(rh); 85 | } 86 | }; 87 | } 88 | struct difference 89 | { 90 | template 91 | class modifier; 92 | }; 93 | 94 | template 95 | class difference::modifier<::strong::type> 96 | : public impl::conditionally_ordered::modifier<::strong::type> 97 | , public equality::modifier<::strong::type> 98 | { 99 | using type = ::strong::type; 100 | public: 101 | friend 102 | STRONG_CONSTEXPR 103 | type& operator+=(type& lh, const type& rh) 104 | noexcept(noexcept(value_of(lh) += value_of(rh))) 105 | { 106 | value_of(lh) += value_of(rh); 107 | return lh; 108 | } 109 | 110 | friend 111 | STRONG_CONSTEXPR 112 | type& operator-=(type& lh, const type& rh) 113 | noexcept(noexcept(value_of(lh) -= value_of(rh))) 114 | { 115 | value_of(lh) -= value_of(rh); 116 | return lh; 117 | } 118 | 119 | friend 120 | STRONG_CONSTEXPR 121 | type& operator*=(type& lh, const T& rh) 122 | noexcept(noexcept(value_of(lh) *= rh)) 123 | { 124 | value_of(lh) *= rh; 125 | return lh; 126 | } 127 | 128 | friend 129 | STRONG_CONSTEXPR 130 | type& operator/=(type& lh, const T& rh) 131 | noexcept(noexcept(value_of(lh) /= rh)) 132 | { 133 | value_of(lh) /= rh; 134 | return lh; 135 | } 136 | 137 | template ()%= std::declval())> 138 | friend 139 | STRONG_CONSTEXPR 140 | type& operator%=(type& lh, const T& rh) 141 | noexcept(noexcept(value_of(lh) %= rh)) 142 | { 143 | value_of(lh)%= rh; 144 | return lh; 145 | } 146 | 147 | STRONG_NODISCARD 148 | friend 149 | STRONG_CONSTEXPR 150 | type operator+(type lh, const type& rh) 151 | { 152 | lh += rh; 153 | return lh; 154 | } 155 | 156 | STRONG_NODISCARD 157 | friend 158 | STRONG_CONSTEXPR 159 | type operator-(type lh, const type& rh) 160 | { 161 | lh -= rh; 162 | return lh; 163 | } 164 | 165 | STRONG_NODISCARD 166 | friend 167 | STRONG_CONSTEXPR 168 | type operator*(type lh, const T& rh) 169 | { 170 | lh *= rh; 171 | return lh; 172 | } 173 | 174 | STRONG_NODISCARD 175 | friend 176 | STRONG_CONSTEXPR 177 | type operator*(const T& lh, type rh) 178 | { 179 | rh *= lh; 180 | return rh; 181 | } 182 | 183 | STRONG_NODISCARD 184 | friend 185 | STRONG_CONSTEXPR 186 | type operator/(type lh, const T& rh) 187 | { 188 | lh /= rh; 189 | return lh; 190 | } 191 | 192 | STRONG_NODISCARD 193 | friend 194 | STRONG_CONSTEXPR 195 | T operator/(const type& lh, const type& rh) 196 | { 197 | return value_of(lh) / value_of(rh); 198 | } 199 | 200 | template () %= std::declval())> 201 | STRONG_NODISCARD 202 | friend 203 | STRONG_CONSTEXPR 204 | type operator%(type lh, const T& rh) 205 | noexcept(noexcept(lh%= rh)) 206 | { 207 | lh %= rh; 208 | return lh; 209 | } 210 | 211 | template () % std::declval())> 212 | STRONG_NODISCARD 213 | friend 214 | STRONG_CONSTEXPR 215 | T operator%(type lh, type rh) 216 | noexcept(noexcept(value_of(lh) % value_of(rh))) 217 | { 218 | return value_of(lh) % value_of(rh); 219 | } 220 | }; 221 | 222 | } 223 | #endif //STRONG_TYPE_DIFFERENCE_HPP 224 | -------------------------------------------------------------------------------- /include/strong_type/equality.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_EQUALITY_HPP 15 | #define STRONG_TYPE_EQUALITY_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | struct equality 22 | { 23 | template 24 | class modifier { 25 | static_assert(impl::always_false, 26 | "Underlying type must be equality comparable"); 27 | }; 28 | }; 29 | 30 | 31 | template 32 | class equality::modifier< 33 | ::strong::type, 34 | impl::void_t() == std::declval())> 35 | > 36 | { 37 | using type = ::strong::type; 38 | public: 39 | STRONG_NODISCARD 40 | friend 41 | STRONG_CONSTEXPR 42 | auto 43 | operator==( 44 | const type& lh, 45 | const type& rh) 46 | noexcept(noexcept(std::declval() == std::declval())) 47 | -> decltype(std::declval() == std::declval()) 48 | { 49 | return value_of(lh) == value_of(rh); 50 | } 51 | 52 | STRONG_NODISCARD 53 | friend 54 | STRONG_CONSTEXPR 55 | auto 56 | operator!=( 57 | const type& lh, 58 | const type& rh) 59 | noexcept(noexcept(std::declval() != std::declval())) 60 | -> decltype(std::declval() != std::declval()) 61 | { 62 | return value_of(lh) != value_of(rh); 63 | } 64 | }; 65 | 66 | } 67 | #endif //STRONG_TYPE_EQUALITY_HPP 68 | -------------------------------------------------------------------------------- /include/strong_type/equality_with.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_EQUALITY_WITH_HPP 15 | #define STRONG_TYPE_EQUALITY_WITH_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | namespace impl 22 | { 23 | template 24 | class typed_equality { 25 | static_assert(impl::always_false, 26 | "Underlying type must be equality comparable with target type"); 27 | }; 28 | 29 | template 30 | class typed_equality< 31 | T, 32 | Other, 33 | impl::void_t&>() == std::declval&>())> 34 | > 35 | { 36 | private: 37 | using TT = underlying_type_t; 38 | using OT = underlying_type_t; 39 | public: 40 | STRONG_NODISCARD 41 | friend 42 | STRONG_CONSTEXPR 43 | auto operator==(const T& lh, const Other& rh) 44 | noexcept(noexcept(std::declval() == std::declval())) 45 | -> decltype(std::declval() == std::declval()) 46 | { 47 | return value_of(lh) == impl::access(rh); 48 | } 49 | STRONG_NODISCARD 50 | friend 51 | STRONG_CONSTEXPR 52 | auto operator==(const Other& lh, const T& rh) 53 | noexcept(noexcept(std::declval() == std::declval())) 54 | -> decltype(std::declval() == std::declval()) 55 | { 56 | return impl::access(lh) == value_of(rh) ; 57 | } 58 | STRONG_NODISCARD 59 | friend 60 | STRONG_CONSTEXPR 61 | auto operator!=(const T& lh, const Other rh) 62 | noexcept(noexcept(std::declval() != std::declval())) 63 | -> decltype(std::declval() != std::declval()) 64 | { 65 | return value_of(lh) != impl::access(rh); 66 | } 67 | STRONG_NODISCARD 68 | friend 69 | STRONG_CONSTEXPR 70 | auto operator!=(const Other& lh, const T& rh) 71 | noexcept(noexcept(std::declval() != std::declval())) 72 | -> decltype(std::declval() != std::declval()) 73 | { 74 | return impl::access(lh) != value_of(rh) ; 75 | } 76 | }; 77 | } 78 | 79 | template 80 | struct equality_with 81 | { 82 | template 83 | class modifier : public impl::typed_equality... 84 | { 85 | }; 86 | }; 87 | 88 | } 89 | #endif //STRONG_TYPE_EQUALITY_WITH_HPP 90 | -------------------------------------------------------------------------------- /include/strong_type/formattable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_FORMATTABLE_HPP 15 | #define STRONG_TYPE_FORMATTABLE_HPP 16 | 17 | #include "type.hpp" 18 | 19 | #ifndef STRONG_HAS_STD_FORMAT 20 | #if __has_include() 21 | #include 22 | #if defined(__cpp_lib_format) && __cpp_lib_format >= 201907 23 | #define STRONG_HAS_STD_FORMAT 1 24 | #endif 25 | #endif 26 | #endif 27 | 28 | #ifndef STRONG_HAS_STD_FORMAT 29 | #define STRONG_HAS_STD_FORMAT 0 30 | #endif 31 | 32 | #ifndef STRONG_HAS_FMT_FORMAT 33 | #if __has_include() 34 | #define STRONG_HAS_FMT_FORMAT 1 35 | #else 36 | #define STRONG_HAS_FMT_FORMAT 0 37 | #endif 38 | #endif 39 | 40 | #if STRONG_HAS_STD_FORMAT 41 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 42 | #include 43 | #endif 44 | #endif 45 | 46 | #if STRONG_HAS_FMT_FORMAT 47 | #include "ostreamable.hpp" 48 | #include 49 | #include 50 | 51 | #endif 52 | 53 | namespace strong 54 | { 55 | 56 | struct formattable 57 | { 58 | template 59 | class modifier{}; 60 | }; 61 | 62 | template 63 | using is_formattable = std::is_base_of, T>; 64 | 65 | } 66 | 67 | 68 | #if STRONG_HAS_STD_FORMAT 69 | 70 | namespace std 71 | { 72 | template 73 | requires std::is_base_of_v<::strong::formattable::modifier<::strong::type>, 74 | ::strong::type> 75 | struct formatter<::strong::type, Char> : formatter 76 | { 77 | template 78 | STRONG_CONSTEXPR 79 | decltype(auto) 80 | format(const Type& t, FormatContext& fc) const 81 | noexcept(noexcept(std::declval>().format(std::declval(), fc))) 82 | { 83 | return formatter::format(value_of(t), fc); 84 | } 85 | 86 | template 87 | STRONG_CONSTEXPR 88 | decltype(auto) 89 | format(const Type& t, FormatContext& fc) 90 | noexcept(noexcept(std::declval>().format(std::declval(), fc))) 91 | { 92 | return formatter::format(value_of(t), fc); 93 | } 94 | }; 95 | } 96 | #endif 97 | 98 | #if STRONG_HAS_FMT_FORMAT 99 | 100 | namespace strong { 101 | 102 | template 103 | struct formatter; 104 | 105 | template 106 | struct formatter, Char> : fmt::formatter 107 | { 108 | template 109 | STRONG_CONSTEXPR 110 | decltype(auto) 111 | format(const Type& t, FormatContext& fc) const 112 | noexcept(noexcept(std::declval>().format(std::declval(), fc))) 113 | { 114 | return fmt::formatter::format(value_of(t), fc); 115 | } 116 | 117 | template 118 | STRONG_CONSTEXPR 119 | decltype(auto) 120 | format(const Type& t, FormatContext& fc) 121 | noexcept(noexcept(std::declval>().format(std::declval(), fc))) 122 | { 123 | return fmt::formatter::format(value_of(t), fc); 124 | } 125 | }; 126 | 127 | #if FMT_VERSION >= 90000 128 | 129 | template ::value> 130 | struct select_formatter; 131 | 132 | template 133 | struct select_formatter 134 | { 135 | using type = formatter; 136 | }; 137 | 138 | template 139 | struct select_formatter 140 | { 141 | using type = fmt::ostream_formatter; 142 | }; 143 | 144 | #endif 145 | } 146 | namespace fmt 147 | { 148 | #if FMT_VERSION >= 90000 149 | template 150 | struct formatter<::strong::type, 151 | Char, 152 | ::strong::impl::void_t>::value || 153 | ::strong::is_formattable<::strong::type>::value>>> 154 | : ::strong::select_formatter<::strong::type, Char>::type 155 | { 156 | }; 157 | #else 158 | template 159 | struct formatter<::strong::type, 160 | Char, 161 | ::strong::impl::void_t>::value>> 162 | > 163 | : ::strong::formatter<::strong::type, Char> 164 | { 165 | }; 166 | #endif 167 | 168 | } 169 | #endif 170 | 171 | #endif //STRONG_TYPE_FORMATTABLE_HPP 172 | -------------------------------------------------------------------------------- /include/strong_type/hashable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_HASHABLE_HPP 15 | #define STRONG_TYPE_HASHABLE_HPP 16 | 17 | #include "type.hpp" 18 | 19 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 20 | #include 21 | #endif 22 | 23 | namespace strong 24 | { 25 | struct hashable 26 | { 27 | template 28 | class modifier{}; 29 | }; 30 | 31 | } 32 | 33 | namespace std { 34 | template 35 | struct hash<::strong::type> 36 | : std::conditional_t< 37 | std::is_base_of< 38 | ::strong::hashable::modifier< 39 | ::strong::type 40 | >, 41 | ::strong::type 42 | >::value, 43 | hash, 44 | std::false_type> 45 | { 46 | using type = ::strong::type; 47 | 48 | STRONG_NODISCARD 49 | decltype(auto) 50 | operator()( 51 | const ::strong::hashable::modifier &t) 52 | const 53 | noexcept(noexcept(std::declval>()( 54 | value_of(std::declval())))) 55 | { 56 | auto &tt = static_cast(t); 57 | return hash::operator()(value_of(tt)); 58 | } 59 | }; 60 | } 61 | #endif //STRONG_TYPE_HASHABLE_HPP 62 | -------------------------------------------------------------------------------- /include/strong_type/implicitly_convertible_to.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP 15 | #define STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | namespace impl { 22 | 23 | template 24 | struct implicit_converter 25 | { 26 | static_assert(impl::always_false, 27 | "Underlying type must be convertible to target type"); 28 | }; 29 | template 30 | struct implicit_converter< 31 | strong::type, 32 | D, 33 | void_t(std::declval()))> 34 | > 35 | { 36 | STRONG_CONSTEXPR operator D() const 37 | noexcept(noexcept(static_cast(std::declval()))) 38 | { 39 | auto& self = static_cast&>(*this); 40 | return static_cast(value_of(self)); 41 | } 42 | }; 43 | } 44 | 45 | template 46 | struct implicitly_convertible_to 47 | { 48 | template 49 | struct modifier : impl::implicit_converter... 50 | { 51 | }; 52 | }; 53 | 54 | } 55 | #endif //STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP 56 | -------------------------------------------------------------------------------- /include/strong_type/incrementable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_INCREMENTABLE_HPP 15 | #define STRONG_TYPE_INCREMENTABLE_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong { 20 | struct incrementable 21 | { 22 | template 23 | class modifier 24 | { 25 | static_assert(impl::always_false, 26 | "Underlying type must be incrementable"); 27 | }; 28 | template 29 | class modifier&>())>> 30 | { 31 | public: 32 | friend 33 | STRONG_CONSTEXPR 34 | T& 35 | operator++(T& t) 36 | noexcept(noexcept(++std::declval().value_of())) 37 | { 38 | ++value_of(t); 39 | return t; 40 | } 41 | 42 | friend 43 | STRONG_CONSTEXPR 44 | T 45 | operator++(T& t, int) 46 | { 47 | auto copy = t; 48 | ++t; 49 | return copy; 50 | } 51 | }; 52 | }; 53 | 54 | } 55 | #endif //STRONG_TYPE_INCREMENTABLE_HPP 56 | -------------------------------------------------------------------------------- /include/strong_type/indexed.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_INDEXED_HPP 15 | #define STRONG_TYPE_INDEXED_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | template 22 | struct indexed 23 | { 24 | template 25 | class modifier 26 | { 27 | static_assert(impl::always_false, 28 | "Underlying type must support indexing using operator[]"); 29 | }; 30 | }; 31 | 32 | template <> 33 | struct indexed { 34 | template 35 | class modifier; 36 | 37 | template 38 | class modifier> { 39 | using ref = T&; 40 | using cref = const T&; 41 | using rref = T&&; 42 | using type = strong::type; 43 | public: 44 | template 45 | STRONG_NODISCARD 46 | auto 47 | operator[]( 48 | const I &i) 49 | const & 50 | noexcept(noexcept(std::declval()[impl::access(i)])) 51 | -> decltype(std::declval()[impl::access(i)]) { 52 | auto& self = static_cast(*this); 53 | return value_of(self)[impl::access(i)]; 54 | } 55 | 56 | template 57 | STRONG_NODISCARD 58 | auto 59 | operator[]( 60 | const I &i) 61 | & 62 | noexcept(noexcept(std::declval()[impl::access(i)])) 63 | -> decltype(std::declval()[impl::access(i)]) { 64 | auto& self = static_cast(*this); 65 | return value_of(self)[impl::access(i)]; 66 | } 67 | 68 | template 69 | STRONG_NODISCARD 70 | auto 71 | operator[]( 72 | const I &i) 73 | && 74 | noexcept(noexcept(std::declval()[impl::access(i)])) 75 | -> decltype(std::declval()[impl::access(i)]) { 76 | auto& self = static_cast(*this); 77 | return value_of(std::move(self))[impl::access(i)]; 78 | } 79 | 80 | template 81 | STRONG_NODISCARD 82 | auto 83 | at( 84 | const I &i) 85 | const & 86 | -> decltype(std::declval().at(impl::access(i))) { 87 | auto& self = static_cast(*this); 88 | return value_of(self).at(impl::access(i)); 89 | } 90 | 91 | template 92 | STRONG_NODISCARD 93 | auto 94 | at( 95 | const I &i) 96 | & 97 | -> decltype(std::declval().at(impl::access(i))) { 98 | auto& self = static_cast(*this); 99 | return value_of(self).at(impl::access(i)); 100 | } 101 | 102 | template 103 | STRONG_NODISCARD 104 | auto 105 | at( 106 | const I &i) 107 | && 108 | -> decltype(std::declval().at(impl::access(i))) { 109 | auto& self = static_cast(*this); 110 | return value_of(std::move(self)).at(impl::access(i)); 111 | } 112 | }; 113 | }; 114 | 115 | template 116 | template 117 | class indexed::modifier< 118 | type, 119 | impl::void_t< decltype( std::declval()[std::declval>()] ) > 120 | > 121 | { 122 | using type = ::strong::type; 123 | public: 124 | STRONG_NODISCARD 125 | auto 126 | operator[]( 127 | const I& i) 128 | const & 129 | noexcept(noexcept(std::declval()[impl::access(i)])) 130 | -> decltype(std::declval()[impl::access(i)]) 131 | { 132 | auto& self = static_cast(*this); 133 | return value_of(self)[impl::access(i)]; 134 | } 135 | 136 | STRONG_NODISCARD 137 | auto 138 | operator[]( 139 | const I& i) 140 | & 141 | noexcept(noexcept(std::declval()[impl::access(i)])) 142 | -> decltype(std::declval()[impl::access(i)]) 143 | { 144 | auto& self = static_cast(*this); 145 | return value_of(self)[impl::access(i)]; 146 | } 147 | 148 | STRONG_NODISCARD 149 | auto 150 | operator[]( 151 | const I& i) 152 | && 153 | noexcept(noexcept(std::declval()[impl::access(i)])) 154 | -> decltype(std::declval()[impl::access(i)]) 155 | { 156 | auto& self = static_cast(*this); 157 | return value_of(std::move(self))[impl::access(i)]; 158 | } 159 | 160 | template 161 | STRONG_NODISCARD 162 | auto 163 | at( 164 | const I& i) 165 | const & 166 | -> decltype(std::declval().at(impl::access(i))) 167 | { 168 | auto& self = static_cast(*this); 169 | return value_of(self).at(impl::access(i)); 170 | } 171 | 172 | template 173 | STRONG_NODISCARD 174 | auto 175 | at( 176 | const I& i) 177 | & 178 | -> decltype(std::declval().at(impl::access(i))) 179 | { 180 | auto& self = static_cast(*this); 181 | return value_of(self).at(impl::access(i)); 182 | } 183 | 184 | template 185 | STRONG_NODISCARD 186 | auto 187 | at( 188 | const I& i) 189 | && 190 | -> decltype(std::declval().at(impl::access(i))) 191 | { 192 | auto& self = static_cast(*this); 193 | return value_of(std::move(self)).at(impl::access(i)); 194 | } 195 | }; 196 | 197 | } 198 | #endif //STRONG_TYPE_INDEXED_HPP 199 | -------------------------------------------------------------------------------- /include/strong_type/invocable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | 15 | #ifndef STRONG_TYPE_INVOCABLE_HPP 16 | #define STRONG_TYPE_INVOCABLE_HPP 17 | 18 | #include "type.hpp" 19 | 20 | namespace strong 21 | { 22 | 23 | struct invocable 24 | { 25 | template 26 | class modifier; 27 | }; 28 | 29 | template 30 | class invocable::modifier> 31 | { 32 | using type = strong::type; 33 | public: 34 | template ()(std::declval()...))> 35 | STRONG_CONSTEXPR 36 | R operator()(Args&& ... args) & 37 | noexcept (noexcept(std::declval()(std::declval()...))) 38 | { 39 | return call(static_cast(*this), std::forward(args)...); 40 | } 41 | template ()(std::declval()...))> 42 | STRONG_CONSTEXPR 43 | R operator()(Args&& ... args) && 44 | noexcept (noexcept(std::declval()(std::declval()...))) 45 | { 46 | return call(static_cast(std::move(*this)), std::forward(args)...); 47 | } 48 | template ()(std::declval()...))> 49 | STRONG_CONSTEXPR 50 | R operator()(Args&& ... args) const & 51 | noexcept (noexcept(std::declval()(std::declval()...))) 52 | { 53 | return call(static_cast(*this), std::forward(args)...); 54 | } 55 | template ()(std::declval()...))> 56 | STRONG_CONSTEXPR 57 | R operator()(Args&& ... args) const && 58 | noexcept (noexcept(std::declval()(std::declval()...))) 59 | { 60 | return call(static_cast(std::move(*this)), std::forward(args)...); 61 | } 62 | private: 63 | template 64 | static STRONG_CONSTEXPR decltype(auto) call(Self&& self, Ts&& ... ts) 65 | { 66 | return value_of(std::forward(self))(std::forward(ts)...); 67 | } 68 | }; 69 | 70 | } 71 | #endif //STRONG_TYPE_INVOCABLE_HPP 72 | -------------------------------------------------------------------------------- /include/strong_type/iostreamable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_IOSTREAMABLE_HPP 15 | #define STRONG_TYPE_IOSTREAMABLE_HPP 16 | 17 | #include "istreamable.hpp" 18 | #include "ostreamable.hpp" 19 | 20 | namespace strong 21 | { 22 | struct iostreamable 23 | { 24 | template 25 | class modifier 26 | : public ostreamable::modifier 27 | , public istreamable::modifier 28 | { 29 | }; 30 | }; 31 | } 32 | #endif //STRONG_TYPE_IOSTREAMABLE_HPP 33 | -------------------------------------------------------------------------------- /include/strong_type/istreamable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_ISTREAMABLE_HPP 15 | #define STRONG_TYPE_ISTREAMABLE_HPP 16 | 17 | #include "type.hpp" 18 | 19 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 20 | #include 21 | #endif 22 | 23 | namespace strong 24 | { 25 | struct istreamable 26 | { 27 | template 28 | class modifier 29 | { 30 | static_assert(impl::always_false, 31 | "Underlying type must support stream input via operator>>"); 32 | }; 33 | template 34 | class modifier() >> std::declval&>())>> 35 | { 36 | public: 37 | friend 38 | std::istream& 39 | operator>>( 40 | std::istream &is, 41 | T &t) 42 | { 43 | return is >> value_of(t); 44 | } 45 | }; 46 | }; 47 | 48 | } 49 | #endif //STRONG_TYPE_ISTREAMABLE_HPP 50 | -------------------------------------------------------------------------------- /include/strong_type/iterator.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_ITERATOR_HPP 15 | #define STRONG_TYPE_ITERATOR_HPP 16 | 17 | #include "pointer.hpp" 18 | #include "bicrementable.hpp" 19 | #include "affine_point.hpp" 20 | #include "indexed.hpp" 21 | 22 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 23 | #include 24 | #endif 25 | 26 | #if __cplusplus >= 202002L && (((! defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 15000)) && (!defined(__GLIBCXX__) || __GLIBCXX__ >= 20230528L)) 27 | #define STRONG_TYPE_CONTIGUOUS_ITERATOR 1 28 | #else 29 | #define STRONG_TYPE_CONTIGUOUS_ITERATOR 0 30 | #endif 31 | 32 | namespace strong 33 | { 34 | namespace internal { 35 | template 36 | struct iterator_traits 37 | { 38 | using iterator_category = std::input_iterator_tag; 39 | using difference_type = typename I::difference_type; 40 | using reference = decltype(*std::declval()); 41 | using value_type = std::remove_cv_t>; 42 | using pointer = value_type*; 43 | }; 44 | template 45 | struct iterator_traits> 46 | { 47 | using iterator_category = typename I::iterator_category; 48 | using difference_type = typename I::difference_type; 49 | using reference = decltype(*std::declval()); 50 | using value_type = std::remove_cv_t>; 51 | using pointer = value_type*; 52 | 53 | }; 54 | template 55 | struct iterator_traits 56 | { 57 | #if STRONG_TYPE_CONTIGUOUS_ITERATOR 58 | using iterator_category = std::contiguous_iterator_tag; 59 | #else 60 | using iterator_category = std::random_access_iterator_tag; 61 | #endif 62 | using difference_type = std::ptrdiff_t; 63 | using value_type = T; 64 | using reference = T&; 65 | using pointer = T*; 66 | 67 | }; 68 | } 69 | class iterator 70 | { 71 | public: 72 | template >::iterator_category> 74 | class modifier 75 | : public pointer::modifier 76 | , public incrementable::modifier 77 | { 78 | public: 79 | using difference_type = typename internal::iterator_traits>::difference_type; 80 | using value_type = typename internal::iterator_traits>::value_type; 81 | using pointer = typename internal::iterator_traits>::pointer; 82 | using reference = typename internal::iterator_traits>::reference; 83 | using iterator_category = typename internal::iterator_traits>::iterator_category; 84 | }; 85 | 86 | template 87 | class modifier 88 | : public modifier 89 | , public strong::equality::modifier 90 | {}; 91 | template 92 | class modifier 93 | : public modifier 94 | , public decrementable::modifier 95 | { 96 | }; 97 | template 98 | class modifier 99 | : public modifier 100 | , public affine_point>::difference_type>::template modifier 101 | , public indexed<>::modifier 102 | , public ordered::modifier 103 | { 104 | }; 105 | 106 | #if STRONG_TYPE_CONTIGUOUS_ITERATOR 107 | template 108 | class modifier 109 | : public modifier 110 | , public affine_point>::difference_type>::template modifier 111 | , public indexed<>::modifier 112 | , public ordered::modifier 113 | { 114 | }; 115 | #endif 116 | }; 117 | 118 | } 119 | #endif //STRONG_TYPE_ITERATOR_HPP -------------------------------------------------------------------------------- /include/strong_type/ordered.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_ORDERED_HPP 15 | #define STRONG_TYPE_ORDERED_HPP 16 | 17 | #include "type.hpp" 18 | 19 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 20 | #if __cpp_impl_three_way_comparison && __has_include() 21 | #include 22 | #endif 23 | #endif 24 | 25 | namespace strong 26 | { 27 | struct ordered 28 | { 29 | template 30 | class modifier 31 | { 32 | static_assert(impl::always_false, 33 | "Underlying type must support ordering relations using <, <=, > and >="); 34 | }; 35 | }; 36 | 37 | 38 | template 39 | class ordered::modifier< 40 | ::strong::type, 41 | impl::void_t< 42 | decltype((std::declval() < std::declval())), 43 | decltype((std::declval() <= std::declval())), 44 | decltype((std::declval() > std::declval())), 45 | decltype((std::declval() >= std::declval()))> 46 | > 47 | { 48 | using type = ::strong::type; 49 | public: 50 | STRONG_NODISCARD 51 | friend 52 | STRONG_CONSTEXPR 53 | auto 54 | operator<( 55 | const type& lh, 56 | const type& rh) 57 | noexcept(noexcept(std::declval() < std::declval())) 58 | -> decltype(std::declval() < std::declval()) 59 | { 60 | return value_of(lh) < value_of(rh); 61 | } 62 | 63 | STRONG_NODISCARD 64 | friend 65 | STRONG_CONSTEXPR 66 | auto 67 | operator<=( 68 | const type& lh, 69 | const type& rh) 70 | noexcept(noexcept(std::declval() <= std::declval())) 71 | -> decltype(std::declval() <= std::declval()) 72 | { 73 | return value_of(lh) <= value_of(rh); 74 | } 75 | 76 | STRONG_NODISCARD 77 | friend 78 | STRONG_CONSTEXPR 79 | auto 80 | operator>( 81 | const type& lh, 82 | const type& rh) 83 | noexcept(noexcept(std::declval() > std::declval())) 84 | -> decltype(std::declval() > std::declval()) 85 | { 86 | return value_of(lh) > value_of(rh); 87 | } 88 | 89 | STRONG_NODISCARD 90 | friend 91 | STRONG_CONSTEXPR 92 | 93 | auto 94 | operator>=( 95 | const type& lh, 96 | const type& rh) 97 | noexcept(noexcept(std::declval() >= std::declval())) 98 | -> decltype(std::declval() >= std::declval()) 99 | { 100 | return value_of(lh) >= value_of(rh); 101 | } 102 | }; 103 | 104 | #if __cpp_impl_three_way_comparison && __has_include() 105 | 106 | namespace detail 107 | { 108 | template 109 | struct spaceship_ordering { 110 | template 111 | struct modifier; 112 | }; 113 | 114 | template 115 | template 116 | struct spaceship_ordering::modifier<::strong::type> 117 | { 118 | using type = ::strong::type; 119 | 120 | STRONG_NODISCARD 121 | friend 122 | STRONG_CONSTEXPR 123 | 124 | Ordering 125 | operator<=>( 126 | const type &lh, 127 | const type &rh) 128 | noexcept(noexcept(std::declval() <=> std::declval())) 129 | requires std::is_convertible_v() <=> std::declval()), Ordering> 130 | { 131 | return value_of(lh) <=> value_of(rh); 132 | } 133 | }; 134 | 135 | } 136 | 137 | using strongly_ordered = detail::spaceship_ordering; 138 | using weakly_ordered = detail::spaceship_ordering; 139 | using partially_ordered = detail::spaceship_ordering; 140 | 141 | #endif 142 | 143 | } 144 | 145 | #endif //STRONG_TYPE_ORDERED_HPP 146 | -------------------------------------------------------------------------------- /include/strong_type/ordered_with.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_ORDERED_WITH_HPP 15 | #define STRONG_TYPE_ORDERED_WITH_HPP 16 | 17 | #include "type.hpp" 18 | 19 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 20 | #if __cpp_impl_three_way_comparison && __has_include() 21 | #include 22 | #endif 23 | #endif 24 | 25 | namespace strong 26 | { 27 | namespace impl 28 | { 29 | template 30 | class typed_ordering 31 | { 32 | static_assert(impl::always_false, 33 | "Underlying type must support ordering relations with target type using operators <, <=, > and >="); 34 | }; 35 | 36 | template 37 | class typed_ordering< 38 | T, 39 | Other, 40 | impl::void_t< 41 | decltype((std::declval>() < std::declval>())), 42 | decltype((std::declval>() <= std::declval>())), 43 | decltype((std::declval>() > std::declval>())), 44 | decltype((std::declval>() >= std::declval>())) 45 | > 46 | > 47 | { 48 | private: 49 | using TT = underlying_type_t; 50 | using OT = underlying_type_t; 51 | public: 52 | STRONG_NODISCARD 53 | friend 54 | STRONG_CONSTEXPR 55 | auto operator<(const T& lh, const Other& rh) 56 | noexcept(noexcept(std::declval() < std::declval())) 57 | -> decltype(std::declval() < std::declval()) 58 | { 59 | return value_of(lh) < impl::access(rh); 60 | } 61 | STRONG_NODISCARD 62 | friend 63 | STRONG_CONSTEXPR 64 | auto operator<(const Other& lh, const T& rh) 65 | noexcept(noexcept(std::declval() < std::declval())) 66 | -> decltype(std::declval() < std::declval()) 67 | { 68 | return impl::access(lh) < value_of(rh) ; 69 | } 70 | 71 | STRONG_NODISCARD 72 | friend 73 | STRONG_CONSTEXPR 74 | auto operator<=(const T& lh, const Other& rh) 75 | noexcept(noexcept(std::declval() <= std::declval())) 76 | -> decltype(std::declval() <= std::declval()) 77 | { 78 | return value_of(lh) <= impl::access(rh); 79 | } 80 | STRONG_NODISCARD 81 | friend 82 | STRONG_CONSTEXPR 83 | auto operator<=(const Other& lh, const T& rh) 84 | noexcept(noexcept(std::declval() <= std::declval())) 85 | -> decltype(std::declval() <= std::declval()) 86 | { 87 | return impl::access(lh) <= value_of(rh) ; 88 | } 89 | 90 | STRONG_NODISCARD 91 | friend 92 | STRONG_CONSTEXPR 93 | auto operator>(const T& lh, const Other& rh) 94 | noexcept(noexcept(std::declval() > std::declval())) 95 | -> decltype(std::declval() > std::declval()) 96 | { 97 | return value_of(lh) > impl::access(rh); 98 | } 99 | STRONG_NODISCARD 100 | friend 101 | STRONG_CONSTEXPR 102 | auto operator>(const Other& lh, const T& rh) 103 | noexcept(noexcept(std::declval() > std::declval())) 104 | -> decltype(std::declval() > std::declval()) 105 | { 106 | return impl::access(lh) > value_of(rh) ; 107 | } 108 | 109 | STRONG_NODISCARD 110 | friend 111 | STRONG_CONSTEXPR 112 | auto operator>=(const T& lh, const Other& rh) 113 | noexcept(noexcept(std::declval() >= std::declval())) 114 | -> decltype(std::declval() >= std::declval()) 115 | { 116 | return value_of(lh) >= impl::access(rh); 117 | } 118 | STRONG_NODISCARD 119 | friend 120 | STRONG_CONSTEXPR 121 | auto operator>=(const Other& lh, const T& rh) 122 | noexcept(noexcept(std::declval() >= std::declval())) 123 | -> decltype(std::declval() >= std::declval()) 124 | { 125 | return impl::access(lh) >= value_of(rh) ; 126 | } 127 | }; 128 | } 129 | 130 | template 131 | struct ordered_with 132 | { 133 | template 134 | class modifier : public impl::typed_ordering... 135 | { 136 | }; 137 | }; 138 | 139 | #if __cpp_impl_three_way_comparison && __has_include() 140 | 141 | namespace detail 142 | { 143 | 144 | 145 | template 146 | struct typed_spaceship_ordering_with 147 | { 148 | private: 149 | using TT = underlying_type_t; 150 | using OT = underlying_type_t; 151 | public: 152 | STRONG_NODISCARD 153 | friend 154 | STRONG_CONSTEXPR 155 | Ordering 156 | operator<=>( 157 | const T& lh, 158 | const Other& rh) 159 | noexcept(noexcept(std::declval() <=> std::declval())) 160 | requires std::is_convertible_v() <=> std::declval()), Ordering> 161 | { 162 | return value_of(lh) <=> impl::access(rh); 163 | } 164 | }; 165 | template 166 | struct spaceship_ordering_with 167 | { 168 | template 169 | struct modifier : public typed_spaceship_ordering_with... 170 | { 171 | }; 172 | }; 173 | 174 | } 175 | 176 | template 177 | using strongly_ordered_with = detail::spaceship_ordering_with; 178 | template 179 | using weakly_ordered_with = detail::spaceship_ordering_with; 180 | template 181 | using partially_ordered_with = detail::spaceship_ordering_with; 182 | 183 | #endif 184 | 185 | } 186 | #endif //STRONG_TYPE_ORDERED_WITH_HPP 187 | -------------------------------------------------------------------------------- /include/strong_type/ostreamable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_OSTREAMABLE_HPP 15 | #define STRONG_TYPE_OSTREAMABLE_HPP 16 | 17 | #include "type.hpp" 18 | 19 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 20 | #include 21 | #endif 22 | 23 | namespace strong 24 | { 25 | struct ostreamable 26 | { 27 | template 28 | class modifier 29 | { 30 | static_assert(impl::always_false, 31 | "Underlying type support stream output via operator<<"); 32 | }; 33 | template 34 | class modifier() << std::declval&>())>> 35 | { 36 | public: 37 | friend 38 | std::ostream& 39 | operator<<( 40 | std::ostream &os, 41 | const T &t) 42 | { 43 | return os << value_of(t); 44 | } 45 | }; 46 | }; 47 | 48 | template 49 | using is_ostreamable = std::is_base_of, T>; 50 | 51 | } 52 | #endif //STRONG_TYPE_OSTREAMABLE_HPP 53 | -------------------------------------------------------------------------------- /include/strong_type/pointer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_POINTER_HPP 15 | #define STRONG_TYPE_POINTER_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | struct pointer 22 | { 23 | template 24 | class modifier; 25 | }; 26 | 27 | template 28 | class pointer::modifier 29 | { 30 | static_assert(impl::always_false, "Underlying type must support dereferencing with operator*"); 31 | }; 32 | 33 | template 34 | class pointer::modifier<::strong::type, impl::void_t())>> 35 | { 36 | using type = strong::type; 37 | public: 38 | template 39 | STRONG_NODISCARD 40 | friend 41 | STRONG_CONSTEXPR 42 | auto 43 | operator==( 44 | const type& t, 45 | std::nullptr_t) 46 | noexcept(noexcept(std::declval() == nullptr)) 47 | -> decltype(std::declval() == nullptr) 48 | { 49 | return value_of(t) == nullptr; 50 | } 51 | 52 | template 53 | STRONG_NODISCARD 54 | friend 55 | STRONG_CONSTEXPR 56 | auto 57 | operator==( 58 | std::nullptr_t, 59 | const type& t) 60 | noexcept(noexcept(nullptr == std::declval())) 61 | -> decltype(nullptr == std::declval()) 62 | { 63 | return value_of(t) == nullptr; 64 | } 65 | 66 | template 67 | STRONG_NODISCARD 68 | friend 69 | STRONG_CONSTEXPR 70 | auto 71 | operator!=( 72 | const type& t, 73 | std::nullptr_t) 74 | noexcept(noexcept(std::declval() != nullptr)) 75 | -> decltype(std::declval() != nullptr) 76 | { 77 | return value_of(t) != nullptr; 78 | } 79 | 80 | template 81 | STRONG_NODISCARD 82 | friend 83 | STRONG_CONSTEXPR 84 | auto 85 | operator!=( 86 | std::nullptr_t, 87 | const type& t) 88 | noexcept(noexcept(nullptr != std::declval())) 89 | -> decltype(nullptr != std::declval()) 90 | { 91 | return value_of(t) != nullptr; 92 | } 93 | 94 | STRONG_NODISCARD 95 | STRONG_CONSTEXPR 96 | decltype(*std::declval()) 97 | operator*() 98 | const 99 | { 100 | auto& self = static_cast(*this); 101 | return *value_of(self); 102 | } 103 | 104 | STRONG_NODISCARD 105 | STRONG_CONSTEXPR 106 | decltype(&(*std::declval())) operator->() const { return &operator*();} 107 | }; 108 | 109 | } 110 | #endif //STRONG_TYPE_POINTER_HPP 111 | -------------------------------------------------------------------------------- /include/strong_type/range.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_RANGE_HPP 15 | #define STRONG_TYPE_RANGE_HPP 16 | 17 | #if __has_include() 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | # include 20 | #endif 21 | #endif 22 | #if defined(_MSC_VER) && __cpp_lib_ranges >= 202110L 23 | # define STRONG_TYPE_HAS_RANGES 24 | #endif 25 | #if __cplusplus >= 202101L 26 | # if (not defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) && (__cpp_lib_ranges >= 202106L) 27 | # define STRONG_TYPE_HAS_RANGES 28 | # endif 29 | # if (not defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 15000) 30 | # define STRONG_TYPE_HAS_RANGES 31 | # endif 32 | #endif 33 | #include "iterator.hpp" 34 | #include "equality_with.hpp" 35 | #include "ordered_with.hpp" 36 | 37 | namespace strong 38 | { 39 | 40 | namespace internal { 41 | struct not_an_iterator {}; 42 | 43 | 44 | #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) 45 | template 46 | auto begin_type(T* t) -> decltype(std::ranges::begin(*t)); 47 | #else 48 | template 49 | auto begin_type(T* t) -> decltype(t->begin()); 50 | #endif 51 | 52 | auto begin_type(...) -> not_an_iterator; 53 | 54 | #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) 55 | template 56 | auto const_begin_type(const T* t) -> decltype(std::ranges::begin(*t)); 57 | #else 58 | template 59 | auto const_begin_type(const T* t) -> decltype(t->begin()); 60 | #endif 61 | auto const_begin_type(...) -> not_an_iterator; 62 | 63 | #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) 64 | template 65 | auto end_type(T* t) -> decltype(std::ranges::end(*t)); 66 | #else 67 | template 68 | auto end_type(T* t) -> decltype(t->end()); 69 | #endif 70 | auto end_type(...) -> not_an_iterator; 71 | 72 | #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) 73 | template 74 | auto const_end_type(const T* t) -> decltype(std::ranges::end(*t)); 75 | #else 76 | template 77 | auto const_end_type(const T* t) -> decltype(t->end()); 78 | #endif 79 | 80 | auto const_end_type(...) -> not_an_iterator; 81 | 82 | #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) 83 | template 84 | auto cbegin_type(const T* t) -> decltype(std::ranges::cbegin(*t)); 85 | #else 86 | template 87 | auto cbegin_type(const T* t) -> decltype(t->cbegin()); 88 | #endif 89 | auto cbegin_type(...) -> not_an_iterator; 90 | 91 | #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) 92 | template 93 | auto cend_type(const T* t) -> decltype(std::ranges::cend(*t)); 94 | #else 95 | template 96 | auto cend_type(const T* t) -> decltype(t->cend()); 97 | #endif 98 | auto cend_type(...) -> not_an_iterator; 99 | 100 | template 101 | struct begin_end_traits 102 | { 103 | using begin_iterator = decltype(begin_type(std::declval())); 104 | using const_begin_iterator = decltype(const_begin_type(std::declval())); 105 | using end_iterator = decltype(end_type(std::declval())); 106 | using const_end_iterator = decltype(const_end_type(std::declval())); 107 | using cbegin_iterator = decltype(cbegin_type(std::declval())); 108 | using cend_iterator = decltype(cend_type(std::declval())); 109 | }; 110 | 111 | constexpr bool is_random_access(std::random_access_iterator_tag) { return true;} 112 | constexpr bool is_random_access(std::input_iterator_tag) { return false;} 113 | constexpr bool is_random_access(std::output_iterator_tag) { return false;} 114 | } 115 | 116 | #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230601L)) 117 | #define STRONG_TYPE_BEGIN(x) std::ranges::begin(x) 118 | #define STRONG_TYPE_END(x) std::ranges::end(x) 119 | #define STRONG_TYPE_CBEGIN(x) std::ranges::cbegin(x) 120 | #define STRONG_TYPE_CEND(x) std::ranges::cend(x) 121 | #else 122 | #define STRONG_TYPE_BEGIN(x) x.begin() 123 | #define STRONG_TYPE_END(x) x.end() 124 | #define STRONG_TYPE_CBEGIN(x) x.cbegin() 125 | #define STRONG_TYPE_CEND(x) x.cend() 126 | #endif 127 | 128 | class range 129 | { 130 | public: 131 | template < 132 | typename R, 133 | typename = typename internal::begin_end_traits>::begin_iterator, 134 | typename = typename internal::begin_end_traits>::end_iterator, 135 | typename = typename internal::begin_end_traits>::const_begin_iterator, 136 | typename = typename internal::begin_end_traits>::const_end_iterator, 137 | typename = typename internal::begin_end_traits>::cbegin_iterator, 138 | typename = typename internal::begin_end_traits>::cend_iterator> 139 | class modifier; 140 | }; 141 | 142 | template 143 | class range::modifier< 144 | R, 145 | internal::not_an_iterator, internal::not_an_iterator, 146 | internal::not_an_iterator, internal::not_an_iterator, 147 | internal::not_an_iterator, internal::not_an_iterator 148 | > 149 | { 150 | static_assert(impl::always_false, 151 | "Underlying type must have begin() and end()"); 152 | 153 | }; 154 | 155 | template 156 | class range::modifier< 157 | type, 158 | r_iterator, r_iterator, 159 | r_iterator, r_iterator, 160 | r_iterator, r_iterator> 161 | { 162 | using type = ::strong::type; 163 | static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits::iterator_category{}); 164 | public: 165 | using const_iterator = std::conditional_t, strong::ordered_with>, 167 | ::strong::type> 168 | >; 169 | 170 | STRONG_NODISCARD 171 | constexpr 172 | const_iterator 173 | begin() 174 | const 175 | noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval()))) 176 | { 177 | auto& self = static_cast(*this); 178 | return const_iterator{STRONG_TYPE_BEGIN(value_of(self))}; 179 | } 180 | 181 | STRONG_NODISCARD 182 | constexpr 183 | const_iterator 184 | end() 185 | const 186 | noexcept(noexcept(STRONG_TYPE_END(std::declval()))) 187 | { 188 | auto& self = static_cast(*this); 189 | return const_iterator{STRONG_TYPE_END(value_of(self))}; 190 | } 191 | 192 | STRONG_NODISCARD 193 | constexpr 194 | const_iterator 195 | cbegin() 196 | const 197 | noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval()))) 198 | { 199 | auto& self = static_cast(*this); 200 | return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))}; 201 | } 202 | 203 | STRONG_NODISCARD 204 | constexpr 205 | const_iterator 206 | cend() 207 | const 208 | noexcept(noexcept(STRONG_TYPE_CEND(std::declval()))) 209 | { 210 | auto& self = static_cast(*this); 211 | return const_iterator{STRONG_TYPE_CEND(value_of(self))}; 212 | } 213 | 214 | template 215 | STRONG_NODISCARD 216 | constexpr 217 | decltype(std::declval().size()) 218 | size() 219 | const 220 | noexcept(noexcept(std::declval().size())) 221 | { 222 | auto& self = static_cast(*this); 223 | return value_of(self).size(); 224 | } 225 | 226 | }; 227 | template 228 | class range::modifier< 229 | type, 230 | r_iterator, r_iterator, 231 | r_const_iterator, r_const_iterator, 232 | r_const_iterator, r_const_iterator 233 | > 234 | { 235 | using type = ::strong::type; 236 | static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits::iterator_category{}); 237 | public: 238 | using iterator = ::strong::type; 239 | using const_iterator = std::conditional_t, strong::ordered_with>, 241 | ::strong::type> 242 | >; 243 | 244 | STRONG_NODISCARD 245 | constexpr 246 | iterator 247 | begin() 248 | noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval()))) 249 | { 250 | auto& self = static_cast(*this); 251 | return iterator{STRONG_TYPE_BEGIN(value_of(self))}; 252 | } 253 | 254 | STRONG_NODISCARD 255 | constexpr 256 | iterator 257 | end() 258 | noexcept(noexcept(STRONG_TYPE_END(std::declval()))) 259 | { 260 | auto& self = static_cast(*this); 261 | return iterator{STRONG_TYPE_END(value_of(self))}; 262 | } 263 | 264 | 265 | STRONG_NODISCARD 266 | constexpr 267 | const_iterator 268 | begin() 269 | const 270 | noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval()))) 271 | { 272 | auto& self = static_cast(*this); 273 | return const_iterator{STRONG_TYPE_BEGIN(value_of(self))}; 274 | } 275 | 276 | STRONG_NODISCARD 277 | constexpr 278 | const_iterator 279 | end() 280 | const 281 | noexcept(noexcept(STRONG_TYPE_END(std::declval()))) 282 | { 283 | auto& self = static_cast(*this); 284 | return const_iterator{STRONG_TYPE_END(value_of(self))}; 285 | } 286 | 287 | STRONG_NODISCARD 288 | constexpr 289 | const_iterator 290 | cbegin() 291 | const 292 | noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval()))) 293 | { 294 | auto& self = static_cast(*this); 295 | return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))}; 296 | } 297 | 298 | STRONG_NODISCARD 299 | constexpr 300 | const_iterator 301 | cend() 302 | const 303 | noexcept(noexcept(STRONG_TYPE_CEND(std::declval()))) 304 | { 305 | auto& self = static_cast(*this); 306 | return const_iterator{STRONG_TYPE_CEND(value_of(self))}; 307 | } 308 | 309 | template 310 | STRONG_NODISCARD 311 | constexpr 312 | decltype(std::declval().size()) 313 | size() 314 | const 315 | noexcept(noexcept(std::declval().size())) 316 | { 317 | auto& self = static_cast(*this); 318 | return value_of(self).size(); 319 | } 320 | }; 321 | 322 | template 323 | class range::modifier< 324 | type, 325 | r_iterator, r_sentinel, 326 | r_iterator, r_sentinel, 327 | r_const_iterator, r_sentinel 328 | > 329 | { 330 | using type = ::strong::type; 331 | static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits::iterator_category{}); 332 | public: 333 | using iterator = ::strong::type; 334 | using const_iterator = std::conditional_t, strong::ordered_with>, 336 | ::strong::type> 337 | >; 338 | using sentinel = strong::type>; 339 | 340 | STRONG_NODISCARD 341 | constexpr 342 | iterator 343 | begin() 344 | noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval()))) 345 | { 346 | auto& self = static_cast(*this); 347 | return iterator{STRONG_TYPE_BEGIN(value_of(self))}; 348 | } 349 | 350 | STRONG_NODISCARD 351 | constexpr 352 | sentinel 353 | end() 354 | noexcept(noexcept(STRONG_TYPE_END(std::declval()))) 355 | { 356 | auto& self = static_cast(*this); 357 | return sentinel{STRONG_TYPE_END(value_of(self))}; 358 | } 359 | 360 | 361 | STRONG_NODISCARD 362 | constexpr 363 | iterator 364 | begin() 365 | const 366 | noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval()))) 367 | { 368 | auto& self = static_cast(*this); 369 | return iterator{STRONG_TYPE_BEGIN(value_of(self))}; 370 | } 371 | 372 | STRONG_NODISCARD 373 | constexpr 374 | sentinel 375 | end() 376 | const 377 | noexcept(noexcept(STRONG_TYPE_END(std::declval()))) 378 | { 379 | auto& self = static_cast(*this); 380 | return sentinel{STRONG_TYPE_END(value_of(self))}; 381 | } 382 | 383 | STRONG_NODISCARD 384 | constexpr 385 | const_iterator 386 | cbegin() 387 | const 388 | noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval()))) 389 | { 390 | auto& self = static_cast(*this); 391 | return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))}; 392 | } 393 | 394 | STRONG_NODISCARD 395 | constexpr 396 | sentinel 397 | cend() 398 | const 399 | noexcept(noexcept(STRONG_TYPE_CEND(std::declval()))) 400 | { 401 | auto& self = static_cast(*this); 402 | return sentinel{STRONG_TYPE_CEND(value_of(self))}; 403 | } 404 | 405 | template 406 | STRONG_NODISCARD 407 | constexpr 408 | decltype(std::declval().size()) 409 | size() 410 | const 411 | noexcept(noexcept(std::declval().size())) 412 | { 413 | auto& self = static_cast(*this); 414 | return value_of(self).size(); 415 | } 416 | }; 417 | 418 | template 419 | class range::modifier< 420 | type, 421 | r_iterator, r_iterator, 422 | internal::not_an_iterator, internal::not_an_iterator, 423 | internal::not_an_iterator, internal::not_an_iterator 424 | > 425 | { 426 | using type = ::strong::type; 427 | public: 428 | using iterator = ::strong::type; 429 | 430 | STRONG_NODISCARD 431 | constexpr 432 | iterator 433 | begin() 434 | noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval()))) 435 | { 436 | auto& self = static_cast(*this); 437 | return iterator{STRONG_TYPE_BEGIN(value_of(self))}; 438 | } 439 | 440 | STRONG_NODISCARD 441 | constexpr 442 | iterator 443 | end() 444 | noexcept(noexcept(STRONG_TYPE_END(std::declval()))) 445 | { 446 | auto& self = static_cast(*this); 447 | return iterator{STRONG_TYPE_END(value_of(self))}; 448 | } 449 | 450 | template 451 | STRONG_NODISCARD 452 | constexpr 453 | decltype(std::declval().size()) 454 | size() 455 | const 456 | noexcept(noexcept(std::declval().size())) 457 | { 458 | auto& self = static_cast(*this); 459 | return value_of(self).size(); 460 | } 461 | }; 462 | 463 | template 464 | class range::modifier< 465 | type, 466 | r_iterator, r_sentinel, 467 | internal::not_an_iterator, internal::not_an_iterator, 468 | internal::not_an_iterator, internal::not_an_iterator 469 | > 470 | { 471 | using type = ::strong::type; 472 | public: 473 | using iterator = ::strong::type; 474 | using sentinel = ::strong::type>; 475 | 476 | STRONG_NODISCARD 477 | constexpr 478 | iterator 479 | begin() 480 | noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval()))) 481 | { 482 | auto& self = static_cast(*this); 483 | return iterator{STRONG_TYPE_BEGIN(value_of(self))}; 484 | } 485 | 486 | STRONG_NODISCARD 487 | constexpr 488 | sentinel 489 | end() 490 | noexcept(noexcept(STRONG_TYPE_END(std::declval()))) 491 | { 492 | auto& self = static_cast(*this); 493 | return sentinel{STRONG_TYPE_END(value_of(self))}; 494 | } 495 | 496 | template 497 | STRONG_NODISCARD 498 | constexpr 499 | decltype(std::declval().size()) 500 | size() 501 | const 502 | noexcept(noexcept(std::declval().size())) 503 | { 504 | auto& self = static_cast(*this); 505 | return value_of(self).size(); 506 | } 507 | }; 508 | 509 | template 510 | class range::modifier< 511 | type, 512 | internal::not_an_iterator, internal::not_an_iterator, 513 | r_const_iterator, r_sentinel, 514 | internal::not_an_iterator, internal::not_an_iterator 515 | > 516 | { 517 | using type = ::strong::type; 518 | public: 519 | using const_iterator = ::strong::type; 520 | using sentinel = ::strong::type>; 521 | 522 | STRONG_NODISCARD 523 | constexpr 524 | const_iterator 525 | begin() 526 | const 527 | noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval()))) 528 | { 529 | auto& self = static_cast(*this); 530 | return const_iterator{STRONG_TYPE_BEGIN(value_of(self))}; 531 | } 532 | 533 | STRONG_NODISCARD 534 | constexpr 535 | sentinel 536 | end() 537 | const 538 | noexcept(noexcept(STRONG_TYPE_END(std::declval()))) 539 | { 540 | auto& self = static_cast(*this); 541 | return sentinel{STRONG_TYPE_END(value_of(self))}; 542 | } 543 | 544 | template 545 | STRONG_NODISCARD 546 | constexpr 547 | decltype(std::declval().size()) 548 | size() 549 | const 550 | noexcept(noexcept(std::declval().size())) 551 | { 552 | auto& self = static_cast(*this); 553 | return value_of(self).size(); 554 | } 555 | }; 556 | 557 | } 558 | #endif //STRONG_TYPE_RANGE_HPP 559 | 560 | 561 | -------------------------------------------------------------------------------- /include/strong_type/regular.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_REGULAR_HPP 15 | #define STRONG_TYPE_REGULAR_HPP 16 | 17 | #include "equality.hpp" 18 | #include "semiregular.hpp" 19 | 20 | namespace strong 21 | { 22 | struct regular 23 | { 24 | template 25 | class modifier 26 | : public semiregular::modifier 27 | , public equality::modifier 28 | { 29 | }; 30 | }; 31 | 32 | } 33 | #endif //STRONG_TYPE_REGULAR_HPP 34 | -------------------------------------------------------------------------------- /include/strong_type/scalable_with.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_SCALABLE_HPP 15 | #define STRONG_TYPE_SCALABLE_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | namespace impl 22 | { 23 | template 24 | struct first_type; 25 | template 26 | struct first_type 27 | { 28 | using type = T; 29 | }; 30 | template 31 | struct first_type { 32 | using type = T; 33 | }; 34 | template 35 | using first_type_t = typename first_type::type; 36 | 37 | template 38 | class typed_scalable 39 | { 40 | static_assert(impl::always_false, 41 | "Underlying type must be multiplyable and divisible by other type"); 42 | }; 43 | template 44 | class typed_scalable< 45 | T, 46 | Other, 47 | impl::void_t&>()/=std::declval>())*=std::declval>())> 48 | > 49 | { 50 | using TT = underlying_type_t; 51 | using OT = underlying_type_t; 52 | public: 53 | friend 54 | STRONG_CONSTEXPR 55 | auto operator/=(T& lh, const Other& rh) 56 | noexcept(noexcept(std::declval() / std::declval()) 57 | && std::is_nothrow_move_assignable::value) 58 | -> T& 59 | { 60 | value_of(lh) = static_cast(value_of(lh) / impl::access(rh)); 61 | return lh; 62 | } 63 | friend 64 | STRONG_CONSTEXPR 65 | auto operator*=(T& lh, const Other& rh) 66 | noexcept(noexcept(std::declval() * std::declval()) 67 | && std::is_nothrow_move_assignable::value) 68 | -> T& 69 | { 70 | value_of(lh) = static_cast(value_of(lh) * impl::access(rh)); 71 | return lh; 72 | } 73 | STRONG_NODISCARD 74 | friend 75 | STRONG_CONSTEXPR 76 | auto operator/(T lh, const Other& rh) 77 | noexcept(noexcept(lh /= rh)) 78 | -> T 79 | { 80 | lh /= rh; 81 | return lh; 82 | } 83 | STRONG_NODISCARD 84 | friend 85 | STRONG_CONSTEXPR 86 | auto operator*(T lh, const Other& rh) 87 | noexcept(noexcept(lh *= rh)) 88 | -> T 89 | { 90 | lh *= rh; 91 | return lh; 92 | } 93 | STRONG_NODISCARD 94 | friend 95 | STRONG_CONSTEXPR 96 | auto operator*(const Other& lh, T rh) 97 | noexcept(noexcept(rh *= lh)) 98 | -> T 99 | { 100 | rh *= lh; 101 | return rh; 102 | } 103 | }; 104 | } 105 | 106 | template 107 | struct scalable_with 108 | { 109 | template 110 | class modifier : public impl::typed_scalable... 111 | { 112 | public: 113 | using scalable_modifier_result_type = impl::first_type_t; 114 | }; 115 | }; 116 | } 117 | 118 | template < 119 | typename TT, 120 | typename UT = strong::underlying_type_t, 121 | typename R = typename TT::scalable_modifier_result_type, 122 | typename = std::enable_if_t() / std::declval())>::value> 123 | > 124 | STRONG_NODISCARD 125 | inline 126 | STRONG_CONSTEXPR 127 | auto operator/(const TT& lh, const TT& rh) 128 | noexcept(noexcept(std::declval() / std::declval())) 129 | -> R 130 | { 131 | return R{value_of(lh) / value_of(rh)}; 132 | } 133 | 134 | #endif //STRONG_TYPE_SCALABLE_HPP 135 | -------------------------------------------------------------------------------- /include/strong_type/semiregular.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_SEMIREGULAR_HPP 15 | #define STRONG_TYPE_SEMIREGULAR_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong 20 | { 21 | namespace impl 22 | { 23 | 24 | template 25 | struct require_semiregular 26 | : valid_type::value && 27 | require_move_constructible::value && 28 | require_copy_assignable::value && 29 | require_move_assignable::value> 30 | { 31 | }; 32 | 33 | } 34 | struct semiregular 35 | { 36 | template 37 | class modifier; 38 | }; 39 | 40 | template 41 | class semiregular::modifier<::strong::type> 42 | : public default_constructible::modifier 43 | , private impl::require_semiregular 44 | { 45 | }; 46 | 47 | } 48 | #endif //STRONG_TYPE_SEMIREGULAR_HPP 49 | -------------------------------------------------------------------------------- /include/strong_type/strong_ordering.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STRONG_TYPE_STRONG_ORDERING_HPP 2 | #define STRONG_TYPE_STRONG_ORDERING_HPP 3 | 4 | #include 5 | 6 | #include "type.hpp" 7 | 8 | namespace strong 9 | { 10 | struct strong_ordering 11 | { 12 | template 13 | class modifier; 14 | }; 15 | 16 | template 17 | class strong_ordering::modifier<::strong::type> 18 | { 19 | using type = ::strong::type; 20 | public: 21 | STRONG_NODISCARD 22 | friend 23 | STRONG_CONSTEXPR 24 | std::strong_ordering operator<=>(const type& lh, const type& rh) noexcept 25 | { 26 | return value_of(lh) <=> value_of(rh); 27 | } 28 | }; 29 | } 30 | 31 | #endif //STRONG_TYPE_STRONG_ORDERING_HPP 32 | -------------------------------------------------------------------------------- /include/strong_type/strong_type.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef ROLLBEAR_STRONG_TYPE_HPP_INCLUDED 15 | #define ROLLBEAR_STRONG_TYPE_HPP_INCLUDED 16 | 17 | #include "type.hpp" 18 | #include "equality.hpp" 19 | #include "equality_with.hpp" 20 | #include "ordered.hpp" 21 | #include "ordered_with.hpp" 22 | #include "semiregular.hpp" 23 | #include "regular.hpp" 24 | #include "unique.hpp" 25 | #include "invocable.hpp" 26 | #include "iostreamable.hpp" 27 | #include "bicrementable.hpp" 28 | #include "boolean.hpp" 29 | #include "pointer.hpp" 30 | #include "hashable.hpp" 31 | #include "difference.hpp" 32 | #include "affine_point.hpp" 33 | #include "arithmetic.hpp" 34 | #include "bitarithmetic.hpp" 35 | #include "indexed.hpp" 36 | #include "iterator.hpp" 37 | #include "range.hpp" 38 | #include "convertible_to.hpp" 39 | #include "implicitly_convertible_to.hpp" 40 | #include "formattable.hpp" 41 | #include "scalable_with.hpp" 42 | 43 | #endif //ROLLBEAR_STRONG_TYPE_HPP_INCLUDED 44 | -------------------------------------------------------------------------------- /include/strong_type/type.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED 15 | #define ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED 16 | 17 | #if defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 18 | import std; 19 | #else 20 | 21 | #include 22 | #include 23 | #include 24 | #endif 25 | 26 | #if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1922 27 | #define STRONG_CONSTEXPR 28 | #else 29 | #define STRONG_CONSTEXPR constexpr 30 | #endif 31 | 32 | #if __cplusplus >= 201703L 33 | #define STRONG_NODISCARD [[nodiscard]] 34 | #else 35 | #define STRONG_NODISCARD 36 | #endif 37 | 38 | namespace strong { 39 | struct uninitialized_t { 40 | }; 41 | static constexpr uninitialized_t uninitialized{}; 42 | 43 | template 44 | using modifier = typename M::template modifier; 45 | 46 | 47 | struct default_constructible { 48 | template 49 | class modifier { 50 | }; 51 | }; 52 | 53 | namespace impl { 54 | template 55 | constexpr bool supports_default_construction( 56 | const ::strong::default_constructible::modifier *) 57 | { 58 | return true; 59 | } 60 | 61 | template 62 | using WhenConstructible = std::enable_if_t::value>; 63 | } 64 | 65 | template 66 | class type : public modifier> ... { 67 | public: 68 | template{}>> 69 | explicit type(uninitialized_t) 70 | noexcept 71 | { 72 | } 73 | 74 | template(nullptr))> 77 | constexpr 78 | type() 79 | noexcept(noexcept(T{})) 80 | : _val{} 81 | { 82 | } 83 | 84 | template>> 86 | constexpr 87 | explicit 88 | type( 89 | std::initializer_list us 90 | ) 91 | noexcept(noexcept(T{us})) 92 | : _val{us} 93 | { 94 | } 95 | 96 | template::value && (sizeof...(U) > 0)>> 99 | constexpr 100 | explicit 101 | type( 102 | U &&... u) 103 | noexcept(std::is_nothrow_constructible::value) 104 | : _val(std::forward(u)...) 105 | {} 106 | 107 | friend STRONG_CONSTEXPR void swap(type &a, type &b) noexcept( 108 | std::is_nothrow_move_constructible::value && 109 | std::is_nothrow_move_assignable::value 110 | ) 111 | { 112 | using std::swap; 113 | swap(a._val, b._val); 114 | } 115 | 116 | STRONG_NODISCARD 117 | constexpr T &value_of() & noexcept 118 | { return _val; } 119 | 120 | STRONG_NODISCARD 121 | constexpr const T &value_of() const & noexcept 122 | { return _val; } 123 | 124 | STRONG_NODISCARD 125 | constexpr T &&value_of() && noexcept 126 | { return std::move(_val); } 127 | 128 | STRONG_NODISCARD 129 | constexpr const T &&value_of() const && noexcept 130 | { return std::move(_val); } 131 | 132 | STRONG_NODISCARD 133 | friend constexpr T &value_of(type &t) noexcept 134 | { return t._val; } 135 | 136 | STRONG_NODISCARD 137 | friend constexpr const T &value_of(const type &t) noexcept 138 | { return t._val; } 139 | 140 | STRONG_NODISCARD 141 | friend constexpr T &&value_of(type &&t) noexcept 142 | { return std::move(t)._val; } 143 | 144 | STRONG_NODISCARD 145 | friend constexpr const T &&value_of(const type &&t) noexcept 146 | { return std::move(t)._val; } 147 | 148 | T _val; 149 | }; 150 | 151 | namespace impl { 152 | template 153 | constexpr bool is_strong_type_func(const strong::type *) 154 | { return true; } 155 | 156 | constexpr bool is_strong_type_func(...) 157 | { return false; } 158 | 159 | template 160 | constexpr T underlying_type(strong::type *); 161 | 162 | } 163 | 164 | template 165 | struct is_strong_type : std::integral_constant(nullptr))> { 167 | }; 168 | 169 | 170 | template::value> 171 | struct underlying_type { 172 | using type = decltype(impl::underlying_type(static_cast(nullptr))); 173 | }; 174 | 175 | template 176 | struct underlying_type { 177 | using type = T; 178 | }; 179 | 180 | template 181 | using underlying_type_t = typename underlying_type::type; 182 | 183 | namespace impl { 184 | template 185 | using WhenStrongType = std::enable_if_t>::value>; 186 | template 187 | using WhenNotStrongType = std::enable_if_t>::value>; 188 | 189 | template< 190 | typename T, 191 | typename = impl::WhenNotStrongType> 192 | constexpr 193 | T && 194 | access(T &&t) 195 | noexcept 196 | { 197 | return std::forward(t); 198 | } 199 | 200 | template< 201 | typename T, 202 | typename = impl::WhenStrongType> 203 | STRONG_NODISCARD 204 | constexpr 205 | auto 206 | access(T &&t) 207 | noexcept 208 | -> decltype(value_of(std::forward(t))) 209 | { 210 | return value_of(std::forward(t)); 211 | } 212 | 213 | template 214 | struct require_copy_constructible 215 | { 216 | static constexpr bool value = std::is_copy_constructible>::value; 217 | static_assert(value, "underlying type must be copy constructible"); 218 | }; 219 | template 220 | struct require_move_constructible 221 | { 222 | static constexpr bool value = std::is_move_constructible>::value; 223 | static_assert(value, "underlying type must be move constructible"); 224 | }; 225 | template 226 | struct require_copy_assignable 227 | { 228 | static constexpr bool value = std::is_copy_assignable>::value; 229 | static_assert(value, "underlying type must be copy assignable"); 230 | }; 231 | template 232 | struct require_move_assignable 233 | { 234 | static constexpr bool value = std::is_move_assignable>::value; 235 | static_assert(value, "underlying type must be move assignable"); 236 | }; 237 | 238 | template 239 | static constexpr bool always_false = false; 240 | 241 | template struct valid_type; 242 | template <> 243 | struct valid_type {}; 244 | 245 | template 246 | using void_t = void; 247 | 248 | 249 | template 250 | static constexpr bool modifier_is 251 | = std::is_base_of, modifier>::value; 252 | 253 | template 254 | static 255 | constexpr 256 | bool 257 | type_implements 258 | = std::is_base_of, modifier>::value; 259 | 260 | #if __cplusplus >= 201703 261 | template < 262 | template class Modifier, 263 | typename Needle, 264 | typename Type, 265 | typename ... Ms 266 | > 267 | static 268 | constexpr 269 | bool 270 | modifier_is> 271 | = (std::is_base_of, modifier, Type>>::value || ...); 272 | 273 | template < 274 | template class Modifier, 275 | typename ... Needles, 276 | typename Type, 277 | typename ... Haystack 278 | > 279 | static 280 | constexpr 281 | bool type_implements, Type, Modifier> 282 | = (modifier_is, Type, Modifier> && ...); 283 | #else 284 | template 285 | struct conjunction; 286 | template 287 | struct conjunction 288 | : std::integral_constant::value> 289 | {}; 290 | template <> 291 | struct conjunction<> : std::true_type {}; 292 | 293 | template 294 | struct disjunction; 295 | template 296 | struct disjunction 297 | : std::integral_constant::value> 298 | {}; 299 | template <> 300 | struct disjunction<> : std::false_type {}; 301 | 302 | template < 303 | template class Modifier, 304 | typename Needle, 305 | typename Type, 306 | typename ... Ms 307 | > 308 | static 309 | constexpr 310 | bool 311 | modifier_is> 312 | = disjunction< 313 | std::is_base_of< 314 | modifier, 315 | modifier, Type> 316 | >... 317 | >::value; 318 | 319 | template < 320 | template class Modifier, 321 | typename ... Needles, 322 | typename Type, 323 | typename ... Haystack 324 | > 325 | static 326 | constexpr 327 | bool 328 | type_implements, Type, Modifier> 329 | = conjunction< 330 | std::integral_constant< 331 | bool, 332 | modifier_is< 333 | Modifier, 334 | Type, 335 | Modifier 336 | > 337 | >... 338 | >::value; 339 | #endif 340 | 341 | template 342 | static constexpr bool type_is = false; 343 | 344 | #if __cplusplus >= 201703L 345 | template 346 | static constexpr bool type_is, M> 347 | = (impl::type_implements, Ms> || ...); 348 | #else 349 | template 350 | static constexpr bool type_is, M> 351 | = impl::disjunction, Ms>>...>::value; 352 | #endif 353 | 354 | template 355 | type get_strong_(const type*); 356 | 357 | template 358 | using get_strong = decltype(get_strong_(static_cast(nullptr))); 359 | } 360 | 361 | template 362 | static constexpr bool type_is_v = impl::type_is, M>; 363 | 364 | template 365 | using type_is = std::integral_constant>; 366 | 367 | } 368 | 369 | #endif //ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED 370 | -------------------------------------------------------------------------------- /include/strong_type/unique.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_UNIQUE_HPP 15 | #define STRONG_TYPE_UNIQUE_HPP 16 | 17 | #include "type.hpp" 18 | 19 | namespace strong { 20 | 21 | struct unique { 22 | template 23 | class modifier 24 | : private impl::valid_type< 25 | impl::require_move_constructible::value && 26 | impl::require_move_assignable::value 27 | > { 28 | public: 29 | constexpr modifier() = default; 30 | modifier(const modifier &) = delete; 31 | constexpr modifier(modifier &&) noexcept = default; 32 | modifier &operator=(const modifier &) = delete; 33 | constexpr modifier &operator=(modifier &&) noexcept = default; 34 | }; 35 | }; 36 | 37 | } 38 | #endif //STRONG_TYPE_UNIQUE_HPP 39 | -------------------------------------------------------------------------------- /strong_type-config.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # strong_type C++14/17/20 strong typedef library 3 | # 4 | # Copyright (C) Björn Fahller 5 | # 6 | # Use, modification and distribution is subject to the 7 | # Boost Software License, Version 1.0. (See accompanying 8 | # file LICENSE_1_0.txt or copy at 9 | # http://www.boost.org/LICENSE_1_0.txt) 10 | # 11 | # Project home: https://github.com/rollbear/strong_type 12 | # 13 | 14 | 15 | include( "${CMAKE_CURRENT_LIST_DIR}/strong_type-targets.cmake" ) 16 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (!CMAKE_CXX_STANDARD) 2 | set(CMAKE_CXX_STANDARD 14) 3 | endif() 4 | set(CMAKE_CXX_STANDARD_REQUIRED YES) 5 | 6 | if(${STRONG_TYPE_IMPORT_STD_LIBRARY}) 7 | # This is currently required to be ON for a clang module build 8 | # https://gitlab.kitware.com/cmake/cmake/-/issues/25916 9 | # https://gitlab.kitware.com/cmake/cmake/-/issues/25539 10 | set(CMAKE_CXX_EXTENSIONS ON) 11 | else() 12 | set(CMAKE_CXX_EXTENSIONS OFF) 13 | endif() 14 | 15 | if(NOT ${STRONG_TYPE_IMPORT_STD_LIBRARY}) 16 | cmake_minimum_required(VERSION 3.22) 17 | endif() 18 | 19 | find_package(Catch2 3 QUIET) 20 | if (${Catch2_FOUND}) 21 | add_compile_definitions(CATCH2=3) 22 | else () 23 | find_package(Catch2 2 QUIET) 24 | endif() 25 | if (TARGET Catch2::Catch2WithMain) 26 | set(CATCHLIBS Catch2::Catch2WithMain) 27 | endif() 28 | if (NOT ${Catch2_FOUND}) 29 | set(TEST_MAIN "test_main.cpp") 30 | set(CATCH_DIR ${CMAKE_CURRENT_BINARY_DIR}/catch) 31 | if(NOT EXISTS ${CATCH_DIR}/catch2/catch.hpp) 32 | if (NOT EXISTS ${CATCH_DIR}/catch2) 33 | file(MAKE_DIRECTORY "${CATCH_DIR}/catch2") 34 | endif() 35 | file( 36 | DOWNLOAD 37 | https://github.com/catchorg/Catch2/releases/download/v2.13.9/catch.hpp ${CATCH_DIR}/catch2/catch.hpp 38 | STATUS 39 | status 40 | LOG 41 | log 42 | ) 43 | list(GET status 0 status_code) 44 | list(GET status 1 status_string) 45 | 46 | if(NOT status_code EQUAL 0) 47 | message(FATAL_ERROR "error downloading catch: ${status_string}" 48 | "${log}") 49 | endif() 50 | 51 | endif() 52 | add_library(Catch2 INTERFACE) 53 | add_library(Catch2::Catch2 ALIAS Catch2) 54 | target_include_directories( 55 | Catch2 56 | INTERFACE 57 | ${CATCH_DIR} 58 | ) 59 | set(CATCH_MAIN "${CMAKE_SOURCE_DIR}/test/test_main.cpp") 60 | add_compile_definitions(CATCH2=2) 61 | endif() 62 | 63 | if(STRONG_TYPE_IMPORT_STD_LIBRARY) 64 | message(STATUS "Building using import std") 65 | add_compile_definitions(STRONG_TYPE_IMPORT_STD_LIBRARY=1) 66 | endif() 67 | 68 | add_executable( 69 | self_test 70 | test.cpp 71 | test_type.cpp 72 | test_equality.cpp 73 | test_equality_with.cpp 74 | test_ordered.cpp 75 | test_ordered_with.cpp 76 | test_semiregular.cpp 77 | test_regular.cpp 78 | test_unique.cpp 79 | test_ostreamable.cpp 80 | test_istreamable.cpp 81 | test_iostreamable.cpp 82 | test_incrementable.cpp 83 | test_decrementable.cpp 84 | test_bicrementable.cpp 85 | test_boolean.cpp 86 | test_pointer.cpp 87 | test_hashable.cpp 88 | test_difference.cpp 89 | test_affine_point.cpp 90 | test_arithmetic.cpp 91 | test_bitarithmetic.cpp 92 | test_indexed.cpp 93 | test_invocable.cpp 94 | test_iterator.cpp 95 | test_range.cpp 96 | test_convertible_to.cpp 97 | test_implicitly_convertible_to.cpp 98 | empty.cpp 99 | test_scalable_with.cpp 100 | ${CATCH_MAIN} 101 | ) 102 | 103 | target_link_libraries( 104 | self_test 105 | PUBLIC 106 | Catch2::Catch2 107 | ${CATCHLIBS} 108 | strong_type::strong_type 109 | ) 110 | 111 | add_subdirectory(test_fmt8) 112 | add_subdirectory(test_fmt9) 113 | add_subdirectory(test_fmt10) 114 | add_subdirectory(test_fmt11) 115 | -------------------------------------------------------------------------------- /test/catch2.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_CATCH2_HPP 15 | #define STRONG_TYPE_CATCH2_HPP 16 | 17 | #if CATCH2 == 3 18 | #include 19 | #else 20 | #include 21 | #endif 22 | 23 | #endif //STRONG_TYPE_CATCH2_HPP 24 | -------------------------------------------------------------------------------- /test/empty.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | 15 | 16 | #include 17 | -------------------------------------------------------------------------------- /test/test_affine_point.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | 19 | TEST_CASE("affine_point types can be subtracted") 20 | { 21 | using D = strong::type; 22 | using T = strong::type>; 23 | 24 | T t1{3}; 25 | T t2{8}; 26 | auto d = t2 - t1; 27 | static_assert(std::is_same{}, ""); 28 | REQUIRE(value_of(d) == 5); 29 | } 30 | 31 | TEST_CASE("affine point type with defaulted difference type yields it when subtracting") 32 | { 33 | using T = strong::type>; 34 | 35 | T t1{3}; 36 | T t2{8}; 37 | auto d = t2 - t1; 38 | static_assert(std::is_same>{},""); 39 | REQUIRE(value_of(d) == 5); 40 | } 41 | 42 | TEST_CASE("affine_point types can be added with the delta type") 43 | { 44 | using D = strong::type; 45 | using T = strong::type>; 46 | 47 | T t1{8}; 48 | D d{3}; 49 | 50 | auto t2 = t1 + d; 51 | static_assert(std::is_same{}, ""); 52 | REQUIRE(value_of(t2) == 11); 53 | auto t3 = d + t1; 54 | static_assert(std::is_same{}, ""); 55 | REQUIRE(value_of(t3) == 11); 56 | t1 += d; 57 | REQUIRE(value_of(t1) == 11); 58 | } 59 | 60 | TEST_CASE("affine_point types can be subtracted with the delta type") 61 | { 62 | using D = strong::type; 63 | using T = strong::type>; 64 | 65 | T t1{8}; 66 | D d{3}; 67 | 68 | auto t2 = t1 - d; 69 | static_assert(std::is_same{}, ""); 70 | REQUIRE(value_of(t2) == 5); 71 | t1 -= d; 72 | REQUIRE(value_of(t1) == 5); 73 | } 74 | -------------------------------------------------------------------------------- /test/test_arithmetic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | namespace strong 19 | { 20 | TEST_CASE("arithmetic types can be added") 21 | { 22 | using T = strong::type; 23 | 24 | T i{3}; 25 | T j{4}; 26 | REQUIRE(value_of(i + j) == 7); 27 | REQUIRE(value_of(i) == 3); 28 | REQUIRE(value_of(j) == 4); 29 | i += j; 30 | REQUIRE(value_of(i) == 7); 31 | REQUIRE(value_of(j) == 4); 32 | } 33 | 34 | TEST_CASE("arithmetic types can be subtracted") 35 | { 36 | using T = strong::type; 37 | 38 | T i{7}; 39 | T j{4}; 40 | REQUIRE(value_of(i - j) == 3); 41 | REQUIRE(value_of(i) == 7); 42 | REQUIRE(value_of(j) == 4); 43 | i -= j; 44 | REQUIRE(value_of(i) == 3); 45 | REQUIRE(value_of(j) == 4); 46 | } 47 | 48 | TEST_CASE("arithmetic types can be multiplied") 49 | { 50 | using T = strong::type; 51 | 52 | T i{12}; 53 | T j{3}; 54 | REQUIRE(value_of(i * j) == 36); 55 | REQUIRE(value_of(i) == 12); 56 | REQUIRE(value_of(j) == 3); 57 | i *= j; 58 | REQUIRE(value_of(i) == 36); 59 | REQUIRE(value_of(j) == 3); 60 | } 61 | 62 | TEST_CASE("arithmetic types can be divided") 63 | { 64 | using T = strong::type; 65 | 66 | T i{12}; 67 | T j{3}; 68 | REQUIRE(value_of(i / j) == 4); 69 | REQUIRE(value_of(i) == 12); 70 | REQUIRE(value_of(j) == 3); 71 | i /= j; 72 | REQUIRE(value_of(i) == 4); 73 | REQUIRE(value_of(j) == 3); 74 | } 75 | 76 | TEST_CASE("the remainder of integral arithmetic types can be calculated") 77 | { 78 | using T = strong::type; 79 | 80 | T i{12}; 81 | T j{5}; 82 | REQUIRE(value_of(i % j) == 2); 83 | REQUIRE(value_of(i) == 12); 84 | REQUIRE(value_of(j) == 5); 85 | i %= j; 86 | REQUIRE(value_of(i) == 2); 87 | REQUIRE(value_of(j) == 5); 88 | } 89 | 90 | TEST_CASE("an aritmmetic type can be negated") 91 | { 92 | using T = strong::type; 93 | 94 | T i{12}; 95 | REQUIRE(value_of(-i) == -12); 96 | REQUIRE(value_of(i) == 12); 97 | } 98 | 99 | } -------------------------------------------------------------------------------- /test/test_bicrementable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | TEST_CASE("a bicrementable goes both ways") 19 | { 20 | using C = strong::type; 21 | 22 | C c{3}; 23 | REQUIRE(value_of(++c) == 4); 24 | REQUIRE(value_of(c) == 4); 25 | REQUIRE(value_of(c++) == 4); 26 | REQUIRE(value_of(c) == 5); 27 | REQUIRE(value_of(--c) == 4); 28 | REQUIRE(value_of(c) == 4); 29 | REQUIRE(value_of(c--) == 4); 30 | REQUIRE(value_of(c) == 3); 31 | } 32 | -------------------------------------------------------------------------------- /test/test_bitarithmetic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | 19 | TEST_CASE("bitarithmetic types can be bitanded") 20 | { 21 | using T = strong::type; 22 | using u = uint16_t; 23 | 24 | T i{u(0x0f0f)}; 25 | T j{u(0x5555)}; 26 | 27 | REQUIRE(value_of(i & j) == u(0x0505)); 28 | REQUIRE(value_of(i) == u(0x0f0f)); 29 | REQUIRE(value_of(j) == u(0x5555)); 30 | REQUIRE(value_of(i &= j) == u(0x0505)); 31 | REQUIRE(value_of(i) == u(0x0505)); 32 | REQUIRE(value_of(j) == u(0x5555)); 33 | } 34 | 35 | TEST_CASE("bitarithmetic types can be bitored") 36 | { 37 | using T = strong::type; 38 | using u = uint16_t; 39 | 40 | T i{u(0x0f0f)}; 41 | T j{u(0x5555)}; 42 | 43 | REQUIRE(value_of(i | j) == u(0x5f5f)); 44 | REQUIRE(value_of(i) == u(0x0f0f)); 45 | REQUIRE(value_of(j) == u(0x5555)); 46 | REQUIRE(value_of(i |= j) == u(0x5f5f)); 47 | REQUIRE(value_of(i) == u(0x5f5f)); 48 | REQUIRE(value_of(j) == u(0x5555)); 49 | } 50 | 51 | TEST_CASE("bitarithmetic types can be bitxored") 52 | { 53 | using T = strong::type; 54 | using u = uint16_t; 55 | 56 | T i{u(0x0f0f)}; 57 | T j{u(0x5555)}; 58 | 59 | REQUIRE(value_of(i ^ j) == u(0x5a5a)); 60 | REQUIRE(value_of(i) == u(0x0f0f)); 61 | REQUIRE(value_of(j) == u(0x5555)); 62 | REQUIRE(value_of(i ^= j) == u(0x5a5a)); 63 | REQUIRE(value_of(i) == u(0x5a5a)); 64 | REQUIRE(value_of(j) == u(0x5555)); 65 | } 66 | 67 | TEST_CASE("bitarithmetic types can be left shifted") 68 | { 69 | using T = strong::type; 70 | using u = uint16_t; 71 | 72 | T i{u(0x0f0f)}; 73 | 74 | REQUIRE(value_of(i << 2) == u(0x3c3c)); 75 | REQUIRE(value_of(i) == u(0x0f0f)); 76 | REQUIRE(value_of(i <<= 3) == u(0x7878)); 77 | REQUIRE(value_of(i) == u(0x7878)); 78 | } 79 | 80 | TEST_CASE("bitarithmetic types can be right shifted") 81 | { 82 | using T = strong::type; 83 | using u = uint16_t; 84 | 85 | T i{u(0x0f0f)}; 86 | 87 | REQUIRE(value_of(i >> 2) == u(0x03c3)); 88 | REQUIRE(value_of(i) == u(0x0f0f)); 89 | REQUIRE(value_of(i >>= 1) == u(0x0787)); 90 | REQUIRE(value_of(i) == u(0x0787)); 91 | } 92 | 93 | TEST_CASE("bitarithmetic types can be inverted") 94 | { 95 | using T = strong::type; 96 | using u = uint16_t; 97 | 98 | T i{u(0x0f0f)}; 99 | 100 | REQUIRE(value_of(~i) == u(0xf0f0)); 101 | REQUIRE(value_of(i) == u(0x0f0f)); 102 | } 103 | -------------------------------------------------------------------------------- /test/test_boolean.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | TEST_CASE("a boolean value can be tested for truth") 19 | { 20 | using I = strong::type; 21 | 22 | I i{3}; 23 | REQUIRE(i); 24 | REQUIRE_FALSE(!i); 25 | i = I{0}; 26 | REQUIRE(!i); 27 | REQUIRE_FALSE(i); 28 | } 29 | -------------------------------------------------------------------------------- /test/test_convertible_to.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #include "test_utils.hpp" 19 | 20 | using type = strong::type>; 21 | using multi_type = strong::type>; 22 | 23 | TEST_CASE("convertible to can be convert in an explicit construction") 24 | { 25 | type t{3}; 26 | int x{t}; 27 | 28 | REQUIRE(x == 3); 29 | } 30 | 31 | TEST_CASE("convertible_to can convert in a static_cast") 32 | { 33 | type t{3}; 34 | int x = 0; 35 | x = static_cast(t); 36 | REQUIRE(x == 3); 37 | } 38 | 39 | TEST_CASE("convertible_to can convert to several types") 40 | { 41 | multi_type t{3}; 42 | int x{t}; 43 | REQUIRE(x == 3); 44 | 45 | bool b{t}; 46 | REQUIRE(b); 47 | 48 | double d{t}; 49 | REQUIRE(d == 3.0); 50 | } 51 | -------------------------------------------------------------------------------- /test/test_decrementable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | TEST_CASE("a decrementable can be decremented") 19 | { 20 | using C = strong::type; 21 | 22 | C c{10}; 23 | REQUIRE(value_of(--c) == 9); 24 | REQUIRE(value_of(c) == 9); 25 | REQUIRE(value_of(c--) == 9); 26 | REQUIRE(value_of(c) == 8); 27 | } 28 | -------------------------------------------------------------------------------- /test/test_difference.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | TEST_CASE("adding difference types yields a difference type") 19 | { 20 | using U = strong::type; 21 | 22 | U u1{3}; 23 | U u2{4}; 24 | 25 | auto r = u1 + u2; 26 | static_assert(std::is_same{},""); 27 | REQUIRE(value_of(r) == 7); 28 | } 29 | 30 | TEST_CASE("subtracting difference types yields a difference type") 31 | { 32 | using U = strong::type; 33 | 34 | U u1{8}; 35 | U u2{3}; 36 | 37 | auto r = u1 - u2; 38 | 39 | static_assert(std::is_same{}, ""); 40 | REQUIRE(value_of(r) == 5); 41 | } 42 | 43 | TEST_CASE("dividing difference types yields a base type") 44 | { 45 | using U = strong::type; 46 | 47 | U u1{8}; 48 | U u2{2}; 49 | 50 | auto r = u1/u2; 51 | static_assert(std::is_same{}, ""); 52 | REQUIRE(r == 4); 53 | } 54 | 55 | TEST_CASE("remainder after division between difference types yields a base type") 56 | { 57 | using U = strong::type; 58 | 59 | U u1{15}; 60 | U u2{6}; 61 | 62 | auto r = u1 % u2; 63 | 64 | static_assert(std::is_same{},""); 65 | REQUIRE(r == 3); 66 | } 67 | 68 | TEST_CASE("remainder after division between difference type and base type yields a difference type") 69 | { 70 | using U = strong::type; 71 | 72 | U u{15}; 73 | 74 | auto r = u % 6; 75 | 76 | static_assert(std::is_same{}, ""); 77 | REQUIRE(r == U{3}); 78 | } 79 | 80 | TEST_CASE("dividing a difference type with its base type yields a difference") 81 | { 82 | using U = strong::type; 83 | 84 | U u{8}; 85 | 86 | auto r = u/2; 87 | static_assert(std::is_same{}, ""); 88 | REQUIRE(value_of(r) == 4); 89 | } 90 | 91 | TEST_CASE("difference types are ordered and equality comparable") 92 | { 93 | using U = strong::type; 94 | 95 | U u1{1}; 96 | U u2{2}; 97 | U u3{1}; 98 | 99 | REQUIRE(u1 == u3); 100 | REQUIRE(!(u1 == u2)); 101 | REQUIRE(u1 != u2); 102 | REQUIRE(!(u1 != u3)); 103 | REQUIRE(u1 < u2); 104 | REQUIRE(!(u1 < u3)); 105 | REQUIRE(u1 <= u2); 106 | REQUIRE(u1 <= u3); 107 | REQUIRE(!(u2 <= u1)); 108 | REQUIRE(u2 > u1); 109 | REQUIRE(!(u3 > u1)); 110 | REQUIRE(!(u3 > u2)); 111 | REQUIRE(u3 >= u1); 112 | REQUIRE(u3 >= u1); 113 | REQUIRE(!(u3 >= u2)); 114 | } 115 | 116 | TEST_CASE("multiplying a difference with its base type yields a difference") 117 | { 118 | using U = strong::type; 119 | 120 | U u{3}; 121 | 122 | auto r1 = u * 2; 123 | static_assert(std::is_same{}, ""); 124 | REQUIRE(value_of(r1) == 6); 125 | 126 | auto r2 = 3 * u; 127 | static_assert(std::is_same{}, ""); 128 | REQUIRE(value_of(r2) == 9); 129 | } 130 | 131 | namespace { 132 | struct S { 133 | int v; 134 | 135 | S(int v_) : v(v_) {} 136 | template 137 | S &operator+=(const S &rh) { v += rh.v; return *this; } 138 | template 139 | friend S operator+(S lh, const S &rh) { return lh += rh; } 140 | template 141 | S &operator-=(const S &rh) { v -= rh.v; return *this; } 142 | template 143 | friend S operator-(S lh, const S &rh) { return lh -= rh; } 144 | template 145 | friend bool operator==(const S &lh, const S &rh) { return lh.v == rh.v; } 146 | template 147 | friend bool operator!=(const S &lh, const S &rh) { return lh.v != rh.v; } 148 | }; 149 | } 150 | 151 | TEST_CASE("an equality comparable arithmetic type without ordering can be a difference") 152 | { 153 | using type = strong::type; 154 | REQUIRE(type{3} - type{2} == type{1}); 155 | } -------------------------------------------------------------------------------- /test/test_equality.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | TEST_CASE("values can be compared using operator==") 19 | { 20 | using type = strong::type; 21 | 22 | type i{3}; 23 | type j{4}; 24 | type k{3}; 25 | REQUIRE_FALSE(i == j); 26 | REQUIRE(i == k); 27 | } 28 | 29 | TEST_CASE("values can be compared using operator!=") 30 | { 31 | using type = strong::type; 32 | 33 | type i{3}; 34 | type j{4}; 35 | type k{3}; 36 | REQUIRE(i != j); 37 | REQUIRE(!(i != k)); 38 | } 39 | -------------------------------------------------------------------------------- /test/test_equality_with.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | TEST_CASE("equality_with can compare with defined type") 19 | { 20 | using t1 = strong::type; 21 | using t2 = strong::type>; 22 | 23 | REQUIRE(t1{1} == t2{1}); 24 | REQUIRE(t2{1} == t1{1}); 25 | REQUIRE(t1{1} != t2{2}); 26 | REQUIRE(t2{2} != t1{1}); 27 | } 28 | -------------------------------------------------------------------------------- /test/test_fmt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "strong_type/formattable.hpp" 15 | 16 | #include "catch2.hpp" 17 | 18 | struct so { 19 | so(int v) : i(v) {} 20 | int i; 21 | friend std::ostream& operator<<(std::ostream& os, const so& obj) 22 | { 23 | return os << "os << " << obj.i; 24 | } 25 | }; 26 | 27 | template 28 | struct fmt::formatter : fmt::formatter 29 | { 30 | template 31 | decltype(auto) 32 | format(const so& t, FormatContext& fc) const 33 | { 34 | return formatter::format(t.i, fc); 35 | } 36 | }; 37 | 38 | using osso = strong::type; 39 | using fmtso = strong::type; 40 | using fmtosso = strong::type; 41 | 42 | TEST_CASE("ostreamable is formattable") 43 | { 44 | osso val{3}; 45 | auto s = fmt::format("{}", val); 46 | REQUIRE(s == "os << 3"); 47 | } 48 | TEST_CASE("formattable is formattable") 49 | { 50 | fmtso val{3}; 51 | auto s = fmt::format("{}", val); 52 | REQUIRE(s == "3"); 53 | } 54 | 55 | TEST_CASE("formattable and ostreamable is formattable as formattable") 56 | { 57 | fmtosso val{3}; 58 | auto s = fmt::format("{}", val); 59 | REQUIRE(s == "3"); 60 | } 61 | -------------------------------------------------------------------------------- /test/test_fmt10/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(fmt 10 QUIET) 2 | if (fmt_FOUND) 3 | add_executable(test_fmt10 ../test_fmt.cpp ${CATCH_MAIN}) 4 | target_link_libraries(test_fmt10 ${CATCHLIBS} Catch2::Catch2 fmt::fmt strong_type::strong_type) 5 | endif() 6 | -------------------------------------------------------------------------------- /test/test_fmt11/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(fmt 11 QUIET) 2 | if (fmt_FOUND) 3 | add_executable(test_fmt11 ../test_fmt.cpp ${CATCH_MAIN}) 4 | target_link_libraries(test_fmt11 ${CATCHLIBS} Catch2::Catch2 fmt::fmt strong_type::strong_type) 5 | endif() 6 | -------------------------------------------------------------------------------- /test/test_fmt8/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(fmt 8...<9 QUIET) 2 | if (fmt_FOUND) 3 | add_executable(test_fmt8 ../test_fmt.cpp ${CATCH_MAIN}) 4 | target_link_libraries(test_fmt8 ${CATCHLIBS} Catch2::Catch2 fmt::fmt strong_type::strong_type) 5 | endif() 6 | -------------------------------------------------------------------------------- /test/test_fmt9/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(fmt 9 QUIET) 2 | if (fmt_FOUND) 3 | add_executable(test_fmt9 ../test_fmt.cpp ${CATCH_MAIN}) 4 | target_link_libraries(test_fmt9 ${CATCHLIBS} Catch2::Catch2 fmt::fmt strong_type::strong_type) 5 | endif() 6 | -------------------------------------------------------------------------------- /test/test_hashable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | #include 18 | 19 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 20 | #include 21 | #endif 22 | 23 | TEST_CASE("strong::hashable can be used in unordered_set") 24 | { 25 | using hs = strong::type; 26 | 27 | using sset = std::unordered_set; 28 | 29 | sset strings{hs{"foo"}, hs{"bar"}}; 30 | 31 | REQUIRE(strings.find(hs{"foo"}) != strings.end()); 32 | REQUIRE(strings.find(hs{"bar"}) != strings.end()); 33 | REQUIRE(strings.find(hs{"baz"}) == strings.end()); 34 | } 35 | -------------------------------------------------------------------------------- /test/test_implicitly_convertible_to.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #include "test_utils.hpp" 19 | 20 | using type = strong::type>; 21 | using multi_type = strong::type>; 22 | 23 | TEST_CASE("implicitly_convertible_to can be convert in an explicit construction") 24 | { 25 | type t{3}; 26 | int x{t}; 27 | 28 | REQUIRE(x == 3); 29 | } 30 | 31 | TEST_CASE("implicitly_convertible_to can convert in a static_cast") 32 | { 33 | type t{3}; 34 | int x = 0; 35 | x = static_cast(t); 36 | REQUIRE(x == 3); 37 | } 38 | 39 | TEST_CASE("implicitly_convertible_to can convert in a comparison") 40 | { 41 | type t{3}; 42 | REQUIRE(t == 3); 43 | } 44 | 45 | template 46 | T as(T t) { return t;} 47 | TEST_CASE("implicitly_convertible_to can convert to several types") 48 | { 49 | multi_type t{3}; 50 | REQUIRE(as(t) == 3); 51 | 52 | REQUIRE(t); 53 | 54 | REQUIRE(as(t) == 3.0); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /test/test_incrementable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | TEST_CASE("an incrementable can be incremented") 19 | { 20 | using C = strong::type; 21 | 22 | C c{3}; 23 | REQUIRE(value_of(++c) == 4); 24 | REQUIRE(value_of(c) == 4); 25 | REQUIRE(value_of(c++) == 4); 26 | REQUIRE(value_of(c) == 5); 27 | } 28 | -------------------------------------------------------------------------------- /test/test_indexed.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #include "test_utils.hpp" 19 | 20 | TEST_CASE("indexed can be accessed using operator [] and .at()") 21 | { 22 | using I = strong::type; 23 | using T = strong::type>; 24 | using TI = strong::type>; 25 | 26 | T s("foo"); 27 | const T c("bar"); 28 | TI si("foo"); 29 | const TI ci("bar"); 30 | 31 | auto& r = s[I{0U}]; 32 | static_assert(!std::is_const>{}, ""); 33 | REQUIRE(r == 'f'); 34 | auto& ri = si[I{0U}]; 35 | static_assert(!std::is_const>{}, ""); 36 | REQUIRE(ri == 'f'); 37 | auto& cr = c[I{0U}]; 38 | static_assert(std::is_const>{}, ""); 39 | REQUIRE(cr == 'b'); 40 | auto& cri = ci[I{0U}]; 41 | static_assert(std::is_const>{}, ""); 42 | REQUIRE(cri == 'b'); 43 | 44 | auto& ar = s.at(I{0U}); 45 | static_assert(!std::is_const>{}, ""); 46 | REQUIRE(ar == 'f'); 47 | auto& ari = si.at(I{0U}); 48 | static_assert(!std::is_const>{}, ""); 49 | REQUIRE(ari == 'f'); 50 | auto& acr = c.at(I{0U}); 51 | static_assert(std::is_const>{}, ""); 52 | REQUIRE(acr == 'b'); 53 | auto& acri = ci.at(I{0U}); 54 | static_assert(std::is_const>{}, ""); 55 | REQUIRE(acri == 'b'); 56 | 57 | // operator[] on std::string returns lvalue reference 58 | static_assert(std::is_same()[1]), char&>{},""); 59 | // hence ... 60 | 61 | auto&& tmp = std::move(s)[1U]; 62 | STATIC_REQUIRE(std::is_same{}); 63 | REQUIRE(tmp == 'o'); 64 | 65 | auto&& tmpat = std::move(s).at(1U); 66 | STATIC_REQUIRE(std::is_same{}); 67 | REQUIRE(tmpat == 'o'); 68 | 69 | 70 | auto&& tmpi = std::move(si)[I{1U}]; 71 | STATIC_REQUIRE(std::is_same{}); 72 | REQUIRE(tmpi == 'o'); 73 | 74 | auto&& tmpiat = std::move(si).at(I{1U}); 75 | STATIC_REQUIRE(std::is_same{}); 76 | REQUIRE(tmpiat == 'o'); 77 | } 78 | 79 | template 80 | class simple_array 81 | { 82 | public: 83 | T& operator[](int x) & { return data_[x];} 84 | T&& operator[](int x) && { return std::move(data_[x]);} 85 | const T& operator[](int x) const & { return data_[x];} 86 | const T& operator[](int x) const && { return data_[x];} 87 | private: 88 | T data_[N] = {}; 89 | }; 90 | 91 | template 92 | using array = strong::type, struct array_, 93 | strong::default_constructible, 94 | strong::indexed>; 95 | template struct S; 96 | TEST_CASE("indexed can be accessed with operator[] without at()") 97 | { 98 | using A = array; 99 | 100 | A a{}; 101 | const A ca{}; 102 | 103 | static_assert(std::is_same{}, ""); 104 | static_assert(std::is_same{}, ""); 105 | static_assert(std::is_same{}, ""); 106 | static_assert(std::is_same{}, ""); 107 | 108 | a[0] = 3; 109 | a[1] = 4; 110 | a[2] = 5; 111 | 112 | REQUIRE(as_const(a)[0] == 3); 113 | REQUIRE(a[1] == 4); 114 | REQUIRE(std::move(as_const(a))[2] == 5); 115 | } 116 | -------------------------------------------------------------------------------- /test/test_invocable.cpp: -------------------------------------------------------------------------------- 1 | #include "catch2.hpp" 2 | 3 | #include 4 | 5 | namespace { 6 | using type = strong::type; 7 | 8 | constexpr int noexcept_func(int x) noexcept { return x + 1; } 9 | constexpr int except_func(int x) { return x - 1; } 10 | constexpr int &identity(int &x){ return x; } 11 | 12 | constexpr type wontthrow{noexcept_func}; 13 | constexpr type maythrow(except_func); 14 | using itype = strong::type; 15 | constexpr itype ident(identity); 16 | 17 | template 18 | constexpr const T &as_const(const T &t) { return t; } 19 | 20 | } 21 | 22 | static_assert(wontthrow(0) == 1,""); 23 | static_assert(maythrow(1) == 0,""); 24 | static_assert(as_const(wontthrow)(0) == 1,""); 25 | static_assert(as_const(maythrow)(1) == 0,""); 26 | static_assert(std::move(wontthrow)(0) == 1,""); 27 | static_assert(std::move(maythrow)(1) == 0,""); 28 | static_assert(std::move(as_const(wontthrow))(0) == 1,""); 29 | static_assert(std::move(as_const(maythrow))(1) == 0,""); 30 | 31 | int global_invoke_x = 0; 32 | static_assert(std::is_same{}, ""); 33 | static_assert(std::is_same{}, ""); 34 | static_assert(std::is_same{}, ""); 35 | static_assert(std::is_same{}, ""); 36 | 37 | TEST_CASE("invocable qualifiers are respected") 38 | { 39 | struct S { 40 | int operator()() & {return 1;} 41 | int operator()() && { return 2;} 42 | int operator()() const & { return 3;} 43 | int operator()() const && { return 4;} 44 | }; 45 | 46 | using T = strong::type; 47 | 48 | T t(S{}); 49 | REQUIRE(t() == 1); 50 | REQUIRE(as_const(t)() == 3); 51 | REQUIRE(std::move(t)() == 2); 52 | REQUIRE(std::move(as_const(t))() == 4); 53 | } -------------------------------------------------------------------------------- /test/test_iostreamable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #endif 21 | 22 | TEST_CASE("an iostreamable type can be both read and written using streams") 23 | { 24 | strong::type i{0}; 25 | std::istringstream is{"3"}; 26 | is >> i; 27 | std::ostringstream os; 28 | os << i; 29 | REQUIRE(os.str() == "3"); 30 | } 31 | -------------------------------------------------------------------------------- /test/test_istreamable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #endif 21 | 22 | TEST_CASE("an istreamable type can be read from a istream") 23 | { 24 | strong::type i{0}, j{0}; 25 | 26 | std::istringstream is{" 3 4"}; 27 | is >> i >> j; 28 | REQUIRE(value_of(i) == 3); 29 | REQUIRE(value_of(j) == 4); 30 | } 31 | -------------------------------------------------------------------------------- /test/test_iterator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #include 21 | #include 22 | #endif 23 | 24 | TEST_CASE("iterators work with algorithms") 25 | { 26 | std::unordered_set is{3,2,8,4,11,9,22,23}; 27 | using si = strong::type::iterator, struct si_, strong::iterator>; 28 | si sb{is.begin()}; 29 | si se{is.end()}; 30 | 31 | std::vector v; 32 | std::copy(sb, se, std::back_inserter(v)); 33 | 34 | using vi = strong::type::iterator, struct vi_, strong::iterator>; 35 | 36 | vi vb{v.begin()}; 37 | vi ve{v.end()}; 38 | std::sort(vb, ve); 39 | REQUIRE(vb[0] == 2); 40 | REQUIRE(vb[7] == 23); 41 | } 42 | -------------------------------------------------------------------------------- /test/test_main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | 15 | #define CATCH_CONFIG_MAIN 16 | #include "catch2/catch.hpp" 17 | 18 | -------------------------------------------------------------------------------- /test/test_ordered.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #endif 21 | 22 | TEST_CASE("ordered type can be compared for ordering") 23 | { 24 | using type = strong::type; 25 | 26 | const type i1{1}; 27 | const type i2{2}; 28 | 29 | REQUIRE(i1 < i2); 30 | REQUIRE(i1 <= i2); 31 | REQUIRE(i1 <= i1); 32 | REQUIRE(i2 > i1); 33 | REQUIRE(i2 >= i2); 34 | REQUIRE(i2 >= i1); 35 | 36 | REQUIRE_FALSE(i2 < i1); 37 | REQUIRE_FALSE(i2 <= i1); 38 | REQUIRE_FALSE(i1 > i2); 39 | REQUIRE_FALSE(i1 >= i2); 40 | } 41 | 42 | #if __cpp_impl_three_way_comparison && __has_include() && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 15000) 43 | 44 | namespace { 45 | template 46 | struct three_way_comparable : std::false_type { 47 | }; 48 | 49 | template 50 | struct three_way_comparable() <=> std::declval())>> : std::true_type { 51 | }; 52 | 53 | template 54 | static constexpr bool three_way_comparable_v = three_way_comparable::value; 55 | } 56 | using istrong = strong::type; 57 | using iweak = strong::type; 58 | using ipartial = strong::type; 59 | using dstrong = strong::type; 60 | using dweak = strong::type; 61 | using dpartial = strong::type; 62 | static_assert(three_way_comparable_v); 63 | static_assert(three_way_comparable_v); 64 | static_assert(three_way_comparable_v); 65 | static_assert(!three_way_comparable_v); 66 | static_assert(!three_way_comparable_v); 67 | static_assert(three_way_comparable_v); 68 | static_assert(std::is_same_v, std::strong_ordering>); 69 | static_assert(std::is_same_v, std::weak_ordering>); 70 | static_assert(std::is_same_v, std::partial_ordering>); 71 | static_assert(std::is_same_v, std::partial_ordering>); 72 | 73 | static_assert(istrong{1} < istrong{2}); 74 | static_assert(iweak{1} < iweak{2}); 75 | static_assert(ipartial{1} < ipartial{2}); 76 | static_assert(dpartial{1} < dpartial{2}); 77 | 78 | TEST_CASE("strongly_ordered type can be compared for ordering") 79 | { 80 | using type = strong::type; 81 | 82 | const type i1{1}; 83 | const type i2{2}; 84 | 85 | static_assert(std::is_same_v i2), std::strong_ordering>); 86 | 87 | REQUIRE(i1 < i2); 88 | REQUIRE(i1 <= i2); 89 | REQUIRE(i1 <= i1); 90 | REQUIRE(i2 > i1); 91 | REQUIRE(i2 >= i2); 92 | REQUIRE(i2 >= i1); 93 | 94 | REQUIRE_FALSE(i2 < i1); 95 | REQUIRE_FALSE(i2 <= i1); 96 | REQUIRE_FALSE(i1 > i2); 97 | REQUIRE_FALSE(i1 >= i2); 98 | 99 | REQUIRE((i1 <=> i2) == std::strong_ordering::less); 100 | } 101 | 102 | TEST_CASE("weakly_ordered type can be compared for ordering") 103 | { 104 | using type = strong::type; 105 | 106 | const type i1{1}; 107 | const type i2{2}; 108 | 109 | static_assert(std::is_same_v i2), std::weak_ordering>); 110 | 111 | REQUIRE(i1 < i2); 112 | REQUIRE(i1 <= i2); 113 | REQUIRE(i1 <= i1); 114 | REQUIRE(i2 > i1); 115 | REQUIRE(i2 >= i2); 116 | REQUIRE(i2 >= i1); 117 | 118 | REQUIRE_FALSE(i2 < i1); 119 | REQUIRE_FALSE(i2 <= i1); 120 | REQUIRE_FALSE(i1 > i2); 121 | REQUIRE_FALSE(i1 >= i2); 122 | 123 | REQUIRE((i1 <=> i2) == std::weak_ordering::less); 124 | } 125 | 126 | TEST_CASE("partially_ordered type can be compared for ordering") 127 | { 128 | using type = strong::type; 129 | 130 | const type i1{1}; 131 | const type i2{2}; 132 | 133 | static_assert(std::is_same_v i2), std::partial_ordering>); 134 | 135 | REQUIRE(i1 < i2); 136 | REQUIRE(i1 <= i2); 137 | REQUIRE(i1 <= i1); 138 | REQUIRE(i2 > i1); 139 | REQUIRE(i2 >= i2); 140 | REQUIRE(i2 >= i1); 141 | 142 | REQUIRE_FALSE(i2 < i1); 143 | REQUIRE_FALSE(i2 <= i1); 144 | REQUIRE_FALSE(i1 > i2); 145 | REQUIRE_FALSE(i1 >= i2); 146 | 147 | REQUIRE((i1 <=> i2) == std::partial_ordering::less); 148 | 149 | REQUIRE((i1 <=> type{NAN}) == std::partial_ordering::unordered); 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /test/test_ordered_with.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #endif 21 | 22 | TEST_CASE("ordered_with") 23 | { 24 | const strong::type> i1{1}; 25 | 26 | REQUIRE(i1 < 2); 27 | REQUIRE(0 < i1); 28 | REQUIRE_FALSE(i1 < 1); 29 | REQUIRE_FALSE(1 < i1); 30 | REQUIRE(i1 <= 1); 31 | REQUIRE(i1 <= 2); 32 | REQUIRE_FALSE(i1 <= 0); 33 | REQUIRE(1 <= i1); 34 | REQUIRE(0 <= i1); 35 | REQUIRE_FALSE(2<= i1); 36 | REQUIRE(i1 >= 1); 37 | REQUIRE(i1 >= 0); 38 | REQUIRE_FALSE(i1 >= 2); 39 | REQUIRE(1 >= i1); 40 | REQUIRE(2 >= i1); 41 | REQUIRE_FALSE(0 >= i1); 42 | REQUIRE(i1 > 0); 43 | REQUIRE_FALSE(i1 > 1); 44 | REQUIRE(2 > i1); 45 | REQUIRE_FALSE(1 > i1); 46 | } 47 | 48 | #if __cpp_impl_three_way_comparison && __has_include() && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 15000) 49 | namespace { 50 | template 51 | struct three_way_comparable : std::false_type { 52 | }; 53 | 54 | template 55 | struct three_way_comparable() <=> std::declval())>> : std::true_type { 56 | }; 57 | 58 | template 59 | static constexpr bool three_way_comparable_v = three_way_comparable::value; 60 | } 61 | 62 | using ihandle = strong::type; 63 | using dhandle = strong::type; 64 | using istrong = strong::type>; 65 | using iweak = strong::type>; 66 | using ipartial = strong::type>; 67 | using dstrong = strong::type>; 68 | using dweak = strong::type>; 69 | using dpartial = strong::type>; 70 | 71 | static_assert(!three_way_comparable_v); 72 | 73 | static_assert(three_way_comparable_v); 74 | static_assert(three_way_comparable_v); 75 | static_assert(!three_way_comparable_v); 76 | static_assert(three_way_comparable_v); 77 | static_assert(three_way_comparable_v); 78 | static_assert(!three_way_comparable_v); 79 | static_assert(three_way_comparable_v); 80 | static_assert(three_way_comparable_v); 81 | static_assert(!three_way_comparable_v); 82 | 83 | static_assert(!three_way_comparable_v); 84 | static_assert(!three_way_comparable_v); 85 | static_assert(!three_way_comparable_v); 86 | static_assert(!three_way_comparable_v); 87 | static_assert(!three_way_comparable_v); 88 | static_assert(!three_way_comparable_v); 89 | static_assert(three_way_comparable_v); 90 | static_assert(three_way_comparable_v); 91 | static_assert(!three_way_comparable_v); 92 | 93 | static_assert(std::is_same_v, std::strong_ordering>); 94 | static_assert(std::is_same_v, std::strong_ordering>); 95 | static_assert(std::is_same_v, std::weak_ordering>); 96 | static_assert(std::is_same_v, std::weak_ordering>); 97 | static_assert(std::is_same_v, std::partial_ordering>); 98 | static_assert(std::is_same_v, std::partial_ordering>); 99 | static_assert(std::is_same_v, std::partial_ordering>); 100 | static_assert(std::is_same_v, std::partial_ordering>); 101 | 102 | static_assert(istrong{1} < 2); 103 | static_assert(istrong{1} < ihandle{2}); 104 | static_assert(iweak{1} < 2); 105 | static_assert(iweak{1} < ihandle{2}); 106 | static_assert(ipartial{1} < 2); 107 | static_assert(ipartial{1} < ihandle{2}); 108 | static_assert(dpartial{1} < 2); 109 | static_assert(dpartial{1} < ihandle{2}); 110 | 111 | TEST_CASE("strongly_ordered_with types can be compared for ordering") 112 | { 113 | using type = strong::type>; 114 | 115 | const type i1{1}; 116 | 117 | static_assert(std::is_same_v 2), std::strong_ordering>); 118 | static_assert(std::is_same_v ihandle{2}), std::strong_ordering>); 119 | 120 | REQUIRE(i1 < 2); 121 | REQUIRE(i1 <= 2); 122 | REQUIRE(i1 <= 1); 123 | REQUIRE(2 > i1); 124 | REQUIRE(1 >= i1); 125 | REQUIRE(2 >= i1); 126 | 127 | REQUIRE_FALSE(2 < i1); 128 | REQUIRE_FALSE(2 <= i1); 129 | REQUIRE_FALSE(i1 > 2); 130 | REQUIRE_FALSE(i1 >= 2); 131 | 132 | REQUIRE((i1 <=> 2) == std::strong_ordering::less); 133 | REQUIRE((i1 <=> ihandle{2}) == std::strong_ordering::less); 134 | } 135 | 136 | TEST_CASE("weakly_ordered_with types can be compared for ordering") 137 | { 138 | using type = strong::type>; 139 | 140 | const type i1{1}; 141 | 142 | static_assert(std::is_same_v 2), std::weak_ordering>); 143 | static_assert(std::is_same_v ihandle{2}), std::weak_ordering>); 144 | 145 | REQUIRE(i1 < 2); 146 | REQUIRE(i1 <= 2); 147 | REQUIRE(i1 <= 1); 148 | REQUIRE(2 > i1); 149 | REQUIRE(1 >= i1); 150 | REQUIRE(2 >= i1); 151 | 152 | REQUIRE_FALSE(2 < i1); 153 | REQUIRE_FALSE(2 <= i1); 154 | REQUIRE_FALSE(i1 > 2); 155 | REQUIRE_FALSE(i1 >= 2); 156 | 157 | REQUIRE((i1 <=> 2) == std::weak_ordering::less); 158 | REQUIRE((i1 <=> ihandle{2}) == std::weak_ordering::less); 159 | } 160 | 161 | TEST_CASE("partially_ordered_with types can be compared for ordering") 162 | { 163 | using type = strong::type>; 164 | 165 | const type i1{1}; 166 | 167 | static_assert(std::is_same_v 2), std::partial_ordering>); 168 | static_assert(std::is_same_v ihandle{2}), std::partial_ordering>); 169 | 170 | REQUIRE(i1 < 2); 171 | REQUIRE(i1 <= 2); 172 | REQUIRE(i1 <= 1); 173 | REQUIRE(2 > i1); 174 | REQUIRE(1 >= i1); 175 | REQUIRE(2 >= i1); 176 | 177 | REQUIRE_FALSE(2 < i1); 178 | REQUIRE_FALSE(2 <= i1); 179 | REQUIRE_FALSE(i1 > 2); 180 | REQUIRE_FALSE(i1 >= 2); 181 | 182 | REQUIRE((i1 <=> 2) == std::partial_ordering::less); 183 | REQUIRE((i1 <=> ihandle{2}) == std::partial_ordering::less); 184 | 185 | REQUIRE((1 <=> type{NAN}) == std::partial_ordering::unordered); 186 | } 187 | 188 | #endif -------------------------------------------------------------------------------- /test/test_ostreamable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #include 21 | #endif 22 | 23 | TEST_CASE("an ostreamable type can be streamed using stream flags") 24 | { 25 | strong::type i{3}; 26 | 27 | std::ostringstream oss; 28 | oss << std::setw(4) << i; 29 | REQUIRE(oss.str() == " 3"); 30 | } 31 | -------------------------------------------------------------------------------- /test/test_pointer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #endif 21 | 22 | TEST_CASE("pointer types can be compared with nullptr") 23 | { 24 | using P = strong::type, struct p_, strong::pointer>; 25 | 26 | P p{nullptr}; 27 | REQUIRE(p == nullptr); 28 | REQUIRE(nullptr == p); 29 | REQUIRE_FALSE(p != nullptr); 30 | REQUIRE_FALSE(nullptr != p); 31 | 32 | p = P{std::make_unique(3)}; 33 | 34 | REQUIRE_FALSE(p == nullptr); 35 | REQUIRE_FALSE(nullptr == p); 36 | REQUIRE(p != nullptr); 37 | REQUIRE(nullptr != p); 38 | } 39 | 40 | TEST_CASE("pointer types can be dereferenced using operator ->") 41 | { 42 | struct S { int i;}; 43 | S s {3}; 44 | strong::type p{&s}; 45 | 46 | REQUIRE(p->i == 3); 47 | } 48 | 49 | TEST_CASE("pointer types can be dereferenced using operator *") 50 | { 51 | int i = 0; 52 | strong::type p{&i}; 53 | *p = 3; 54 | REQUIRE(i == 3); 55 | } 56 | -------------------------------------------------------------------------------- /test/test_range.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #include 21 | #include 22 | #include 23 | #endif 24 | 25 | namespace { 26 | template 27 | constexpr bool ignore(const T&) { return true;} 28 | template 29 | struct has_size : std::false_type { 30 | }; 31 | 32 | template 33 | struct has_size().size()))> 34 | : std::true_type 35 | { 36 | }; 37 | using v = strong::type, struct v_, strong::range>; 38 | static_assert(has_size{}, ""); 39 | using f = strong::type, struct f_, strong::range>; 40 | static_assert(!has_size{}, ""); 41 | } 42 | 43 | TEST_CASE("a range can be used with range based for") 44 | { 45 | using iv = strong::type, struct vi_, strong::range>; 46 | 47 | iv v{3,2,1}; 48 | int n = 3; 49 | for (auto& e : v) 50 | { 51 | REQUIRE(e-- == n--); 52 | } 53 | auto& cv = v; 54 | n = 2; 55 | for (auto& e : cv) 56 | { 57 | REQUIRE(e == n--); 58 | } 59 | } 60 | 61 | TEST_CASE("iterator type can be used from range") 62 | { 63 | using iv = strong::type, struct vi_, strong::range>; 64 | 65 | iv v{3,2,1}; 66 | int n = 3; 67 | for (iv::iterator i{v.begin()}; i != v.end(); ++i) 68 | { 69 | REQUIRE((*i)-- == n--); 70 | } 71 | const auto& cv = v; 72 | n = 2; 73 | for (iv::const_iterator i{cv.begin()}; i != cv.end(); ++i) 74 | { 75 | REQUIRE(*i == n--); 76 | } 77 | n = 2; 78 | for (iv::const_iterator i{v.cbegin()}; i != v.cend(); ++i) 79 | { 80 | REQUIRE(*i == n--); 81 | } 82 | } 83 | 84 | #if __cplusplus >= 201703L 85 | TEST_CASE("begin() and end() are constexpr") 86 | { 87 | using ia = strong::type 88 | < 89 | std::array, 90 | struct ia_, 91 | strong::range, 92 | strong::default_constructible 93 | >; 94 | static constexpr ia a{}; 95 | STATIC_REQUIRE(a.end() == a.begin() + 4); 96 | STATIC_REQUIRE(a.cend() == a.cbegin() + 4); 97 | STATIC_REQUIRE(*a.begin() == 0); 98 | } 99 | #endif 100 | 101 | TEST_CASE("range of sized type has size") 102 | { 103 | using iv = strong::type, struct vi_, strong::range>; 104 | 105 | iv v{3,2,1, 0}; 106 | REQUIRE(v.size() == 4); 107 | } 108 | 109 | TEST_CASE("constexpr size") 110 | { 111 | using ia = strong::type 112 | < 113 | std::array, 114 | struct ia_, 115 | strong::range, 116 | strong::default_constructible 117 | >; 118 | 119 | static constexpr ia a{}; 120 | REQUIRE(a.size() == 4); 121 | STATIC_REQUIRE(a.size() == 4); 122 | } 123 | 124 | TEST_CASE("a range with only const_iterators is still a range") 125 | { 126 | using is = strong::type 127 | < 128 | std::set, 129 | struct is_, 130 | strong::range, 131 | strong::default_constructible 132 | >; 133 | is set{1,3,5,7,9}; 134 | REQUIRE(set.size() == 5); 135 | int v = 1; 136 | for (auto x : set) 137 | { 138 | REQUIRE(x == v); 139 | v+= 2; 140 | } 141 | REQUIRE(v == 11); 142 | } 143 | 144 | #if defined(STRONG_TYPE_HAS_RANGES) 145 | #if (!defined(_LIBCPP_VERSION)) || (_LIBCPP_VERSION >= 16000) 146 | TEST_CASE("a range with a sentinel can be iterated") 147 | { 148 | constexpr auto iteration = [](auto&& r) { 149 | int i = 1; 150 | for (auto x : r) { 151 | REQUIRE(x == i); 152 | ++i; 153 | } 154 | REQUIRE(i == 4); 155 | }; 156 | GIVEN("a non-const strong vector") { 157 | using va = strong::type, struct va_, strong::range>; 158 | va numbers{1, 2, 3, 4, 5}; 159 | THEN("a ranges view can be used to iterate over it") { 160 | iteration(numbers | std::ranges::views::take(3)); 161 | } 162 | AND_THEN("a filter view can iterate over it") { 163 | iteration(numbers | std::ranges::views::filter([](auto x) { return x < 4;})); 164 | } 165 | } 166 | AND_GIVEN("a const strong vector") { 167 | using va = strong::type, struct va_, strong::range>; 168 | const va numbers{1, 2, 3, 4, 5}; 169 | THEN("a ranges view can be used to iterate over it") { 170 | iteration(numbers | std::ranges::views::take(3)); 171 | } 172 | AND_THEN("a filter view can iterate over it") { 173 | iteration(numbers | std::ranges::views::filter([](auto x) { return x < 4;})); 174 | } 175 | } 176 | AND_GIVEN("a filter view over a const vector") { 177 | const std::vector input{1,2,3,4,5}; 178 | auto filter = input | std::ranges::views::filter([](auto x){return x < 4;}); 179 | auto sf = strong::type(filter); 180 | THEN("the filter view can iterate over it") { 181 | iteration(sf); 182 | } 183 | } 184 | AND_GIVEN("a filter view over a non-const vector") { 185 | std::vector input{1,2,3,4,5}; 186 | auto filter = input | std::ranges::views::filter([](auto x){return x < 4;}); 187 | auto sf = strong::type(filter); 188 | THEN("the filter view can iterate over it") { 189 | iteration(sf); 190 | } 191 | } 192 | AND_GIVEN("a non-const forward_list") { 193 | std::forward_list input{1,2,3,4,5}; 194 | WHEN("a filter view is created from it") { 195 | auto filter = input | std::ranges::views::filter([](auto x) { return x < 4; }); 196 | auto sf = strong::type(filter); 197 | THEN("the filter view can iterate over it") 198 | { 199 | iteration(sf); 200 | } 201 | } 202 | AND_WHEN("a take view is created from it") { 203 | auto first3 = input | std::ranges::views::take(3); 204 | auto sf = strong::type(first3); 205 | THEN("the first3 view can iterate over it") 206 | { 207 | iteration(sf); 208 | } 209 | } 210 | } 211 | AND_GIVEN("a non-const forward_list") { 212 | std::forward_list input{1,2,3,4,5}; 213 | AND_WHEN("a const take view is created from it") { 214 | auto first3 = input | std::ranges::views::take(3); 215 | auto const sf = strong::type(first3); 216 | THEN("the first3 view can iterate over it") 217 | { 218 | iteration(sf); 219 | } 220 | } 221 | } 222 | AND_GIVEN("a const forward_list") { 223 | const std::forward_list input{1,2,3,4,5}; 224 | WHEN("a filter view is created from it") { 225 | auto filter = input | std::ranges::views::filter([](auto x) { return x < 4; }); 226 | auto sf = strong::type(filter); 227 | THEN("the filter view can iterate over it") 228 | { 229 | iteration(sf); 230 | } 231 | } 232 | AND_WHEN("a take view is created from it") { 233 | auto first3 = input | std::ranges::views::take(3); 234 | auto sf = strong::type(first3); 235 | THEN("the first3 view can iterate over it") 236 | { 237 | iteration(sf); 238 | } 239 | } 240 | AND_WHEN("a const take view is created from it") { 241 | auto first3 = input | std::ranges::views::take(3); 242 | const auto sf = strong::type(first3); 243 | THEN("the first3 view can iterate over it") 244 | { 245 | iteration(sf); 246 | } 247 | } 248 | } 249 | 250 | #if __cpp_lib_ranges >= 202110L 251 | AND_GIVEN("a string with numbers") 252 | { 253 | std::istringstream is("1 2 3"); 254 | WHEN("a stream view is created from it") { 255 | auto stream = std::views::istream(is); 256 | auto sf = strong::type(stream); 257 | THEN("the stream can be iterated over") { 258 | iteration(sf); 259 | } 260 | } 261 | } 262 | #endif 263 | } 264 | #endif 265 | 266 | #endif 267 | -------------------------------------------------------------------------------- /test/test_regular.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #endif 21 | 22 | namespace { 23 | using type = strong::type; 24 | } 25 | TEST_CASE("a regular type can be default constructed") 26 | { 27 | type v; 28 | REQUIRE(value_of(v) == 0); 29 | } 30 | 31 | TEST_CASE("a regular type can be value initialized") 32 | { 33 | type v{3}; 34 | REQUIRE(value_of(v) == 3); 35 | } 36 | 37 | TEST_CASE("a regular type can be copy constructed") 38 | { 39 | type v1{2}; 40 | type t2(v1); 41 | 42 | REQUIRE(value_of(t2) == 2); 43 | } 44 | 45 | TEST_CASE("a regular type can be move constructed") 46 | { 47 | using t = strong::type, struct tag_, strong::regular>; 48 | t v1{std::make_shared(3)}; 49 | t v2(std::move(v1)); 50 | REQUIRE(value_of(v1).use_count() == 0); 51 | REQUIRE(value_of(v2).use_count() == 1); 52 | REQUIRE(*value_of(v2) == 3); 53 | } 54 | 55 | TEST_CASE("a regular type can me copy assigned") 56 | { 57 | using t = strong::type, struct tag_, strong::regular>; 58 | t v1{nullptr}; 59 | t v2(std::make_shared(3)); 60 | v1 = v2; 61 | REQUIRE(value_of(v1).get() == value_of(v2).get()); 62 | REQUIRE(*value_of(v1) == 3); 63 | } 64 | 65 | TEST_CASE("a regular type can be move assigned") 66 | { 67 | using t = strong::type, struct tag_, strong::regular>; 68 | t v1{nullptr}; 69 | t v2(std::make_shared(3)); 70 | v1 = std::move(v2); 71 | REQUIRE(value_of(v1).use_count() == 1); 72 | REQUIRE(value_of(v2).use_count() == 0); 73 | REQUIRE(*value_of(v1) == 3); 74 | } 75 | 76 | TEST_CASE("a regular type can be compared using operator==") 77 | { 78 | type i{3}; 79 | type j{4}; 80 | type k{3}; 81 | REQUIRE_FALSE(i == j); 82 | REQUIRE(i == k); 83 | } 84 | 85 | TEST_CASE("a regular can be compared using operator!=") 86 | { 87 | type i{3}; 88 | type j{4}; 89 | type k{3}; 90 | REQUIRE(i != j); 91 | REQUIRE(!(i != k)); 92 | } -------------------------------------------------------------------------------- /test/test_scalable_with.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | namespace { 19 | struct line { 20 | line(int x_) : x(x_) 21 | {} 22 | 23 | line &operator/=(int y) 24 | { 25 | x /= y; 26 | return *this; 27 | } 28 | friend line operator/(line lh, int rh) 29 | { 30 | return lh /= rh; 31 | } 32 | line &operator*=(int y) 33 | { 34 | x *= y; 35 | return *this; 36 | } 37 | friend line operator*(line lh, int rh) 38 | { 39 | return lh *= rh; 40 | } 41 | int operator/(line rh) const 42 | { 43 | return x / rh.x; 44 | } 45 | 46 | int x; 47 | }; 48 | 49 | struct plane { 50 | plane(int x_, int y_) : x(x_), y(y_) 51 | {} 52 | 53 | plane &operator/=(int f) 54 | { 55 | x /= f; 56 | y /= f; 57 | return *this; 58 | } 59 | friend plane operator/(plane lh, int rh) 60 | { 61 | return lh /= rh; 62 | } 63 | plane &operator*=(int f) 64 | { 65 | x *= f; 66 | y *= f; 67 | return *this; 68 | } 69 | friend plane operator*(plane lh, int rh) 70 | { 71 | return lh *= rh; 72 | } 73 | plane &operator/=(double d) 74 | { 75 | x = static_cast(x / d); 76 | y = static_cast(y / d); 77 | return *this; 78 | } 79 | friend plane operator/(plane lh, double rh) 80 | { 81 | return lh /= rh; 82 | } 83 | int x; 84 | int y; 85 | }; 86 | 87 | } 88 | 89 | TEST_CASE("one dimensional") 90 | { 91 | GIVEN("a scalable int, scalable with int") 92 | { 93 | using lt = strong::type>; 94 | lt var(30); 95 | WHEN("mulltiplying by an int") 96 | { 97 | auto v1 = var * 2; 98 | auto v2 = 2 * var; 99 | THEN("dhe dimension is multiplied") 100 | { 101 | REQUIRE(value_of(v1).x == 60); 102 | REQUIRE(value_of(v2).x == 60); 103 | } 104 | } 105 | AND_WHEN("dividing by an int") 106 | { 107 | auto w = var / 2; 108 | THEN("the dimension is divided") 109 | { 110 | REQUIRE(value_of(w).x == 15); 111 | } 112 | } 113 | AND_WHEN("dividing by another scalable of same type") 114 | { 115 | auto x = var / lt(5); 116 | THEN("the result is an int") 117 | { 118 | STATIC_REQUIRE(std::is_same::value); 119 | } 120 | AND_THEN("the value is the result of dividing the dimensins") 121 | { 122 | REQUIRE(x == 6); 123 | } 124 | } 125 | } 126 | } 127 | 128 | TEST_CASE("two dimensional") 129 | { 130 | GIVEN("a dwo dimensional scalable, scalable with int, double and other scalable type") 131 | { 132 | using si = strong::type; 133 | using pt = strong::type>; 134 | 135 | pt p{30, 40}; 136 | WHEN("multiplied by an int") 137 | { 138 | auto v1 = p * 2; 139 | auto v2 = 2 * p; 140 | THEN("the value of each dimension is multiplied") 141 | { 142 | REQUIRE(value_of(v1).x == 60); 143 | REQUIRE(value_of(v1).y == 80); 144 | REQUIRE(value_of(v2).x == 60); 145 | REQUIRE(value_of(v2).y == 80); 146 | } 147 | } 148 | AND_WHEN("divided by an int") 149 | { 150 | auto w = p / 2; 151 | THEN("the value of each dimension is divided") 152 | { 153 | REQUIRE(value_of(w).x == 15); 154 | REQUIRE(value_of(w).y == 20); 155 | } 156 | } 157 | AND_WHEN("divided by a floating point number") 158 | { 159 | auto y = p / 0.5; 160 | THEN("the value of each dimension is divided") 161 | { 162 | REQUIRE(value_of(y).x == 60); 163 | REQUIRE(value_of(y).y == 80); 164 | } 165 | } 166 | AND_WHEN("divided by another scalable") 167 | { 168 | auto z = p / si{2}; 169 | THEN("the value of each dimension is divided") 170 | { 171 | REQUIRE(value_of(z).x == 15); 172 | REQUIRE(value_of(z).y == 20); 173 | } 174 | } 175 | } 176 | } 177 | 178 | TEST_CASE("integral promotion") 179 | { 180 | /* 181 | * The primary purpose of this test is to ensure that it 182 | * builds without warnings when compiled with -Wconversion 183 | * and without complaint from -fsanitize=undefined 184 | */ 185 | GIVEN("a scalable short, scalable by short") 186 | { 187 | using ss = strong::type>; 188 | ss val{short(30)}; 189 | WHEN("divided by a short") 190 | { 191 | val /= short(2); 192 | THEN("the value is divided") 193 | { 194 | REQUIRE(value_of(val) == 15); 195 | } 196 | } 197 | AND_WHEN("multiplied by a short") 198 | { 199 | val *= short(3); 200 | THEN("the value is multiplied") 201 | { 202 | REQUIRE(value_of(val) == 90); 203 | } 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /test/test_semiregular.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #endif 21 | 22 | namespace { 23 | using type = strong::type; 24 | } 25 | TEST_CASE("a semiregular type can be default constructed") 26 | { 27 | type v; 28 | REQUIRE(value_of(v) == 0); 29 | } 30 | 31 | TEST_CASE("a semiregular type can be value initialized") 32 | { 33 | type v{3}; 34 | REQUIRE(value_of(v) == 3); 35 | } 36 | 37 | TEST_CASE("a semiregular type can be copy constructed") 38 | { 39 | type v1{2}; 40 | type t2(v1); 41 | 42 | REQUIRE(value_of(t2) == 2); 43 | } 44 | 45 | TEST_CASE("a semiregular type can be move constructed") 46 | { 47 | using t = strong::type, struct tag_, strong::semiregular>; 48 | t v1{std::make_shared(3)}; 49 | t v2(std::move(v1)); 50 | REQUIRE(value_of(v1).use_count() == 0); 51 | REQUIRE(value_of(v2).use_count() == 1); 52 | REQUIRE(*value_of(v2) == 3); 53 | } 54 | 55 | TEST_CASE("a semiregular type can me copy assigned") 56 | { 57 | using t = strong::type, struct tag_, strong::semiregular>; 58 | t v1{nullptr}; 59 | t v2(std::make_shared(3)); 60 | v1 = v2; 61 | REQUIRE(value_of(v1).get() == value_of(v2).get()); 62 | REQUIRE(*value_of(v1) == 3); 63 | } 64 | 65 | TEST_CASE("a semiregular type can be move assigned") 66 | { 67 | using t = strong::type, struct tag_, strong::semiregular>; 68 | t v1{nullptr}; 69 | t v2(std::make_shared(3)); 70 | v1 = std::move(v2); 71 | REQUIRE(value_of(v1).use_count() == 1); 72 | REQUIRE(value_of(v2).use_count() == 0); 73 | REQUIRE(*value_of(v1) == 3); 74 | } 75 | -------------------------------------------------------------------------------- /test/test_type.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #include "test_utils.hpp" 19 | 20 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 21 | #include 22 | #endif 23 | 24 | TEST_CASE("default_constructible initializes with underlying default constructor") 25 | { 26 | constexpr strong::type vc; 27 | STATIC_REQUIRE(value_of(vc) == 0); 28 | strong::type vr; 29 | REQUIRE(value_of(vr) == 0); 30 | } 31 | 32 | TEST_CASE("Construction from a value type lvalue copies it") 33 | { 34 | auto orig = std::make_shared(3); 35 | strong::type, struct int_> i{orig}; 36 | REQUIRE(*value_of(i) == 3); 37 | REQUIRE(orig.use_count() == 2); 38 | REQUIRE(value_of(i).get() == orig.get()); 39 | } 40 | 41 | TEST_CASE("Construction from multiple parameters constructs value from them") 42 | { 43 | strong::type s(3U, 'a'); 44 | REQUIRE(value_of(s) == "aaa"); 45 | } 46 | 47 | TEST_CASE("construction from an rvalue reference moves from it") 48 | { 49 | auto orig = std::make_unique(3); 50 | auto addr = orig.get(); 51 | strong::type, struct p_> p(std::move(orig)); 52 | REQUIRE(*value_of(p) == 3); 53 | REQUIRE(!orig); 54 | REQUIRE(value_of(p).get() == addr); 55 | } 56 | 57 | TEST_CASE("value can be copy constructed if member can") 58 | { 59 | using ptr = strong::type, struct p_>; 60 | ptr orig{std::make_shared(3)}; 61 | ptr p{orig}; 62 | REQUIRE(value_of(orig).use_count() == 2); 63 | REQUIRE(*value_of(p) == 3); 64 | } 65 | 66 | TEST_CASE("value can be copy assigned") 67 | { 68 | using ptr = strong::type, struct p_>; 69 | ptr orig{std::make_shared(3)}; 70 | ptr p{nullptr}; 71 | p = orig; 72 | REQUIRE(value_of(orig).use_count() == 2); 73 | REQUIRE(*value_of(p) == 3); 74 | } 75 | 76 | TEST_CASE("value can be move assigned") 77 | { 78 | using ptr = strong::type, struct p_>; 79 | ptr orig{std::make_unique(3)}; 80 | ptr p{nullptr}; 81 | p = std::move(orig); 82 | REQUIRE(value_of(orig)== nullptr); 83 | REQUIRE(*value_of(p) == 3); 84 | } 85 | 86 | TEST_CASE("value can be retained from const lvalue ref") 87 | { 88 | const strong::type i{3}; 89 | auto&& r = value_of(i); 90 | REQUIRE(r == 3); 91 | static_assert(std::is_const>{},""); 92 | static_assert(std::is_lvalue_reference{},""); 93 | } 94 | 95 | TEST_CASE("value can be retained from rvalue ref") 96 | { 97 | strong::type i{3}; 98 | auto&& r = value_of(std::move(i)); 99 | REQUIRE(r == 3); 100 | static_assert(!std::is_const>{},""); 101 | static_assert(std::is_rvalue_reference{},""); 102 | } 103 | 104 | TEST_CASE("freestanding value_of() gets the underlying value") 105 | { 106 | GIVEN("a strong value") 107 | { 108 | using type = strong::type; 109 | type var{3}; 110 | WHEN("calling value_of() on a const lvalue") 111 | { 112 | auto &&v = value_of(as_const(var)); 113 | THEN("a const lvalue reference is returned") 114 | { 115 | STATIC_REQUIRE(std::is_same{}); 116 | } 117 | AND_THEN("the value is the one constructed from") 118 | { 119 | REQUIRE(v == 3); 120 | } 121 | } 122 | AND_WHEN("calling value_of() on a non-const lvalue") 123 | { 124 | auto&& v = value_of(var); 125 | THEN("a non-const lvalue reference is returned") 126 | { 127 | STATIC_REQUIRE(std::is_same{}); 128 | } 129 | AND_THEN("the value is the one constructed from") 130 | { 131 | REQUIRE(v == 3); 132 | } 133 | AND_THEN("a write to the returned reference changes the value") 134 | { 135 | v = 4; 136 | REQUIRE(value_of(var) == 4); 137 | } 138 | } 139 | AND_WHEN("calling value_of() on a non-const rvalue") 140 | { 141 | auto&& v = value_of(std::move(var)); 142 | THEN("a non-const rvalue reference is returned") 143 | { 144 | STATIC_REQUIRE(std::is_same{}); 145 | } 146 | AND_THEN("the value is the one constructed from") 147 | { 148 | REQUIRE(v == 3); 149 | } 150 | } 151 | AND_WHEN("calling value_of() on a const rvalue") 152 | { 153 | auto&& v = value_of(std::move(as_const(var))); 154 | THEN("a const lvalue refercence is returned") 155 | { 156 | STATIC_REQUIRE(std::is_same{}); 157 | } 158 | AND_THEN("the value is the one constructed from") 159 | { 160 | REQUIRE(v == 3); 161 | } 162 | } 163 | } 164 | } 165 | 166 | TEST_CASE("member value_of() gets the underlying value") 167 | { 168 | GIVEN("a strong value") 169 | { 170 | using type = strong::type; 171 | type var{3}; 172 | WHEN("calling value_of() on a const lvalue") 173 | { 174 | auto &&v = as_const(var).value_of(); 175 | THEN("a const lvalue reference is returned") 176 | { 177 | STATIC_REQUIRE(std::is_same{}); 178 | } 179 | AND_THEN("the value is the one constructed from") 180 | { 181 | REQUIRE(v == 3); 182 | } 183 | } 184 | AND_WHEN("calling value_of() on a non-const lvalue") 185 | { 186 | auto&& v = var.value_of(); 187 | THEN("a non-const lvalue reference is returned") 188 | { 189 | STATIC_REQUIRE(std::is_same{}); 190 | } 191 | AND_THEN("the value is the one constructed from") 192 | { 193 | REQUIRE(v == 3); 194 | } 195 | AND_THEN("a write to the returned reference changes the value") 196 | { 197 | v = 4; 198 | REQUIRE(value_of(var) == 4); 199 | } 200 | } 201 | AND_WHEN("calling value_of() on a non-const rvalue") 202 | { 203 | auto&& v = std::move(var).value_of(); 204 | THEN("a non-const rvalue reference is returned") 205 | { 206 | STATIC_REQUIRE(std::is_same{}); 207 | } 208 | AND_THEN("the value is the one constructed from") 209 | { 210 | REQUIRE(v == 3); 211 | } 212 | } 213 | AND_WHEN("calling value_of() on a const rvalue") 214 | { 215 | auto&& v = std::move(as_const(var)).value_of(); 216 | THEN("a const lvalue refercence is returned") 217 | { 218 | STATIC_REQUIRE(std::is_same{}); 219 | } 220 | AND_THEN("the value is the one constructed from") 221 | { 222 | REQUIRE(v == 3); 223 | } 224 | } 225 | } 226 | } 227 | 228 | TEST_CASE("swap") 229 | { 230 | using strong_int = strong::type; 231 | 232 | strong_int v1{6}; 233 | strong_int v2{34}; 234 | 235 | swap(v1, v2); 236 | 237 | CHECK(v1.value_of() == 34); 238 | CHECK(v2.value_of() == 6); 239 | } 240 | 241 | #if (__cpp_nontype_template_args >= 201911L) || \ 242 | (__cplusplus >= 202002 && __cpp_nontype_template_args >= 201411 && __clang_major__ >= 12) 243 | 244 | template class foo {}; 245 | 246 | TEST_CASE("value can be used as non-type template parameter") 247 | { 248 | using strong_int = strong::type; 249 | [[maybe_unused]] foo foo; 250 | } 251 | 252 | #endif 253 | -------------------------------------------------------------------------------- /test/test_unique.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #include "catch2.hpp" 15 | 16 | #include 17 | 18 | #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 19 | #include 20 | #endif 21 | 22 | TEST_CASE("strong::unique is movable") 23 | { 24 | using t = strong::type, struct t_, strong::unique>; 25 | 26 | GIVEN("an initialized source") 27 | { 28 | t source{std::make_unique(3)}; 29 | auto* addr = value_of(source).get(); 30 | 31 | WHEN("move constructing a dest") 32 | { 33 | auto dest = std::move(source); 34 | THEN("the source is moved from") 35 | { 36 | REQUIRE(value_of(source).get() == nullptr); 37 | } 38 | AND_THEN("the dest has the value that source had") 39 | { 40 | REQUIRE(*value_of(dest) == 3); 41 | REQUIRE(value_of(dest).get() == addr); 42 | } 43 | } 44 | AND_WHEN("move assigning to another instance") 45 | { 46 | t dest{std::make_unique(4)}; 47 | dest = std::move(source); 48 | THEN("the source is moved from") 49 | { 50 | REQUIRE(value_of(source).get() == nullptr); 51 | } 52 | AND_THEN("the dest has the value that source had") 53 | { 54 | REQUIRE(*value_of(dest) == 3); 55 | REQUIRE(value_of(dest).get() == addr); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test/test_utils.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * strong_type C++14/17/20 strong typedef library 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/strong_type 12 | */ 13 | 14 | #ifndef STRONG_TYPE_TEST_UTILS_HPP 15 | #define STRONG_TYPE_TEST_UTILS_HPP 16 | 17 | #if defined(STRONG_TYPE_IMPORT_STD_LIBRARY) 18 | import std; 19 | #else 20 | #include 21 | #endif 22 | 23 | template 24 | const T& as_const(T& t) { return t;} 25 | template 26 | const T&& as_const(T&& t) { return std::move(t);} 27 | 28 | #endif //STRONG_TYPE_TEST_UTILS_HPP 29 | --------------------------------------------------------------------------------