├── .gitignore ├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake ├── global_flags.cmake └── project_flags.cmake └── src ├── .clang-format ├── include ├── opt.h └── opt_bits.h └── tests ├── CMakeLists.txt └── tests.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | .idea/ 32 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/external/googletest"] 2 | path = src/external/googletest 3 | url = https://github.com/google/googletest.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Mateusz Pusz 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | language: c++ 24 | sudo: false 25 | 26 | addons: 27 | apt: 28 | packages: 29 | - g++-6 30 | sources: &sources 31 | - ubuntu-toolchain-r-test 32 | 33 | cache: 34 | directories: 35 | - ${TRAVIS_BUILD_DIR}/deps/llvm-4.0.0 36 | 37 | matrix: 38 | include: 39 | - os: linux 40 | env: COMPILER=g++-6 UNIT_TESTS=ON CODECOV=ON 41 | compiler: gcc 42 | 43 | - os: linux 44 | env: LLVM_VERSION=4.0.0 UNIT_TESTS=OFF CODECOV=OFF 45 | compiler: clang 46 | 47 | install: 48 | ############################################################################ 49 | # All the dependencies are installed in ${TRAVIS_BUILD_DIR}/deps/ 50 | ############################################################################ 51 | - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" 52 | - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} 53 | 54 | ############################################################################ 55 | # Setup default versions and override compiler if needed 56 | ############################################################################ 57 | - if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi 58 | 59 | ############################################################################ 60 | # Install a recent CMake 61 | ############################################################################ 62 | - | 63 | if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then 64 | CMAKE_URL="http://www.cmake.org/files/v3.7/cmake-3.7.2-Linux-x86_64.tar.gz" 65 | mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake 66 | export PATH=${DEPS_DIR}/cmake/bin:${PATH} 67 | else 68 | brew upgrade cmake || brew install cmake 69 | fi 70 | - cmake --version 71 | 72 | ############################################################################ 73 | # Install Clang, libc++ and libc++abi 74 | ############################################################################ 75 | - | 76 | if [[ "${LLVM_VERSION}" != "" ]]; then 77 | LLVM_DIR=${DEPS_DIR}/llvm-${LLVM_VERSION} 78 | if [[ -z "$(ls -A ${LLVM_DIR})" ]]; then 79 | LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz" 80 | LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz" 81 | LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz" 82 | CLANG_URL="http://llvm.org/releases/${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz" 83 | mkdir -p ${LLVM_DIR} ${LLVM_DIR}/build ${LLVM_DIR}/projects/libcxx ${LLVM_DIR}/projects/libcxxabi ${LLVM_DIR}/clang 84 | travis_retry wget --quiet -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C ${LLVM_DIR} 85 | travis_retry wget --quiet -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C ${LLVM_DIR}/projects/libcxx 86 | travis_retry wget --quiet -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C ${LLVM_DIR}/projects/libcxxabi 87 | travis_retry wget --quiet -O - ${CLANG_URL} | tar --strip-components=1 -xJ -C ${LLVM_DIR}/clang 88 | (cd ${LLVM_DIR}/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_DIR}/install -DCMAKE_CXX_COMPILER=clang++) 89 | (cd ${LLVM_DIR}/build/projects/libcxx && make install -j2) 90 | (cd ${LLVM_DIR}/build/projects/libcxxabi && make install -j2) 91 | fi 92 | export CXXFLAGS="-nostdinc++ -isystem ${LLVM_DIR}/install/include/c++/v1" 93 | export LDFLAGS="-L ${LLVM_DIR}/install/lib -l c++ -l c++abi" 94 | export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_DIR}/install/lib" 95 | export PATH="${LLVM_DIR}/clang/bin:${PATH}" 96 | fi 97 | - ${CXX} --version 98 | 99 | before_script: 100 | ############################################################################ 101 | # Go back to the root of the project and setup the build directory 102 | ############################################################################ 103 | - cd ${TRAVIS_BUILD_DIR} 104 | - mkdir build && cd build && cmake .. -DCODE_COVERAGE=${CODECOV} 105 | 106 | script: 107 | - cmake --build . 108 | - | 109 | if [[ "${UNIT_TESTS}" == "ON" ]]; then 110 | src/tests/unit_tests 111 | fi 112 | 113 | after_success: 114 | - | 115 | if [[ "${CODECOV}" == "ON" ]]; then 116 | bash <(curl -s https://codecov.io/bash) -x gcov-6 117 | fi 118 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Mateusz Pusz 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | cmake_minimum_required(VERSION 3.5) 24 | project(opt C CXX) 25 | 26 | # The project version number. 27 | set(VERSION_MAJOR 1 CACHE STRING "Project major version number.") 28 | set(VERSION_MINOR 1 CACHE STRING "Project minor version number.") 29 | set(VERSION_PATCH 0 CACHE STRING "Project patch version number.") 30 | 31 | #set(CMAKE_CXX_STANDARD 17) 32 | if(MSVC) 33 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest") 34 | else() 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z") 36 | endif() 37 | set(CMAKE_CXX_STANDARD_REQUIRED on) 38 | 39 | # global compilation flags 40 | include(cmake/global_flags.cmake OPTIONAL) 41 | 42 | # add dependencies 43 | set(gtest_force_shared_crt ON CACHE BOOL "Use shared (DLL) run-time lib even when Google Test is built as static lib.") 44 | if(MSVC) 45 | add_definitions(-DGTEST_LANG_CXX11=1 -DGTEST_HAS_TR1_TUPLE=0) 46 | endif() 47 | add_subdirectory(src/external/googletest EXCLUDE_FROM_ALL) 48 | add_library(google::test ALIAS gtest_main) 49 | 50 | # project-specific compilation flags 51 | include(cmake/project_flags.cmake OPTIONAL) 52 | 53 | # add project code 54 | include_directories(src/include) 55 | 56 | # add unit tests 57 | add_subdirectory(src/tests) 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Mateusz Pusz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?maxAge=3600)](https://raw.githubusercontent.com/mpusz/opt/master/LICENSE) 2 | [![Travis CI](https://img.shields.io/travis/mpusz/opt/master.svg?label=Travis%20CI)](https://travis-ci.org/mpusz/opt) 3 | [![AppVeyor](https://img.shields.io/appveyor/ci/mpusz/opt/master.svg?label=AppVeyor)](https://ci.appveyor.com/project/mpusz/opt) 4 | [![Codecov](https://img.shields.io/codecov/c/github/mpusz/opt/master.svg)](https://codecov.io/github/mpusz/opt?branch=master) 5 | 6 | # `mp::opt` 7 | 8 | `mp::opt` is a class template designed to express optionality. 9 | 10 | It has interface similar to `std::optional` ([see here](http://en.cppreference.com/w/cpp/utility/optional)) 11 | but it does not use additional storage space for boolean flag needed to keep information if 12 | the value is set or not. On the other hand type `T` should be a type that does not use all 13 | values from its underlying representation thus leaving a possibly to use one of them as a _Null_ 14 | value that express emptiness of type `T`. 15 | 16 | ## Dependencies 17 | 18 | `mp::opt` library depends on C++14 constexpr features and `std::optional` existence so 19 | a fairly modern compiler is needed. 20 | 21 | ## Installation 22 | 23 | `mp::opt` is a header-only library. Its implementation was split to: 24 | - `opt.h` that contains the most important implementation and is intended to be included by the user with 25 | `#include ` in the code 26 | - `opt_bits.h` that contains less important implementation details and is already included by `opt.h` header file 27 | 28 | ## Usage 29 | 30 | Here is a simple example of how to use `mp::opt` for some artificial type `price`: 31 | 32 | ```cpp 33 | using namespace mp; 34 | using price = int; 35 | using opt_price = opt>; 36 | static_assert(sizeof(opt_price) == sizeof(int)); 37 | 38 | opt_price o1; 39 | assert(static_cast(o1) == false); 40 | assert(o1.has_value() == false); 41 | assert(o1.value_or(123) == 123); 42 | 43 | constexpr opt_price o2{99}; 44 | assert(static_cast(o2) == true); 45 | assert(o2.has_value() == true); 46 | assert(*o2 == 99); 47 | assert(o2.value() == 99); 48 | assert(o2.value_or(123) == 99); 49 | 50 | opt_price o3{o2}; 51 | assert(o3.has_value() == true); 52 | assert(*o3 == 99); 53 | 54 | o3 = o1; 55 | assert(o3.has_value() == false); 56 | 57 | o3 = o2; 58 | assert(o3.has_value() == true); 59 | assert(*o3 == 99); 60 | 61 | o3 = nullopt; 62 | assert(o3.has_value() == false); 63 | ``` 64 | 65 | ### `Policy` basic interface 66 | 67 | `mp::opt` uses `Policy` class to provide all necessary information needed for proper class operation. The 68 | simplest interface of `Policy` class for type `my_type` that uses `my_type_null_value` as _Null_ value contains 69 | only one member function: 70 | ```cpp 71 | struct my_opt_policy { 72 | static constexpr my_type null_value() noexcept { return my_type_null_value; } 73 | }; 74 | mp::opt my_opt_val; 75 | ``` 76 | - `null_value()` member function returns (by value or reference) special value of type `my_type` that should be 77 | used by `mp::opt` as a special _Null_ value to mark emptiness. 78 | 79 | `mp::opt` by default uses `mp::opt_default_policy` that can be specialized for user's type `T` so above 80 | example may be refactored in the following way: 81 | ```cpp 82 | namespace mp { 83 | template<> 84 | struct opt_default_policy { 85 | static constexpr my_type null_value() noexcept { return my_type_null_value; } 86 | }; 87 | } 88 | mp::opt my_opt_val; 89 | ``` 90 | 91 | The latter solution is suggested for user's types that will always have the same special value used as _Null_ while 92 | the former should be used for builtin types like 'int' where the type can express different quantities thus having 93 | different _Null_ special values (e.g. age, price, month, etc). 94 | 95 | ### `Policy` types provided with the library 96 | 97 | Beside already mentioned `mp::opt_default_policy` that can be specialized by the user for his/her type `my_type`, 98 | the library provides 2 additional policy types: 99 | - `mp::opt_null_value_policy` 100 | may be used to provide _Null_ value for integral type right in the class type definition. For example: 101 | ```cpp 102 | mp::opt> opt_int; 103 | ``` 104 | 105 | - `mp::opt_null_type_policy` may be used for types which values cannot be used as template argument 106 | (e.g. `float`). That policy type assumes that `NullType::null_value` will represent _Null_ value. For example: 107 | ```cpp 108 | struct my_null_float { static constexpr float null_value = 0.0f; }; 109 | mp::opt> opt_float; 110 | ``` 111 | 112 | ### What if `my_type` does not provide equality comparison? 113 | 114 | `mp::opt` needs to compare contained value with special _Null_ value provided by the _Policy_ type. By default 115 | it tries to use `operator==()`. If the equality comparison is not provided for `my_type` than either: 116 | - `operator==()` should be provided, or 117 | - additional `has_value(const T& value)` member function should be provided in the `Policy` type and it should return 118 | `false` if `value == null_value()` or `true` otherwise: 119 | ```cpp 120 | struct my_opt_policy { 121 | static constexpr my_type null_value() noexcept { return my_type_null_value; } 122 | static constexpr bool has_value(const T& value) noexcept { return value != null_value(); } 123 | }; 124 | mp::opt my_opt_val; 125 | ``` 126 | 127 | ### What if `my_type` prevents me from setting value out of allowed range? 128 | 129 | Sometimes `my_type` has some non-trivial logic or validation in its contructors or assignment operators that prevents 130 | one to set special out-of-range value as _Null_ value for the type. In such case it is possible to extend `Policy` 131 | class with following additional `storage_type` public member type. Such `storage_type` type: 132 | - should be of the same size as `my_type` type 133 | - should be constructible and assignable in the same way as `my_type` 134 | - when storing not _Null_ value should have exactly the same memory representation as if the value was stored by 135 | `my_type` type 136 | - should be used in `null_value()` and `has_value()` member functions instead of `my_type`. 137 | 138 | Below is an example of how `opt` could be implemented: 139 | ```cpp 140 | namepace mp { 141 | template<> 142 | struct opt_default_policy { 143 | private: 144 | union storage { 145 | bool value; 146 | std::int8_t null_value = -1; 147 | storage() = default; 148 | constexpr storage(bool v) noexcept : value{v} {} 149 | }; 150 | public: 151 | using storage_type = storage; 152 | static constexpr storage_type null_value() noexcept { return storage_type{}; } 153 | static constexpr bool has_value(storage_type s) noexcept { return s.null_value != -1; } 154 | }; 155 | } 156 | ``` 157 | 158 | Here is another a bit more complicated example for some (not too smart ;-) ) `weekday` class: 159 | ```cpp 160 | class weekday { 161 | public: 162 | using underlying_type = std::int8_t; 163 | constexpr explicit weekday(underlying_type v) : value_{v} 164 | { 165 | if(v < 0 || v > 6) throw std::out_of_range{"weekday value outside of allowed range"}; 166 | } 167 | constexpr weekday& operator=(underlying_type v) 168 | { 169 | if(v < 0 || v > 6) throw std::out_of_range{"weekday value outside of allowed range"}; 170 | value_ = v; 171 | return *this; 172 | } 173 | constexpr underlying_type get() const noexcept { return value_; } 174 | private: 175 | underlying_type value_; // 0 - 6 176 | }; 177 | constexpr bool operator==(weekday lhs, weekday rhs) noexcept { return lhs.get() == rhs.get(); } 178 | constexpr bool operator==(weekday::underlying_type lhs, weekday rhs) noexcept { return lhs == rhs.get(); } 179 | constexpr bool operator==(weekday lhs, weekday::underlying_type rhs) noexcept { return lhs.get() == rhs; } 180 | 181 | namespace mp { 182 | template<> 183 | struct opt_default_policy { 184 | union storage_type { 185 | weekday value; 186 | weekday::underlying_type null_value = std::numeric_limits::max(); 187 | 188 | constexpr storage_type() noexcept {}; 189 | constexpr storage_type(weekday v) : value{v} {} 190 | constexpr storage_type(weekday::underlying_type v) : value{v} {} 191 | storage_type& operator=(weekday v) 192 | { 193 | value = v; 194 | return *this; 195 | } 196 | }; 197 | 198 | public: 199 | static storage_type null_value() noexcept { return storage_type{}; } 200 | static bool has_value(storage_type value) noexcept 201 | { 202 | return value.null_value != std::numeric_limits::max(); 203 | } 204 | }; 205 | } 206 | ``` 207 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | branches: 4 | except: 5 | - gh-pages 6 | 7 | skip_commits: 8 | message: /\[ci skip\]/ 9 | 10 | image: Visual Studio 2017 11 | 12 | platform: 13 | - x64 14 | 15 | configuration: 16 | - Release 17 | - Debug 18 | 19 | init: 20 | - git config --global core.autocrlf input 21 | 22 | clone_depth: 5 23 | 24 | install: 25 | - git submodule update --init --recursive 26 | 27 | before_build: 28 | - mkdir build && cd build 29 | - cmake -G"Visual Studio 15 2017 Win64" .. 30 | 31 | build: 32 | parallel: true 33 | project: $(APPVEYOR_BUILD_FOLDER)\build\$(APPVEYOR_PROJECT_NAME).sln 34 | 35 | test_script: 36 | - '%APPVEYOR_BUILD_FOLDER%\build\src\tests\%CONFIGURATION%\unit_tests.exe --gtest_output=xml:unit_tests.xml' 37 | 38 | on_finish: 39 | - ps: (new-object net.webclient).UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\unit_tests.xml)) 40 | -------------------------------------------------------------------------------- /cmake/global_flags.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Mateusz Pusz 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | # define options 24 | option(LTCG "Link time code generation" OFF) 25 | set(ARCHITECTURE "native" CACHE STRING 26 | "Target architecture to be set for gcc 'march' (or 'none' if option should not be used)") 27 | 28 | # print options 29 | message(STATUS "LTCG=${LTCG}") 30 | message(STATUS "ARCHITECTURE=${ARCHITECTURE}") 31 | 32 | # configure flags 33 | if(MSVC) 34 | if(LTCG) 35 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GL") 36 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") 37 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") 38 | set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") 39 | set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") 40 | set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG") 41 | 42 | set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /GL") 43 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GL") 44 | set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") 45 | set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") 46 | set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") 47 | set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") 48 | endif() 49 | 50 | # enable intrinsic functions 51 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi") 52 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi") 53 | elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 54 | if(LTCG) 55 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto") 56 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -flto") 57 | endif() 58 | 59 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") 60 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fno-omit-frame-pointer") 61 | 62 | if(NOT ARCHITECTURE STREQUAL 'none') 63 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -march=${ARCHITECTURE}") 64 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -march=${ARCHITECTURE}") 65 | endif() 66 | endif() 67 | -------------------------------------------------------------------------------- /cmake/project_flags.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Mateusz Pusz 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | # define options 24 | option(CODE_COVERAGE "Compile project for C++ code coverage" OFF) 25 | 26 | # print options 27 | message(STATUS "CODE_COVERAGE=${CODE_COVERAGE}") 28 | 29 | # configure compiler warning level 30 | if(MSVC) 31 | # set warnings 32 | if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") 33 | string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 34 | else() 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") 36 | endif() 37 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /w44062 /w44263 /w44266 /w44640") 38 | 39 | # disable language extensions 40 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Za") 41 | 42 | # treat warnings as errors 43 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") 44 | elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 45 | # set warnings 46 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -pedantic") 47 | 48 | # treat warnings as errors 49 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") 50 | endif() 51 | 52 | # enable Code Coverage 53 | if(CODE_COVERAGE) 54 | if(MSVC) 55 | message(WARNING "Code Coverage on Visual Studio not supported") 56 | elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 57 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -coverage -fno-inline -fno-inline-small-functions -fno-default-inline") 58 | endif() 59 | endif() 60 | -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | --- 4 | Language: Cpp 5 | AccessModifierOffset: -2 6 | # AlignAfterOpenBracket: Align 7 | # AlignConsecutiveAssignments: false 8 | # AlignConsecutiveDeclarations: false 9 | # AlignEscapedNewlinesLeft: true 10 | # AlignOperands: true 11 | # AlignTrailingComments: true 12 | # AllowAllParametersOfDeclarationOnNextLine: true 13 | # AllowShortBlocksOnASingleLine: false 14 | # AllowShortCaseLabelsOnASingleLine: false 15 | # AllowShortFunctionsOnASingleLine: All 16 | # AllowShortIfStatementsOnASingleLine: true 17 | # AllowShortLoopsOnASingleLine: true 18 | # AlwaysBreakAfterDefinitionReturnType: None 19 | # AlwaysBreakAfterReturnType: None 20 | # AlwaysBreakBeforeMultilineStrings: true 21 | # AlwaysBreakTemplateDeclarations: true 22 | # BinPackArguments: true 23 | # BinPackParameters: true 24 | # BraceWrapping: 25 | # AfterClass: false 26 | # AfterControlStatement: false 27 | # AfterEnum: false 28 | # AfterFunction: false 29 | # AfterNamespace: false 30 | # AfterObjCDeclaration: false 31 | # AfterStruct: false 32 | # AfterUnion: false 33 | # BeforeCatch: false 34 | # BeforeElse: false 35 | # IndentBraces: false 36 | # BreakBeforeBinaryOperators: None 37 | BreakBeforeBraces: Stroustrup 38 | # BreakBeforeTernaryOperators: true 39 | BreakConstructorInitializersBeforeComma: true 40 | # BreakAfterJavaFieldAnnotations: false 41 | # BreakStringLiterals: true 42 | ColumnLimit: 120 43 | # CommentPragmas: '^ IWYU pragma:' 44 | # ConstructorInitializerAllOnOneLineOrOnePerLine: true 45 | # ConstructorInitializerIndentWidth: 4 46 | # ContinuationIndentWidth: 4 47 | # Cpp11BracedListStyle: true 48 | DerivePointerAlignment: false 49 | # DisableFormat: false 50 | # ExperimentalAutoDetectBinPacking: false 51 | # ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 52 | IncludeCategories: 53 | - Regex: '^".*' 54 | Priority: 1 55 | - Regex: '^".+/.*' 56 | Priority: 2 57 | - Regex: '^<.+/.*' 58 | Priority: 3 59 | - Regex: '^<.*\.h>' 60 | Priority: 4 61 | - Regex: '^<.*' 62 | Priority: 5 63 | # IncludeIsMainRegex: '([-_](test|unittest))?$' 64 | # IndentCaseLabels: true 65 | # IndentWidth: 2 66 | # IndentWrappedFunctionNames: false 67 | # JavaScriptQuotes: Leave 68 | # JavaScriptWrapImports: true 69 | KeepEmptyLinesAtTheStartOfBlocks: true 70 | # MacroBlockBegin: '' 71 | # MacroBlockEnd: '' 72 | # MaxEmptyLinesToKeep: 1 73 | NamespaceIndentation: All 74 | # ObjCBlockIndentWidth: 2 75 | # ObjCSpaceAfterProperty: false 76 | # ObjCSpaceBeforeProtocolList: false 77 | # PenaltyBreakBeforeFirstCallParameter: 1 78 | # PenaltyBreakComment: 300 79 | # PenaltyBreakFirstLessLess: 120 80 | # PenaltyBreakString: 1000 81 | # PenaltyExcessCharacter: 1000000 82 | # PenaltyReturnTypeOnItsOwnLine: 200 83 | # PointerAlignment: Left 84 | # ReflowComments: true 85 | # SortIncludes: true 86 | # SpaceAfterCStyleCast: false 87 | SpaceAfterTemplateKeyword: false 88 | # SpaceBeforeAssignmentOperators: true 89 | SpaceBeforeParens: Never 90 | # SpaceInEmptyParentheses: false 91 | # SpacesBeforeTrailingComments: 2 92 | # SpacesInAngles: false 93 | # SpacesInContainerLiterals: true 94 | # SpacesInCStyleCastParentheses: false 95 | # SpacesInParentheses: false 96 | # SpacesInSquareBrackets: false 97 | Standard: Cpp11 98 | # TabWidth: 8 99 | # UseTab: Never 100 | ... 101 | -------------------------------------------------------------------------------- /src/include/opt.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Mateusz Pusz 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #pragma once 24 | 25 | #include "opt_bits.h" 26 | 27 | namespace mp { 28 | 29 | template 30 | struct opt_default_policy { 31 | static constexpr bool has_value(const T& value) noexcept = delete; 32 | static constexpr T null_value() noexcept = delete; 33 | }; 34 | 35 | template 36 | struct opt_null_value_policy { 37 | static constexpr T null_value() noexcept { return NullValue; } 38 | }; 39 | 40 | template 41 | struct opt_null_type_policy { 42 | static constexpr bool has_value(T value) noexcept { return value != null_value(); } 43 | static constexpr T null_value() noexcept { return NullType::null_value; } 44 | }; 45 | 46 | // opt_policy_traits class template provides the standardized way to access properties of user Policy types 47 | template 48 | struct opt_policy_traits { 49 | // Policy::storage_type if exists, T otherwise 50 | using storage_type = typename detail::detect_storage_type::type; 51 | 52 | // always calls Policy::null_value() 53 | static constexpr storage_type null_value() noexcept(noexcept(Policy::null_value())) { return Policy::null_value(); } 54 | 55 | // calls Policy::has_value() if available, otherwise uses operator==() for comparison 56 | template> = true> 57 | static constexpr bool has_value(const U& storage) noexcept(noexcept(Policy::has_value(storage))) 58 | { 59 | return Policy::has_value(storage); 60 | } 61 | 62 | template>> = true> 64 | static constexpr bool has_value(const U& value) noexcept(noexcept(null_value())) 65 | { 66 | return !(value == null_value()); 67 | } 68 | }; 69 | 70 | template> 71 | class opt { 72 | public: 73 | using value_type = T; 74 | using policy_type = Policy; 75 | using traits_type = opt_policy_traits; 76 | 77 | private: 78 | using storage_type = typename traits_type::storage_type; 79 | storage_type storage_; 80 | 81 | constexpr const T& data() const { return *reinterpret_cast(&storage_); } 82 | constexpr T& data() { return *reinterpret_cast(&storage_); } 83 | 84 | public: 85 | // constructors 86 | constexpr opt() noexcept(noexcept(storage_type{traits_type::null_value()})) : storage_{traits_type::null_value()} {} 87 | 88 | constexpr opt(std::nullopt_t) noexcept(noexcept(opt{})) : opt{} {} 89 | 90 | opt(const opt&) = default; 91 | opt(opt&&) = default; 92 | 93 | template> = true> 94 | constexpr explicit opt(std::in_place_t, Args&&... args) : storage_{std::forward(args)...} 95 | { 96 | assert(has_value()); 97 | } 98 | 99 | template&, Args&&...>> = true> 101 | constexpr explicit opt(std::in_place_t, std::initializer_list ilist, Args&&... args) 102 | : storage_{ilist, std::forward(args)...} 103 | { 104 | assert(has_value()); 105 | } 106 | 107 | template, 109 | std::negation, std::in_place_t>>, 110 | std::negation, std::decay_t>>, 111 | std::negation>>> = true, 112 | detail::Requires>> = true> 113 | explicit constexpr opt(U&& value) : storage_{std::forward(value)} 114 | { 115 | assert(has_value()); 116 | } 117 | 118 | template, 120 | std::negation, std::in_place_t>>, 121 | std::negation, std::decay_t>>, 122 | std::negation>>> = true, 123 | detail::Requires> = true> 124 | constexpr opt(U&& value) : storage_{std::forward(value)} 125 | { 126 | assert(has_value()); 127 | } 128 | 129 | template, 131 | std::disjunction, bool>, 132 | std::negation>>> = true, 133 | detail::Requires>> = true> 134 | explicit opt(const opt& other) : storage_{other.has_value() ? T{*other} : traits_type::null_value()} 135 | { 136 | } 137 | 138 | template, 140 | std::disjunction, bool>, 141 | std::negation>>> = true, 142 | detail::Requires> = true> 143 | opt(const opt& other) : storage_{other.has_value() ? T{*other} : traits_type::null_value()} 144 | { 145 | } 146 | 147 | template, 149 | std::disjunction, bool>, 150 | std::negation>>> = true, 151 | detail::Requires>> = true> 152 | explicit constexpr opt(opt&& other) 153 | : storage_{other.has_value() ? T{std::move(*other)} : traits_type::null_value()} 154 | { 155 | } 156 | 157 | template, 159 | std::disjunction, bool>, 160 | std::negation>>> = true, 161 | detail::Requires> = true> 162 | constexpr opt(opt&& other) : storage_{other.has_value() ? T{std::move(*other)} : traits_type::null_value()} 163 | { 164 | } 165 | 166 | // assignment 167 | opt& operator=(std::nullopt_t) noexcept(noexcept(std::declval>().reset())) 168 | { 169 | reset(); 170 | return *this; 171 | } 172 | opt& operator=(const opt& other) = default; 173 | opt& operator=(opt&& other) = default; 174 | 175 | template, std::decay>>, 177 | std::negation, std::is_same>>>, 178 | std::is_constructible, std::is_assignable> = true> 179 | opt& operator=(U&& value) 180 | { 181 | data() = std::forward(value); 182 | assert(has_value()); 183 | return *this; 184 | } 185 | 186 | template, std::is_assignable, 188 | std::negation>, 189 | std::negation>> = true> 190 | opt& operator=(const opt& other) 191 | { 192 | if(other.has_value()) 193 | *this = *other; 194 | else 195 | reset(); 196 | return *this; 197 | } 198 | 199 | template, std::is_assignable, 201 | std::negation>, 202 | std::negation>> = true> 203 | opt& operator=(opt&& other) 204 | { 205 | if(other.has_value()) 206 | *this = std::move(*other); 207 | else 208 | reset(); 209 | return *this; 210 | } 211 | 212 | // swap 213 | void swap(opt& other) noexcept( 214 | std::is_nothrow_move_constructible::value /* && std::is_nothrow_swappable::value */) 215 | { 216 | std::swap(storage_, other.storage_); 217 | } 218 | 219 | // observers 220 | constexpr const T* operator->() const { assert(has_value()); return &data(); } 221 | constexpr T* operator->() { assert(has_value()); return &data(); } 222 | constexpr const T& operator*() const & { assert(has_value()); return data(); } 223 | constexpr T& operator*() & { assert(has_value()); return data(); } 224 | constexpr T&& operator*() && { assert(has_value()); return std::move(data()); } 225 | constexpr const T&& operator*() const && { assert(has_value()); return std::move(data()); } 226 | 227 | constexpr bool has_value() const noexcept(noexcept(traits_type::has_value(std::declval()))) 228 | { 229 | return traits_type::has_value(storage_); 230 | } 231 | constexpr explicit operator bool() const noexcept(noexcept(std::declval>().has_value())) 232 | { 233 | return has_value(); 234 | } 235 | 236 | // clang-format off 237 | constexpr const T& value() const& { if (!has_value()) throw std::bad_optional_access{}; return **this; } 238 | constexpr T& value() & { if (!has_value()) throw std::bad_optional_access{}; return **this; } 239 | constexpr T&& value() && { if (!has_value()) throw std::bad_optional_access{}; return std::move(**this); } 240 | constexpr const T&& value() const&& { if (!has_value()) throw std::bad_optional_access{}; return std::move(**this); } 241 | template 242 | constexpr T value_or(U&& default_value) const& { return has_value() ? **this : T{ std::forward(default_value) }; } 243 | template 244 | constexpr T value_or(U&& default_value) && { return has_value() ? std::move(**this) : T{ std::forward(default_value) }; } 245 | // clang-format on 246 | 247 | // modifiers 248 | void reset() noexcept(noexcept(traits_type::null_value())) { storage_ = traits_type::null_value(); } 249 | }; 250 | 251 | // relational operators 252 | template 253 | constexpr bool operator==(const opt& lhs, const opt& rhs) 254 | { 255 | return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); 256 | } 257 | 258 | template 259 | constexpr bool operator!=(const opt& lhs, const opt& rhs) 260 | { 261 | return !(lhs == rhs); 262 | } 263 | 264 | #ifdef OPT_REL_OPS 265 | template 266 | constexpr bool operator<(const opt& lhs, const opt& rhs) 267 | { 268 | return (!rhs) ? false : (!lhs) ? true : *lhs < *rhs; 269 | } 270 | 271 | template 272 | constexpr bool operator>(const opt& lhs, const opt& rhs) 273 | { 274 | return (rhs < lhs); 275 | } 276 | 277 | template 278 | constexpr bool operator<=(const opt& lhs, const opt& rhs) 279 | { 280 | return !(rhs < lhs); 281 | } 282 | 283 | template 284 | constexpr bool operator>=(const opt& lhs, const opt& rhs) 285 | { 286 | return !(lhs < rhs); 287 | } 288 | #endif 289 | 290 | // clang-format off 291 | // comparison with nullopt 292 | template constexpr bool operator==(const opt& o, std::nullopt_t) noexcept { return !o; } 293 | template constexpr bool operator==(std::nullopt_t, const opt& o) noexcept { return !o; } 294 | template constexpr bool operator!=(const opt& o, std::nullopt_t) noexcept { return static_cast(o); } 295 | template constexpr bool operator!=(std::nullopt_t, const opt& o) noexcept { return static_cast(o); } 296 | 297 | #ifdef OPT_REL_OPS 298 | template constexpr bool operator< (const opt&, std::nullopt_t) noexcept { return false; } 299 | template constexpr bool operator< (std::nullopt_t, const opt& o) noexcept { return static_cast(o); } 300 | template constexpr bool operator<=(const opt& o, std::nullopt_t) noexcept { return !o; } 301 | template constexpr bool operator<=(std::nullopt_t, const opt&) noexcept { return true; } 302 | template constexpr bool operator> (const opt& o, std::nullopt_t) noexcept { return static_cast(o); } 303 | template constexpr bool operator> (std::nullopt_t, const opt&) noexcept { return false; } 304 | template constexpr bool operator>=(const opt&, std::nullopt_t) noexcept { return true; } 305 | template constexpr bool operator>=(std::nullopt_t, const opt& o) noexcept { return !o; } 306 | #endif 307 | 308 | // comparison with T 309 | template constexpr bool operator==(const opt& o, const U& value) { return o && *o == value; } 310 | template constexpr bool operator==(const U& value, const opt& o) { return o && value == *o; } 311 | template constexpr bool operator!=(const opt& o, const U& value) { return !o || *o != value; } 312 | template constexpr bool operator!=(const U& value, const opt& o) { return !o || value != *o; } 313 | 314 | #ifdef OPT_REL_OPS 315 | template constexpr bool operator< (const opt& o, const U& value) { return !o || *o < value; } 316 | template constexpr bool operator< (const U& value, const opt& o) { return o && value < *o; } 317 | template constexpr bool operator<=(const opt& o, const U& value) { return !o || *o <= value; } 318 | template constexpr bool operator<=(const U& value, const opt& o) { return o && value <= *o; } 319 | template constexpr bool operator> (const opt& o, const U& value) { return o && *o > value; } 320 | template constexpr bool operator> (const U& value, const opt& o) { return !o || value > *o; } 321 | template constexpr bool operator>=(const opt& o, const U& value) { return o && *o >= value; } 322 | template constexpr bool operator>=(const U& value, const opt& o) { return !o || value >= *o; } 323 | #endif 324 | // clang-format on 325 | } 326 | 327 | // specialized algorithms 328 | namespace std { 329 | 330 | template 331 | inline void swap(mp::opt& lhs, mp::opt& rhs) noexcept(noexcept(lhs.swap(rhs))) 332 | { 333 | lhs.swap(rhs); 334 | } 335 | 336 | // hash support 337 | // template 338 | // struct hash; 339 | // template 340 | // struct hash>; 341 | } 342 | -------------------------------------------------------------------------------- /src/include/opt_bits.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Mateusz Pusz 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace mp { 30 | 31 | template 32 | class opt; 33 | 34 | namespace detail { 35 | 36 | template 37 | using Requires = std::enable_if_t::value, bool>; 38 | 39 | // concepts needed by opt class template 40 | template 41 | struct is_opt : std::false_type { 42 | }; 43 | template 44 | struct is_opt> : std::true_type { 45 | }; 46 | 47 | template 48 | using constructs_or_converts_from_opt = 49 | std::disjunction&>, std::is_constructible&>, 50 | std::is_constructible&&>, std::is_constructible&&>, 51 | std::is_convertible&, T>, std::is_convertible&, T>, 52 | std::is_convertible&&, T>, std::is_convertible&&, T>>; 53 | 54 | template 55 | using assigns_from_opt = 56 | std::disjunction&>, std::is_assignable&>, 57 | std::is_assignable&&>, std::is_assignable&&>>; 58 | 59 | // detect if Policy::has_value() is present 60 | template 61 | using has_value_t = decltype(std::declval

().has_value(std::declval())); 62 | 63 | template> 64 | struct has_has_value : std::false_type { 65 | }; 66 | template 67 | struct has_has_value>> : std::is_same, bool> { 68 | }; 69 | 70 | // detect if Policy::storage_type is present 71 | template> 72 | struct detect_storage_type { 73 | using type = T; 74 | }; 75 | template 76 | struct detect_storage_type> { 77 | using type = typename Policy::storage_type; 78 | static_assert(sizeof(T) == sizeof(type), 79 | "'sizeof(Policy::storage_type) != sizeof(T)' consider using std::optional"); 80 | }; 81 | 82 | } // namespace detail 83 | } 84 | -------------------------------------------------------------------------------- /src/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Mateusz Pusz 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | set(SOURCE_FILES tests.cpp) 24 | 25 | add_definitions(-DOPT_REL_OPS) 26 | add_executable(unit_tests ${SOURCE_FILES}) 27 | target_link_libraries(unit_tests 28 | PRIVATE google::test) 29 | add_test(unit_tests unit_tests) 30 | -------------------------------------------------------------------------------- /src/tests/tests.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Mateusz Pusz 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #include "opt.h" 24 | #include 25 | 26 | namespace { 27 | 28 | using namespace mp; 29 | using namespace std; 30 | 31 | struct my_bool { 32 | std::uint8_t value_; 33 | my_bool() = default; 34 | constexpr my_bool(bool v) noexcept : value_{v} {} 35 | explicit constexpr my_bool(std::uint8_t v) noexcept : value_{v} {} 36 | constexpr operator bool() const noexcept { return value_; } 37 | }; 38 | 39 | class weekday { 40 | public: 41 | using underlying_type = std::int8_t; 42 | constexpr explicit weekday(underlying_type v) : value_{v} 43 | { 44 | if(v < 0 || v > 6) throw std::out_of_range{"weekday value outside of allowed range"}; 45 | } 46 | constexpr weekday& operator=(underlying_type v) 47 | { 48 | if(v < 0 || v > 6) throw std::out_of_range{"weekday value outside of allowed range"}; 49 | value_ = v; 50 | return *this; 51 | } 52 | constexpr underlying_type get() const noexcept { return value_; } 53 | 54 | private: 55 | underlying_type value_; // 0 - 6 56 | }; 57 | constexpr bool operator==(weekday lhs, weekday rhs) noexcept { return lhs.get() == rhs.get(); } 58 | constexpr bool operator==(weekday::underlying_type lhs, weekday rhs) noexcept { return lhs == rhs.get(); } 59 | constexpr bool operator==(weekday lhs, weekday::underlying_type rhs) noexcept { return lhs.get() == rhs; } 60 | 61 | class weekday_mask { 62 | public: 63 | using underlying_type = std::uint8_t; 64 | explicit weekday_mask(std::initializer_list days) 65 | { 66 | for(auto d : days) 67 | mask_ |= (1 << d.get()); 68 | } 69 | underlying_type mask() const noexcept { return mask_; } 70 | 71 | private: 72 | underlying_type mask_ = 0; 73 | }; 74 | 75 | } 76 | 77 | namespace mp { 78 | 79 | template<> 80 | struct opt_default_policy { 81 | private: 82 | union storage { 83 | bool value; 84 | std::int8_t null_value = -1; 85 | storage() = default; 86 | constexpr storage(bool v) noexcept : value{v} {} 87 | }; 88 | 89 | public: 90 | using storage_type = storage; 91 | static constexpr storage_type null_value() noexcept { return storage_type{}; } 92 | static constexpr bool has_value(storage_type s) noexcept { return s.null_value != -1; } 93 | }; 94 | 95 | template<> 96 | struct opt_default_policy { 97 | static my_bool null_value() noexcept { return my_bool{std::uint8_t{255}}; } 98 | static bool has_value(my_bool value) noexcept { return value.value_ != 255; } 99 | }; 100 | 101 | template<> 102 | struct opt_default_policy { 103 | union storage_type { 104 | weekday value; 105 | weekday::underlying_type null_value = 7; 106 | 107 | constexpr storage_type() noexcept {}; 108 | constexpr storage_type(weekday v) : value{v} {} 109 | constexpr storage_type(weekday::underlying_type v) : value{v} {} 110 | storage_type& operator=(weekday v) 111 | { 112 | value = v; 113 | return *this; 114 | } 115 | }; 116 | 117 | public: 118 | static constexpr storage_type null_value() noexcept { return storage_type{}; } 119 | static constexpr bool has_value(storage_type value) noexcept { return value.null_value != 7; } 120 | }; 121 | 122 | template<> 123 | struct opt_default_policy { 124 | union storage_type { 125 | weekday_mask value; 126 | weekday_mask::underlying_type null_value = 0b1111'1111; 127 | 128 | storage_type() noexcept {}; 129 | storage_type(weekday_mask v) : value{v} {} 130 | explicit storage_type(std::initializer_list days) : value{days} {} 131 | 132 | storage_type& operator=(weekday_mask v) 133 | { 134 | value = v; 135 | return *this; 136 | } 137 | }; 138 | 139 | public: 140 | static storage_type null_value() noexcept { return storage_type{}; } 141 | static bool has_value(storage_type value) noexcept { return value.null_value != 0b1111'1111; } 142 | }; 143 | } 144 | 145 | namespace { 146 | 147 | template 148 | struct null_floating { 149 | static constexpr T null_value = 0.0f; 150 | }; 151 | 152 | template 153 | struct opt_traits; 154 | 155 | template<> 156 | struct opt_traits { 157 | static_assert(std::is_constructible::value); 158 | static_assert(std::is_convertible::value); 159 | 160 | static constexpr bool value_1 = true; 161 | static constexpr bool value_2 = false; 162 | 163 | using other_type = my_bool; 164 | using other_policy_type = opt_default_policy; 165 | static const other_type other_value_1; 166 | static const other_type other_value_2; 167 | }; 168 | constexpr opt_traits::other_type opt_traits::other_value_1 = true; 169 | constexpr opt_traits::other_type opt_traits::other_value_2 = false; 170 | 171 | template<> 172 | struct opt_traits { 173 | static_assert(std::is_constructible::value); 174 | static_assert(std::is_convertible::value); 175 | 176 | static constexpr long value_1 = 123; 177 | static constexpr long value_2 = 999; 178 | 179 | using other_type = int; 180 | using other_policy_type = opt_null_value_policy::max()>; 181 | static constexpr other_type other_value_1 = 123; 182 | static constexpr other_type other_value_2 = 999; 183 | }; 184 | 185 | template<> 186 | struct opt_traits { 187 | static_assert(std::is_constructible::value); 188 | static_assert(!std::is_convertible::value); 189 | 190 | static const weekday value_1; 191 | static const weekday value_2; 192 | 193 | using other_type = weekday::underlying_type; 194 | using other_policy_type = opt_null_value_policy; 195 | static constexpr other_type other_value_1 = 0; 196 | static constexpr other_type other_value_2 = 3; 197 | }; 198 | constexpr weekday opt_traits::value_1{0}; 199 | constexpr weekday opt_traits::value_2{3}; 200 | 201 | template<> 202 | struct opt_traits { 203 | static_assert(std::is_constructible::value); 204 | static_assert(std::is_convertible::value); 205 | 206 | static constexpr double value_1 = 3.14f; 207 | static constexpr double value_2 = 123.456f; 208 | 209 | using other_type = float; 210 | using other_policy_type = opt_null_type_policy>; 211 | static constexpr other_type other_value_1 = 3.14f; 212 | static constexpr other_type other_value_2 = 123.456f; 213 | }; 214 | 215 | template 216 | class optTyped : public ::testing::Test { 217 | public: 218 | using type = T; 219 | using traits = opt_traits; 220 | const typename type::value_type value_1 = traits::value_1; 221 | const typename type::value_type value_2 = traits::value_2; 222 | const typename traits::other_type other_value_1 = traits::other_value_1; 223 | const typename traits::other_type other_value_2 = traits::other_value_2; 224 | }; 225 | using test_types = ::testing::Types, opt, opt>, 226 | opt>>>; 227 | TYPED_TEST_CASE(optTyped, test_types); 228 | } 229 | 230 | TEST(opt, Price) 231 | { 232 | using price = int; 233 | using opt_price = opt>; 234 | static_assert(sizeof(opt_price) == sizeof(int)); 235 | 236 | opt_price o1; 237 | EXPECT_TRUE(static_cast(o1) == false); 238 | EXPECT_TRUE(o1.has_value() == false); 239 | EXPECT_TRUE(o1.value_or(123) == 123); 240 | 241 | opt_price o2{99}; 242 | EXPECT_TRUE(static_cast(o2) == true); 243 | EXPECT_TRUE(o2.has_value() == true); 244 | EXPECT_TRUE(*o2 == 99); 245 | EXPECT_TRUE(o2.value() == 99); 246 | EXPECT_TRUE(o2.value_or(123) == 99); 247 | 248 | opt_price o3{o2}; 249 | EXPECT_TRUE(o3.has_value() == true); 250 | EXPECT_TRUE(*o3 == 99); 251 | 252 | o3 = o1; 253 | EXPECT_TRUE(o3.has_value() == false); 254 | 255 | o3 = o2; 256 | EXPECT_TRUE(o3.has_value() == true); 257 | EXPECT_TRUE(*o3 == 99); 258 | 259 | o3 = nullopt; 260 | EXPECT_TRUE(o3.has_value() == false); 261 | } 262 | 263 | TYPED_TEST(optTyped, defaultConstructor) 264 | { 265 | using opt_type = typename TestFixture::type; 266 | opt_type o; 267 | EXPECT_FALSE(o); 268 | EXPECT_FALSE(o.has_value()); 269 | EXPECT_THROW(o.value(), bad_optional_access); 270 | EXPECT_EQ(this->value_2, o.value_or(this->value_2)); 271 | 272 | const opt_type& co{o}; 273 | EXPECT_FALSE(co); 274 | EXPECT_FALSE(co.has_value()); 275 | EXPECT_THROW(co.value(), bad_optional_access); 276 | EXPECT_EQ(this->value_2, co.value_or(this->value_2)); 277 | } 278 | 279 | TYPED_TEST(optTyped, defaultConstructorRvalue) 280 | { 281 | using opt_type = typename TestFixture::type; 282 | auto make = [] { return opt_type{}; }; 283 | EXPECT_FALSE(make()); 284 | EXPECT_FALSE(make().has_value()); 285 | EXPECT_THROW(make().value(), bad_optional_access); 286 | EXPECT_EQ(this->value_2, make().value_or(this->value_2)); 287 | } 288 | 289 | TYPED_TEST(optTyped, defaultConstructorConstRvalue) 290 | { 291 | using opt_type = typename TestFixture::type; 292 | auto make = []() -> const opt_type { return opt_type{}; }; 293 | EXPECT_FALSE(make()); 294 | EXPECT_FALSE(make().has_value()); 295 | EXPECT_THROW(make().value(), bad_optional_access); 296 | EXPECT_EQ(this->value_2, make().value_or(this->value_2)); 297 | } 298 | 299 | TYPED_TEST(optTyped, nulloptConstructor) 300 | { 301 | using opt_type = typename TestFixture::type; 302 | opt_type o{nullopt}; 303 | EXPECT_FALSE(o); 304 | EXPECT_FALSE(o.has_value()); 305 | EXPECT_THROW(o.value(), bad_optional_access); 306 | EXPECT_EQ(this->value_2, o.value_or(this->value_2)); 307 | 308 | const opt_type& co{o}; 309 | EXPECT_FALSE(co); 310 | EXPECT_FALSE(co.has_value()); 311 | EXPECT_THROW(co.value(), bad_optional_access); 312 | EXPECT_EQ(this->value_2, co.value_or(this->value_2)); 313 | } 314 | 315 | TYPED_TEST(optTyped, valueConstructor1) 316 | { 317 | using opt_type = typename TestFixture::type; 318 | opt_type o{this->value_1}; 319 | EXPECT_TRUE(o); 320 | EXPECT_TRUE(o.has_value()); 321 | EXPECT_EQ(this->value_1, *o); 322 | EXPECT_EQ(this->value_1, o.value()); 323 | EXPECT_EQ(this->value_1, o.value_or(this->value_2)); 324 | 325 | const opt_type& co{o}; 326 | EXPECT_TRUE(co); 327 | EXPECT_TRUE(co.has_value()); 328 | EXPECT_EQ(this->value_1, *co); 329 | EXPECT_EQ(this->value_1, co.value()); 330 | EXPECT_EQ(this->value_1, co.value_or(this->value_2)); 331 | } 332 | 333 | TYPED_TEST(optTyped, valueConstructor2) 334 | { 335 | using opt_type = typename TestFixture::type; 336 | opt_type o = this->value_1; 337 | EXPECT_TRUE(o); 338 | EXPECT_TRUE(o.has_value()); 339 | EXPECT_EQ(this->value_1, *o); 340 | EXPECT_EQ(this->value_1, o.value()); 341 | EXPECT_EQ(this->value_1, o.value_or(this->value_2)); 342 | 343 | const opt_type& co{o}; 344 | EXPECT_TRUE(co); 345 | EXPECT_TRUE(co.has_value()); 346 | EXPECT_EQ(this->value_1, *co); 347 | EXPECT_EQ(this->value_1, co.value()); 348 | EXPECT_EQ(this->value_1, co.value_or(this->value_2)); 349 | } 350 | 351 | TYPED_TEST(optTyped, valueConstructorOther1) 352 | { 353 | using opt_type = typename TestFixture::type; 354 | opt_type o{this->other_value_1}; 355 | EXPECT_TRUE(o); 356 | EXPECT_TRUE(o.has_value()); 357 | EXPECT_EQ(this->value_1, *o); 358 | EXPECT_EQ(this->value_1, o.value()); 359 | EXPECT_EQ(this->value_1, o.value_or(this->value_2)); 360 | 361 | const opt_type& co{o}; 362 | EXPECT_TRUE(co); 363 | EXPECT_TRUE(co.has_value()); 364 | EXPECT_EQ(this->value_1, *co); 365 | EXPECT_EQ(this->value_1, co.value()); 366 | EXPECT_EQ(this->value_1, co.value_or(this->value_2)); 367 | } 368 | 369 | TYPED_TEST(optTyped, valueConstructorRvalue) 370 | { 371 | using opt_type = typename TestFixture::type; 372 | auto make = [&] { return opt_type{this->value_1}; }; 373 | EXPECT_TRUE(make()); 374 | EXPECT_TRUE(make().has_value()); 375 | EXPECT_EQ(this->value_1, *make()); 376 | EXPECT_EQ(this->value_1, make().value()); 377 | EXPECT_EQ(this->value_1, make().value_or(this->value_2)); 378 | } 379 | 380 | TYPED_TEST(optTyped, valueConstructorConstRvalue) 381 | { 382 | using opt_type = typename TestFixture::type; 383 | auto make = [&]() -> const opt_type { return opt_type{this->value_1}; }; 384 | EXPECT_TRUE(make()); 385 | EXPECT_TRUE(make().has_value()); 386 | EXPECT_EQ(this->value_1, *make()); 387 | EXPECT_EQ(this->value_1, make().value()); 388 | EXPECT_EQ(this->value_1, make().value_or(this->value_2)); 389 | } 390 | 391 | TYPED_TEST(optTyped, inPlaceConstructor) 392 | { 393 | using opt_type = typename TestFixture::type; 394 | opt_type o{in_place, this->value_1}; 395 | EXPECT_TRUE(o); 396 | EXPECT_TRUE(o.has_value()); 397 | EXPECT_EQ(this->value_1, *o); 398 | EXPECT_EQ(this->value_1, o.value()); 399 | EXPECT_EQ(this->value_1, o.value_or(this->value_2)); 400 | 401 | const opt_type& co{o}; 402 | EXPECT_TRUE(co); 403 | EXPECT_TRUE(co.has_value()); 404 | EXPECT_EQ(this->value_1, *co); 405 | EXPECT_EQ(this->value_1, co.value()); 406 | EXPECT_EQ(this->value_1, co.value_or(this->value_2)); 407 | } 408 | 409 | // TEST(opt, inPlaceConstructorInitList) 410 | //{ 411 | // null_value_opt o{in_place, {123}}; 412 | // EXPECT_TRUE(o); 413 | // EXPECT_TRUE(o.has_value()); 414 | // EXPECT_EQ(123, *o); 415 | // EXPECT_EQ(123, o.value()); 416 | // EXPECT_EQ(123, o.value_or(999)); 417 | //} 418 | 419 | TYPED_TEST(optTyped, copyConstructionForEmpty) 420 | { 421 | using opt_type = typename TestFixture::type; 422 | opt_type o1; 423 | auto o2{o1}; 424 | EXPECT_FALSE(o2); 425 | EXPECT_FALSE(o2.has_value()); 426 | EXPECT_THROW(o2.value(), bad_optional_access); 427 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 428 | } 429 | 430 | TYPED_TEST(optTyped, copyConstructionForNotEmpty) 431 | { 432 | using opt_type = typename TestFixture::type; 433 | opt_type o1{this->value_1}; 434 | auto o2{o1}; 435 | EXPECT_TRUE(o2); 436 | EXPECT_TRUE(o2.has_value()); 437 | EXPECT_EQ(this->value_1, *o2); 438 | EXPECT_EQ(this->value_1, o2.value()); 439 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 440 | } 441 | 442 | TYPED_TEST(optTyped, moveConstructionForEmpty) 443 | { 444 | using opt_type = typename TestFixture::type; 445 | opt_type o1; 446 | auto o2{std::move(o1)}; 447 | EXPECT_FALSE(o2); 448 | EXPECT_FALSE(o2.has_value()); 449 | EXPECT_THROW(o2.value(), bad_optional_access); 450 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 451 | } 452 | 453 | TYPED_TEST(optTyped, moveConstructionForNotEmpty) 454 | { 455 | using opt_type = typename TestFixture::type; 456 | opt_type o1{this->value_1}; 457 | auto o2{std::move(o1)}; 458 | EXPECT_TRUE(o2); 459 | EXPECT_TRUE(o2.has_value()); 460 | EXPECT_EQ(this->value_1, *o2); 461 | EXPECT_EQ(this->value_1, o2.value()); 462 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 463 | } 464 | 465 | TYPED_TEST(optTyped, otherTypeCopyConstructionForEmpty) 466 | { 467 | using opt_type = typename TestFixture::type; 468 | using other_opt_type = opt; 469 | other_opt_type o1; 470 | opt_type o2{o1}; 471 | EXPECT_FALSE(o1); 472 | EXPECT_FALSE(o1.has_value()); 473 | EXPECT_THROW(o1.value(), bad_optional_access); 474 | EXPECT_EQ(this->value_2, o1.value_or(this->other_value_2)); 475 | EXPECT_FALSE(o2); 476 | EXPECT_FALSE(o2.has_value()); 477 | EXPECT_THROW(o2.value(), bad_optional_access); 478 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 479 | } 480 | 481 | TYPED_TEST(optTyped, otherTypeCopyConstructionForNotEmpty) 482 | { 483 | using opt_type = typename TestFixture::type; 484 | using other_opt_type = opt; 485 | other_opt_type o1{this->other_value_1}; 486 | opt_type o2{o1}; 487 | EXPECT_TRUE(o1); 488 | EXPECT_TRUE(o1.has_value()); 489 | EXPECT_EQ(this->value_1, *o1); 490 | EXPECT_EQ(this->value_1, o1.value()); 491 | EXPECT_EQ(this->value_1, o1.value_or(this->other_value_2)); 492 | EXPECT_TRUE(o2); 493 | EXPECT_TRUE(o2.has_value()); 494 | EXPECT_EQ(this->value_1, *o2); 495 | EXPECT_EQ(this->value_1, o2.value()); 496 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 497 | } 498 | 499 | TYPED_TEST(optTyped, otherTypeMoveConstructionForEmpty) 500 | { 501 | using opt_type = typename TestFixture::type; 502 | using other_opt_type = opt; 503 | other_opt_type o1; 504 | opt_type o2{std::move(o1)}; 505 | EXPECT_FALSE(o2); 506 | EXPECT_FALSE(o2.has_value()); 507 | EXPECT_THROW(o2.value(), bad_optional_access); 508 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 509 | } 510 | 511 | TYPED_TEST(optTyped, otherTypeMoveConstructionForNotEmpty) 512 | { 513 | using opt_type = typename TestFixture::type; 514 | using other_opt_type = opt; 515 | other_opt_type o1{this->other_value_1}; 516 | opt_type o2{std::move(o1)}; 517 | EXPECT_TRUE(o2); 518 | EXPECT_TRUE(o2.has_value()); 519 | EXPECT_EQ(this->value_1, *o2); 520 | EXPECT_EQ(this->value_1, o2.value()); 521 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 522 | } 523 | 524 | TYPED_TEST(optTyped, nullAssignmentEmptyForEmpty) 525 | { 526 | using opt_type = typename TestFixture::type; 527 | opt_type o; 528 | o = nullopt; 529 | EXPECT_FALSE(o); 530 | EXPECT_FALSE(o.has_value()); 531 | EXPECT_THROW(o.value(), bad_optional_access); 532 | EXPECT_EQ(this->value_2, o.value_or(this->value_2)); 533 | } 534 | 535 | TYPED_TEST(optTyped, nullAssignmentEmptyForNotEmpty) 536 | { 537 | using opt_type = typename TestFixture::type; 538 | opt_type o{this->value_1}; 539 | o = nullopt; 540 | EXPECT_FALSE(o); 541 | EXPECT_FALSE(o.has_value()); 542 | EXPECT_THROW(o.value(), bad_optional_access); 543 | EXPECT_EQ(this->value_2, o.value_or(this->value_2)); 544 | } 545 | 546 | TYPED_TEST(optTyped, copyAssignmentEmptyForEmpty) 547 | { 548 | using opt_type = typename TestFixture::type; 549 | opt_type o1; 550 | opt_type o2; 551 | o2 = o1; 552 | EXPECT_FALSE(o2); 553 | EXPECT_FALSE(o2.has_value()); 554 | EXPECT_THROW(o2.value(), bad_optional_access); 555 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 556 | } 557 | 558 | TYPED_TEST(optTyped, copyAssignmentNotEmptyForEmpty) 559 | { 560 | using opt_type = typename TestFixture::type; 561 | opt_type o1{this->value_1}; 562 | opt_type o2; 563 | o2 = o1; 564 | EXPECT_TRUE(o2); 565 | EXPECT_TRUE(o2.has_value()); 566 | EXPECT_EQ(this->value_1, *o2); 567 | EXPECT_EQ(this->value_1, o2.value()); 568 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 569 | } 570 | 571 | TYPED_TEST(optTyped, copyAssignmentEmptyForNotEmpty) 572 | { 573 | using opt_type = typename TestFixture::type; 574 | opt_type o1; 575 | opt_type o2{this->value_1}; 576 | o2 = o1; 577 | EXPECT_FALSE(o2); 578 | EXPECT_FALSE(o2.has_value()); 579 | EXPECT_THROW(o2.value(), bad_optional_access); 580 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 581 | } 582 | 583 | TYPED_TEST(optTyped, copyAssignmentNotEmptyForNotEmpty) 584 | { 585 | using opt_type = typename TestFixture::type; 586 | opt_type o1{this->value_1}; 587 | opt_type o2{this->value_2}; 588 | o2 = o1; 589 | EXPECT_TRUE(o2); 590 | EXPECT_TRUE(o2.has_value()); 591 | EXPECT_EQ(this->value_1, *o2); 592 | EXPECT_EQ(this->value_1, o2.value()); 593 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 594 | } 595 | 596 | TYPED_TEST(optTyped, moveAssignmentEmptyForEmpty) 597 | { 598 | using opt_type = typename TestFixture::type; 599 | opt_type o1; 600 | opt_type o2; 601 | o2 = std::move(o1); 602 | EXPECT_FALSE(o2); 603 | EXPECT_FALSE(o2.has_value()); 604 | EXPECT_THROW(o2.value(), bad_optional_access); 605 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 606 | } 607 | 608 | TYPED_TEST(optTyped, moveAssignmentNotEmptyForEmpty) 609 | { 610 | using opt_type = typename TestFixture::type; 611 | opt_type o1{this->value_1}; 612 | opt_type o2; 613 | o2 = std::move(o1); 614 | EXPECT_TRUE(o2); 615 | EXPECT_TRUE(o2.has_value()); 616 | EXPECT_EQ(this->value_1, *o2); 617 | EXPECT_EQ(this->value_1, o2.value()); 618 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 619 | } 620 | 621 | TYPED_TEST(optTyped, moveAssignmentEmptyForNotEmpty) 622 | { 623 | using opt_type = typename TestFixture::type; 624 | opt_type o1; 625 | opt_type o2{this->value_1}; 626 | o2 = std::move(o1); 627 | EXPECT_FALSE(o2); 628 | EXPECT_FALSE(o2.has_value()); 629 | EXPECT_THROW(o2.value(), bad_optional_access); 630 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 631 | } 632 | 633 | TYPED_TEST(optTyped, moveAssignmentNotEmptyForNotEmpty) 634 | { 635 | using opt_type = typename TestFixture::type; 636 | opt_type o1{this->value_1}; 637 | opt_type o2{this->value_2}; 638 | o2 = std::move(o1); 639 | EXPECT_TRUE(o2); 640 | EXPECT_TRUE(o2.has_value()); 641 | EXPECT_EQ(this->value_1, *o2); 642 | EXPECT_EQ(this->value_1, o2.value()); 643 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 644 | } 645 | 646 | TYPED_TEST(optTyped, otherTypeCopyAssignmentEmptyForEmpty) 647 | { 648 | using opt_type = typename TestFixture::type; 649 | using other_opt_type = opt; 650 | other_opt_type o1; 651 | opt_type o2; 652 | o2 = o1; 653 | EXPECT_FALSE(o1); 654 | EXPECT_FALSE(o1.has_value()); 655 | EXPECT_THROW(o1.value(), bad_optional_access); 656 | EXPECT_EQ(this->value_2, o1.value_or(this->other_value_2)); 657 | EXPECT_FALSE(o2); 658 | EXPECT_FALSE(o2.has_value()); 659 | EXPECT_THROW(o2.value(), bad_optional_access); 660 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 661 | } 662 | 663 | TYPED_TEST(optTyped, otherTypeCopyAssignmentNotEmptyForEmpty) 664 | { 665 | using opt_type = typename TestFixture::type; 666 | using other_opt_type = opt; 667 | other_opt_type o1{this->other_value_1}; 668 | opt_type o2; 669 | o2 = o1; 670 | EXPECT_TRUE(o1); 671 | EXPECT_TRUE(o1.has_value()); 672 | EXPECT_EQ(this->value_1, *o1); 673 | EXPECT_EQ(this->value_1, o1.value()); 674 | EXPECT_EQ(this->value_1, o1.value_or(this->other_value_2)); 675 | EXPECT_TRUE(o2); 676 | EXPECT_TRUE(o2.has_value()); 677 | EXPECT_EQ(this->value_1, *o2); 678 | EXPECT_EQ(this->value_1, o2.value()); 679 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 680 | } 681 | 682 | TYPED_TEST(optTyped, otherTypeCopyAssignmentEmptyForNotEmpty) 683 | { 684 | using opt_type = typename TestFixture::type; 685 | using other_opt_type = opt; 686 | other_opt_type o1; 687 | opt_type o2{this->value_1}; 688 | o2 = o1; 689 | EXPECT_FALSE(o1); 690 | EXPECT_FALSE(o1.has_value()); 691 | EXPECT_THROW(o1.value(), bad_optional_access); 692 | EXPECT_EQ(this->value_2, o1.value_or(this->other_value_2)); 693 | EXPECT_FALSE(o2); 694 | EXPECT_FALSE(o2.has_value()); 695 | EXPECT_THROW(o2.value(), bad_optional_access); 696 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 697 | } 698 | 699 | TYPED_TEST(optTyped, otherTypeCopyAssignmentNotEmptyForNotEmpty) 700 | { 701 | using opt_type = typename TestFixture::type; 702 | using other_opt_type = opt; 703 | other_opt_type o1{this->other_value_1}; 704 | opt_type o2{this->value_2}; 705 | o2 = o1; 706 | EXPECT_TRUE(o1); 707 | EXPECT_TRUE(o1.has_value()); 708 | EXPECT_EQ(this->value_1, *o1); 709 | EXPECT_EQ(this->value_1, o1.value()); 710 | EXPECT_EQ(this->value_1, o1.value_or(this->other_value_2)); 711 | EXPECT_TRUE(o2); 712 | EXPECT_TRUE(o2.has_value()); 713 | EXPECT_EQ(this->value_1, *o2); 714 | EXPECT_EQ(this->value_1, o2.value()); 715 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 716 | } 717 | 718 | TYPED_TEST(optTyped, otherTypeMoveAssignmentEmptyForEmpty) 719 | { 720 | using opt_type = typename TestFixture::type; 721 | using other_opt_type = opt; 722 | other_opt_type o1; 723 | opt_type o2; 724 | o2 = std::move(o1); 725 | EXPECT_FALSE(o2); 726 | EXPECT_FALSE(o2.has_value()); 727 | EXPECT_THROW(o2.value(), bad_optional_access); 728 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 729 | } 730 | 731 | TYPED_TEST(optTyped, otherTypeMoveAssignmentNotEmptyForEmpty) 732 | { 733 | using opt_type = typename TestFixture::type; 734 | using other_opt_type = opt; 735 | other_opt_type o1{this->other_value_1}; 736 | opt_type o2; 737 | o2 = std::move(o1); 738 | EXPECT_TRUE(o2); 739 | EXPECT_TRUE(o2.has_value()); 740 | EXPECT_EQ(this->value_1, *o2); 741 | EXPECT_EQ(this->value_1, o2.value()); 742 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 743 | } 744 | 745 | TYPED_TEST(optTyped, otherTypeMoveAssignmentEmptyForNotEmpty) 746 | { 747 | using opt_type = typename TestFixture::type; 748 | using other_opt_type = opt; 749 | other_opt_type o1; 750 | opt_type o2{this->value_1}; 751 | o2 = std::move(o1); 752 | EXPECT_FALSE(o2); 753 | EXPECT_FALSE(o2.has_value()); 754 | EXPECT_THROW(o2.value(), bad_optional_access); 755 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 756 | } 757 | 758 | TYPED_TEST(optTyped, otherTypeMoveAssignmentNotEmptyForNotEmpty) 759 | { 760 | using opt_type = typename TestFixture::type; 761 | using other_opt_type = opt; 762 | other_opt_type o1{this->other_value_1}; 763 | opt_type o2{this->value_2}; 764 | o2 = std::move(o1); 765 | EXPECT_TRUE(o2); 766 | EXPECT_TRUE(o2.has_value()); 767 | EXPECT_EQ(this->value_1, *o2); 768 | EXPECT_EQ(this->value_1, o2.value()); 769 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 770 | } 771 | 772 | TYPED_TEST(optTyped, valueAssignmentForEmpty) 773 | { 774 | using opt_type = typename TestFixture::type; 775 | opt_type o; 776 | o = this->value_1; 777 | EXPECT_TRUE(o); 778 | EXPECT_TRUE(o.has_value()); 779 | EXPECT_EQ(this->value_1, *o); 780 | EXPECT_EQ(this->value_1, o.value()); 781 | EXPECT_EQ(this->value_1, o.value_or(this->value_2)); 782 | } 783 | 784 | TYPED_TEST(optTyped, valueAssignmentForNotEmpty) 785 | { 786 | using opt_type = typename TestFixture::type; 787 | opt_type o{this->value_2}; 788 | o = this->value_1; 789 | EXPECT_TRUE(o); 790 | EXPECT_TRUE(o.has_value()); 791 | EXPECT_EQ(this->value_1, *o); 792 | EXPECT_EQ(this->value_1, o.value()); 793 | EXPECT_EQ(this->value_1, o.value_or(this->value_2)); 794 | } 795 | 796 | TYPED_TEST(optTyped, swapEmptyWithEmpty) 797 | { 798 | using opt_type = typename TestFixture::type; 799 | opt_type o1; 800 | opt_type o2; 801 | std::swap(o1, o2); 802 | EXPECT_FALSE(o1); 803 | EXPECT_FALSE(o1.has_value()); 804 | EXPECT_THROW(o1.value(), bad_optional_access); 805 | EXPECT_EQ(this->value_2, o1.value_or(this->value_2)); 806 | EXPECT_FALSE(o2); 807 | EXPECT_FALSE(o2.has_value()); 808 | EXPECT_THROW(o2.value(), bad_optional_access); 809 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 810 | } 811 | 812 | TYPED_TEST(optTyped, swapNotEmptyWithEmpty) 813 | { 814 | using opt_type = typename TestFixture::type; 815 | opt_type o1{this->value_1}; 816 | opt_type o2; 817 | std::swap(o1, o2); 818 | EXPECT_FALSE(o1); 819 | EXPECT_FALSE(o1.has_value()); 820 | EXPECT_THROW(o1.value(), bad_optional_access); 821 | EXPECT_EQ(this->value_2, o1.value_or(this->value_2)); 822 | EXPECT_TRUE(o2); 823 | EXPECT_TRUE(o2.has_value()); 824 | EXPECT_EQ(this->value_1, *o2); 825 | EXPECT_EQ(this->value_1, o2.value()); 826 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 827 | } 828 | 829 | TYPED_TEST(optTyped, swapEmptyWithNotEmpty) 830 | { 831 | using opt_type = typename TestFixture::type; 832 | opt_type o1; 833 | opt_type o2{this->value_1}; 834 | std::swap(o1, o2); 835 | EXPECT_TRUE(o1); 836 | EXPECT_TRUE(o1.has_value()); 837 | EXPECT_EQ(this->value_1, *o1); 838 | EXPECT_EQ(this->value_1, o1.value()); 839 | EXPECT_EQ(this->value_1, o1.value_or(this->value_2)); 840 | EXPECT_FALSE(o2); 841 | EXPECT_FALSE(o2.has_value()); 842 | EXPECT_THROW(o2.value(), bad_optional_access); 843 | EXPECT_EQ(this->value_2, o2.value_or(this->value_2)); 844 | } 845 | 846 | TYPED_TEST(optTyped, swapNotEmptyWithNotEmpty) 847 | { 848 | using opt_type = typename TestFixture::type; 849 | opt_type o1{this->value_1}; 850 | opt_type o2{this->value_2}; 851 | std::swap(o1, o2); 852 | EXPECT_TRUE(o1); 853 | EXPECT_TRUE(o1.has_value()); 854 | EXPECT_EQ(this->value_2, *o1); 855 | EXPECT_EQ(this->value_2, o1.value()); 856 | EXPECT_EQ(this->value_2, o1.value_or(this->value_1)); 857 | EXPECT_TRUE(o2); 858 | EXPECT_TRUE(o2.has_value()); 859 | EXPECT_EQ(this->value_1, *o2); 860 | EXPECT_EQ(this->value_1, o2.value()); 861 | EXPECT_EQ(this->value_1, o2.value_or(this->value_2)); 862 | } 863 | 864 | TEST(opt, constructorInitializerList) 865 | { 866 | using wd = weekday; 867 | weekday_mask mask{wd{0}, wd{2}, wd{6}}; 868 | opt o1{in_place, {wd{0}, wd{2}, wd{6}}}; 869 | EXPECT_TRUE(o1); 870 | EXPECT_TRUE(o1.has_value()); 871 | EXPECT_EQ(0b0100'0101, (*o1).mask()); 872 | EXPECT_EQ(0b0100'0101, o1.value().mask()); 873 | EXPECT_EQ(0b0100'0101, o1.value_or(weekday_mask{wd{0}, wd{1}, wd{3}}).mask()); 874 | } 875 | 876 | TEST(opt, constructOutOfRange) 877 | { 878 | weekday::underlying_type d1{7}; 879 | EXPECT_THROW(opt{d1}, std::out_of_range); 880 | weekday::underlying_type d2{-1}; 881 | EXPECT_THROW(opt{d2}, std::out_of_range); 882 | } 883 | 884 | TEST(opt, assignOutOfRange) 885 | { 886 | weekday::underlying_type d1{7}; 887 | weekday::underlying_type d2{-1}; 888 | opt o; 889 | EXPECT_THROW(o = d1, std::out_of_range); 890 | EXPECT_THROW(o = d2, std::out_of_range); 891 | } 892 | 893 | TEST(opt, dereferenceOperator) 894 | { 895 | weekday::underlying_type d{1}; 896 | opt w{d}; 897 | EXPECT_TRUE(w); 898 | EXPECT_TRUE(w.has_value()); 899 | EXPECT_EQ(d, *w); 900 | EXPECT_EQ(d, w.value()); 901 | EXPECT_EQ(d, w->get()); 902 | EXPECT_EQ(d, w.value_or(weekday::underlying_type{3})); 903 | } 904 | 905 | TEST(opt, dereferenceOperatorRvalue) 906 | { 907 | weekday::underlying_type d{1}; 908 | auto make = [&] { return opt{d}; }; 909 | EXPECT_TRUE(make()); 910 | EXPECT_TRUE(make().has_value()); 911 | EXPECT_EQ(d, *make()); 912 | EXPECT_EQ(d, make().value()); 913 | EXPECT_EQ(d, make()->get()); 914 | EXPECT_EQ(d, make().value_or(weekday::underlying_type{3})); 915 | } 916 | 917 | TEST(opt, dereferenceOperatorConstRvalue) 918 | { 919 | weekday::underlying_type d{1}; 920 | auto make = [&]() -> const opt { return opt{d}; }; 921 | EXPECT_TRUE(make()); 922 | EXPECT_TRUE(make().has_value()); 923 | EXPECT_EQ(d, *make()); 924 | EXPECT_EQ(d, make().value()); 925 | EXPECT_EQ(d, make()->get()); 926 | EXPECT_EQ(d, make().value_or(weekday::underlying_type{3})); 927 | } 928 | 929 | TEST(optCompare, bothNotEmptyEqual) 930 | { 931 | using opt_int = opt>; 932 | opt_int i1{1}, i2{1}; 933 | EXPECT_TRUE(i1 == i2); 934 | EXPECT_FALSE(i1 != i2); 935 | EXPECT_FALSE(i1 < i2); 936 | EXPECT_FALSE(i1 > i2); 937 | EXPECT_TRUE(i1 <= i2); 938 | EXPECT_TRUE(i1 >= i2); 939 | } 940 | 941 | TEST(optCompare, bothNotEmptyLess) 942 | { 943 | using opt_int = opt>; 944 | opt_int i1{1}, i2{2}; 945 | EXPECT_FALSE(i1 == i2); 946 | EXPECT_TRUE(i1 != i2); 947 | EXPECT_TRUE(i1 < i2); 948 | EXPECT_FALSE(i1 > i2); 949 | EXPECT_TRUE(i1 <= i2); 950 | EXPECT_FALSE(i1 >= i2); 951 | } 952 | 953 | TEST(optCompare, bothNotEmptyGreater) 954 | { 955 | using opt_int = opt>; 956 | opt_int i1{2}, i2{1}; 957 | EXPECT_FALSE(i1 == i2); 958 | EXPECT_TRUE(i1 != i2); 959 | EXPECT_FALSE(i1 < i2); 960 | EXPECT_TRUE(i1 > i2); 961 | EXPECT_FALSE(i1 <= i2); 962 | EXPECT_TRUE(i1 >= i2); 963 | } 964 | 965 | TEST(optCompare, bothEmpty) 966 | { 967 | using opt_int = opt>; 968 | opt_int i1, i2; 969 | EXPECT_TRUE(i1 == i2); 970 | EXPECT_FALSE(i1 != i2); 971 | EXPECT_FALSE(i1 < i2); 972 | EXPECT_FALSE(i1 > i2); 973 | EXPECT_TRUE(i1 <= i2); 974 | EXPECT_TRUE(i1 >= i2); 975 | } 976 | 977 | TEST(optCompare, emptyNotEmpty) 978 | { 979 | using opt_int = opt>; 980 | opt_int i1, i2{1}; 981 | EXPECT_FALSE(i1 == i2); 982 | EXPECT_TRUE(i1 != i2); 983 | EXPECT_TRUE(i1 < i2); 984 | EXPECT_FALSE(i1 > i2); 985 | EXPECT_TRUE(i1 <= i2); 986 | EXPECT_FALSE(i1 >= i2); 987 | } 988 | 989 | TEST(optCompare, notEmptyEmpty) 990 | { 991 | using opt_int = opt>; 992 | opt_int i1{1}, i2; 993 | EXPECT_FALSE(i1 == i2); 994 | EXPECT_TRUE(i1 != i2); 995 | EXPECT_FALSE(i1 < i2); 996 | EXPECT_TRUE(i1 > i2); 997 | EXPECT_FALSE(i1 <= i2); 998 | EXPECT_TRUE(i1 >= i2); 999 | } 1000 | 1001 | TEST(optCompare, optNotEmptyValueEqual) 1002 | { 1003 | using opt_int = opt>; 1004 | opt_int i{1}; 1005 | EXPECT_TRUE(i == 1); 1006 | EXPECT_FALSE(i != 1); 1007 | EXPECT_FALSE(i < 1); 1008 | EXPECT_FALSE(i > 1); 1009 | EXPECT_TRUE(i <= 1); 1010 | EXPECT_TRUE(i >= 1); 1011 | } 1012 | 1013 | TEST(optCompare, optNotEmptyValueLess) 1014 | { 1015 | using opt_int = opt>; 1016 | opt_int i{1}; 1017 | EXPECT_FALSE(i == 2); 1018 | EXPECT_TRUE(i != 2); 1019 | EXPECT_TRUE(i < 2); 1020 | EXPECT_FALSE(i > 2); 1021 | EXPECT_TRUE(i <= 2); 1022 | EXPECT_FALSE(i >= 2); 1023 | } 1024 | 1025 | TEST(optCompare, optNotEmptyValueGreater) 1026 | { 1027 | using opt_int = opt>; 1028 | opt_int i{2}; 1029 | EXPECT_FALSE(i == 1); 1030 | EXPECT_TRUE(i != 1); 1031 | EXPECT_FALSE(i < 1); 1032 | EXPECT_TRUE(i > 1); 1033 | EXPECT_FALSE(i <= 1); 1034 | EXPECT_TRUE(i >= 1); 1035 | } 1036 | 1037 | TEST(optCompare, optEmptyValue) 1038 | { 1039 | using opt_int = opt>; 1040 | opt_int i; 1041 | EXPECT_FALSE(i == 1); 1042 | EXPECT_TRUE(i != 1); 1043 | EXPECT_TRUE(i < 1); 1044 | EXPECT_FALSE(i > 1); 1045 | EXPECT_TRUE(i <= 1); 1046 | EXPECT_FALSE(i >= 1); 1047 | } 1048 | 1049 | TEST(optCompare, valueOptNotEmptyEqual) 1050 | { 1051 | using opt_int = opt>; 1052 | opt_int i{1}; 1053 | EXPECT_TRUE(1 == i); 1054 | EXPECT_FALSE(1 != i); 1055 | EXPECT_FALSE(1 < i); 1056 | EXPECT_FALSE(1 > i); 1057 | EXPECT_TRUE(1 <= i); 1058 | EXPECT_TRUE(1 >= i); 1059 | } 1060 | 1061 | TEST(optCompare, valueOptNotEmptyLess) 1062 | { 1063 | using opt_int = opt>; 1064 | opt_int i{2}; 1065 | EXPECT_FALSE(1 == i); 1066 | EXPECT_TRUE(1 != i); 1067 | EXPECT_TRUE(1 < i); 1068 | EXPECT_FALSE(1 > i); 1069 | EXPECT_TRUE(1 <= i); 1070 | EXPECT_FALSE(1 >= i); 1071 | } 1072 | 1073 | TEST(optCompare, valueOptNotEmptyGreater) 1074 | { 1075 | using opt_int = opt>; 1076 | opt_int i{1}; 1077 | EXPECT_FALSE(2 == i); 1078 | EXPECT_TRUE(2 != i); 1079 | EXPECT_FALSE(2 < i); 1080 | EXPECT_TRUE(2 > i); 1081 | EXPECT_FALSE(2 <= i); 1082 | EXPECT_TRUE(2 >= i); 1083 | } 1084 | 1085 | TEST(optCompare, valueOptEmpty) 1086 | { 1087 | using opt_int = opt>; 1088 | opt_int i; 1089 | EXPECT_FALSE(1 == i); 1090 | EXPECT_TRUE(1 != i); 1091 | EXPECT_FALSE(1 < i); 1092 | EXPECT_TRUE(1 > i); 1093 | EXPECT_FALSE(1 <= i); 1094 | EXPECT_TRUE(1 >= i); 1095 | } 1096 | 1097 | TEST(optCompare, optEmptyNullopt) 1098 | { 1099 | using opt_int = opt>; 1100 | opt_int i; 1101 | EXPECT_TRUE(i == nullopt); 1102 | EXPECT_FALSE(i != nullopt); 1103 | EXPECT_FALSE(i < nullopt); 1104 | EXPECT_FALSE(i > nullopt); 1105 | EXPECT_TRUE(i <= nullopt); 1106 | EXPECT_TRUE(i >= nullopt); 1107 | } 1108 | 1109 | TEST(optCompare, optNotEmptyNullopt) 1110 | { 1111 | using opt_int = opt>; 1112 | opt_int i{1}; 1113 | EXPECT_FALSE(i == nullopt); 1114 | EXPECT_TRUE(i != nullopt); 1115 | EXPECT_FALSE(i < nullopt); 1116 | EXPECT_TRUE(i > nullopt); 1117 | EXPECT_FALSE(i <= nullopt); 1118 | EXPECT_TRUE(i >= nullopt); 1119 | } 1120 | 1121 | TEST(optCompare, nulloptOptEmpty) 1122 | { 1123 | using opt_int = opt>; 1124 | opt_int i; 1125 | EXPECT_TRUE(nullopt == i); 1126 | EXPECT_FALSE(nullopt != i); 1127 | EXPECT_FALSE(nullopt < i); 1128 | EXPECT_FALSE(nullopt > i); 1129 | EXPECT_TRUE(nullopt <= i); 1130 | EXPECT_TRUE(nullopt >= i); 1131 | } 1132 | 1133 | TEST(optCompare, nulloptOptNotEmpty) 1134 | { 1135 | using opt_int = opt>; 1136 | opt_int i{1}; 1137 | EXPECT_FALSE(nullopt == i); 1138 | EXPECT_TRUE(nullopt != i); 1139 | EXPECT_TRUE(nullopt < i); 1140 | EXPECT_FALSE(nullopt > i); 1141 | EXPECT_TRUE(nullopt <= i); 1142 | EXPECT_FALSE(nullopt >= i); 1143 | } 1144 | --------------------------------------------------------------------------------