├── .appveyor.yml ├── .clang-format ├── .gitignore ├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── cmake └── mpark_variant-config.cmake.in ├── include └── mpark │ ├── config.hpp │ ├── in_place.hpp │ ├── lib.hpp │ └── variant.hpp ├── support ├── ninja.py ├── single-header.py ├── vs.py ├── wandbox.cpp └── wandbox.py └── test ├── CMakeLists.txt ├── README.md ├── assign.copy.cpp ├── assign.fwd.cpp ├── assign.move.cpp ├── ctor.copy.cpp ├── ctor.default.cpp ├── ctor.fwd.cpp ├── ctor.in_place.cpp ├── ctor.move.cpp ├── dtor.cpp ├── get.cpp ├── hash.cpp ├── intro.cpp ├── issue.cpp ├── json.cpp ├── libcxx.sh ├── mod.cpp ├── relops.cpp ├── swap.cpp ├── util.hpp └── visit.cpp /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | # 3 | # Copyright Michael Park, 2015-2017 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | build: 9 | verbosity: detailed 10 | 11 | branches: 12 | only: 13 | - master 14 | - dev 15 | 16 | clone_depth: 1 17 | 18 | platform: x64 19 | 20 | environment: 21 | matrix: 22 | # Visual Studio 2015 23 | - GENERATOR: Visual Studio 14 2015 Win64 24 | TESTS: mpark 25 | SCRIPT: support/vs.py 26 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 27 | 28 | # Previous Visual Studio 2017 29 | - GENERATOR: Visual Studio 15 2017 Win64 30 | STDFLAGS: /std:c++14 /std:c++17 /std:c++latest 31 | TESTS: mpark 32 | SCRIPT: support/vs.py 33 | APPVEYOR_BUILD_WORKER_IMAGE: Previous Visual Studio 2017 34 | 35 | # Visual Studio 2017 36 | - GENERATOR: Visual Studio 15 2017 Win64 37 | STDFLAGS: /std:c++14 /std:c++17 /std:c++latest 38 | TESTS: mpark 39 | SCRIPT: support/vs.py 40 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 41 | 42 | # Clang/LLVM 43 | - CC: clang-cl 44 | CXX: clang-cl 45 | STDFLAGS: /std:c++14 /std:c++17 /std:c++latest 46 | TESTS: mpark 47 | SCRIPT: support/ninja.py 48 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 49 | 50 | install: 51 | - git submodule -q update --init 52 | # Directory for dependency installation. 53 | - set DEPS=%APPVEYOR_BUILD_FOLDER%\deps 54 | - mkdir %DEPS% 55 | # Install Ninja 56 | - set NINJA_URL="https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-win.zip" 57 | - curl -fsSL %NINJA_URL% -o ninja.zip 58 | - 7z x ninja.zip -o%DEPS%\ninja > nul 59 | - set PATH=%DEPS%\ninja;%PATH% 60 | - ninja --version 61 | 62 | before_build: 63 | # Enable the Visual C++ toolset for command-line builds. 64 | - IF "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( 65 | call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" 66 | ) 67 | - IF "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" ( 68 | call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 69 | ) 70 | 71 | build_script: 72 | - python %SCRIPT% 73 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | 4 | # Good: 5 | # 6 | # class TFoo { 7 | # public: 8 | # 9 | # TFoo() = default; 10 | # 11 | # } // TFoo 12 | # 13 | # Bad: 14 | # 15 | # class TFoo { 16 | # public: 17 | # 18 | # TFoo() = default; 19 | # 20 | # } // TFoo 21 | # 22 | AccessModifierOffset: 0 23 | 24 | ### AlignEscapedNewlinesLeft: true 25 | 26 | # Good: 27 | # 28 | # int x = 100; // comment1 29 | # std::string y = "one hundred"; // comment2 30 | # 31 | # Bad: 32 | # 33 | # int x = 100; // comment1 34 | # std::string y = "one hundred"; // comment2 35 | # 36 | AlignTrailingComments: false 37 | 38 | ### AllowAllParametersOfDeclarationOnNextLine: true 39 | 40 | AllowShortIfStatementsOnASingleLine: true 41 | 42 | # Good: 43 | # 44 | # while (flag) 45 | # x = 42; 46 | # 47 | # Bad: 48 | # 49 | # while (flag) x = 42; 50 | # 51 | AllowShortLoopsOnASingleLine: false 52 | 53 | # Good: 54 | # 55 | # const char *text = 56 | # "hello" 57 | # "world"; 58 | # 59 | # Bad: 60 | # 61 | # const char *text = "hello" 62 | # "world"; 63 | # 64 | AlwaysBreakBeforeMultilineStrings: true 65 | 66 | # Good: 67 | # 68 | # template 69 | # void F() {} 70 | # 71 | # Bad: 72 | # 73 | # template void F() {} 74 | # 75 | AlwaysBreakTemplateDeclarations: true 76 | 77 | # Good: 78 | # 79 | # F(first, 80 | # second, 81 | # third, 82 | # fourth, 83 | # fifth, 84 | # sixth, 85 | # seventh, 86 | # eighth); 87 | # 88 | # Bad: 89 | # 90 | # F(first, second, third, fourth, fifth, sixth, 91 | # seventh, eighth); 92 | # 93 | BinPackArguments: false 94 | 95 | # Good: 96 | # 97 | # void F(int first, 98 | # int second, 99 | # int third, 100 | # int fourth, 101 | # int fifth, 102 | # int sixth, 103 | # int seventh, 104 | # int eighth) {} 105 | # 106 | # Bad: 107 | # 108 | # void F(int first, int second, int third, int fourth, int fifth, int sixth, 109 | # int seventh, int eighth) {} 110 | # 111 | BinPackParameters: false 112 | 113 | # Good: 114 | # 115 | # int x = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + 116 | # bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; 117 | # 118 | # Bad: 119 | # 120 | # int x = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 121 | # + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; 122 | # 123 | BreakBeforeBinaryOperators: false 124 | 125 | # Good: 126 | # 127 | # void F() {} 128 | # 129 | # Bad: 130 | # 131 | # void F() 132 | # { 133 | # } 134 | # 135 | BreakBeforeBraces: Attach 136 | 137 | # Good: 138 | # 139 | # class TFoo { 140 | # public: 141 | # 142 | # TFoo() 143 | # : Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(1), 144 | # Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(2) {} 145 | # 146 | # }; // TFoo 147 | # 148 | # Bad: 149 | # 150 | # class TFoo { 151 | # public: 152 | # 153 | # TFoo() 154 | # : Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(1) 155 | # , Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(2) {} 156 | # 157 | # }; // TFoo 158 | # 159 | BreakConstructorInitializersBeforeComma: false 160 | 161 | ColumnLimit: 80 162 | 163 | # Good: 164 | # 165 | # class TFoo { 166 | # public: 167 | # 168 | # TFoo() 169 | # : First(1), 170 | # Second(2), 171 | # Third(3), 172 | # Fourth(4), 173 | # Fifth(5), 174 | # Sixth(6), 175 | # Seventh(7), 176 | # Eighth(8) {} 177 | # 178 | # }; // TFoo 179 | # 180 | # Bad: 181 | # 182 | # class TFoo { 183 | # public: 184 | # 185 | # TFoo() 186 | # : First(1), Second(2), Third(3), Fourth(4), Fifth(5), Sixth(6), 187 | # Seventh(7), Eighth(8) {} 188 | # 189 | # }; // TFoo 190 | # 191 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 192 | 193 | ConstructorInitializerIndentWidth: 4 194 | 195 | Cpp11BracedListStyle: true 196 | 197 | DerivePointerBinding: false 198 | 199 | # Good: 200 | # 201 | # int x; 202 | # switch (x) { 203 | # case 0: { 204 | # x = 0; 205 | # break; 206 | # } // case 207 | # case 1: { 208 | # x = 1; 209 | # break; 210 | # } // case 211 | # } // switch 212 | # 213 | # Bad: 214 | # 215 | # int x; 216 | # switch (x) { 217 | # case 0: { 218 | # x = 0; 219 | # break; 220 | # } // case 221 | # case 1: { 222 | # x = 1; 223 | # break; 224 | # } // case 225 | # } // switch 226 | # 227 | IndentCaseLabels: true 228 | 229 | # Good: 230 | # 231 | # std::tuple 232 | # Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(); 233 | # 234 | # Bad: 235 | # 236 | # std::tuple 237 | # Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(); 238 | # 239 | IndentFunctionDeclarationAfterType: false 240 | 241 | IndentWidth: 2 242 | 243 | MaxEmptyLinesToKeep: 1 244 | 245 | # Good: 246 | # 247 | # namespace Foo { 248 | # 249 | # class TFoo {}; 250 | # 251 | # } // Foo 252 | # 253 | # Bad: 254 | # 255 | # namespace Foo { 256 | # 257 | # class TFoo {}; 258 | # 259 | # } // Foo 260 | # 261 | NamespaceIndentation: All 262 | 263 | ### ObjCSpaceBeforeProtocolList: false 264 | 265 | ### PenaltyBreakComment: 60 266 | 267 | ### PenaltyBreakFirstLessLess: 120 268 | 269 | ### PenaltyBreakString: 1000 270 | 271 | ### PenaltyExcessCharacter: 1000000 272 | 273 | ### PenaltyReturnTypeOnItsOwnLine: 200 274 | 275 | # Good: 276 | # 277 | # int *ptr = nullptr; 278 | # 279 | # Bad: 280 | # 281 | # int* ptr = nullptr; 282 | # 283 | PointerBindsToType: false 284 | 285 | # Good: 286 | # 287 | # if (flag) { 288 | # flag = true; 289 | # } // if 290 | # 291 | # Bad: 292 | # 293 | # if(flag) { 294 | # flag = true; 295 | # } // if 296 | # 297 | SpaceAfterControlStatementKeyword: true 298 | 299 | # Good: 300 | # 301 | # x = 42; 302 | # 303 | # Bad: 304 | # 305 | # x= 42; 306 | # 307 | SpaceBeforeAssignmentOperators: true 308 | 309 | # Good: 310 | # 311 | # F(); 312 | # 313 | # Bad: 314 | # 315 | # F( ); 316 | # 317 | SpaceInEmptyParentheses: false 318 | 319 | # Good: 320 | # 321 | # x = 42; // Comment 322 | # 323 | # Bad: 324 | # 325 | # x = 42; // Comment 326 | # 327 | SpacesBeforeTrailingComments: 2 328 | 329 | # Good: 330 | # 331 | # bool y = (bool)x; 332 | # 333 | # Bad: 334 | # 335 | # bool y = ( bool )x; 336 | # 337 | SpacesInCStyleCastParentheses: false 338 | 339 | # Good: 340 | # 341 | # if (flag) { 342 | # flag = true; 343 | # } // if 344 | # 345 | # Bad: 346 | # 347 | # if ( flag ) { 348 | # flag = true; 349 | # } // if 350 | # 351 | SpacesInParentheses: false 352 | 353 | Standard: Cpp11 354 | 355 | TabWidth: 2 356 | 357 | UseTab: false 358 | ... 359 | 360 | -------------------------------------------------------------------------------- /.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 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # build 31 | /build 32 | 33 | 3rdparty/benchmark 34 | 3rdparty/metabench 35 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/googletest"] 2 | path = 3rdparty/googletest 3 | url = https://github.com/abseil/googletest.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | # 3 | # Copyright Michael Park, 2015-2017 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | language: cpp 9 | dist: xenial 10 | sudo: false 11 | 12 | branches: 13 | only: 14 | - master 15 | - dev 16 | 17 | git: 18 | depth: 1 19 | 20 | env: 21 | global: 22 | - secure: jL8hAVoa2B512uGeoh5DL2YXrAznfKPz3GbcaUPzR6mR2Izj2yHFihLLeHrEY8vUdadS8zbn2CwtWnmJjNz5kIT/RxESxJJtgVNruwo0u4piIfxVI/tTRObMXKaGrfquDAHS/hjAhQlPSNNr+89oFSBvSfNpAVECd/ERhhnjIugD+MFFzaxi26qvM6li9toxPNJIxBq9jHRuZzlpWez6d6RcTsaqr30BaCEuJhVcg7J4SiSL8xeW2sokAG65pZ/aig23cCSJkhazbMd7Cy/OFNjQrhc2PQ+E0c2xEwdwCNA8qTnsMrUeo9NXc+lozOf23LWD1EvZtcNNG5arPhSuGGYs90T1GdL2jqyS1E+1Xf0cOWqB4VMho7H+vV55SgZb+TYDrmB63YvgxcUKgsDRvPI9bBv3S3uxgktbE6gwnrfQirKowbscC07X3R1RJiI6hSkVNdrLnQF28BHMRlCpyhDejIWm4qHgOrWCN+I6hZtk+nsRuJF8sCSFPUWuzlG+/kSwaBwm/eEy+ZI66ufJamHUqC8bxa+6kINxtJTMN79ZnbIPwOvey9cfVfzwxefaStwpQbCJuZlMbuo4738HxUQpscxgv6LA5ZEMz8hlKO82cWDZSEDxSrUowueu1Az0u5tfzBUXaU5pZCnGdK6aMGHcTznaeUFebq8uhLR3uc0= 23 | 24 | jobs: 25 | include: 26 | # ubuntu 16.04, gcc-4.8 27 | - env: VER=4.8 STDFLAGS="-std=c++11 -std=c++1y" TESTS="mpark" 28 | compiler: gcc 29 | os: linux 30 | addons: { apt: { packages: ["g++-4.8", "ninja-build"], 31 | sources: ["ubuntu-toolchain-r-test"] } } 32 | 33 | # ubuntu 16.04, gcc-4.9 34 | - env: VER=4.9 STDFLAGS="-std=c++11 -std=c++14" TESTS="mpark" 35 | compiler: gcc 36 | os: linux 37 | addons: { apt: { packages: ["g++-4.9", "ninja-build"], 38 | sources: ["ubuntu-toolchain-r-test"] } } 39 | 40 | # ubuntu 16.04, gcc-5 41 | - env: VER=5 STDFLAGS="-std=c++11 -std=c++14 -std=c++1z" TESTS="mpark" 42 | compiler: gcc 43 | os: linux 44 | addons: { apt: { packages: ["g++-5", "ninja-build"], 45 | sources: ["ubuntu-toolchain-r-test"] } } 46 | 47 | # ubuntu 16.04, gcc-6 48 | - env: VER=6 STDFLAGS="-std=c++11 -std=c++14 -std=c++1z" TESTS="mpark" 49 | compiler: gcc 50 | os: linux 51 | addons: { apt: { packages: ["g++-6", "ninja-build"], 52 | sources: ["ubuntu-toolchain-r-test"] } } 53 | 54 | # ubuntu 16.04, gcc-7 55 | - env: VER=7 STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark libc++" 56 | compiler: gcc 57 | os: linux 58 | addons: { apt: { packages: ["g++-7", "ninja-build"], 59 | sources: ["ubuntu-toolchain-r-test"] } } 60 | 61 | # ubuntu 16.04, gcc-8 62 | - env: VER=8 STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark libc++" 63 | compiler: gcc 64 | os: linux 65 | addons: { apt: { packages: ["g++-8", "ninja-build"], 66 | sources: ["ubuntu-toolchain-r-test"] } } 67 | 68 | # ubuntu 16.04, gcc-9 69 | - env: VER=9 STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark libc++" 70 | compiler: gcc 71 | os: linux 72 | addons: { apt: { packages: ["g++-9", "ninja-build"], 73 | sources: ["ubuntu-toolchain-r-test"] } } 74 | 75 | # ubuntu 16.04, clang-3.6 76 | - env: VER=3.6 STDFLAGS="-std=c++11 -std=c++14" TESTS="mpark" 77 | compiler: clang 78 | os: linux 79 | addons: { apt: { packages: ["clang-3.6", "ninja-build"] } } 80 | 81 | # ubuntu 16.04, clang-3.7 82 | - env: VER=3.7 STDFLAGS="-std=c++11 -std=c++14" TESTS="mpark" 83 | compiler: clang 84 | os: linux 85 | addons: { apt: { packages: ["clang-3.7", "ninja-build"] } } 86 | 87 | # ubuntu 16.04, clang-3.8 88 | - env: VER=3.8 STDFLAGS="-std=c++11 -std=c++14" TESTS="mpark" 89 | compiler: clang 90 | os: linux 91 | addons: { apt: { packages: ["clang-3.8", "ninja-build"] } } 92 | 93 | # ubuntu 16.04, clang-3.9 94 | - env: VER=3.9 STDFLAGS="-std=c++11 -std=c++14 -std=c++1z" TESTS="mpark" 95 | compiler: clang 96 | os: linux 97 | addons: { apt: { packages: ["clang-3.9", "ninja-build"] } } 98 | 99 | # ubuntu 16.04, clang-4.0 100 | - env: VER=4.0 STDFLAGS="-std=c++11 -std=c++14 -std=c++1z" TESTS="mpark" 101 | compiler: clang 102 | os: linux 103 | addons: { apt: { packages: ["clang-4.0", "ninja-build"] } } 104 | 105 | # ubuntu 16.04, clang-5.0 106 | - env: VER=5.0 STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark libc++" 107 | compiler: clang 108 | os: linux 109 | addons: { apt: { packages: ["clang-5.0", "ninja-build"] } } 110 | 111 | # ubuntu 16.04, clang-6.0 112 | - env: VER=6.0 STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark libc++" 113 | compiler: clang 114 | os: linux 115 | addons: { apt: { packages: ["clang-6.0", "ninja-build"] } } 116 | 117 | # ubuntu 16.04, clang-7 118 | - env: VER=7 STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark libc++" 119 | compiler: clang 120 | os: linux 121 | addons: { apt: { packages: ["clang-7", "ninja-build"], 122 | sources: ["llvm-toolchain-xenial-7"] } } 123 | 124 | # ubuntu 16.04, clang-8 125 | - env: VER=8 STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark libc++" 126 | compiler: clang 127 | os: linux 128 | addons: { apt: { packages: ["clang-8", "ninja-build"], 129 | sources: ["llvm-toolchain-xenial-8"] } } 130 | 131 | # OS X Sierra 10.12 132 | - env: STDFLAGS="-std=c++11 -std=c++14 -std=c++1z" TESTS="mpark" 133 | compiler: clang 134 | os: osx 135 | osx_image: xcode8.3 136 | 137 | # OS X High Sierra 10.13 138 | - env: STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark" 139 | compiler: clang 140 | os: osx 141 | osx_image: xcode9.4 142 | 143 | # OS X High Sierra 10.13 144 | - env: STDFLAGS="-std=c++11 -std=c++14 -std=c++17" TESTS="mpark" 145 | compiler: clang 146 | os: osx 147 | osx_image: xcode10.1 148 | 149 | - stage: deploy 150 | name: "Single Header" 151 | if: branch = master AND type = push 152 | install: skip 153 | before_script: 154 | - git config --global user.name "Travis CI" 155 | - git config --global user.email "<>" 156 | - travis_retry git clone https://$GITHUB_TOKEN@github.com/mpark/variant 157 | --depth 1 --branch=single-header single-header &>/dev/null 158 | script: 159 | - SHA=$(git rev-parse --short HEAD) 160 | - python support/single-header.py > single-header/master/variant.hpp 161 | - pushd single-header 162 | - | 163 | if git diff-index --quiet HEAD --; then 164 | echo "Nothing to do. No changes were made to 'variant.hpp'." 165 | else 166 | git add --all 167 | git commit -m "Updated 'variant.hpp' @${SHA}." 168 | travis_retry git pull --rebase && git push origin single-header &>/dev/null 169 | fi 170 | - popd 171 | 172 | install: 173 | # Upgrade CMake and install Ninja on OS X. 174 | - | 175 | if [ "${TRAVIS_OS_NAME}" = "osx" ]; then 176 | brew update 177 | brew upgrade cmake 178 | brew install ninja 179 | fi 180 | - cmake --version 181 | - ninja --version 182 | # Set the correct `CC` and `CXX` environment variables. 183 | - | 184 | if [ -n "${VER}" ]; then 185 | export CC="${CC}-${VER}" 186 | export CXX="${CXX}-${VER}" 187 | fi 188 | - ${CXX} --version 189 | 190 | script: 191 | - python support/ninja.py 192 | 193 | notifications: 194 | email: false 195 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | # 3 | # Copyright Michael Park, 2015-2017 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | cmake_minimum_required(VERSION 3.6.3) 9 | 10 | project(MPark.Variant VERSION 1.4.1 LANGUAGES CXX) 11 | 12 | # Option. 13 | set(MPARK_VARIANT_INCLUDE_TESTS "" CACHE STRING 14 | "Semicolon-separated list of tests to build. \ 15 | Possible values are `mpark`, and `libc++`.") 16 | 17 | # Target. 18 | add_library(mpark_variant INTERFACE) 19 | target_include_directories(mpark_variant INTERFACE 20 | $ 21 | $) 22 | 23 | # Config. 24 | include(CMakePackageConfigHelpers) 25 | 26 | configure_package_config_file( 27 | cmake/mpark_variant-config.cmake.in 28 | "${CMAKE_CURRENT_BINARY_DIR}/cmake/mpark_variant-config.cmake" 29 | INSTALL_DESTINATION lib/cmake/mpark_variant 30 | NO_CHECK_REQUIRED_COMPONENTS_MACRO) 31 | 32 | write_basic_package_version_file( 33 | "${CMAKE_CURRENT_BINARY_DIR}/cmake/mpark_variant-config-version.cmake" 34 | COMPATIBILITY AnyNewerVersion) 35 | 36 | # Export. 37 | export( 38 | TARGETS mpark_variant 39 | FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/mpark_variant-targets.cmake") 40 | 41 | # Install. 42 | install(TARGETS mpark_variant EXPORT mpark_variant) 43 | 44 | install( 45 | EXPORT mpark_variant 46 | FILE mpark_variant-targets.cmake 47 | DESTINATION lib/cmake/mpark_variant) 48 | 49 | install(DIRECTORY include/mpark DESTINATION include) 50 | 51 | install( 52 | FILES 53 | "${CMAKE_CURRENT_BINARY_DIR}/cmake/mpark_variant-config.cmake" 54 | "${CMAKE_CURRENT_BINARY_DIR}/cmake/mpark_variant-config-version.cmake" 55 | DESTINATION lib/cmake/mpark_variant) 56 | 57 | # Test. 58 | list(REMOVE_DUPLICATES MPARK_VARIANT_INCLUDE_TESTS) 59 | 60 | list(FIND MPARK_VARIANT_INCLUDE_TESTS "mpark" MPARK_VARIANT_INDEX) 61 | if(NOT MPARK_VARIANT_INDEX EQUAL -1) 62 | set(MPARK_VARIANT_INCLUDE_MPARK_TESTS ON) 63 | list(REMOVE_AT MPARK_VARIANT_INCLUDE_TESTS MPARK_VARIANT_INDEX) 64 | endif() 65 | 66 | list(FIND MPARK_VARIANT_INCLUDE_TESTS "libc++" MPARK_VARIANT_INDEX) 67 | if(NOT MPARK_VARIANT_INDEX EQUAL -1) 68 | set(MPARK_VARIANT_INCLUDE_LIBCXX_TESTS ON) 69 | list(REMOVE_AT MPARK_VARIANT_INCLUDE_TESTS MPARK_VARIANT_INDEX) 70 | endif() 71 | 72 | list(LENGTH MPARK_VARIANT_INCLUDE_TESTS MPARK_VARIANT_LENGTH) 73 | if(MPARK_VARIANT_LENGTH GREATER 0) 74 | message(FATAL_ERROR 75 | "The following values in `MPARK_VARIANT_INCLUDE_TESTS` are not one of " 76 | "the possible values, `mpark`, and `libc++`: ${MPARK_VARIANT_INCLUDE_TESTS}") 77 | endif() 78 | 79 | if(MPARK_VARIANT_INCLUDE_MPARK_TESTS OR MPARK_VARIANT_INCLUDE_LIBCXX_TESTS) 80 | enable_testing() 81 | add_subdirectory(test) 82 | endif() 83 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | 3 | > __C++17__ `std::variant` for __C++11__/__14__/__17__ 4 | 5 | [![release][badge.release]][release] 6 | [![header][badge.header]][header] 7 | [![travis][badge.travis]][travis] 8 | [![appveyor][badge.appveyor]][appveyor] 9 | [![license][badge.license]][license] 10 | [![godbolt][badge.godbolt]][godbolt] 11 | [![wandbox][badge.wandbox]][wandbox] 12 | 13 | [badge.release]: https://img.shields.io/github/release/mpark/variant.svg 14 | [badge.header]: https://img.shields.io/badge/single%20header-master-blue.svg 15 | [badge.travis]: https://travis-ci.org/mpark/variant.svg?branch=master 16 | [badge.appveyor]: https://ci.appveyor.com/api/projects/status/github/mpark/variant?branch=master&svg=true 17 | [badge.license]: https://img.shields.io/badge/license-boost-blue.svg 18 | [badge.godbolt]: https://img.shields.io/badge/try%20it-on%20godbolt-222266.svg 19 | [badge.wandbox]: https://img.shields.io/badge/try%20it-on%20wandbox-5cb85c.svg 20 | 21 | [release]: https://github.com/mpark/variant/releases/latest 22 | [header]: https://github.com/mpark/variant/blob/single-header/master/variant.hpp 23 | [travis]: https://travis-ci.org/mpark/variant 24 | [appveyor]: https://ci.appveyor.com/project/mpark/variant 25 | [license]: https://github.com/mpark/variant/blob/master/LICENSE.md 26 | [godbolt]: https://godbolt.org/z/4r7hEy 27 | [wandbox]: https://wandbox.org/permlink/dTZxf85MVhehOqx1 28 | 29 | ## Introduction 30 | 31 | __MPark.Variant__ is an implementation of __C++17__ `std::variant` for __C++11__/__14__/__17__. 32 | 33 | - Based on [my implementation of `std::variant` for __libc++__][libcxx-impl] 34 | - Continuously tested against __libc++__'s `std::variant` test suite. 35 | 36 | [libcxx-impl]: https://reviews.llvm.org/rL288547 37 | 38 | ## Documentation 39 | 40 | - [cppreference.com](http://en.cppreference.com/w/cpp/utility/variant) 41 | - [eel.is/c++draft](http://eel.is/c++draft/variant) 42 | 43 | ## Integration 44 | 45 | ### Single Header 46 | 47 | The [single-header] branch provides a standalone `variant.hpp` 48 | file for each [release](https://github.com/mpark/variant/releases). 49 | Copy it and `#include` away! 50 | 51 | [single-header]: https://github.com/mpark/variant/tree/single-header 52 | 53 | ### Submodule 54 | 55 | You can add `mpark/variant` as a submodule to your project. 56 | 57 | ```bash 58 | git submodule add https://github.com/mpark/variant.git 3rdparty/variant 59 | ``` 60 | 61 | Add the `include` directory to your include path with 62 | `-I3rdparty/variant/include` then `#include` the `variant.hpp` header 63 | with `#include `. 64 | 65 | If you use CMake, you can simply use `add_subdirectory(3rdparty/variant)`: 66 | 67 | ```cmake 68 | cmake_minimum_required(VERSION 3.6.3) 69 | 70 | project(HelloWorld CXX) 71 | 72 | add_subdirectory(3rdparty/variant) 73 | 74 | add_executable(hello-world hello_world.cpp) 75 | target_link_libraries(hello-world mpark_variant) 76 | ``` 77 | 78 | ### Installation / CMake `find_package` 79 | 80 | ```bash 81 | git clone https://github.com/mpark/variant.git 82 | mkdir variant/build && cd variant/build 83 | cmake .. 84 | cmake --build . --target install 85 | ``` 86 | 87 | This will install `mpark/variant` to the default install-directory for 88 | your platform (`/usr/local` for Unix, `C:\Program Files` for Windows). 89 | You can also install at a custom location via the `CMAKE_INSTALL_PREFIX` 90 | variable, (e.g., `cmake .. -DCMAKE_INSTALL_PREFIX=/opt`). 91 | 92 | The installed `mpark/variant` can then be found by CMake via `find_package`: 93 | 94 | ```cmake 95 | cmake_minimum_required(VERSION 3.6.3) 96 | 97 | project(HelloWorld CXX) 98 | 99 | find_package(mpark_variant 1.3.0 REQUIRED) 100 | 101 | add_executable(hello-world hello_world.cpp) 102 | target_link_libraries(hello-world mpark_variant) 103 | ``` 104 | 105 | CMake will search for `mpark/variant` in its default set of 106 | installation prefixes. If `mpark/variant` is installed in 107 | a custom location via the `CMAKE_INSTALL_PREFIX` variable, 108 | you'll likely need to use the `CMAKE_PREFIX_PATH` to specify 109 | the location (e.g., `cmake .. -DCMAKE_PREFIX_PATH=/opt`). 110 | 111 | ## Requirements 112 | 113 | This library requires a standard conformant __C++11__ compiler. 114 | The following compilers are continously tested: 115 | 116 | | Compiler | Operating System | Version String | 117 | | -------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------- | 118 | | GCC 4.8.5 | Ubuntu 16.04.6 LTS | g++-4.8 (Ubuntu 4.8.5-4ubuntu8~16.04.1) 4.8.5 | 119 | | GCC 4.9.4 | Ubuntu 16.04.6 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~16.04) 4.9.4 | 120 | | GCC 5.5.0 | Ubuntu 16.04.6 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~16.04) 5.5.0 20171010 | 121 | | GCC 6.5.0 | Ubuntu 16.04.6 LTS | g++-6 (Ubuntu 6.5.0-2ubuntu1~16.04) 6.5.0 20181026 | 122 | | GCC 7.4.0 | Ubuntu 16.04.6 LTS | g++-7 (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0 | 123 | | GCC 8.3.0 | Ubuntu 16.04.6 LTS | g++-8 (Ubuntu 8.3.0-16ubuntu3~16.04) 8.3.0 | 124 | | GCC 9.2.1 | Ubuntu 16.04.6 LTS | g++-9 (Ubuntu 9.2.1-17ubuntu1~16.04) 9.2.1 20191102 | 125 | | Clang 3.6.2 | Ubuntu 16.04.6 LTS | Ubuntu clang version 3.6.2-3ubuntu2 (tags/RELEASE_362/final) (based on LLVM 3.6.2) | 126 | | Clang 3.7.1 | Ubuntu 16.04.6 LTS | Ubuntu clang version 3.7.1-2ubuntu2 (tags/RELEASE_371/final) (based on LLVM 3.7.1) | 127 | | Clang 3.8.0 | Ubuntu 16.04.6 LTS | clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final) | 128 | | Clang 3.9.1 | Ubuntu 16.04.6 LTS | clang version 3.9.1-4ubuntu3~16.04.2 (tags/RELEASE_391/rc2) | 129 | | Clang 4.0.0 | Ubuntu 16.04.6 LTS | clang version 4.0.0-1ubuntu1~16.04.2 (tags/RELEASE_400/rc1) | 130 | | Clang 5.0.0 | Ubuntu 16.04.6 LTS | clang version 5.0.0-3~16.04.1 (tags/RELEASE_500/final) | 131 | | Clang 6.0.0 | Ubuntu 16.04.6 LTS | clang version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final) | 132 | | Clang 7.1.0 | Ubuntu 16.04.6 LTS | clang version 7.1.0-svn353565-1~exp1~20190408084827.60 (branches/release_70) | 133 | | Clang 8.0.1 | Ubuntu 16.04.6 LTS | clang version 8.0.1-svn369350-1~exp1~20190820122438.78 (branches/release_80) | 134 | | Clang Xcode 8.3 | Darwin Kernel Version 16.7.0 (OS X 10.12.6) | Apple LLVM version 8.1.0 (clang-802.0.42) | 135 | | Clang Xcode 9.4 | Darwin Kernel Version 17.4.0 (OS X 10.13.3) | Apple LLVM version 9.1.0 (clang-902.0.39.2) | 136 | | Clang Xcode 10.1 | Darwin Kernel Version 17.7.0 (OS X 10.13.6) | Apple LLVM version 10.0.0 (clang-1000.11.45.5) | 137 | | Visual Studio 14 2015 | Visual Studio 2015 with Update 3 | MSVC 19.0.24241.7 | 138 | | Visual Studio 15 2017 | Visual Studio 2017 with Update 8 | MSVC 19.15.26732.1 | 139 | | Visual Studio 15 2017 | Visual Studio 2017 with Update 9 | MSVC 19.16.27025.1 | 140 | | Visual Studio 15 2017 (__Clang/LLVM__) | Visual Studio 2017 | Clang 7.0.0 | 141 | 142 | #### NOTES 143 | - __GCC 4.8__/__4.9__: `constexpr` support is not available for `visit` and relational operators. 144 | - Enabling __libc++__ `std::variant` tests require `-std=c++17` support. 145 | 146 | ## CMake Variables 147 | 148 | - __`MPARK_VARIANT_INCLUDE_TESTS`__:`STRING` (__default__: `""`) 149 | 150 | Semicolon-separated list of tests to build. 151 | Possible values are `mpark`, and `libc++`. 152 | 153 | __NOTE__: The __libc++__ `std::variant` tests are built with `-std=c++17`. 154 | 155 | ## Unit Tests 156 | 157 | Refer to [test/README.md](test/README.md). 158 | 159 | ## License 160 | 161 | Distributed under the [Boost Software License, Version 1.0](LICENSE.md). 162 | -------------------------------------------------------------------------------- /cmake/mpark_variant-config.cmake.in: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | # 3 | # Copyright Michael Park, 2015-2017 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | # Config file for MPark.Variant 9 | # 10 | # `MPARK_VARIANT_INCLUDE_DIRS` - include directories 11 | # `MPARK_VARIANT_LIBRARIES` - libraries to link against 12 | # 13 | # The following `IMPORTED` target is also defined: 14 | # 15 | # `mpark_variant` 16 | 17 | @PACKAGE_INIT@ 18 | 19 | include("${CMAKE_CURRENT_LIST_DIR}/mpark_variant-targets.cmake") 20 | 21 | get_target_property( 22 | MPARK_VARIANT_INCLUDE_DIRS 23 | mpark_variant INTERFACE_INCLUDE_DIRECTORIES) 24 | 25 | set_and_check(MPARK_VARIANT_INCLUDE_DIRS "${MPARK_VARIANT_INCLUDE_DIRS}") 26 | set(MPARK_VARIANT_LIBRARIES mpark_variant) 27 | -------------------------------------------------------------------------------- /include/mpark/config.hpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #ifndef MPARK_CONFIG_HPP 9 | #define MPARK_CONFIG_HPP 10 | 11 | // MSVC 2015 Update 3. 12 | #if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) 13 | #error "MPark.Variant requires C++11 support." 14 | #endif 15 | 16 | #ifndef __has_attribute 17 | #define __has_attribute(x) 0 18 | #endif 19 | 20 | #ifndef __has_builtin 21 | #define __has_builtin(x) 0 22 | #endif 23 | 24 | #ifndef __has_include 25 | #define __has_include(x) 0 26 | #endif 27 | 28 | #ifndef __has_feature 29 | #define __has_feature(x) 0 30 | #endif 31 | 32 | #if __has_attribute(always_inline) || defined(__GNUC__) 33 | #define MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline 34 | #elif defined(_MSC_VER) 35 | #define MPARK_ALWAYS_INLINE __forceinline 36 | #else 37 | #define MPARK_ALWAYS_INLINE inline 38 | #endif 39 | 40 | #if __has_builtin(__builtin_addressof) || \ 41 | (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) 42 | #define MPARK_BUILTIN_ADDRESSOF 43 | #endif 44 | 45 | #if __has_builtin(__builtin_unreachable) || defined(__GNUC__) 46 | #define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() 47 | #elif defined(_MSC_VER) 48 | #define MPARK_BUILTIN_UNREACHABLE __assume(false) 49 | #else 50 | #define MPARK_BUILTIN_UNREACHABLE 51 | #endif 52 | 53 | #if __has_builtin(__type_pack_element) && !(defined(__ICC)) 54 | #define MPARK_TYPE_PACK_ELEMENT 55 | #endif 56 | 57 | #if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ 58 | !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) 59 | #define MPARK_CPP11_CONSTEXPR 60 | #endif 61 | 62 | #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 63 | #define MPARK_CPP14_CONSTEXPR 64 | #endif 65 | 66 | #if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ 67 | (defined(_MSC_VER) && defined(_CPPUNWIND)) || \ 68 | defined(__EXCEPTIONS) 69 | #define MPARK_EXCEPTIONS 70 | #endif 71 | 72 | #if defined(__cpp_generic_lambdas) || defined(_MSC_VER) 73 | #define MPARK_GENERIC_LAMBDAS 74 | #endif 75 | 76 | #if defined(__cpp_lib_integer_sequence) 77 | #define MPARK_INTEGER_SEQUENCE 78 | #endif 79 | 80 | #if (defined(__cpp_decltype_auto) && defined(__cpp_return_type_deduction)) || defined(_MSC_VER) 81 | #define MPARK_RETURN_TYPE_DEDUCTION 82 | #endif 83 | 84 | #if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) 85 | #define MPARK_TRANSPARENT_OPERATORS 86 | #endif 87 | 88 | #if defined(__cpp_variable_templates) || defined(_MSC_VER) 89 | #define MPARK_VARIABLE_TEMPLATES 90 | #endif 91 | 92 | #if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 93 | #define MPARK_TRIVIALITY_TYPE_TRAITS 94 | #define MPARK_INCOMPLETE_TYPE_TRAITS 95 | #endif 96 | 97 | #endif // MPARK_CONFIG_HPP 98 | -------------------------------------------------------------------------------- /include/mpark/in_place.hpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #ifndef MPARK_IN_PLACE_HPP 9 | #define MPARK_IN_PLACE_HPP 10 | 11 | #include 12 | 13 | #include "config.hpp" 14 | 15 | namespace mpark { 16 | 17 | struct in_place_t { explicit in_place_t() = default; }; 18 | 19 | template 20 | struct in_place_index_t { explicit in_place_index_t() = default; }; 21 | 22 | template 23 | struct in_place_type_t { explicit in_place_type_t() = default; }; 24 | 25 | #ifdef MPARK_VARIABLE_TEMPLATES 26 | constexpr in_place_t in_place{}; 27 | 28 | template constexpr in_place_index_t in_place_index{}; 29 | 30 | template constexpr in_place_type_t in_place_type{}; 31 | #endif 32 | 33 | } // namespace mpark 34 | 35 | #endif // MPARK_IN_PLACE_HPP 36 | -------------------------------------------------------------------------------- /include/mpark/lib.hpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #ifndef MPARK_LIB_HPP 9 | #define MPARK_LIB_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "config.hpp" 17 | 18 | #define MPARK_RETURN(...) \ 19 | noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } 20 | 21 | namespace mpark { 22 | namespace lib { 23 | template 24 | struct identity { using type = T; }; 25 | 26 | inline namespace cpp14 { 27 | template 28 | struct array { 29 | constexpr const T &operator[](std::size_t index) const { 30 | return data[index]; 31 | } 32 | 33 | T data[N == 0 ? 1 : N]; 34 | }; 35 | 36 | template 37 | using add_pointer_t = typename std::add_pointer::type; 38 | 39 | template 40 | using common_type_t = typename std::common_type::type; 41 | 42 | template 43 | using decay_t = typename std::decay::type; 44 | 45 | template 46 | using enable_if_t = typename std::enable_if::type; 47 | 48 | template 49 | using remove_const_t = typename std::remove_const::type; 50 | 51 | template 52 | using remove_reference_t = typename std::remove_reference::type; 53 | 54 | template 55 | using remove_cvref_t = 56 | typename std::remove_cv>::type; 57 | 58 | template 59 | inline constexpr T &&forward(remove_reference_t &t) noexcept { 60 | return static_cast(t); 61 | } 62 | 63 | template 64 | inline constexpr T &&forward(remove_reference_t &&t) noexcept { 65 | static_assert(!std::is_lvalue_reference::value, 66 | "can not forward an rvalue as an lvalue"); 67 | return static_cast(t); 68 | } 69 | 70 | template 71 | inline constexpr remove_reference_t &&move(T &&t) noexcept { 72 | return static_cast &&>(t); 73 | } 74 | 75 | #ifdef MPARK_INTEGER_SEQUENCE 76 | using std::integer_sequence; 77 | using std::index_sequence; 78 | using std::make_index_sequence; 79 | using std::index_sequence_for; 80 | #else 81 | template 82 | struct integer_sequence { 83 | using value_type = T; 84 | static constexpr std::size_t size() noexcept { return sizeof...(Is); } 85 | }; 86 | 87 | template 88 | using index_sequence = integer_sequence; 89 | 90 | template 91 | struct make_index_sequence_concat; 92 | 93 | template 94 | struct make_index_sequence_concat, 95 | index_sequence> 96 | : identity> {}; 97 | 98 | template 99 | struct make_index_sequence_impl; 100 | 101 | template 102 | using make_index_sequence = typename make_index_sequence_impl::type; 103 | 104 | template 105 | struct make_index_sequence_impl 106 | : make_index_sequence_concat, 107 | make_index_sequence> {}; 108 | 109 | template <> 110 | struct make_index_sequence_impl<0> : identity> {}; 111 | 112 | template <> 113 | struct make_index_sequence_impl<1> : identity> {}; 114 | 115 | template 116 | using index_sequence_for = make_index_sequence; 117 | #endif 118 | 119 | // 120 | #ifdef MPARK_TRANSPARENT_OPERATORS 121 | using equal_to = std::equal_to<>; 122 | #else 123 | struct equal_to { 124 | template 125 | inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const 126 | MPARK_RETURN(lib::forward(lhs) == lib::forward(rhs)) 127 | }; 128 | #endif 129 | 130 | #ifdef MPARK_TRANSPARENT_OPERATORS 131 | using not_equal_to = std::not_equal_to<>; 132 | #else 133 | struct not_equal_to { 134 | template 135 | inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const 136 | MPARK_RETURN(lib::forward(lhs) != lib::forward(rhs)) 137 | }; 138 | #endif 139 | 140 | #ifdef MPARK_TRANSPARENT_OPERATORS 141 | using less = std::less<>; 142 | #else 143 | struct less { 144 | template 145 | inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const 146 | MPARK_RETURN(lib::forward(lhs) < lib::forward(rhs)) 147 | }; 148 | #endif 149 | 150 | #ifdef MPARK_TRANSPARENT_OPERATORS 151 | using greater = std::greater<>; 152 | #else 153 | struct greater { 154 | template 155 | inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const 156 | MPARK_RETURN(lib::forward(lhs) > lib::forward(rhs)) 157 | }; 158 | #endif 159 | 160 | #ifdef MPARK_TRANSPARENT_OPERATORS 161 | using less_equal = std::less_equal<>; 162 | #else 163 | struct less_equal { 164 | template 165 | inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const 166 | MPARK_RETURN(lib::forward(lhs) <= lib::forward(rhs)) 167 | }; 168 | #endif 169 | 170 | #ifdef MPARK_TRANSPARENT_OPERATORS 171 | using greater_equal = std::greater_equal<>; 172 | #else 173 | struct greater_equal { 174 | template 175 | inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const 176 | MPARK_RETURN(lib::forward(lhs) >= lib::forward(rhs)) 177 | }; 178 | #endif 179 | } // namespace cpp14 180 | 181 | inline namespace cpp17 { 182 | 183 | // 184 | template 185 | using bool_constant = std::integral_constant; 186 | 187 | template 188 | struct voider : identity {}; 189 | 190 | template 191 | using void_t = typename voider::type; 192 | 193 | namespace detail { 194 | namespace swappable { 195 | 196 | using std::swap; 197 | 198 | template 199 | struct is_swappable { 200 | private: 201 | template (), 203 | std::declval()))> 204 | inline static std::true_type test(int); 205 | 206 | template 207 | inline static std::false_type test(...); 208 | 209 | public: 210 | static constexpr bool value = decltype(test(0))::value; 211 | }; 212 | 213 | template 214 | struct is_nothrow_swappable { 215 | static constexpr bool value = 216 | noexcept(swap(std::declval(), std::declval())); 217 | }; 218 | 219 | template 220 | struct is_nothrow_swappable : std::false_type {}; 221 | 222 | } // namespace swappable 223 | } // namespace detail 224 | 225 | using detail::swappable::is_swappable; 226 | 227 | template 228 | using is_nothrow_swappable = 229 | detail::swappable::is_nothrow_swappable::value, T>; 230 | 231 | // 232 | namespace detail { 233 | 234 | template 235 | struct is_reference_wrapper : std::false_type {}; 236 | 237 | template 238 | struct is_reference_wrapper> 239 | : std::true_type {}; 240 | 241 | template 242 | struct Invoke; 243 | 244 | template <> 245 | struct Invoke { 246 | template 247 | inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) 248 | MPARK_RETURN((lib::forward(arg).*pmf)(lib::forward(args)...)) 249 | }; 250 | 251 | template <> 252 | struct Invoke { 253 | template 254 | inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) 255 | MPARK_RETURN((lib::forward(arg).get().*pmf)(lib::forward(args)...)) 256 | }; 257 | 258 | template <> 259 | struct Invoke { 260 | template 261 | inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) 262 | MPARK_RETURN(((*lib::forward(arg)).*pmf)(lib::forward(args)...)) 263 | }; 264 | 265 | template <> 266 | struct Invoke { 267 | template 268 | inline static constexpr auto invoke(R T::*pmo, Arg &&arg) 269 | MPARK_RETURN(lib::forward(arg).*pmo) 270 | }; 271 | 272 | template <> 273 | struct Invoke { 274 | template 275 | inline static constexpr auto invoke(R T::*pmo, Arg &&arg) 276 | MPARK_RETURN(lib::forward(arg).get().*pmo) 277 | }; 278 | 279 | template <> 280 | struct Invoke { 281 | template 282 | inline static constexpr auto invoke(R T::*pmo, Arg &&arg) 283 | MPARK_RETURN((*lib::forward(arg)).*pmo) 284 | }; 285 | 286 | template 287 | inline constexpr auto invoke(R T::*f, Arg &&arg, Args &&... args) 288 | MPARK_RETURN( 289 | Invoke::value, 290 | (std::is_base_of>::value 291 | ? 0 292 | : is_reference_wrapper>::value 293 | ? 1 294 | : 2)>::invoke(f, 295 | lib::forward(arg), 296 | lib::forward(args)...)) 297 | 298 | #ifdef _MSC_VER 299 | #pragma warning(push) 300 | #pragma warning(disable : 4100) 301 | #endif 302 | template 303 | inline constexpr auto invoke(F &&f, Args &&... args) 304 | MPARK_RETURN(lib::forward(f)(lib::forward(args)...)) 305 | #ifdef _MSC_VER 306 | #pragma warning(pop) 307 | #endif 308 | } // namespace detail 309 | 310 | template 311 | inline constexpr auto invoke(F &&f, Args &&... args) 312 | MPARK_RETURN(detail::invoke(lib::forward(f), 313 | lib::forward(args)...)) 314 | 315 | namespace detail { 316 | 317 | template 318 | struct invoke_result {}; 319 | 320 | template 321 | struct invoke_result(), std::declval()...))>, 323 | F, 324 | Args...> 325 | : identity(), std::declval()...))> {}; 327 | 328 | } // namespace detail 329 | 330 | template 331 | using invoke_result = detail::invoke_result; 332 | 333 | template 334 | using invoke_result_t = typename invoke_result::type; 335 | 336 | namespace detail { 337 | 338 | template 339 | struct is_invocable : std::false_type {}; 340 | 341 | template 342 | struct is_invocable>, F, Args...> 343 | : std::true_type {}; 344 | 345 | template 346 | struct is_invocable_r : std::false_type {}; 347 | 348 | template 349 | struct is_invocable_r>, 350 | R, 351 | F, 352 | Args...> 353 | : std::is_convertible, R> {}; 354 | 355 | } // namespace detail 356 | 357 | template 358 | using is_invocable = detail::is_invocable; 359 | 360 | template 361 | using is_invocable_r = detail::is_invocable_r; 362 | 363 | // 364 | #ifdef MPARK_BUILTIN_ADDRESSOF 365 | template 366 | inline constexpr T *addressof(T &arg) noexcept { 367 | return __builtin_addressof(arg); 368 | } 369 | #else 370 | namespace detail { 371 | 372 | namespace has_addressof_impl { 373 | 374 | struct fail; 375 | 376 | template 377 | inline fail operator&(T &&); 378 | 379 | template 380 | inline static constexpr bool impl() { 381 | return (std::is_class::value || std::is_union::value) && 382 | !std::is_same()), fail>::value; 383 | } 384 | 385 | } // namespace has_addressof_impl 386 | 387 | template 388 | using has_addressof = bool_constant()>; 389 | 390 | template 391 | inline constexpr T *addressof(T &arg, std::true_type) noexcept { 392 | return std::addressof(arg); 393 | } 394 | 395 | template 396 | inline constexpr T *addressof(T &arg, std::false_type) noexcept { 397 | return &arg; 398 | } 399 | 400 | } // namespace detail 401 | 402 | template 403 | inline constexpr T *addressof(T &arg) noexcept { 404 | return detail::addressof(arg, detail::has_addressof{}); 405 | } 406 | #endif 407 | 408 | template 409 | inline constexpr T *addressof(const T &&) = delete; 410 | 411 | } // namespace cpp17 412 | 413 | template 414 | struct remove_all_extents : identity {}; 415 | 416 | template 417 | struct remove_all_extents> : remove_all_extents {}; 418 | 419 | template 420 | using remove_all_extents_t = typename remove_all_extents::type; 421 | 422 | template 423 | using size_constant = std::integral_constant; 424 | 425 | template 426 | struct indexed_type : size_constant { using type = T; }; 427 | 428 | template 429 | using all = std::is_same, 430 | integer_sequence>; 431 | 432 | #ifdef MPARK_TYPE_PACK_ELEMENT 433 | template 434 | using type_pack_element_t = __type_pack_element; 435 | #else 436 | template 437 | struct type_pack_element_impl { 438 | private: 439 | template 440 | struct set; 441 | 442 | template 443 | struct set> : indexed_type... {}; 444 | 445 | template 446 | inline static std::enable_if impl(indexed_type); 447 | 448 | inline static std::enable_if impl(...); 449 | 450 | public: 451 | using type = decltype(impl(set>{})); 452 | }; 453 | 454 | template 455 | using type_pack_element = typename type_pack_element_impl::type; 456 | 457 | template 458 | using type_pack_element_t = typename type_pack_element::type; 459 | #endif 460 | 461 | #ifdef MPARK_TRIVIALITY_TYPE_TRAITS 462 | using std::is_trivially_copy_constructible; 463 | using std::is_trivially_move_constructible; 464 | using std::is_trivially_copy_assignable; 465 | using std::is_trivially_move_assignable; 466 | #else 467 | template 468 | struct is_trivially_copy_constructible 469 | : bool_constant< 470 | std::is_copy_constructible::value && __has_trivial_copy(T)> {}; 471 | 472 | template 473 | struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; 474 | 475 | template 476 | struct is_trivially_copy_assignable 477 | : bool_constant< 478 | std::is_copy_assignable::value && __has_trivial_assign(T)> {}; 479 | 480 | template 481 | struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; 482 | #endif 483 | 484 | template 485 | struct dependent_type : T {}; 486 | 487 | template 488 | struct push_back; 489 | 490 | template 491 | using push_back_t = typename push_back::type; 492 | 493 | template 494 | struct push_back, J> { 495 | using type = index_sequence; 496 | }; 497 | 498 | } // namespace lib 499 | } // namespace mpark 500 | 501 | #undef MPARK_RETURN 502 | 503 | #endif // MPARK_LIB_HPP 504 | -------------------------------------------------------------------------------- /include/mpark/variant.hpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #ifndef MPARK_VARIANT_HPP 9 | #define MPARK_VARIANT_HPP 10 | 11 | /* 12 | variant synopsis 13 | 14 | namespace std { 15 | 16 | // 20.7.2, class template variant 17 | template 18 | class variant { 19 | public: 20 | 21 | // 20.7.2.1, constructors 22 | constexpr variant() noexcept(see below); 23 | variant(const variant&); 24 | variant(variant&&) noexcept(see below); 25 | 26 | template constexpr variant(T&&) noexcept(see below); 27 | 28 | template 29 | constexpr explicit variant(in_place_type_t, Args&&...); 30 | 31 | template 32 | constexpr explicit variant( 33 | in_place_type_t, initializer_list, Args&&...); 34 | 35 | template 36 | constexpr explicit variant(in_place_index_t, Args&&...); 37 | 38 | template 39 | constexpr explicit variant( 40 | in_place_index_t, initializer_list, Args&&...); 41 | 42 | // 20.7.2.2, destructor 43 | ~variant(); 44 | 45 | // 20.7.2.3, assignment 46 | variant& operator=(const variant&); 47 | variant& operator=(variant&&) noexcept(see below); 48 | 49 | template variant& operator=(T&&) noexcept(see below); 50 | 51 | // 20.7.2.4, modifiers 52 | template 53 | T& emplace(Args&&...); 54 | 55 | template 56 | T& emplace(initializer_list, Args&&...); 57 | 58 | template 59 | variant_alternative& emplace(Args&&...); 60 | 61 | template 62 | variant_alternative& emplace(initializer_list, Args&&...); 63 | 64 | // 20.7.2.5, value status 65 | constexpr bool valueless_by_exception() const noexcept; 66 | constexpr size_t index() const noexcept; 67 | 68 | // 20.7.2.6, swap 69 | void swap(variant&) noexcept(see below); 70 | }; 71 | 72 | // 20.7.3, variant helper classes 73 | template struct variant_size; // undefined 74 | 75 | template 76 | constexpr size_t variant_size_v = variant_size::value; 77 | 78 | template struct variant_size; 79 | template struct variant_size; 80 | template struct variant_size; 81 | 82 | template 83 | struct variant_size>; 84 | 85 | template struct variant_alternative; // undefined 86 | 87 | template 88 | using variant_alternative_t = typename variant_alternative::type; 89 | 90 | template struct variant_alternative; 91 | template struct variant_alternative; 92 | template struct variant_alternative; 93 | 94 | template 95 | struct variant_alternative>; 96 | 97 | constexpr size_t variant_npos = -1; 98 | 99 | // 20.7.4, value access 100 | template 101 | constexpr bool holds_alternative(const variant&) noexcept; 102 | 103 | template 104 | constexpr variant_alternative_t>& 105 | get(variant&); 106 | 107 | template 108 | constexpr variant_alternative_t>&& 109 | get(variant&&); 110 | 111 | template 112 | constexpr variant_alternative_t> const& 113 | get(const variant&); 114 | 115 | template 116 | constexpr variant_alternative_t> const&& 117 | get(const variant&&); 118 | 119 | template 120 | constexpr T& get(variant&); 121 | 122 | template 123 | constexpr T&& get(variant&&); 124 | 125 | template 126 | constexpr const T& get(const variant&); 127 | 128 | template 129 | constexpr const T&& get(const variant&&); 130 | 131 | template 132 | constexpr add_pointer_t>> 133 | get_if(variant*) noexcept; 134 | 135 | template 136 | constexpr add_pointer_t>> 137 | get_if(const variant*) noexcept; 138 | 139 | template 140 | constexpr add_pointer_t 141 | get_if(variant*) noexcept; 142 | 143 | template 144 | constexpr add_pointer_t 145 | get_if(const variant*) noexcept; 146 | 147 | // 20.7.5, relational operators 148 | template 149 | constexpr bool operator==(const variant&, const variant&); 150 | 151 | template 152 | constexpr bool operator!=(const variant&, const variant&); 153 | 154 | template 155 | constexpr bool operator<(const variant&, const variant&); 156 | 157 | template 158 | constexpr bool operator>(const variant&, const variant&); 159 | 160 | template 161 | constexpr bool operator<=(const variant&, const variant&); 162 | 163 | template 164 | constexpr bool operator>=(const variant&, const variant&); 165 | 166 | // 20.7.6, visitation 167 | template 168 | constexpr see below visit(Visitor&&, Variants&&...); 169 | 170 | // 20.7.7, class monostate 171 | struct monostate; 172 | 173 | // 20.7.8, monostate relational operators 174 | constexpr bool operator<(monostate, monostate) noexcept; 175 | constexpr bool operator>(monostate, monostate) noexcept; 176 | constexpr bool operator<=(monostate, monostate) noexcept; 177 | constexpr bool operator>=(monostate, monostate) noexcept; 178 | constexpr bool operator==(monostate, monostate) noexcept; 179 | constexpr bool operator!=(monostate, monostate) noexcept; 180 | 181 | // 20.7.9, specialized algorithms 182 | template 183 | void swap(variant&, variant&) noexcept(see below); 184 | 185 | // 20.7.10, class bad_variant_access 186 | class bad_variant_access; 187 | 188 | // 20.7.11, hash support 189 | template struct hash; 190 | template struct hash>; 191 | template <> struct hash; 192 | 193 | } // namespace std 194 | 195 | */ 196 | 197 | #include 198 | #include 199 | #include 200 | #include 201 | #include 202 | #include 203 | #include 204 | #include 205 | 206 | #include "config.hpp" 207 | #include "in_place.hpp" 208 | #include "lib.hpp" 209 | 210 | namespace mpark { 211 | 212 | #ifdef MPARK_RETURN_TYPE_DEDUCTION 213 | 214 | #define AUTO auto 215 | #define AUTO_RETURN(...) { return __VA_ARGS__; } 216 | 217 | #define AUTO_REFREF auto && 218 | #define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } 219 | 220 | #define DECLTYPE_AUTO decltype(auto) 221 | #define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } 222 | 223 | #else 224 | 225 | #define AUTO auto 226 | #define AUTO_RETURN(...) \ 227 | -> lib::decay_t { return __VA_ARGS__; } 228 | 229 | #define AUTO_REFREF auto 230 | #define AUTO_REFREF_RETURN(...) \ 231 | -> decltype((__VA_ARGS__)) { \ 232 | static_assert(std::is_reference::value, ""); \ 233 | return __VA_ARGS__; \ 234 | } 235 | 236 | #define DECLTYPE_AUTO auto 237 | #define DECLTYPE_AUTO_RETURN(...) \ 238 | -> decltype(__VA_ARGS__) { return __VA_ARGS__; } 239 | 240 | #endif 241 | 242 | class bad_variant_access : public std::exception { 243 | public: 244 | virtual const char *what() const noexcept override { return "bad_variant_access"; } 245 | }; 246 | 247 | [[noreturn]] inline void throw_bad_variant_access() { 248 | #ifdef MPARK_EXCEPTIONS 249 | throw bad_variant_access{}; 250 | #else 251 | std::terminate(); 252 | MPARK_BUILTIN_UNREACHABLE; 253 | #endif 254 | } 255 | 256 | template 257 | class variant; 258 | 259 | template 260 | struct variant_size; 261 | 262 | #ifdef MPARK_VARIABLE_TEMPLATES 263 | template 264 | constexpr std::size_t variant_size_v = variant_size::value; 265 | #endif 266 | 267 | template 268 | struct variant_size : variant_size {}; 269 | 270 | template 271 | struct variant_size : variant_size {}; 272 | 273 | template 274 | struct variant_size : variant_size {}; 275 | 276 | template 277 | struct variant_size> : lib::size_constant {}; 278 | 279 | template 280 | struct variant_alternative; 281 | 282 | template 283 | using variant_alternative_t = typename variant_alternative::type; 284 | 285 | template 286 | struct variant_alternative 287 | : std::add_const> {}; 288 | 289 | template 290 | struct variant_alternative 291 | : std::add_volatile> {}; 292 | 293 | template 294 | struct variant_alternative 295 | : std::add_cv> {}; 296 | 297 | template 298 | struct variant_alternative> { 299 | static_assert(I < sizeof...(Ts), 300 | "index out of bounds in `std::variant_alternative<>`"); 301 | using type = lib::type_pack_element_t; 302 | }; 303 | 304 | constexpr std::size_t variant_npos = static_cast(-1); 305 | 306 | namespace detail { 307 | 308 | constexpr std::size_t not_found = static_cast(-1); 309 | constexpr std::size_t ambiguous = static_cast(-2); 310 | 311 | #ifdef MPARK_CPP14_CONSTEXPR 312 | template 313 | inline constexpr std::size_t find_index() { 314 | constexpr lib::array matches = { 315 | {std::is_same::value...} 316 | }; 317 | std::size_t result = not_found; 318 | for (std::size_t i = 0; i < sizeof...(Ts); ++i) { 319 | if (matches[i]) { 320 | if (result != not_found) { 321 | return ambiguous; 322 | } 323 | result = i; 324 | } 325 | } 326 | return result; 327 | } 328 | #else 329 | inline constexpr std::size_t find_index_impl(std::size_t result, 330 | std::size_t) { 331 | return result; 332 | } 333 | 334 | template 335 | inline constexpr std::size_t find_index_impl(std::size_t result, 336 | std::size_t idx, 337 | bool b, 338 | Bs... bs) { 339 | return b ? (result != not_found ? ambiguous 340 | : find_index_impl(idx, idx + 1, bs...)) 341 | : find_index_impl(result, idx + 1, bs...); 342 | } 343 | 344 | template 345 | inline constexpr std::size_t find_index() { 346 | return find_index_impl(not_found, 0, std::is_same::value...); 347 | } 348 | #endif 349 | 350 | template 351 | using find_index_sfinae_impl = 352 | lib::enable_if_t>; 354 | 355 | template 356 | using find_index_sfinae = find_index_sfinae_impl()>; 357 | 358 | template 359 | struct find_index_checked_impl : lib::size_constant { 360 | static_assert(I != not_found, "the specified type is not found."); 361 | static_assert(I != ambiguous, "the specified type is ambiguous."); 362 | }; 363 | 364 | template 365 | using find_index_checked = find_index_checked_impl()>; 366 | 367 | struct valueless_t {}; 368 | 369 | enum class Trait { TriviallyAvailable, Available, Unavailable }; 370 | 371 | template class IsTriviallyAvailable, 373 | template class IsAvailable> 374 | inline constexpr Trait trait() { 375 | return IsTriviallyAvailable::value 376 | ? Trait::TriviallyAvailable 377 | : IsAvailable::value ? Trait::Available 378 | : Trait::Unavailable; 379 | } 380 | 381 | #ifdef MPARK_CPP14_CONSTEXPR 382 | template 383 | inline constexpr Trait common_trait(Traits... traits_) { 384 | Trait result = Trait::TriviallyAvailable; 385 | lib::array traits = {{traits_...}}; 386 | for (std::size_t i = 0; i < sizeof...(Traits); ++i) { 387 | Trait t = traits[i]; 388 | if (static_cast(t) > static_cast(result)) { 389 | result = t; 390 | } 391 | } 392 | return result; 393 | } 394 | #else 395 | inline constexpr Trait common_trait_impl(Trait result) { return result; } 396 | 397 | template 398 | inline constexpr Trait common_trait_impl(Trait result, 399 | Trait t, 400 | Traits... ts) { 401 | return static_cast(t) > static_cast(result) 402 | ? common_trait_impl(t, ts...) 403 | : common_trait_impl(result, ts...); 404 | } 405 | 406 | template 407 | inline constexpr Trait common_trait(Traits... ts) { 408 | return common_trait_impl(Trait::TriviallyAvailable, ts...); 409 | } 410 | #endif 411 | 412 | template 413 | struct traits { 414 | static constexpr Trait copy_constructible_trait = 415 | common_trait(trait()...); 418 | 419 | static constexpr Trait move_constructible_trait = 420 | common_trait(trait()...); 423 | 424 | static constexpr Trait copy_assignable_trait = 425 | common_trait(copy_constructible_trait, 426 | trait()...); 429 | 430 | static constexpr Trait move_assignable_trait = 431 | common_trait(move_constructible_trait, 432 | trait()...); 435 | 436 | static constexpr Trait destructible_trait = 437 | common_trait(trait()...); 440 | }; 441 | 442 | namespace access { 443 | 444 | struct recursive_union { 445 | #ifdef MPARK_RETURN_TYPE_DEDUCTION 446 | template 447 | inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { 448 | return lib::forward(v).head_; 449 | } 450 | 451 | template 452 | inline static constexpr auto &&get_alt(V &&v, in_place_index_t) { 453 | return get_alt(lib::forward(v).tail_, in_place_index_t{}); 454 | } 455 | #else 456 | template 457 | struct get_alt_impl { 458 | template 459 | inline constexpr AUTO_REFREF operator()(V &&v) const 460 | AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) 461 | }; 462 | 463 | template 464 | struct get_alt_impl<0, Dummy> { 465 | template 466 | inline constexpr AUTO_REFREF operator()(V &&v) const 467 | AUTO_REFREF_RETURN(lib::forward(v).head_) 468 | }; 469 | 470 | template 471 | inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t) 472 | AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) 473 | #endif 474 | }; 475 | 476 | struct base { 477 | template 478 | inline static constexpr AUTO_REFREF get_alt(V &&v) 479 | #ifdef _MSC_VER 480 | AUTO_REFREF_RETURN(recursive_union::get_alt( 481 | lib::forward(v).data_, in_place_index_t{})) 482 | #else 483 | AUTO_REFREF_RETURN(recursive_union::get_alt( 484 | data(lib::forward(v)), in_place_index_t{})) 485 | #endif 486 | }; 487 | 488 | struct variant { 489 | template 490 | inline static constexpr AUTO_REFREF get_alt(V &&v) 491 | AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) 492 | }; 493 | 494 | } // namespace access 495 | 496 | namespace visitation { 497 | 498 | #if defined(MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) 499 | #define MPARK_VARIANT_SWITCH_VISIT 500 | #endif 501 | 502 | struct base { 503 | template 504 | using dispatch_result_t = decltype( 505 | lib::invoke(std::declval(), 506 | access::base::get_alt<0>(std::declval())...)); 507 | 508 | template 509 | struct expected { 510 | template 511 | inline static constexpr bool but_got() { 512 | return std::is_same::value; 513 | } 514 | }; 515 | 516 | template 517 | struct visit_return_type_check { 518 | static_assert( 519 | expected::template but_got(), 520 | "`visit` requires the visitor to have a single return type"); 521 | 522 | template 523 | inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, 524 | Alts &&... alts) 525 | DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), 526 | lib::forward(alts)...)) 527 | }; 528 | 529 | #ifdef MPARK_VARIANT_SWITCH_VISIT 530 | template 531 | struct dispatcher; 532 | 533 | template 534 | struct dispatcher { 535 | template 536 | MPARK_ALWAYS_INLINE static constexpr R dispatch( 537 | F &&, typename ITs::type &&..., Vs &&...) { 538 | MPARK_BUILTIN_UNREACHABLE; 539 | } 540 | 541 | template 542 | MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&, Vs &&...) { 543 | MPARK_BUILTIN_UNREACHABLE; 544 | } 545 | 546 | template 547 | MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t, 548 | F &&, 549 | Vs &&...) { 550 | MPARK_BUILTIN_UNREACHABLE; 551 | } 552 | }; 553 | 554 | template 555 | struct dispatcher { 556 | template 557 | MPARK_ALWAYS_INLINE static constexpr R dispatch( 558 | F &&f, typename ITs::type &&... visited_vs) { 559 | using Expected = R; 560 | using Actual = decltype(lib::invoke( 561 | lib::forward(f), 562 | access::base::get_alt( 563 | lib::forward(visited_vs))...)); 564 | return visit_return_type_check::invoke( 565 | lib::forward(f), 566 | access::base::get_alt( 567 | lib::forward(visited_vs))...); 568 | } 569 | 570 | template 571 | MPARK_ALWAYS_INLINE static constexpr R dispatch( 572 | F &&f, typename ITs::type &&... visited_vs, V &&v, Vs &&... vs) { 573 | #define MPARK_DISPATCH(I) \ 574 | dispatcher<(I < lib::decay_t::size()), \ 575 | R, \ 576 | ITs..., \ 577 | lib::indexed_type>:: \ 578 | template dispatch<0>(lib::forward(f), \ 579 | lib::forward(visited_vs)..., \ 580 | lib::forward(v), \ 581 | lib::forward(vs)...) 582 | 583 | #define MPARK_DEFAULT(I) \ 584 | dispatcher<(I < lib::decay_t::size()), R, ITs...>::template dispatch( \ 585 | lib::forward(f), \ 586 | lib::forward(visited_vs)..., \ 587 | lib::forward(v), \ 588 | lib::forward(vs)...) 589 | 590 | switch (v.index()) { 591 | case B + 0: return MPARK_DISPATCH(B + 0); 592 | case B + 1: return MPARK_DISPATCH(B + 1); 593 | case B + 2: return MPARK_DISPATCH(B + 2); 594 | case B + 3: return MPARK_DISPATCH(B + 3); 595 | case B + 4: return MPARK_DISPATCH(B + 4); 596 | case B + 5: return MPARK_DISPATCH(B + 5); 597 | case B + 6: return MPARK_DISPATCH(B + 6); 598 | case B + 7: return MPARK_DISPATCH(B + 7); 599 | case B + 8: return MPARK_DISPATCH(B + 8); 600 | case B + 9: return MPARK_DISPATCH(B + 9); 601 | case B + 10: return MPARK_DISPATCH(B + 10); 602 | case B + 11: return MPARK_DISPATCH(B + 11); 603 | case B + 12: return MPARK_DISPATCH(B + 12); 604 | case B + 13: return MPARK_DISPATCH(B + 13); 605 | case B + 14: return MPARK_DISPATCH(B + 14); 606 | case B + 15: return MPARK_DISPATCH(B + 15); 607 | case B + 16: return MPARK_DISPATCH(B + 16); 608 | case B + 17: return MPARK_DISPATCH(B + 17); 609 | case B + 18: return MPARK_DISPATCH(B + 18); 610 | case B + 19: return MPARK_DISPATCH(B + 19); 611 | case B + 20: return MPARK_DISPATCH(B + 20); 612 | case B + 21: return MPARK_DISPATCH(B + 21); 613 | case B + 22: return MPARK_DISPATCH(B + 22); 614 | case B + 23: return MPARK_DISPATCH(B + 23); 615 | case B + 24: return MPARK_DISPATCH(B + 24); 616 | case B + 25: return MPARK_DISPATCH(B + 25); 617 | case B + 26: return MPARK_DISPATCH(B + 26); 618 | case B + 27: return MPARK_DISPATCH(B + 27); 619 | case B + 28: return MPARK_DISPATCH(B + 28); 620 | case B + 29: return MPARK_DISPATCH(B + 29); 621 | case B + 30: return MPARK_DISPATCH(B + 30); 622 | case B + 31: return MPARK_DISPATCH(B + 31); 623 | default: return MPARK_DEFAULT(B + 32); 624 | } 625 | 626 | #undef MPARK_DEFAULT 627 | #undef MPARK_DISPATCH 628 | } 629 | 630 | template 631 | MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&f, 632 | Vs &&... vs) { 633 | using Expected = R; 634 | using Actual = decltype( 635 | lib::invoke(lib::forward(f), 636 | access::base::get_alt(lib::forward(vs))...)); 637 | return visit_return_type_check::invoke( 638 | lib::forward(f), 639 | access::base::get_alt(lib::forward(vs))...); 640 | } 641 | 642 | template 643 | MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t index, 644 | F &&f, 645 | V &&v, 646 | Vs &&... vs) { 647 | static_assert(lib::all<(lib::decay_t::size() == 648 | lib::decay_t::size())...>::value, 649 | "all of the variants must be the same size."); 650 | #define MPARK_DISPATCH_AT(I) \ 651 | dispatcher<(I < lib::decay_t::size()), R>::template dispatch_case( \ 652 | lib::forward(f), lib::forward(v), lib::forward(vs)...) 653 | 654 | #define MPARK_DEFAULT(I) \ 655 | dispatcher<(I < lib::decay_t::size()), R>::template dispatch_at( \ 656 | index, lib::forward(f), lib::forward(v), lib::forward(vs)...) 657 | 658 | switch (index) { 659 | case B + 0: return MPARK_DISPATCH_AT(B + 0); 660 | case B + 1: return MPARK_DISPATCH_AT(B + 1); 661 | case B + 2: return MPARK_DISPATCH_AT(B + 2); 662 | case B + 3: return MPARK_DISPATCH_AT(B + 3); 663 | case B + 4: return MPARK_DISPATCH_AT(B + 4); 664 | case B + 5: return MPARK_DISPATCH_AT(B + 5); 665 | case B + 6: return MPARK_DISPATCH_AT(B + 6); 666 | case B + 7: return MPARK_DISPATCH_AT(B + 7); 667 | case B + 8: return MPARK_DISPATCH_AT(B + 8); 668 | case B + 9: return MPARK_DISPATCH_AT(B + 9); 669 | case B + 10: return MPARK_DISPATCH_AT(B + 10); 670 | case B + 11: return MPARK_DISPATCH_AT(B + 11); 671 | case B + 12: return MPARK_DISPATCH_AT(B + 12); 672 | case B + 13: return MPARK_DISPATCH_AT(B + 13); 673 | case B + 14: return MPARK_DISPATCH_AT(B + 14); 674 | case B + 15: return MPARK_DISPATCH_AT(B + 15); 675 | case B + 16: return MPARK_DISPATCH_AT(B + 16); 676 | case B + 17: return MPARK_DISPATCH_AT(B + 17); 677 | case B + 18: return MPARK_DISPATCH_AT(B + 18); 678 | case B + 19: return MPARK_DISPATCH_AT(B + 19); 679 | case B + 20: return MPARK_DISPATCH_AT(B + 20); 680 | case B + 21: return MPARK_DISPATCH_AT(B + 21); 681 | case B + 22: return MPARK_DISPATCH_AT(B + 22); 682 | case B + 23: return MPARK_DISPATCH_AT(B + 23); 683 | case B + 24: return MPARK_DISPATCH_AT(B + 24); 684 | case B + 25: return MPARK_DISPATCH_AT(B + 25); 685 | case B + 26: return MPARK_DISPATCH_AT(B + 26); 686 | case B + 27: return MPARK_DISPATCH_AT(B + 27); 687 | case B + 28: return MPARK_DISPATCH_AT(B + 28); 688 | case B + 29: return MPARK_DISPATCH_AT(B + 29); 689 | case B + 30: return MPARK_DISPATCH_AT(B + 30); 690 | case B + 31: return MPARK_DISPATCH_AT(B + 31); 691 | default: return MPARK_DEFAULT(B + 32); 692 | } 693 | 694 | #undef MPARK_DEFAULT 695 | #undef MPARK_DISPATCH_AT 696 | } 697 | }; 698 | #else 699 | template 700 | inline static constexpr const T &at(const T &elem) noexcept { 701 | return elem; 702 | } 703 | 704 | template 705 | inline static constexpr const lib::remove_all_extents_t &at( 706 | const lib::array &elems, std::size_t i, Is... is) noexcept { 707 | return at(elems[i], is...); 708 | } 709 | 710 | template 711 | inline static constexpr lib::array, sizeof...(Fs) + 1> 712 | make_farray(F &&f, Fs &&... fs) { 713 | return {{lib::forward(f), lib::forward(fs)...}}; 714 | } 715 | 716 | template 717 | struct make_fmatrix_impl { 718 | 719 | template 720 | inline static constexpr dispatch_result_t dispatch( 721 | F &&f, Vs &&... vs) { 722 | using Expected = dispatch_result_t; 723 | using Actual = decltype(lib::invoke( 724 | lib::forward(f), 725 | access::base::get_alt(lib::forward(vs))...)); 726 | return visit_return_type_check::invoke( 727 | lib::forward(f), 728 | access::base::get_alt(lib::forward(vs))...); 729 | } 730 | 731 | #ifdef MPARK_RETURN_TYPE_DEDUCTION 732 | template 733 | inline static constexpr auto impl(lib::index_sequence) { 734 | return &dispatch; 735 | } 736 | 737 | template 738 | inline static constexpr auto impl(Is, 739 | lib::index_sequence, 740 | Ls... ls) { 741 | return make_farray(impl(lib::push_back_t{}, ls...)...); 742 | } 743 | #else 744 | template 745 | struct impl; 746 | 747 | template 748 | struct impl> { 749 | inline constexpr AUTO operator()() const 750 | AUTO_RETURN(&dispatch) 751 | }; 752 | 753 | template 754 | struct impl, Ls...> { 755 | inline constexpr AUTO operator()() const 756 | AUTO_RETURN( 757 | make_farray(impl, Ls...>{}()...)) 758 | }; 759 | #endif 760 | }; 761 | 762 | #ifdef MPARK_RETURN_TYPE_DEDUCTION 763 | template 764 | inline static constexpr auto make_fmatrix() { 765 | return make_fmatrix_impl::impl( 766 | lib::index_sequence<>{}, 767 | lib::make_index_sequence::size()>{}...); 768 | } 769 | #else 770 | template 771 | inline static constexpr AUTO make_fmatrix() 772 | AUTO_RETURN( 773 | typename make_fmatrix_impl::template impl< 774 | lib::index_sequence<>, 775 | lib::make_index_sequence::size()>...>{}()) 776 | #endif 777 | 778 | template 779 | struct make_fdiagonal_impl { 780 | template 781 | inline static constexpr dispatch_result_t dispatch( 782 | F &&f, Vs &&... vs) { 783 | using Expected = dispatch_result_t; 784 | using Actual = decltype( 785 | lib::invoke(lib::forward(f), 786 | access::base::get_alt(lib::forward(vs))...)); 787 | return visit_return_type_check::invoke( 788 | lib::forward(f), 789 | access::base::get_alt(lib::forward(vs))...); 790 | } 791 | 792 | template 793 | inline static constexpr AUTO impl(lib::index_sequence) 794 | AUTO_RETURN(make_farray(&dispatch...)) 795 | }; 796 | 797 | template 798 | inline static constexpr auto make_fdiagonal() 799 | -> decltype(make_fdiagonal_impl::impl( 800 | lib::make_index_sequence::size()>{})) { 801 | static_assert(lib::all<(lib::decay_t::size() == 802 | lib::decay_t::size())...>::value, 803 | "all of the variants must be the same size."); 804 | return make_fdiagonal_impl::impl( 805 | lib::make_index_sequence::size()>{}); 806 | } 807 | #endif 808 | }; 809 | 810 | #if !defined(MPARK_VARIANT_SWITCH_VISIT) && \ 811 | (!defined(_MSC_VER) || _MSC_VER >= 1910) 812 | template 813 | using fmatrix_t = decltype(base::make_fmatrix()); 814 | 815 | template 816 | struct fmatrix { 817 | static constexpr fmatrix_t value = 818 | base::make_fmatrix(); 819 | }; 820 | 821 | template 822 | constexpr fmatrix_t fmatrix::value; 823 | 824 | template 825 | using fdiagonal_t = decltype(base::make_fdiagonal()); 826 | 827 | template 828 | struct fdiagonal { 829 | static constexpr fdiagonal_t value = 830 | base::make_fdiagonal(); 831 | }; 832 | 833 | template 834 | constexpr fdiagonal_t fdiagonal::value; 835 | #endif 836 | 837 | struct alt { 838 | template 839 | inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, 840 | Vs &&... vs) 841 | #ifdef MPARK_VARIANT_SWITCH_VISIT 842 | DECLTYPE_AUTO_RETURN( 843 | base::dispatcher< 844 | true, 845 | base::dispatch_result_t(vs)))...>>:: 848 | template dispatch<0>(lib::forward(visitor), 849 | as_base(lib::forward(vs))...)) 850 | #elif !defined(_MSC_VER) || _MSC_VER >= 1910 851 | DECLTYPE_AUTO_RETURN(base::at( 852 | fmatrix(vs)))...>::value, 854 | vs.index()...)(lib::forward(visitor), 855 | as_base(lib::forward(vs))...)) 856 | #else 857 | DECLTYPE_AUTO_RETURN(base::at( 858 | base::make_fmatrix(vs)))...>(), 860 | vs.index()...)(lib::forward(visitor), 861 | as_base(lib::forward(vs))...)) 862 | #endif 863 | 864 | template 865 | inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, 866 | Visitor &&visitor, 867 | Vs &&... vs) 868 | #ifdef MPARK_VARIANT_SWITCH_VISIT 869 | DECLTYPE_AUTO_RETURN( 870 | base::dispatcher< 871 | true, 872 | base::dispatch_result_t(vs)))...>>:: 875 | template dispatch_at<0>(index, 876 | lib::forward(visitor), 877 | as_base(lib::forward(vs))...)) 878 | #elif !defined(_MSC_VER) || _MSC_VER >= 1910 879 | DECLTYPE_AUTO_RETURN(base::at( 880 | fdiagonal(vs)))...>::value, 882 | index)(lib::forward(visitor), 883 | as_base(lib::forward(vs))...)) 884 | #else 885 | DECLTYPE_AUTO_RETURN(base::at( 886 | base::make_fdiagonal(vs)))...>(), 888 | index)(lib::forward(visitor), 889 | as_base(lib::forward(vs))...)) 890 | #endif 891 | }; 892 | 893 | struct variant { 894 | private: 895 | template 896 | struct visitor { 897 | template 898 | inline static constexpr bool does_not_handle() { 899 | return lib::is_invocable::value; 900 | } 901 | }; 902 | 903 | template 904 | struct visit_exhaustiveness_check { 905 | static_assert(visitor::template does_not_handle(), 906 | "`visit` requires the visitor to be exhaustive."); 907 | 908 | inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, 909 | Values &&... values) 910 | DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), 911 | lib::forward(values)...)) 912 | }; 913 | 914 | template 915 | struct value_visitor { 916 | Visitor &&visitor_; 917 | 918 | template 919 | inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const 920 | DECLTYPE_AUTO_RETURN( 921 | visit_exhaustiveness_check< 922 | Visitor, 923 | decltype((lib::forward(alts).value))...>:: 924 | invoke(lib::forward(visitor_), 925 | lib::forward(alts).value...)) 926 | }; 927 | 928 | template 929 | inline static constexpr AUTO make_value_visitor(Visitor &&visitor) 930 | AUTO_RETURN(value_visitor{lib::forward(visitor)}) 931 | 932 | public: 933 | template 934 | inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, 935 | Vs &&... vs) 936 | DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward(visitor), 937 | lib::forward(vs).impl_...)) 938 | 939 | template 940 | inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, 941 | Visitor &&visitor, 942 | Vs &&... vs) 943 | DECLTYPE_AUTO_RETURN( 944 | alt::visit_alt_at(index, 945 | lib::forward(visitor), 946 | lib::forward(vs).impl_...)) 947 | 948 | template 949 | inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, 950 | Vs &&... vs) 951 | DECLTYPE_AUTO_RETURN( 952 | visit_alt(make_value_visitor(lib::forward(visitor)), 953 | lib::forward(vs)...)) 954 | 955 | template 956 | inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, 957 | Visitor &&visitor, 958 | Vs &&... vs) 959 | DECLTYPE_AUTO_RETURN( 960 | visit_alt_at(index, 961 | make_value_visitor(lib::forward(visitor)), 962 | lib::forward(vs)...)) 963 | }; 964 | 965 | } // namespace visitation 966 | 967 | template 968 | struct alt { 969 | using value_type = T; 970 | 971 | #ifdef _MSC_VER 972 | #pragma warning(push) 973 | #pragma warning(disable : 4244) 974 | #endif 975 | template 976 | inline explicit constexpr alt(in_place_t, Args &&... args) 977 | : value(lib::forward(args)...) {} 978 | #ifdef _MSC_VER 979 | #pragma warning(pop) 980 | #endif 981 | 982 | T value; 983 | }; 984 | 985 | template 986 | union recursive_union; 987 | 988 | template 989 | union recursive_union {}; 990 | 991 | #define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ 992 | template \ 993 | union recursive_union { \ 994 | public: \ 995 | inline explicit constexpr recursive_union(valueless_t) noexcept \ 996 | : dummy_{} {} \ 997 | \ 998 | template \ 999 | inline explicit constexpr recursive_union(in_place_index_t<0>, \ 1000 | Args &&... args) \ 1001 | : head_(in_place_t{}, lib::forward(args)...) {} \ 1002 | \ 1003 | template \ 1004 | inline explicit constexpr recursive_union(in_place_index_t, \ 1005 | Args &&... args) \ 1006 | : tail_(in_place_index_t{}, lib::forward(args)...) {} \ 1007 | \ 1008 | recursive_union(const recursive_union &) = default; \ 1009 | recursive_union(recursive_union &&) = default; \ 1010 | \ 1011 | destructor \ 1012 | \ 1013 | recursive_union &operator=(const recursive_union &) = default; \ 1014 | recursive_union &operator=(recursive_union &&) = default; \ 1015 | \ 1016 | private: \ 1017 | char dummy_; \ 1018 | alt head_; \ 1019 | recursive_union tail_; \ 1020 | \ 1021 | friend struct access::recursive_union; \ 1022 | } 1023 | 1024 | MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, 1025 | ~recursive_union() = default;); 1026 | MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, 1027 | ~recursive_union() {}); 1028 | MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, 1029 | ~recursive_union() = delete;); 1030 | 1031 | #undef MPARK_VARIANT_RECURSIVE_UNION 1032 | 1033 | template 1034 | using index_t = typename std::conditional< 1035 | sizeof...(Ts) < (std::numeric_limits::max)(), 1036 | unsigned char, 1037 | typename std::conditional< 1038 | sizeof...(Ts) < (std::numeric_limits::max)(), 1039 | unsigned short, 1040 | unsigned int>::type 1041 | >::type; 1042 | 1043 | template 1044 | class base { 1045 | public: 1046 | inline explicit constexpr base(valueless_t tag) noexcept 1047 | : data_(tag), index_(static_cast>(-1)) {} 1048 | 1049 | template 1050 | inline explicit constexpr base(in_place_index_t, Args &&... args) 1051 | : data_(in_place_index_t{}, lib::forward(args)...), 1052 | index_(I) {} 1053 | 1054 | inline constexpr bool valueless_by_exception() const noexcept { 1055 | return index_ == static_cast>(-1); 1056 | } 1057 | 1058 | inline constexpr std::size_t index() const noexcept { 1059 | return valueless_by_exception() ? variant_npos : index_; 1060 | } 1061 | 1062 | protected: 1063 | using data_t = recursive_union; 1064 | 1065 | friend inline constexpr base &as_base(base &b) { return b; } 1066 | friend inline constexpr const base &as_base(const base &b) { return b; } 1067 | friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } 1068 | friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } 1069 | 1070 | friend inline constexpr data_t &data(base &b) { return b.data_; } 1071 | friend inline constexpr const data_t &data(const base &b) { return b.data_; } 1072 | friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } 1073 | friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } 1074 | 1075 | inline static constexpr std::size_t size() { return sizeof...(Ts); } 1076 | 1077 | data_t data_; 1078 | index_t index_; 1079 | 1080 | friend struct access::base; 1081 | friend struct visitation::base; 1082 | }; 1083 | 1084 | struct dtor { 1085 | #ifdef _MSC_VER 1086 | #pragma warning(push) 1087 | #pragma warning(disable : 4100) 1088 | #endif 1089 | template 1090 | inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } 1091 | #ifdef _MSC_VER 1092 | #pragma warning(pop) 1093 | #endif 1094 | }; 1095 | 1096 | #if !defined(_MSC_VER) || _MSC_VER >= 1910 1097 | #define MPARK_INHERITING_CTOR(type, base) using base::base; 1098 | #else 1099 | #define MPARK_INHERITING_CTOR(type, base) \ 1100 | template \ 1101 | inline explicit constexpr type(Args &&... args) \ 1102 | : base(lib::forward(args)...) {} 1103 | #endif 1104 | 1105 | template 1106 | class destructor; 1107 | 1108 | #define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ 1109 | template \ 1110 | class destructor, destructible_trait> \ 1111 | : public base { \ 1112 | using super = base; \ 1113 | \ 1114 | public: \ 1115 | MPARK_INHERITING_CTOR(destructor, super) \ 1116 | using super::operator=; \ 1117 | \ 1118 | destructor(const destructor &) = default; \ 1119 | destructor(destructor &&) = default; \ 1120 | definition \ 1121 | destructor &operator=(const destructor &) = default; \ 1122 | destructor &operator=(destructor &&) = default; \ 1123 | \ 1124 | protected: \ 1125 | destroy \ 1126 | } 1127 | 1128 | MPARK_VARIANT_DESTRUCTOR( 1129 | Trait::TriviallyAvailable, 1130 | ~destructor() = default;, 1131 | inline void destroy() noexcept { 1132 | this->index_ = static_cast>(-1); 1133 | }); 1134 | 1135 | MPARK_VARIANT_DESTRUCTOR( 1136 | Trait::Available, 1137 | ~destructor() { destroy(); }, 1138 | inline void destroy() noexcept { 1139 | if (!this->valueless_by_exception()) { 1140 | visitation::alt::visit_alt(dtor{}, *this); 1141 | } 1142 | this->index_ = static_cast>(-1); 1143 | }); 1144 | 1145 | MPARK_VARIANT_DESTRUCTOR( 1146 | Trait::Unavailable, 1147 | ~destructor() = delete;, 1148 | inline void destroy() noexcept = delete;); 1149 | 1150 | #undef MPARK_VARIANT_DESTRUCTOR 1151 | 1152 | template 1153 | class constructor : public destructor { 1154 | using super = destructor; 1155 | 1156 | public: 1157 | MPARK_INHERITING_CTOR(constructor, super) 1158 | using super::operator=; 1159 | 1160 | protected: 1161 | #ifndef MPARK_GENERIC_LAMBDAS 1162 | struct ctor { 1163 | template 1164 | inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { 1165 | constructor::construct_alt(lhs_alt, 1166 | lib::forward(rhs_alt).value); 1167 | } 1168 | }; 1169 | #endif 1170 | 1171 | template 1172 | inline static T &construct_alt(alt &a, Args &&... args) { 1173 | auto *result = ::new (static_cast(lib::addressof(a))) 1174 | alt(in_place_t{}, lib::forward(args)...); 1175 | return result->value; 1176 | } 1177 | 1178 | template 1179 | inline static void generic_construct(constructor &lhs, Rhs &&rhs) { 1180 | lhs.destroy(); 1181 | if (!rhs.valueless_by_exception()) { 1182 | visitation::alt::visit_alt_at( 1183 | rhs.index(), 1184 | #ifdef MPARK_GENERIC_LAMBDAS 1185 | [](auto &lhs_alt, auto &&rhs_alt) { 1186 | constructor::construct_alt( 1187 | lhs_alt, lib::forward(rhs_alt).value); 1188 | } 1189 | #else 1190 | ctor{} 1191 | #endif 1192 | , 1193 | lhs, 1194 | lib::forward(rhs)); 1195 | lhs.index_ = rhs.index_; 1196 | } 1197 | } 1198 | }; 1199 | 1200 | template 1201 | class move_constructor; 1202 | 1203 | #define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ 1204 | template \ 1205 | class move_constructor, move_constructible_trait> \ 1206 | : public constructor> { \ 1207 | using super = constructor>; \ 1208 | \ 1209 | public: \ 1210 | MPARK_INHERITING_CTOR(move_constructor, super) \ 1211 | using super::operator=; \ 1212 | \ 1213 | move_constructor(const move_constructor &) = default; \ 1214 | definition \ 1215 | ~move_constructor() = default; \ 1216 | move_constructor &operator=(const move_constructor &) = default; \ 1217 | move_constructor &operator=(move_constructor &&) = default; \ 1218 | } 1219 | 1220 | MPARK_VARIANT_MOVE_CONSTRUCTOR( 1221 | Trait::TriviallyAvailable, 1222 | move_constructor(move_constructor &&that) = default;); 1223 | 1224 | MPARK_VARIANT_MOVE_CONSTRUCTOR( 1225 | Trait::Available, 1226 | move_constructor(move_constructor &&that) noexcept( 1227 | lib::all::value...>::value) 1228 | : move_constructor(valueless_t{}) { 1229 | this->generic_construct(*this, lib::move(that)); 1230 | }); 1231 | 1232 | MPARK_VARIANT_MOVE_CONSTRUCTOR( 1233 | Trait::Unavailable, 1234 | move_constructor(move_constructor &&) = delete;); 1235 | 1236 | #undef MPARK_VARIANT_MOVE_CONSTRUCTOR 1237 | 1238 | template 1239 | class copy_constructor; 1240 | 1241 | #define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ 1242 | template \ 1243 | class copy_constructor, copy_constructible_trait> \ 1244 | : public move_constructor> { \ 1245 | using super = move_constructor>; \ 1246 | \ 1247 | public: \ 1248 | MPARK_INHERITING_CTOR(copy_constructor, super) \ 1249 | using super::operator=; \ 1250 | \ 1251 | definition \ 1252 | copy_constructor(copy_constructor &&) = default; \ 1253 | ~copy_constructor() = default; \ 1254 | copy_constructor &operator=(const copy_constructor &) = default; \ 1255 | copy_constructor &operator=(copy_constructor &&) = default; \ 1256 | } 1257 | 1258 | MPARK_VARIANT_COPY_CONSTRUCTOR( 1259 | Trait::TriviallyAvailable, 1260 | copy_constructor(const copy_constructor &that) = default;); 1261 | 1262 | MPARK_VARIANT_COPY_CONSTRUCTOR( 1263 | Trait::Available, 1264 | copy_constructor(const copy_constructor &that) 1265 | : copy_constructor(valueless_t{}) { 1266 | this->generic_construct(*this, that); 1267 | }); 1268 | 1269 | MPARK_VARIANT_COPY_CONSTRUCTOR( 1270 | Trait::Unavailable, 1271 | copy_constructor(const copy_constructor &) = delete;); 1272 | 1273 | #undef MPARK_VARIANT_COPY_CONSTRUCTOR 1274 | 1275 | template 1276 | class assignment : public copy_constructor { 1277 | using super = copy_constructor; 1278 | 1279 | public: 1280 | MPARK_INHERITING_CTOR(assignment, super) 1281 | using super::operator=; 1282 | 1283 | template 1284 | inline /* auto & */ auto emplace(Args &&... args) 1285 | -> decltype(this->construct_alt(access::base::get_alt(*this), 1286 | lib::forward(args)...)) { 1287 | this->destroy(); 1288 | auto &result = this->construct_alt(access::base::get_alt(*this), 1289 | lib::forward(args)...); 1290 | this->index_ = I; 1291 | return result; 1292 | } 1293 | 1294 | protected: 1295 | #ifndef MPARK_GENERIC_LAMBDAS 1296 | template 1297 | struct assigner { 1298 | template 1299 | inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { 1300 | self->assign_alt(this_alt, lib::forward(that_alt).value); 1301 | } 1302 | assignment *self; 1303 | }; 1304 | #endif 1305 | 1306 | template 1307 | inline void assign_alt(alt &a, Arg &&arg) { 1308 | if (this->index() == I) { 1309 | #ifdef _MSC_VER 1310 | #pragma warning(push) 1311 | #pragma warning(disable : 4244) 1312 | #endif 1313 | a.value = lib::forward(arg); 1314 | #ifdef _MSC_VER 1315 | #pragma warning(pop) 1316 | #endif 1317 | } else { 1318 | struct { 1319 | void operator()(std::true_type) const { 1320 | this_->emplace(lib::forward(arg_)); 1321 | } 1322 | void operator()(std::false_type) const { 1323 | this_->emplace(T(lib::forward(arg_))); 1324 | } 1325 | assignment *this_; 1326 | Arg &&arg_; 1327 | } impl{this, lib::forward(arg)}; 1328 | impl(lib::bool_constant< 1329 | std::is_nothrow_constructible::value || 1330 | !std::is_nothrow_move_constructible::value>{}); 1331 | } 1332 | } 1333 | 1334 | template 1335 | inline void generic_assign(That &&that) { 1336 | if (this->valueless_by_exception() && that.valueless_by_exception()) { 1337 | // do nothing. 1338 | } else if (that.valueless_by_exception()) { 1339 | this->destroy(); 1340 | } else { 1341 | visitation::alt::visit_alt_at( 1342 | that.index(), 1343 | #ifdef MPARK_GENERIC_LAMBDAS 1344 | [this](auto &this_alt, auto &&that_alt) { 1345 | this->assign_alt( 1346 | this_alt, lib::forward(that_alt).value); 1347 | } 1348 | #else 1349 | assigner{this} 1350 | #endif 1351 | , 1352 | *this, 1353 | lib::forward(that)); 1354 | } 1355 | } 1356 | }; 1357 | 1358 | template 1359 | class move_assignment; 1360 | 1361 | #define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ 1362 | template \ 1363 | class move_assignment, move_assignable_trait> \ 1364 | : public assignment> { \ 1365 | using super = assignment>; \ 1366 | \ 1367 | public: \ 1368 | MPARK_INHERITING_CTOR(move_assignment, super) \ 1369 | using super::operator=; \ 1370 | \ 1371 | move_assignment(const move_assignment &) = default; \ 1372 | move_assignment(move_assignment &&) = default; \ 1373 | ~move_assignment() = default; \ 1374 | move_assignment &operator=(const move_assignment &) = default; \ 1375 | definition \ 1376 | } 1377 | 1378 | MPARK_VARIANT_MOVE_ASSIGNMENT( 1379 | Trait::TriviallyAvailable, 1380 | move_assignment &operator=(move_assignment &&that) = default;); 1381 | 1382 | MPARK_VARIANT_MOVE_ASSIGNMENT( 1383 | Trait::Available, 1384 | move_assignment & 1385 | operator=(move_assignment &&that) noexcept( 1386 | lib::all<(std::is_nothrow_move_constructible::value && 1387 | std::is_nothrow_move_assignable::value)...>::value) { 1388 | this->generic_assign(lib::move(that)); 1389 | return *this; 1390 | }); 1391 | 1392 | MPARK_VARIANT_MOVE_ASSIGNMENT( 1393 | Trait::Unavailable, 1394 | move_assignment &operator=(move_assignment &&) = delete;); 1395 | 1396 | #undef MPARK_VARIANT_MOVE_ASSIGNMENT 1397 | 1398 | template 1399 | class copy_assignment; 1400 | 1401 | #define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ 1402 | template \ 1403 | class copy_assignment, copy_assignable_trait> \ 1404 | : public move_assignment> { \ 1405 | using super = move_assignment>; \ 1406 | \ 1407 | public: \ 1408 | MPARK_INHERITING_CTOR(copy_assignment, super) \ 1409 | using super::operator=; \ 1410 | \ 1411 | copy_assignment(const copy_assignment &) = default; \ 1412 | copy_assignment(copy_assignment &&) = default; \ 1413 | ~copy_assignment() = default; \ 1414 | definition \ 1415 | copy_assignment &operator=(copy_assignment &&) = default; \ 1416 | } 1417 | 1418 | MPARK_VARIANT_COPY_ASSIGNMENT( 1419 | Trait::TriviallyAvailable, 1420 | copy_assignment &operator=(const copy_assignment &that) = default;); 1421 | 1422 | MPARK_VARIANT_COPY_ASSIGNMENT( 1423 | Trait::Available, 1424 | copy_assignment &operator=(const copy_assignment &that) { 1425 | this->generic_assign(that); 1426 | return *this; 1427 | }); 1428 | 1429 | MPARK_VARIANT_COPY_ASSIGNMENT( 1430 | Trait::Unavailable, 1431 | copy_assignment &operator=(const copy_assignment &) = delete;); 1432 | 1433 | #undef MPARK_VARIANT_COPY_ASSIGNMENT 1434 | 1435 | template 1436 | class impl : public copy_assignment> { 1437 | using super = copy_assignment>; 1438 | 1439 | public: 1440 | MPARK_INHERITING_CTOR(impl, super) 1441 | using super::operator=; 1442 | 1443 | impl(const impl&) = default; 1444 | impl(impl&&) = default; 1445 | ~impl() = default; 1446 | impl &operator=(const impl &) = default; 1447 | impl &operator=(impl &&) = default; 1448 | 1449 | template 1450 | inline void assign(Arg &&arg) { 1451 | this->assign_alt(access::base::get_alt(*this), 1452 | lib::forward(arg)); 1453 | } 1454 | 1455 | inline void swap(impl &that) { 1456 | if (this->valueless_by_exception() && that.valueless_by_exception()) { 1457 | // do nothing. 1458 | } else if (this->index() == that.index()) { 1459 | visitation::alt::visit_alt_at(this->index(), 1460 | #ifdef MPARK_GENERIC_LAMBDAS 1461 | [](auto &this_alt, auto &that_alt) { 1462 | using std::swap; 1463 | swap(this_alt.value, 1464 | that_alt.value); 1465 | } 1466 | #else 1467 | swapper{} 1468 | #endif 1469 | , 1470 | *this, 1471 | that); 1472 | } else { 1473 | impl *lhs = this; 1474 | impl *rhs = lib::addressof(that); 1475 | if (lhs->move_nothrow() && !rhs->move_nothrow()) { 1476 | std::swap(lhs, rhs); 1477 | } 1478 | impl tmp(lib::move(*rhs)); 1479 | #ifdef MPARK_EXCEPTIONS 1480 | // EXTENSION: When the move construction of `lhs` into `rhs` throws 1481 | // and `tmp` is nothrow move constructible then we move `tmp` back 1482 | // into `rhs` and provide the strong exception safety guarantee. 1483 | try { 1484 | this->generic_construct(*rhs, lib::move(*lhs)); 1485 | } catch (...) { 1486 | if (tmp.move_nothrow()) { 1487 | this->generic_construct(*rhs, lib::move(tmp)); 1488 | } 1489 | throw; 1490 | } 1491 | #else 1492 | this->generic_construct(*rhs, lib::move(*lhs)); 1493 | #endif 1494 | this->generic_construct(*lhs, lib::move(tmp)); 1495 | } 1496 | } 1497 | 1498 | private: 1499 | #ifndef MPARK_GENERIC_LAMBDAS 1500 | struct swapper { 1501 | template 1502 | inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { 1503 | using std::swap; 1504 | swap(this_alt.value, that_alt.value); 1505 | } 1506 | }; 1507 | #endif 1508 | 1509 | inline constexpr bool move_nothrow() const { 1510 | return this->valueless_by_exception() || 1511 | lib::array{ 1512 | {std::is_nothrow_move_constructible::value...} 1513 | }[this->index()]; 1514 | } 1515 | }; 1516 | 1517 | #undef MPARK_INHERITING_CTOR 1518 | 1519 | template 1520 | struct is_non_narrowing_convertible { 1521 | template 1522 | static std::true_type test(T(&&)[1]); 1523 | 1524 | template 1525 | static auto impl(int) -> decltype(test({std::declval()})); 1526 | 1527 | template 1528 | static auto impl(...) -> std::false_type; 1529 | 1530 | static constexpr bool value = decltype(impl(0))::value; 1531 | }; 1532 | 1533 | template ::value, 1537 | typename = void> 1538 | struct overload_leaf {}; 1539 | 1540 | template 1541 | struct overload_leaf { 1542 | using impl = lib::size_constant (*)(T); 1543 | operator impl() const { return nullptr; }; 1544 | }; 1545 | 1546 | template 1547 | struct overload_leaf< 1548 | Arg, 1549 | I, 1550 | T, 1551 | true 1552 | #if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5 1553 | , 1554 | lib::enable_if_t< 1555 | std::is_same, bool>::value 1556 | ? std::is_same, bool>::value 1557 | : is_non_narrowing_convertible::value> 1558 | #endif 1559 | > { 1560 | using impl = lib::size_constant (*)(T); 1561 | operator impl() const { return nullptr; }; 1562 | }; 1563 | 1564 | template 1565 | struct overload_impl { 1566 | private: 1567 | template 1568 | struct impl; 1569 | 1570 | template 1571 | struct impl> : overload_leaf... {}; 1572 | 1573 | public: 1574 | using type = impl>; 1575 | }; 1576 | 1577 | template 1578 | using overload = typename overload_impl::type; 1579 | 1580 | template 1581 | using best_match = lib::invoke_result_t, Arg>; 1582 | 1583 | template 1584 | struct is_in_place_index : std::false_type {}; 1585 | 1586 | template 1587 | struct is_in_place_index> : std::true_type {}; 1588 | 1589 | template 1590 | struct is_in_place_type : std::false_type {}; 1591 | 1592 | template 1593 | struct is_in_place_type> : std::true_type {}; 1594 | 1595 | } // detail 1596 | 1597 | template 1598 | class variant { 1599 | static_assert(0 < sizeof...(Ts), 1600 | "variant must consist of at least one alternative."); 1601 | 1602 | static_assert(lib::all::value...>::value, 1603 | "variant can not have an array type as an alternative."); 1604 | 1605 | static_assert(lib::all::value...>::value, 1606 | "variant can not have a reference type as an alternative."); 1607 | 1608 | static_assert(lib::all::value...>::value, 1609 | "variant can not have a void type as an alternative."); 1610 | 1611 | public: 1612 | template < 1613 | typename Front = lib::type_pack_element_t<0, Ts...>, 1614 | lib::enable_if_t::value, int> = 0> 1615 | inline constexpr variant() noexcept( 1616 | std::is_nothrow_default_constructible::value) 1617 | : impl_(in_place_index_t<0>{}) {} 1618 | 1619 | variant(const variant &) = default; 1620 | variant(variant &&) = default; 1621 | 1622 | template < 1623 | typename Arg, 1624 | typename Decayed = lib::decay_t, 1625 | lib::enable_if_t::value, int> = 0, 1626 | lib::enable_if_t::value, int> = 0, 1627 | lib::enable_if_t::value, int> = 0, 1628 | std::size_t I = detail::best_match::value, 1629 | typename T = lib::type_pack_element_t, 1630 | lib::enable_if_t::value, int> = 0> 1631 | inline constexpr variant(Arg &&arg) noexcept( 1632 | std::is_nothrow_constructible::value) 1633 | : impl_(in_place_index_t{}, lib::forward(arg)) {} 1634 | 1635 | template < 1636 | std::size_t I, 1637 | typename... Args, 1638 | typename T = lib::type_pack_element_t, 1639 | lib::enable_if_t::value, int> = 0> 1640 | inline explicit constexpr variant( 1641 | in_place_index_t, 1642 | Args &&... args) noexcept(std::is_nothrow_constructible::value) 1644 | : impl_(in_place_index_t{}, lib::forward(args)...) {} 1645 | 1646 | template < 1647 | std::size_t I, 1648 | typename Up, 1649 | typename... Args, 1650 | typename T = lib::type_pack_element_t, 1651 | lib::enable_if_t &, 1653 | Args...>::value, 1654 | int> = 0> 1655 | inline explicit constexpr variant( 1656 | in_place_index_t, 1657 | std::initializer_list il, 1658 | Args &&... args) noexcept(std:: 1659 | is_nothrow_constructible< 1660 | T, 1661 | std::initializer_list &, 1662 | Args...>::value) 1663 | : impl_(in_place_index_t{}, il, lib::forward(args)...) {} 1664 | 1665 | template < 1666 | typename T, 1667 | typename... Args, 1668 | std::size_t I = detail::find_index_sfinae::value, 1669 | lib::enable_if_t::value, int> = 0> 1670 | inline explicit constexpr variant( 1671 | in_place_type_t, 1672 | Args &&... args) noexcept(std::is_nothrow_constructible::value) 1674 | : impl_(in_place_index_t{}, lib::forward(args)...) {} 1675 | 1676 | template < 1677 | typename T, 1678 | typename Up, 1679 | typename... Args, 1680 | std::size_t I = detail::find_index_sfinae::value, 1681 | lib::enable_if_t &, 1683 | Args...>::value, 1684 | int> = 0> 1685 | inline explicit constexpr variant( 1686 | in_place_type_t, 1687 | std::initializer_list il, 1688 | Args &&... args) noexcept(std:: 1689 | is_nothrow_constructible< 1690 | T, 1691 | std::initializer_list &, 1692 | Args...>::value) 1693 | : impl_(in_place_index_t{}, il, lib::forward(args)...) {} 1694 | 1695 | ~variant() = default; 1696 | 1697 | variant &operator=(const variant &) = default; 1698 | variant &operator=(variant &&) = default; 1699 | 1700 | template , variant>::value, 1702 | int> = 0, 1703 | std::size_t I = detail::best_match::value, 1704 | typename T = lib::type_pack_element_t, 1705 | lib::enable_if_t<(std::is_assignable::value && 1706 | std::is_constructible::value), 1707 | int> = 0> 1708 | inline variant &operator=(Arg &&arg) noexcept( 1709 | (std::is_nothrow_assignable::value && 1710 | std::is_nothrow_constructible::value)) { 1711 | impl_.template assign(lib::forward(arg)); 1712 | return *this; 1713 | } 1714 | 1715 | template < 1716 | std::size_t I, 1717 | typename... Args, 1718 | typename T = lib::type_pack_element_t, 1719 | lib::enable_if_t::value, int> = 0> 1720 | inline T &emplace(Args &&... args) { 1721 | return impl_.template emplace(lib::forward(args)...); 1722 | } 1723 | 1724 | template < 1725 | std::size_t I, 1726 | typename Up, 1727 | typename... Args, 1728 | typename T = lib::type_pack_element_t, 1729 | lib::enable_if_t &, 1731 | Args...>::value, 1732 | int> = 0> 1733 | inline T &emplace(std::initializer_list il, Args &&... args) { 1734 | return impl_.template emplace(il, lib::forward(args)...); 1735 | } 1736 | 1737 | template < 1738 | typename T, 1739 | typename... Args, 1740 | std::size_t I = detail::find_index_sfinae::value, 1741 | lib::enable_if_t::value, int> = 0> 1742 | inline T &emplace(Args &&... args) { 1743 | return impl_.template emplace(lib::forward(args)...); 1744 | } 1745 | 1746 | template < 1747 | typename T, 1748 | typename Up, 1749 | typename... Args, 1750 | std::size_t I = detail::find_index_sfinae::value, 1751 | lib::enable_if_t &, 1753 | Args...>::value, 1754 | int> = 0> 1755 | inline T &emplace(std::initializer_list il, Args &&... args) { 1756 | return impl_.template emplace(il, lib::forward(args)...); 1757 | } 1758 | 1759 | inline constexpr bool valueless_by_exception() const noexcept { 1760 | return impl_.valueless_by_exception(); 1761 | } 1762 | 1763 | inline constexpr std::size_t index() const noexcept { 1764 | return impl_.index(); 1765 | } 1766 | 1767 | template , 1771 | Dummy>::value && 1772 | lib::dependent_type, 1773 | Dummy>::value)...>::value, 1774 | int> = 0> 1775 | inline void swap(variant &that) noexcept( 1776 | lib::all<(std::is_nothrow_move_constructible::value && 1777 | lib::is_nothrow_swappable::value)...>::value) { 1778 | impl_.swap(that.impl_); 1779 | } 1780 | 1781 | private: 1782 | detail::impl impl_; 1783 | 1784 | friend struct detail::access::variant; 1785 | friend struct detail::visitation::variant; 1786 | }; 1787 | 1788 | template 1789 | inline constexpr bool holds_alternative(const variant &v) noexcept { 1790 | return v.index() == I; 1791 | } 1792 | 1793 | template 1794 | inline constexpr bool holds_alternative(const variant &v) noexcept { 1795 | return holds_alternative::value>(v); 1796 | } 1797 | 1798 | namespace detail { 1799 | template 1800 | struct generic_get_impl { 1801 | constexpr generic_get_impl(int) noexcept {} 1802 | 1803 | constexpr AUTO_REFREF operator()(V &&v) const 1804 | AUTO_REFREF_RETURN( 1805 | access::variant::get_alt(lib::forward(v)).value) 1806 | }; 1807 | 1808 | template 1809 | inline constexpr AUTO_REFREF generic_get(V &&v) 1810 | AUTO_REFREF_RETURN(generic_get_impl( 1811 | holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))( 1812 | lib::forward(v))) 1813 | } // namespace detail 1814 | 1815 | template 1816 | inline constexpr variant_alternative_t> &get( 1817 | variant &v) { 1818 | return detail::generic_get(v); 1819 | } 1820 | 1821 | template 1822 | inline constexpr variant_alternative_t> &&get( 1823 | variant &&v) { 1824 | return detail::generic_get(lib::move(v)); 1825 | } 1826 | 1827 | template 1828 | inline constexpr const variant_alternative_t> &get( 1829 | const variant &v) { 1830 | return detail::generic_get(v); 1831 | } 1832 | 1833 | template 1834 | inline constexpr const variant_alternative_t> &&get( 1835 | const variant &&v) { 1836 | return detail::generic_get(lib::move(v)); 1837 | } 1838 | 1839 | template 1840 | inline constexpr T &get(variant &v) { 1841 | return get::value>(v); 1842 | } 1843 | 1844 | template 1845 | inline constexpr T &&get(variant &&v) { 1846 | return get::value>(lib::move(v)); 1847 | } 1848 | 1849 | template 1850 | inline constexpr const T &get(const variant &v) { 1851 | return get::value>(v); 1852 | } 1853 | 1854 | template 1855 | inline constexpr const T &&get(const variant &&v) { 1856 | return get::value>(lib::move(v)); 1857 | } 1858 | 1859 | namespace detail { 1860 | 1861 | template 1862 | inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept 1863 | AUTO_RETURN(v && holds_alternative(*v) 1864 | ? lib::addressof(access::variant::get_alt(*v).value) 1865 | : nullptr) 1866 | 1867 | } // namespace detail 1868 | 1869 | template 1870 | inline constexpr lib::add_pointer_t>> 1871 | get_if(variant *v) noexcept { 1872 | return detail::generic_get_if(v); 1873 | } 1874 | 1875 | template 1876 | inline constexpr lib::add_pointer_t< 1877 | const variant_alternative_t>> 1878 | get_if(const variant *v) noexcept { 1879 | return detail::generic_get_if(v); 1880 | } 1881 | 1882 | template 1883 | inline constexpr lib::add_pointer_t 1884 | get_if(variant *v) noexcept { 1885 | return get_if::value>(v); 1886 | } 1887 | 1888 | template 1889 | inline constexpr lib::add_pointer_t 1890 | get_if(const variant *v) noexcept { 1891 | return get_if::value>(v); 1892 | } 1893 | 1894 | namespace detail { 1895 | template 1896 | struct convert_to_bool { 1897 | template 1898 | inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { 1899 | static_assert(std::is_convertible, 1900 | bool>::value, 1901 | "relational operators must return a type" 1902 | " implicitly convertible to bool"); 1903 | return lib::invoke( 1904 | RelOp{}, lib::forward(lhs), lib::forward(rhs)); 1905 | } 1906 | }; 1907 | } // namespace detail 1908 | 1909 | template 1910 | inline constexpr bool operator==(const variant &lhs, 1911 | const variant &rhs) { 1912 | using detail::visitation::variant; 1913 | using equal_to = detail::convert_to_bool; 1914 | #ifdef MPARK_CPP14_CONSTEXPR 1915 | if (lhs.index() != rhs.index()) return false; 1916 | if (lhs.valueless_by_exception()) return true; 1917 | return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); 1918 | #else 1919 | return lhs.index() == rhs.index() && 1920 | (lhs.valueless_by_exception() || 1921 | variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); 1922 | #endif 1923 | } 1924 | 1925 | template 1926 | inline constexpr bool operator!=(const variant &lhs, 1927 | const variant &rhs) { 1928 | using detail::visitation::variant; 1929 | using not_equal_to = detail::convert_to_bool; 1930 | #ifdef MPARK_CPP14_CONSTEXPR 1931 | if (lhs.index() != rhs.index()) return true; 1932 | if (lhs.valueless_by_exception()) return false; 1933 | return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); 1934 | #else 1935 | return lhs.index() != rhs.index() || 1936 | (!lhs.valueless_by_exception() && 1937 | variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); 1938 | #endif 1939 | } 1940 | 1941 | template 1942 | inline constexpr bool operator<(const variant &lhs, 1943 | const variant &rhs) { 1944 | using detail::visitation::variant; 1945 | using less = detail::convert_to_bool; 1946 | #ifdef MPARK_CPP14_CONSTEXPR 1947 | if (rhs.valueless_by_exception()) return false; 1948 | if (lhs.valueless_by_exception()) return true; 1949 | if (lhs.index() < rhs.index()) return true; 1950 | if (lhs.index() > rhs.index()) return false; 1951 | return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); 1952 | #else 1953 | return !rhs.valueless_by_exception() && 1954 | (lhs.valueless_by_exception() || lhs.index() < rhs.index() || 1955 | (lhs.index() == rhs.index() && 1956 | variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); 1957 | #endif 1958 | } 1959 | 1960 | template 1961 | inline constexpr bool operator>(const variant &lhs, 1962 | const variant &rhs) { 1963 | using detail::visitation::variant; 1964 | using greater = detail::convert_to_bool; 1965 | #ifdef MPARK_CPP14_CONSTEXPR 1966 | if (lhs.valueless_by_exception()) return false; 1967 | if (rhs.valueless_by_exception()) return true; 1968 | if (lhs.index() > rhs.index()) return true; 1969 | if (lhs.index() < rhs.index()) return false; 1970 | return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); 1971 | #else 1972 | return !lhs.valueless_by_exception() && 1973 | (rhs.valueless_by_exception() || lhs.index() > rhs.index() || 1974 | (lhs.index() == rhs.index() && 1975 | variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); 1976 | #endif 1977 | } 1978 | 1979 | template 1980 | inline constexpr bool operator<=(const variant &lhs, 1981 | const variant &rhs) { 1982 | using detail::visitation::variant; 1983 | using less_equal = detail::convert_to_bool; 1984 | #ifdef MPARK_CPP14_CONSTEXPR 1985 | if (lhs.valueless_by_exception()) return true; 1986 | if (rhs.valueless_by_exception()) return false; 1987 | if (lhs.index() < rhs.index()) return true; 1988 | if (lhs.index() > rhs.index()) return false; 1989 | return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); 1990 | #else 1991 | return lhs.valueless_by_exception() || 1992 | (!rhs.valueless_by_exception() && 1993 | (lhs.index() < rhs.index() || 1994 | (lhs.index() == rhs.index() && 1995 | variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); 1996 | #endif 1997 | } 1998 | 1999 | template 2000 | inline constexpr bool operator>=(const variant &lhs, 2001 | const variant &rhs) { 2002 | using detail::visitation::variant; 2003 | using greater_equal = detail::convert_to_bool; 2004 | #ifdef MPARK_CPP14_CONSTEXPR 2005 | if (rhs.valueless_by_exception()) return true; 2006 | if (lhs.valueless_by_exception()) return false; 2007 | if (lhs.index() > rhs.index()) return true; 2008 | if (lhs.index() < rhs.index()) return false; 2009 | return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); 2010 | #else 2011 | return rhs.valueless_by_exception() || 2012 | (!lhs.valueless_by_exception() && 2013 | (lhs.index() > rhs.index() || 2014 | (lhs.index() == rhs.index() && 2015 | variant::visit_value_at( 2016 | lhs.index(), greater_equal{}, lhs, rhs)))); 2017 | #endif 2018 | } 2019 | 2020 | struct monostate {}; 2021 | 2022 | inline constexpr bool operator<(monostate, monostate) noexcept { 2023 | return false; 2024 | } 2025 | 2026 | inline constexpr bool operator>(monostate, monostate) noexcept { 2027 | return false; 2028 | } 2029 | 2030 | inline constexpr bool operator<=(monostate, monostate) noexcept { 2031 | return true; 2032 | } 2033 | 2034 | inline constexpr bool operator>=(monostate, monostate) noexcept { 2035 | return true; 2036 | } 2037 | 2038 | inline constexpr bool operator==(monostate, monostate) noexcept { 2039 | return true; 2040 | } 2041 | 2042 | inline constexpr bool operator!=(monostate, monostate) noexcept { 2043 | return false; 2044 | } 2045 | 2046 | #ifdef MPARK_CPP14_CONSTEXPR 2047 | namespace detail { 2048 | 2049 | inline constexpr bool any(std::initializer_list bs) { 2050 | for (bool b : bs) { 2051 | if (b) { 2052 | return true; 2053 | } 2054 | } 2055 | return false; 2056 | } 2057 | 2058 | } // namespace detail 2059 | 2060 | template 2061 | inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { 2062 | return (!detail::any({vs.valueless_by_exception()...}) 2063 | ? (void)0 2064 | : throw_bad_variant_access()), 2065 | detail::visitation::variant::visit_value( 2066 | lib::forward(visitor), lib::forward(vs)...); 2067 | } 2068 | #else 2069 | namespace detail { 2070 | 2071 | template 2072 | inline constexpr bool all_impl(const lib::array &bs, 2073 | std::size_t idx) { 2074 | return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); 2075 | } 2076 | 2077 | template 2078 | inline constexpr bool all(const lib::array &bs) { 2079 | return all_impl(bs, 0); 2080 | } 2081 | 2082 | } // namespace detail 2083 | 2084 | template 2085 | inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) 2086 | DECLTYPE_AUTO_RETURN( 2087 | (detail::all( 2088 | lib::array{{!vs.valueless_by_exception()...}}) 2089 | ? (void)0 2090 | : throw_bad_variant_access()), 2091 | detail::visitation::variant::visit_value(lib::forward(visitor), 2092 | lib::forward(vs)...)) 2093 | #endif 2094 | 2095 | template 2096 | inline auto swap(variant &lhs, 2097 | variant &rhs) noexcept(noexcept(lhs.swap(rhs))) 2098 | -> decltype(lhs.swap(rhs)) { 2099 | lhs.swap(rhs); 2100 | } 2101 | 2102 | namespace detail { 2103 | 2104 | template 2105 | using enabled_type = T; 2106 | 2107 | namespace hash { 2108 | 2109 | template 2110 | constexpr bool meets_requirements() noexcept { 2111 | return std::is_copy_constructible::value && 2112 | std::is_move_constructible::value && 2113 | lib::is_invocable_r::value; 2114 | } 2115 | 2116 | template 2117 | constexpr bool is_enabled() noexcept { 2118 | using H = std::hash; 2119 | return meets_requirements() && 2120 | std::is_default_constructible::value && 2121 | std::is_copy_assignable::value && 2122 | std::is_move_assignable::value; 2123 | } 2124 | 2125 | } // namespace hash 2126 | 2127 | } // namespace detail 2128 | 2129 | #undef AUTO 2130 | #undef AUTO_RETURN 2131 | 2132 | #undef AUTO_REFREF 2133 | #undef AUTO_REFREF_RETURN 2134 | 2135 | #undef DECLTYPE_AUTO 2136 | #undef DECLTYPE_AUTO_RETURN 2137 | 2138 | } // namespace mpark 2139 | 2140 | namespace std { 2141 | 2142 | template 2143 | struct hash, 2145 | mpark::lib::enable_if_t>()...>::value>>> { 2147 | using argument_type = mpark::variant; 2148 | using result_type = std::size_t; 2149 | 2150 | inline result_type operator()(const argument_type &v) const { 2151 | using mpark::detail::visitation::variant; 2152 | std::size_t result = 2153 | v.valueless_by_exception() 2154 | ? 299792458 // Random value chosen by the universe upon creation 2155 | : variant::visit_alt( 2156 | #ifdef MPARK_GENERIC_LAMBDAS 2157 | [](const auto &alt) { 2158 | using alt_type = mpark::lib::decay_t; 2159 | using value_type = mpark::lib::remove_const_t< 2160 | typename alt_type::value_type>; 2161 | return hash{}(alt.value); 2162 | } 2163 | #else 2164 | hasher{} 2165 | #endif 2166 | , 2167 | v); 2168 | return hash_combine(result, hash{}(v.index())); 2169 | } 2170 | 2171 | private: 2172 | #ifndef MPARK_GENERIC_LAMBDAS 2173 | struct hasher { 2174 | template 2175 | inline std::size_t operator()(const Alt &alt) const { 2176 | using alt_type = mpark::lib::decay_t; 2177 | using value_type = 2178 | mpark::lib::remove_const_t; 2179 | return hash{}(alt.value); 2180 | } 2181 | }; 2182 | #endif 2183 | 2184 | static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { 2185 | return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); 2186 | } 2187 | }; 2188 | 2189 | template <> 2190 | struct hash { 2191 | using argument_type = mpark::monostate; 2192 | using result_type = std::size_t; 2193 | 2194 | inline result_type operator()(const argument_type &) const noexcept { 2195 | return 66740831; // return a fundamentally attractive random value. 2196 | } 2197 | }; 2198 | 2199 | } // namespace std 2200 | 2201 | #endif // MPARK_VARIANT_HPP 2202 | -------------------------------------------------------------------------------- /support/ninja.py: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | # 3 | # Copyright Michael Park, 2015-2017 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | import os 9 | import pprint 10 | import subprocess 11 | 12 | result = {} 13 | 14 | std_flags = os.getenv('STDFLAGS') 15 | for std_flag in std_flags.split() if std_flags is not None else ['']: 16 | os.environ['CXXFLAGS'] = std_flag 17 | for exceptions in ['OFF', 'ON']: 18 | for build_type in ['Debug', 'Release']: 19 | config = '{}-{}-{}'.format( 20 | filter(str.isalnum, std_flag), exceptions, build_type) 21 | build_dir = 'build-{}'.format(config) 22 | os.mkdir(build_dir) 23 | os.chdir(build_dir) 24 | result[config] = { 'Configure': None, 'Build': None, 'Test': None } 25 | 26 | tests = os.environ['TESTS'].split() 27 | if std_flag.endswith(('11', '1y', '14', '1z')) and 'libc++' in tests: 28 | tests.remove('libc++') 29 | 30 | result[config]['Configure'] = subprocess.call([ 31 | 'cmake', '-GNinja', 32 | '-DCMAKE_BUILD_TYPE={}'.format(build_type), 33 | '-DMPARK_VARIANT_EXCEPTIONS={}'.format(exceptions), 34 | '-DMPARK_VARIANT_INCLUDE_TESTS={}'.format(';'.join(tests)), 35 | '..', 36 | ]) 37 | if result[config]['Configure'] == 0: 38 | result[config]['Build'] = subprocess.call([ 39 | 'cmake', '--build', '.', '--', '-k', '0']) 40 | if result[config]['Build'] == 0: 41 | result[config]['Test'] = subprocess.call([ 42 | 'ctest', '--output-on-failure']) 43 | os.chdir('..') 44 | 45 | pprint.pprint(result) 46 | exit(any(status != 0 for d in result.itervalues() for status in d.itervalues())) 47 | -------------------------------------------------------------------------------- /support/single-header.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # MPark.Variant 4 | # 5 | # Copyright Michael Park, 2017 6 | # 7 | # Distributed under the Boost Software License, Version 1.0. 8 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | 10 | import os.path 11 | import re 12 | import subprocess 13 | import sys 14 | 15 | # Prints a single header version of `include/mpark/variant.hpp` to stdout. 16 | 17 | processed = [] 18 | 19 | def process(header): 20 | result = '' 21 | with open(header, 'r') as f: 22 | for line in f: 23 | p = re.compile('^#include "(.+)"') 24 | m = p.match(line) 25 | if m is None: 26 | result += line 27 | else: 28 | g = m.group(1) 29 | include = os.path.normpath(os.path.join(os.path.dirname(header), g)) 30 | if include not in processed: 31 | result += process(include) 32 | result += '\n' 33 | processed.append(include) 34 | return result 35 | 36 | root = subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).strip() 37 | result = process(os.path.join(root, 'include/mpark/variant.hpp')) 38 | 39 | sys.stdout.write(result) 40 | -------------------------------------------------------------------------------- /support/vs.py: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | # 3 | # Copyright Michael Park, 2015-2017 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | import os 9 | import pprint 10 | import subprocess 11 | 12 | result = {} 13 | 14 | std_flags = os.getenv('STDFLAGS') 15 | for std_flag in std_flags.split() if std_flags is not None else ['']: 16 | os.environ['CXXFLAGS'] = std_flag 17 | for exceptions in ['OFF', 'ON']: 18 | config = '{}-{}'.format(filter(str.isalnum, std_flag), exceptions) 19 | build_dir = 'build-{}'.format(config) 20 | os.mkdir(build_dir) 21 | os.chdir(build_dir) 22 | result[config] = { 23 | 'Configure': None, 24 | 'Build-Debug': None, 25 | 'Build-Release': None, 26 | 'Test-Debug': None, 27 | 'Test-Release': None 28 | } 29 | 30 | tests = os.environ['TESTS'].split() 31 | if std_flag.endswith(('11', '1y', '14', '1z')) and 'libc++' in tests: 32 | tests.remove('libc++') 33 | 34 | configure = [ 35 | 'cmake', '-G', os.environ['GENERATOR'], 36 | '-DMPARK_VARIANT_EXCEPTIONS={}'.format(exceptions), 37 | '-DMPARK_VARIANT_INCLUDE_TESTS={}'.format(';'.join(tests)), 38 | '..', 39 | ] 40 | result[config]['Configure'] = subprocess.call(configure) 41 | if result[config]['Configure'] == 0: 42 | for build_type in ['Debug', 'Release']: 43 | result[config]['Build-{}'.format(build_type)] = subprocess.call([ 44 | 'cmake', '--build', '.', '--config', build_type]) 45 | if result[config]['Build-{}'.format(build_type)] == 0: 46 | result[config]['Test-{}'.format(build_type)] = subprocess.call([ 47 | 'ctest', '--output-on-failure', '--build-config', build_type]) 48 | os.chdir('..') 49 | 50 | pprint.pprint(result) 51 | exit(any(status != 0 for d in result.itervalues() for status in d.itervalues())) 52 | -------------------------------------------------------------------------------- /support/wandbox.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | int main() { 15 | std::vector> vs = { 101, "+", 202, "==", 303 }; 16 | for (const auto& v : vs) { 17 | mpark::visit([](const auto& x) { std::cout << x << ' '; }, v); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /support/wandbox.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # MPark.Variant 4 | # 5 | # This script uploads a directory to Wandbox (http://melpon.org/wandbox), 6 | # which is an online compiler environment, and prints a permalink to the 7 | # uploaded code. We use this to provide a "Try it online" version of the 8 | # library to make the barrier to entry as low as possible. 9 | # 10 | # This script was adapted from the script proposed in 11 | # https://github.com/melpon/wandbox/issues/153. 12 | # 13 | # To know how to use this script: ./wandbox.py --help 14 | # 15 | # Copyright Louis Dionne 2015 16 | # 17 | # Distributed under the Boost Software License, Version 1.0. 18 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 19 | # 20 | # Copyright Michael Park, 2017 21 | # 22 | # Distributed under the Boost Software License, Version 1.0. 23 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 24 | 25 | import argparse 26 | import fnmatch 27 | import json 28 | import os 29 | import re 30 | import urllib2 31 | 32 | # Post the given JSON data to Wandbox's API, and return the result 33 | # as a JSON object. 34 | def upload(options): 35 | request = urllib2.Request('http://melpon.org/wandbox/api/compile.json') 36 | request.add_header('Content-Type', 'application/json') 37 | response = urllib2.urlopen(request, json.dumps(options)) 38 | return json.loads(response.read()) 39 | 40 | # Returns a list of the '.hpp' headers in the given directory and in 41 | # subdirectories. 42 | # 43 | # The path must be absolute, and the returned paths are all absolute too. 44 | def headers(path): 45 | return [ 46 | os.path.join(dir, file) 47 | for (dir, _, files) in os.walk(path) 48 | for file in fnmatch.filter(files, "*.hpp") 49 | ] 50 | 51 | def main(): 52 | parser = argparse.ArgumentParser(description= 53 | """Upload a directory to Wandbox (http://melpon.org/wandbox). 54 | 55 | On success, the program prints a permalink to the uploaded 56 | directory on Wandbox and returns 0. On error, it prints the 57 | response from the Wandbox API and returns 1. 58 | 59 | Note that the comments are stripped from all the headers in the 60 | uploaded directory. 61 | """ 62 | ) 63 | parser.add_argument('directory', type=str, help= 64 | """A directory to upload to Wandbox. 65 | 66 | The path may be either absolute or relative to the current directory. 67 | However, the names of the files uploaded to Wandbox will all be 68 | relative to this directory. This way, one can easily specify the 69 | directory to be '/some/project/include', and the uploaded files 70 | will be uploaded as-if they were rooted at '/some/project/include' 71 | """) 72 | parser.add_argument('main', type=str, help= 73 | """The main source file. 74 | 75 | The path may be either absolute or relative to the current directory. 76 | """ 77 | ) 78 | args = parser.parse_args() 79 | directory = os.path.abspath(args.directory) 80 | if not os.path.exists(directory): 81 | raise Exception("'%s' is not a valid directory" % args.directory) 82 | 83 | cpp = os.path.abspath(args.main) 84 | if not os.path.exists(cpp): 85 | raise Exception("'%s' is not a valid file name" % args.main) 86 | 87 | response = upload({ 88 | 'code': open(cpp).read().strip(), 89 | 'codes': [{ 90 | 'file': os.path.relpath(header, directory).replace('\\', '/'), 91 | 'code': open(header).read().strip() 92 | } for header in headers(directory)], 93 | 'options': 'warning,optimize,c++14', 94 | 'compiler': 'clang-7.0.0', 95 | 'save': True, 96 | 'compiler-option-raw': '-I.' 97 | }) 98 | 99 | if response['status'] == '0': 100 | print response['url'] 101 | return 0 102 | else: 103 | print response 104 | return 1 105 | 106 | exit(main()) 107 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | # 3 | # Copyright Michael Park, 2015-2017 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | cmake_minimum_required(VERSION 3.6.3) 9 | 10 | option(MPARK_VARIANT_EXCEPTIONS 11 | "Build the tests with exceptions support." ON) 12 | 13 | if(MPARK_VARIANT_INCLUDE_MPARK_TESTS) 14 | 15 | add_definitions(-DGTEST_HAS_TR1_TUPLE=0) 16 | add_definitions(-DGTEST_HAS_STD_TUPLE=1) 17 | 18 | add_subdirectory(${CMAKE_SOURCE_DIR}/3rdparty/googletest 19 | ${CMAKE_BINARY_DIR}/3rdparty/googletest) 20 | 21 | config_compiler_and_linker() 22 | 23 | if(MPARK_VARIANT_EXCEPTIONS) 24 | set(compile_flags ${cxx_strict}) 25 | else() 26 | set(compile_flags ${cxx_no_exception}) 27 | endif() 28 | 29 | if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR 30 | (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) 31 | set(compile_flags "${compile_flags} /wd4577") 32 | endif() 33 | 34 | set(MPARK_TESTS 35 | assign.copy 36 | assign.fwd 37 | assign.move 38 | ctor.copy 39 | ctor.default 40 | ctor.fwd 41 | ctor.in_place 42 | ctor.move 43 | dtor 44 | get 45 | hash 46 | intro 47 | issue 48 | json 49 | mod 50 | relops 51 | swap 52 | visit) 53 | 54 | foreach(test ${MPARK_TESTS}) 55 | add_executable(${test} ${test}.cpp) 56 | set_target_properties(${test} PROPERTIES COMPILE_FLAGS "${compile_flags}") 57 | target_link_libraries(${test} gtest_main mpark_variant) 58 | add_test(${test} ${test} --gtest_color=yes) 59 | endforeach() 60 | 61 | endif() 62 | 63 | if(MPARK_VARIANT_INCLUDE_LIBCXX_TESTS) 64 | 65 | include(ExternalProject) 66 | 67 | set(MPARK_VARIANT_LLVM_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/llvm) 68 | set(MPARK_VARIANT_LLVM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/llvm-build) 69 | 70 | ExternalProject_Add(llvm 71 | GIT_REPOSITORY https://git.llvm.org/git/llvm.git 72 | GIT_SHALLOW 1 73 | CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release 74 | -DCMAKE_CXX_FLAGS="-w" 75 | -DLIBCXX_ENABLE_EXCEPTIONS=${MPARK_VARIANT_EXCEPTIONS} 76 | SOURCE_DIR ${MPARK_VARIANT_LLVM_SOURCE_DIR} 77 | BINARY_DIR ${MPARK_VARIANT_LLVM_BINARY_DIR} 78 | BUILD_COMMAND ${CMAKE_COMMAND} --build . --target cxx 79 | COMMAND ${CMAKE_COMMAND} --build . --target cxxabi 80 | COMMAND ${CMAKE_COMMAND} --build . --target cxx_experimental 81 | INSTALL_COMMAND "" # Disable install step 82 | STEP_TARGETS download 83 | ) 84 | 85 | set(MPARK_VARIANT_LIBCXX_SOURCE_DIR ${MPARK_VARIANT_LLVM_SOURCE_DIR}/projects/libcxx) 86 | set(MPARK_VARIANT_LIBCXX_BINARY_DIR ${MPARK_VARIANT_LLVM_BINARY_DIR}/projects/libcxx) 87 | 88 | ExternalProject_Add(libcxx-download 89 | GIT_REPOSITORY https://git.llvm.org/git/libcxx.git 90 | GIT_SHALLOW 1 91 | DEPENDS llvm-download 92 | SOURCE_DIR ${MPARK_VARIANT_LIBCXX_SOURCE_DIR} 93 | BINARY_DIR ${MPARK_VARIANT_LIBCXX_BINARY_DIR} 94 | CONFIGURE_COMMAND "" # Disable configure step 95 | BUILD_COMMAND "" # Disable build step 96 | INSTALL_COMMAND "" # Disable install step 97 | ) 98 | 99 | set(MPARK_VARIANT_LIBCXXABI_SOURCE_DIR ${MPARK_VARIANT_LLVM_SOURCE_DIR}/projects/libcxxabi) 100 | set(MPARK_VARIANT_LIBCXXABI_BINARY_DIR ${MPARK_VARIANT_LLVM_BINARY_DIR}/projects/libcxxabi) 101 | 102 | ExternalProject_Add(libcxxabi-download 103 | GIT_REPOSITORY https://git.llvm.org/git/libcxxabi.git 104 | GIT_SHALLOW 1 105 | DEPENDS llvm-download 106 | SOURCE_DIR ${MPARK_VARIANT_LIBCXXABI_SOURCE_DIR} 107 | BINARY_DIR ${MPARK_VARIANT_LIBCXXABI_BINARY_DIR} 108 | CONFIGURE_COMMAND "" # Disable configure step 109 | BUILD_COMMAND "" # Disable build step 110 | INSTALL_COMMAND "" # Disable install step 111 | ) 112 | 113 | ExternalProject_Add_StepDependencies(llvm configure libcxx-download libcxxabi-download) 114 | 115 | add_test(libcxx 116 | ${CMAKE_COMMAND} -E 117 | env MPARK_VARIANT_CXX_COMPILER=${CMAKE_CXX_COMPILER} 118 | env MPARK_VARIANT_SOURCE_DIR=${CMAKE_SOURCE_DIR} 119 | env MPARK_VARIANT_LIBCXX_SOURCE_DIR=${MPARK_VARIANT_LIBCXX_SOURCE_DIR} 120 | env MPARK_VARIANT_LIBCXX_SITE_CONFIG=${MPARK_VARIANT_LIBCXX_BINARY_DIR}/test/lit.site.cfg 121 | env MPARK_VARIANT_LIT=${MPARK_VARIANT_LLVM_BINARY_DIR}/bin/llvm-lit 122 | ${CMAKE_CURRENT_SOURCE_DIR}/libcxx.sh 123 | ) 124 | 125 | endif() 126 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | 3 | > __C++17__ `std::variant` for __C++11__/__14__/__17__ 4 | 5 | [![release][badge.release]][release] 6 | [![header][badge.header]][header] 7 | [![travis][badge.travis]][travis] 8 | [![appveyor][badge.appveyor]][appveyor] 9 | [![license][badge.license]][license] 10 | [![godbolt][badge.godbolt]][godbolt] 11 | [![wandbox][badge.wandbox]][wandbox] 12 | 13 | [badge.release]: https://img.shields.io/github/release/mpark/variant.svg 14 | [badge.header]: https://img.shields.io/badge/single%20header-master-blue.svg 15 | [badge.travis]: https://travis-ci.org/mpark/variant.svg?branch=master 16 | [badge.appveyor]: https://ci.appveyor.com/api/projects/status/github/mpark/variant?branch=master&svg=true 17 | [badge.license]: https://img.shields.io/badge/license-boost-blue.svg 18 | [badge.godbolt]: https://img.shields.io/badge/try%20it-on%20godbolt-222266.svg 19 | [badge.wandbox]: https://img.shields.io/badge/try%20it-on%20wandbox-5cb85c.svg 20 | 21 | [release]: https://github.com/mpark/variant/releases/latest 22 | [header]: https://github.com/mpark/variant/blob/single-header/master/variant.hpp 23 | [travis]: https://travis-ci.org/mpark/variant 24 | [appveyor]: https://ci.appveyor.com/project/mpark/variant 25 | [license]: https://github.com/mpark/variant/blob/master/LICENSE.md 26 | [godbolt]: https://godbolt.org/z/4r7hEy 27 | [wandbox]: https://wandbox.org/permlink/dTZxf85MVhehOqx1 28 | 29 | ## Test 30 | 31 | This directory contains the tests for __MPark.Variant__. 32 | 33 | ## CMake Variables 34 | 35 | - __`MPARK_VARIANT_EXCEPTIONS`__:`BOOL` (__default__: `ON`) 36 | 37 | Build the tests with exceptions support. 38 | 39 | ## Build / Run 40 | 41 | Execute the following commands from the top-level directory: 42 | 43 | ```bash 44 | mkdir build 45 | cd build 46 | cmake -DMPARK_VARIANT_INCLUDE_TESTS="mpark;libc++" .. 47 | cmake --build . 48 | ctest --output-on-failure 49 | ``` 50 | -------------------------------------------------------------------------------- /test/assign.copy.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include "util.hpp" 13 | 14 | TEST(Assign_Copy, SameType) { 15 | struct Obj { 16 | constexpr Obj() {} 17 | Obj(const Obj &) noexcept { EXPECT_TRUE(false); } 18 | Obj(Obj &&) = default; 19 | Obj &operator=(const Obj &) noexcept { EXPECT_TRUE(true); return *this; } 20 | Obj &operator=(Obj &&) = delete; 21 | }; 22 | // `v`, `w`. 23 | mpark::variant v, w; 24 | // copy assignment. 25 | v = w; 26 | } 27 | 28 | TEST(Assign_Copy, DiffType) { 29 | struct Obj { 30 | constexpr Obj() {} 31 | Obj(const Obj &) noexcept { EXPECT_TRUE(true); } 32 | Obj(Obj &&) = default; 33 | Obj &operator=(const Obj &) noexcept { EXPECT_TRUE(false); return *this; } 34 | Obj &operator=(Obj &&) = delete; 35 | }; 36 | // `v`, `w`. 37 | mpark::variant v(42), w; 38 | // copy assignment. 39 | v = w; 40 | } 41 | 42 | #ifdef MPARK_EXCEPTIONS 43 | TEST(Assign_Copy, ValuelessByException) { 44 | mpark::variant v(42); 45 | EXPECT_THROW(v = move_thrower_t{}, MoveConstruction); 46 | EXPECT_TRUE(v.valueless_by_exception()); 47 | mpark::variant w(42); 48 | w = v; 49 | EXPECT_TRUE(w.valueless_by_exception()); 50 | } 51 | #endif 52 | -------------------------------------------------------------------------------- /test/assign.fwd.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "util.hpp" 17 | 18 | TEST(Assign_Fwd, SameType) { 19 | mpark::variant v(101); 20 | EXPECT_EQ(101, mpark::get(v)); 21 | v = 202; 22 | EXPECT_EQ(202, mpark::get(v)); 23 | } 24 | 25 | TEST(Assign_Fwd, DiffType) { 26 | mpark::variant v(42); 27 | EXPECT_EQ(42, mpark::get(v)); 28 | v = "42"; 29 | EXPECT_EQ("42", mpark::get(v)); 30 | } 31 | 32 | TEST(Assign_Fwd, ExactMatch) { 33 | mpark::variant v; 34 | v = std::string("hello"); 35 | EXPECT_EQ("hello", mpark::get(v)); 36 | } 37 | 38 | TEST(Assign_Fwd, BetterMatch) { 39 | mpark::variant v; 40 | // `char` -> `int` is better than `char` -> `double` 41 | v = 'x'; 42 | EXPECT_EQ(static_cast('x'), mpark::get(v)); 43 | } 44 | 45 | TEST(Assign_Fwd, NoMatch) { 46 | struct x {}; 47 | static_assert(!std::is_assignable, x>{}, 48 | "variant v; v = x;"); 49 | } 50 | 51 | TEST(Assign_Fwd, WideningOrAmbiguous) { 52 | #if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5 53 | static_assert(std::is_assignable, int>{}, 54 | "variant v; v = 42;"); 55 | #else 56 | static_assert(!std::is_assignable, int>{}, 57 | "variant v; v = 42;"); 58 | #endif 59 | } 60 | 61 | TEST(Assign_Fwd, SameTypeOptimization) { 62 | mpark::variant v("hello world!"); 63 | // Check `v`. 64 | const std::string &x = mpark::get(v); 65 | EXPECT_EQ("hello world!", x); 66 | // Save the "hello world!"'s capacity. 67 | auto capacity = x.capacity(); 68 | // Use `std::string::operator=(const char *)` to assign into `v`. 69 | v = "hello"; 70 | // Check `v`. 71 | const std::string &y = mpark::get(v); 72 | EXPECT_EQ("hello", y); 73 | // Since "hello" is shorter than "hello world!", we should have preserved the 74 | // existing capacity of the string!. 75 | EXPECT_EQ(capacity, y.capacity()); 76 | } 77 | 78 | #ifdef MPARK_EXCEPTIONS 79 | TEST(Assign_Fwd, ThrowOnAssignment) { 80 | mpark::variant v( 81 | mpark::in_place_type_t{}); 82 | // Since `variant` is already in `move_thrower_t`, assignment optimization 83 | // kicks and we simply invoke 84 | // `move_thrower_t &operator=(move_thrower_t &&);` which throws. 85 | EXPECT_THROW(v = move_thrower_t{}, MoveAssignment); 86 | EXPECT_FALSE(v.valueless_by_exception()); 87 | EXPECT_EQ(1u, v.index()); 88 | // We can still assign into a variant in an invalid state. 89 | v = 42; 90 | // Check `v`. 91 | EXPECT_FALSE(v.valueless_by_exception()); 92 | EXPECT_EQ(42, mpark::get(v)); 93 | } 94 | #endif 95 | 96 | #if 0 97 | TEST(Assign_Fwd, ThrowOnTemporaryConstruction) { 98 | mpark::variant v(42); 99 | // Since `copy_thrower_t`'s copy constructor always throws, we will fail to 100 | // construct the variant. This results in our variant staying in 101 | // its original state. 102 | copy_thrower_t copy_thrower{}; 103 | EXPECT_THROW(v = copy_thrower, CopyConstruction); 104 | EXPECT_FALSE(v.valueless_by_exception()); 105 | EXPECT_EQ(0u, v.index()); 106 | EXPECT_EQ(42, mpark::get(v)); 107 | } 108 | 109 | TEST(Assign_Fwd, ThrowOnVariantConstruction) { 110 | mpark::variant v(42); 111 | // Since `move_thrower_t`'s copy constructor never throws, we successfully 112 | // construct the temporary object by copying `move_thrower_t`. We then 113 | // proceed to move the temporary object into our variant, at which point 114 | // `move_thrower_t`'s move constructor throws. This results in our `variant` 115 | // transitioning into the invalid state. 116 | move_thrower_t move_thrower; 117 | EXPECT_THROW(v = move_thrower, MoveConstruction); 118 | EXPECT_TRUE(v.valueless_by_exception()); 119 | // We can still assign into a variant in an invalid state. 120 | v = 42; 121 | // Check `v`. 122 | EXPECT_FALSE(v.valueless_by_exception()); 123 | EXPECT_EQ(42, mpark::get(v)); 124 | } 125 | #endif 126 | -------------------------------------------------------------------------------- /test/assign.move.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include "util.hpp" 13 | 14 | namespace lib = mpark::lib; 15 | 16 | TEST(Assign_Move, SameType) { 17 | struct Obj { 18 | constexpr Obj() {} 19 | Obj(const Obj &) = delete; 20 | Obj(Obj &&) noexcept { EXPECT_TRUE(false); } 21 | Obj &operator=(const Obj &) = delete; 22 | Obj &operator=(Obj &&) noexcept { EXPECT_TRUE(true); return *this; } 23 | }; 24 | // `v`, `w`. 25 | mpark::variant v, w; 26 | // move assignment. 27 | v = lib::move(w); 28 | } 29 | 30 | TEST(Assign_Move, DiffType) { 31 | struct Obj { 32 | constexpr Obj() {} 33 | Obj(const Obj &) = delete; 34 | Obj(Obj &&) noexcept { EXPECT_TRUE(true); } 35 | Obj &operator=(const Obj &) = delete; 36 | Obj &operator=(Obj &&) noexcept { EXPECT_TRUE(false); return *this; } 37 | }; 38 | // `v`, `w`. 39 | mpark::variant v(42), w; 40 | // move assignment. 41 | v = lib::move(w); 42 | } 43 | 44 | #ifdef MPARK_EXCEPTIONS 45 | TEST(Assign_Move, ValuelessByException) { 46 | mpark::variant v(42); 47 | EXPECT_THROW(v = move_thrower_t{}, MoveConstruction); 48 | EXPECT_TRUE(v.valueless_by_exception()); 49 | mpark::variant w(42); 50 | w = lib::move(v); 51 | EXPECT_TRUE(w.valueless_by_exception()); 52 | } 53 | #endif 54 | -------------------------------------------------------------------------------- /test/ctor.copy.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include "util.hpp" 15 | 16 | TEST(Ctor_Copy, Value) { 17 | // `v` 18 | mpark::variant v("hello"); 19 | EXPECT_EQ("hello", mpark::get(v)); 20 | // `w` 21 | mpark::variant w(v); 22 | EXPECT_EQ("hello", mpark::get(w)); 23 | // Check `v` 24 | EXPECT_EQ("hello", mpark::get(v)); 25 | 26 | /* constexpr */ { 27 | // `cv` 28 | constexpr mpark::variant cv(42); 29 | static_assert(42 == mpark::get(cv), ""); 30 | // `cw` 31 | constexpr mpark::variant cw(cv); 32 | static_assert(42 == mpark::get(cw), ""); 33 | } 34 | } 35 | 36 | #ifdef MPARK_EXCEPTIONS 37 | TEST(Ctor_Copy, ValuelessByException) { 38 | mpark::variant v(42); 39 | EXPECT_THROW(v = move_thrower_t{}, MoveConstruction); 40 | EXPECT_TRUE(v.valueless_by_exception()); 41 | mpark::variant w(v); 42 | EXPECT_TRUE(w.valueless_by_exception()); 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /test/ctor.default.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | TEST(Ctor_Default, Variant) { 15 | mpark::variant v; 16 | EXPECT_EQ(0, mpark::get<0>(v)); 17 | 18 | /* constexpr */ { 19 | constexpr mpark::variant cv{}; 20 | static_assert(0 == mpark::get<0>(cv), ""); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/ctor.fwd.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | TEST(Ctor_Fwd, Direct) { 15 | mpark::variant v(42); 16 | EXPECT_EQ(42, mpark::get(v)); 17 | 18 | /* constexpr */ { 19 | constexpr mpark::variant cv(42); 20 | static_assert(42 == mpark::get(cv), ""); 21 | } 22 | } 23 | 24 | TEST(Ctor_Fwd, DirectConversion) { 25 | mpark::variant v("42"); 26 | EXPECT_EQ("42", mpark::get(v)); 27 | 28 | /* constexpr */ { 29 | constexpr mpark::variant cv('A'); 30 | static_assert(65 == mpark::get(cv), ""); 31 | } 32 | } 33 | 34 | TEST(Ctor_Fwd, CopyInitialization) { 35 | mpark::variant v = 42; 36 | EXPECT_EQ(42, mpark::get(v)); 37 | 38 | /* constexpr */ { 39 | constexpr mpark::variant cv = 42; 40 | static_assert(42 == mpark::get(cv), ""); 41 | } 42 | } 43 | 44 | TEST(Ctor_Fwd, CopyInitializationConversion) { 45 | mpark::variant v = "42"; 46 | EXPECT_EQ("42", mpark::get(v)); 47 | 48 | /* constexpr */ { 49 | constexpr mpark::variant cv = 'A'; 50 | static_assert(65 == mpark::get(cv), ""); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/ctor.in_place.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | TEST(Ctor_InPlace, IndexDirect) { 15 | mpark::variant v(mpark::in_place_index_t<0>{}, 42); 16 | EXPECT_EQ(42, mpark::get<0>(v)); 17 | 18 | /* constexpr */ { 19 | constexpr mpark::variant cv(mpark::in_place_index_t<0>{}, 20 | 42); 21 | static_assert(42 == mpark::get<0>(cv), ""); 22 | } 23 | } 24 | 25 | TEST(Ctor_InPlace, IndexDirectDuplicate) { 26 | mpark::variant v(mpark::in_place_index_t<0>{}, 42); 27 | EXPECT_EQ(42, mpark::get<0>(v)); 28 | 29 | /* constexpr */ { 30 | constexpr mpark::variant cv(mpark::in_place_index_t<0>{}, 42); 31 | static_assert(42 == mpark::get<0>(cv), ""); 32 | } 33 | } 34 | 35 | TEST(Ctor_InPlace, IndexConversion) { 36 | mpark::variant v(mpark::in_place_index_t<1>{}, "42"); 37 | EXPECT_EQ("42", mpark::get<1>(v)); 38 | 39 | /* constexpr */ { 40 | constexpr mpark::variant cv(mpark::in_place_index_t<0>{}, 41 | 1.1); 42 | static_assert(1 == mpark::get<0>(cv), ""); 43 | } 44 | } 45 | 46 | TEST(Ctor_InPlace, IndexInitializerList) { 47 | mpark::variant v(mpark::in_place_index_t<1>{}, {'4', '2'}); 48 | EXPECT_EQ("42", mpark::get<1>(v)); 49 | } 50 | 51 | TEST(Ctor_InPlace, TypeDirect) { 52 | mpark::variant v(mpark::in_place_type_t{}, 53 | "42"); 54 | EXPECT_EQ("42", mpark::get(v)); 55 | 56 | /* constexpr */ { 57 | constexpr mpark::variant cv( 58 | mpark::in_place_type_t{}, 42); 59 | static_assert(42 == mpark::get(cv), ""); 60 | } 61 | } 62 | 63 | TEST(Ctor_InPlace, TypeConversion) { 64 | mpark::variant v(mpark::in_place_type_t{}, 42.5); 65 | EXPECT_EQ(42, mpark::get(v)); 66 | 67 | /* constexpr */ { 68 | constexpr mpark::variant cv( 69 | mpark::in_place_type_t{}, 42.5); 70 | static_assert(42 == mpark::get(cv), ""); 71 | } 72 | } 73 | 74 | TEST(Ctor_InPlace, TypeInitializerList) { 75 | mpark::variant v(mpark::in_place_type_t{}, 76 | {'4', '2'}); 77 | EXPECT_EQ("42", mpark::get(v)); 78 | } 79 | -------------------------------------------------------------------------------- /test/ctor.move.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include "util.hpp" 15 | 16 | namespace lib = mpark::lib; 17 | 18 | TEST(Ctor_Move, Value) { 19 | // `v` 20 | mpark::variant v("hello"); 21 | EXPECT_EQ("hello", mpark::get(v)); 22 | // `w` 23 | mpark::variant w(lib::move(v)); 24 | EXPECT_EQ("hello", mpark::get(w)); 25 | 26 | /* constexpr */ { 27 | // `cv` 28 | constexpr mpark::variant cv(42); 29 | static_assert(42 == mpark::get(cv), ""); 30 | // `cw` 31 | constexpr mpark::variant cw(lib::move(cv)); 32 | static_assert(42 == mpark::get(cw), ""); 33 | } 34 | } 35 | 36 | #ifdef MPARK_EXCEPTIONS 37 | TEST(Ctor_Move, ValuelessByException) { 38 | mpark::variant v(42); 39 | EXPECT_THROW(v = move_thrower_t{}, MoveConstruction); 40 | EXPECT_TRUE(v.valueless_by_exception()); 41 | mpark::variant w(lib::move(v)); 42 | EXPECT_TRUE(w.valueless_by_exception()); 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /test/dtor.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | struct Obj { 13 | Obj(bool &dtor_called) : dtor_called_(dtor_called) {} 14 | ~Obj() { dtor_called_ = true; } 15 | bool &dtor_called_; 16 | }; // Obj 17 | 18 | TEST(Dtor, Value) { 19 | bool dtor_called = false; 20 | // Construct/Destruct `Obj`. 21 | { 22 | mpark::variant v(mpark::in_place_type_t{}, dtor_called); 23 | } 24 | // Check that the destructor was called. 25 | EXPECT_TRUE(dtor_called); 26 | } 27 | -------------------------------------------------------------------------------- /test/get.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include "util.hpp" 13 | 14 | namespace lib = mpark::lib; 15 | 16 | TEST(Get, HoldsAlternative) { 17 | mpark::variant v(42); 18 | EXPECT_TRUE(mpark::holds_alternative<0>(v)); 19 | EXPECT_FALSE(mpark::holds_alternative<1>(v)); 20 | EXPECT_TRUE(mpark::holds_alternative(v)); 21 | EXPECT_FALSE(mpark::holds_alternative(v)); 22 | 23 | /* constexpr */ { 24 | constexpr mpark::variant cv(42); 25 | static_assert(mpark::holds_alternative<0>(cv), ""); 26 | static_assert(!mpark::holds_alternative<1>(cv), ""); 27 | static_assert(mpark::holds_alternative(cv), ""); 28 | static_assert(!mpark::holds_alternative(cv), ""); 29 | } 30 | } 31 | 32 | TEST(Get, MutVarMutType) { 33 | mpark::variant v(42); 34 | EXPECT_EQ(42, mpark::get(v)); 35 | // Check qualifier. 36 | EXPECT_EQ(LRef, get_qual(mpark::get(v))); 37 | EXPECT_EQ(RRef, get_qual(mpark::get(lib::move(v)))); 38 | } 39 | 40 | TEST(Get, MutVarConstType) { 41 | mpark::variant v(42); 42 | EXPECT_EQ(42, mpark::get(v)); 43 | // Check qualifier. 44 | EXPECT_EQ(ConstLRef, get_qual(mpark::get(v))); 45 | EXPECT_EQ(ConstRRef, get_qual(mpark::get(lib::move(v)))); 46 | } 47 | 48 | TEST(Get, ConstVarMutType) { 49 | const mpark::variant v(42); 50 | EXPECT_EQ(42, mpark::get(v)); 51 | // Check qualifier. 52 | EXPECT_EQ(ConstLRef, get_qual(mpark::get(v))); 53 | EXPECT_EQ(ConstRRef, get_qual(mpark::get(lib::move(v)))); 54 | 55 | /* constexpr */ { 56 | constexpr mpark::variant cv(42); 57 | static_assert(42 == mpark::get(cv), ""); 58 | // Check qualifier. 59 | static_assert(ConstLRef == get_qual(mpark::get(cv)), ""); 60 | static_assert(ConstRRef == get_qual(mpark::get(lib::move(cv))), ""); 61 | } 62 | } 63 | 64 | TEST(Get, ConstVarConstType) { 65 | const mpark::variant v(42); 66 | EXPECT_EQ(42, mpark::get(v)); 67 | // Check qualifier. 68 | EXPECT_EQ(ConstLRef, get_qual(mpark::get(v))); 69 | EXPECT_EQ(ConstRRef, get_qual(mpark::get(lib::move(v)))); 70 | 71 | /* constexpr */ { 72 | constexpr mpark::variant cv(42); 73 | static_assert(42 == mpark::get(cv), ""); 74 | // Check qualifier. 75 | static_assert(ConstLRef == get_qual(mpark::get(cv)), ""); 76 | static_assert(ConstRRef == get_qual(mpark::get(lib::move(cv))), 77 | ""); 78 | } 79 | } 80 | 81 | #ifdef MPARK_EXCEPTIONS 82 | TEST(Get, ValuelessByException) { 83 | mpark::variant v(42); 84 | EXPECT_THROW(v = move_thrower_t{}, MoveConstruction); 85 | EXPECT_TRUE(v.valueless_by_exception()); 86 | EXPECT_THROW(mpark::get(v), mpark::bad_variant_access); 87 | EXPECT_THROW(mpark::get(v), mpark::bad_variant_access); 88 | } 89 | #endif 90 | 91 | TEST(GetIf, MutVarMutType) { 92 | mpark::variant v(42); 93 | EXPECT_EQ(42, *mpark::get_if(&v)); 94 | // Check qualifier. 95 | EXPECT_EQ(Ptr, get_qual(mpark::get_if(&v))); 96 | } 97 | 98 | TEST(GetIf, MutVarConstType) { 99 | mpark::variant v(42); 100 | EXPECT_EQ(42, *mpark::get_if(&v)); 101 | // Check qualifier. 102 | EXPECT_EQ(ConstPtr, get_qual(mpark::get_if(&v))); 103 | } 104 | 105 | TEST(GetIf, ConstVarMutType) { 106 | const mpark::variant v(42); 107 | EXPECT_EQ(42, *mpark::get_if(&v)); 108 | // Check qualifier. 109 | EXPECT_EQ(ConstPtr, get_qual(mpark::get_if(&v))); 110 | 111 | /* constexpr */ { 112 | static constexpr mpark::variant cv(42); 113 | static_assert(42 == *mpark::get_if(&cv), ""); 114 | // Check qualifier. 115 | static_assert(ConstPtr == get_qual(mpark::get_if(&cv)), ""); 116 | } 117 | } 118 | 119 | TEST(GetIf, ConstVarConstType) { 120 | const mpark::variant v(42); 121 | EXPECT_EQ(42, *mpark::get_if(&v)); 122 | // Check qualifier. 123 | EXPECT_EQ(ConstPtr, get_qual(mpark::get_if(&v))); 124 | 125 | /* constexpr */ { 126 | static constexpr mpark::variant cv(42); 127 | static_assert(42 == *mpark::get_if(&cv), ""); 128 | // Check qualifier. 129 | static_assert(ConstPtr == get_qual(mpark::get_if(&cv)), ""); 130 | } 131 | } 132 | 133 | #ifdef MPARK_EXCEPTONS 134 | TEST(GetIf, ValuelessByException) { 135 | mpark::variant v(42); 136 | EXPECT_THROW(v = move_thrower_t{}, MoveConstruction); 137 | EXPECT_TRUE(v.valueless_by_exception()); 138 | EXPECT_EQ(nullptr, mpark::get_if(&v)); 139 | EXPECT_EQ(nullptr, mpark::get_if(&v)); 140 | } 141 | #endif 142 | -------------------------------------------------------------------------------- /test/hash.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | TEST(Hash, Monostate) { 15 | mpark::variant v(mpark::monostate{}); 16 | // Construct hash function objects. 17 | std::hash monostate_hash; 18 | std::hash> variant_hash; 19 | // Check the hash. 20 | EXPECT_NE(monostate_hash(mpark::monostate{}), variant_hash(v)); 21 | } 22 | 23 | TEST(Hash, String) { 24 | mpark::variant v("hello"); 25 | EXPECT_EQ("hello", mpark::get(v)); 26 | // Construct hash function objects. 27 | std::hash string_hash; 28 | std::hash> variant_hash; 29 | // Check the hash. 30 | EXPECT_NE(string_hash("hello"), variant_hash(v)); 31 | } 32 | -------------------------------------------------------------------------------- /test/intro.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | TEST(Variant, Intro) { 16 | // direct initialization. 17 | mpark::variant v("hello world!"); 18 | 19 | // direct access via reference. 20 | EXPECT_EQ("hello world!", mpark::get(v)); 21 | 22 | // bad access. 23 | #ifdef MPARK_EXCEPTIONS 24 | EXPECT_THROW(mpark::get(v), mpark::bad_variant_access); 25 | #endif 26 | 27 | // copy construction. 28 | mpark::variant w(v); 29 | 30 | // direct access via pointer. 31 | EXPECT_FALSE(mpark::get_if(&w)); 32 | EXPECT_TRUE(mpark::get_if(&w)); 33 | 34 | // diff-type assignment. 35 | v = 42; 36 | 37 | struct unary { 38 | int operator()(int) const noexcept { return 0; } 39 | int operator()(const std::string &) const noexcept { return 1; } 40 | }; // unary 41 | 42 | // single visitation. 43 | EXPECT_EQ(0, mpark::visit(unary{}, v)); 44 | 45 | // same-type assignment. 46 | w = "hello"; 47 | 48 | EXPECT_NE(v, w); 49 | 50 | // make `w` equal to `v`. 51 | w = 42; 52 | 53 | EXPECT_EQ(v, w); 54 | 55 | struct binary { 56 | int operator()(int, int) const noexcept { return 0; } 57 | int operator()(int, const std::string &) const noexcept { return 1; } 58 | int operator()(const std::string &, int) const noexcept { return 2; } 59 | int operator()(const std::string &, const std::string &) const noexcept { 60 | return 3; 61 | } 62 | }; // binary 63 | 64 | // binary visitation. 65 | EXPECT_EQ(0, mpark::visit(binary{}, v, w)); 66 | } 67 | -------------------------------------------------------------------------------- /test/issue.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #ifdef MPARK_INCOMPLETE_TYPE_TRAITS 17 | // https://github.com/mpark/variant/issues/34 18 | TEST(Issue, 34) { 19 | struct S { 20 | S(const S &) = default; 21 | S(S &&) = default; 22 | S &operator=(const S &) = default; 23 | S &operator=(S &&) = default; 24 | 25 | mpark::variant> value; 26 | }; 27 | } 28 | #endif 29 | 30 | // https://github.com/mpark/variant/pull/57 31 | TEST(Issue, 57) { 32 | std::vector>> vec; 33 | vec.emplace_back(0); 34 | } 35 | -------------------------------------------------------------------------------- /test/json.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | struct JsonIsh { 18 | JsonIsh(bool b) : data(b) {} 19 | JsonIsh(int i) : data(i) {} 20 | JsonIsh(std::string s) : data(std::move(s)) {} 21 | JsonIsh(std::vector v) : data(std::move(v)) {} 22 | 23 | mpark::variant> data; 24 | }; 25 | 26 | TEST(Variant, Bool) { 27 | JsonIsh json_ish = true; 28 | EXPECT_TRUE(mpark::get(json_ish.data)); 29 | json_ish = false; 30 | EXPECT_FALSE(mpark::get(json_ish.data)); 31 | } 32 | 33 | TEST(Variant, Int) { 34 | JsonIsh json_ish = 42; 35 | EXPECT_EQ(42, mpark::get(json_ish.data)); 36 | } 37 | 38 | TEST(Variant, String) { 39 | JsonIsh json_ish = std::string("hello"); 40 | EXPECT_EQ("hello", mpark::get(json_ish.data)); 41 | } 42 | 43 | TEST(Variant, Array) { 44 | JsonIsh json_ish = std::vector{true, 42, std::string("world")}; 45 | const auto &array = mpark::get>(json_ish.data); 46 | EXPECT_TRUE(mpark::get(array[0].data)); 47 | EXPECT_EQ(42, mpark::get(array[1].data)); 48 | EXPECT_EQ("world", mpark::get(array[2].data)); 49 | } 50 | -------------------------------------------------------------------------------- /test/libcxx.sh: -------------------------------------------------------------------------------- 1 | # MPark.Variant 2 | # 3 | # Copyright Michael Park, 2015-2017 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #!/usr/bin/env bash 9 | 10 | set -e 11 | 12 | trap "cd ${MPARK_VARIANT_LIBCXX_SOURCE_DIR} && git checkout ." EXIT 13 | 14 | cat < ${MPARK_VARIANT_LIBCXX_SOURCE_DIR}/include/variant 15 | #define mpark std 16 | #define MPARK_IN_PLACE_HPP 17 | $(cat ${MPARK_VARIANT_SOURCE_DIR}/include/mpark/variant.hpp) 18 | #undef MPARK_IN_PLACE_HPP 19 | #undef mpark 20 | EOF 21 | 22 | ${MPARK_VARIANT_LIT} \ 23 | -v \ 24 | --param color_diagnostics \ 25 | --param cxx_under_test="${MPARK_VARIANT_CXX_COMPILER}" \ 26 | --param compile_flags=-I${MPARK_VARIANT_SOURCE_DIR}/include/mpark \ 27 | --param libcxx_site_config=${MPARK_VARIANT_LIBCXX_SITE_CONFIG} \ 28 | --param std=c++17 \ 29 | --param use_clang_verify=false \ 30 | ${MPARK_VARIANT_LIBCXX_SOURCE_DIR}/test/std/utilities/variant \ 31 | -------------------------------------------------------------------------------- /test/mod.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | TEST(Assign_Emplace, IndexDirect) { 15 | mpark::variant v; 16 | v.emplace<1>("42"); 17 | EXPECT_EQ("42", mpark::get<1>(v)); 18 | } 19 | 20 | TEST(Assign_Emplace, IndexDirectDuplicate) { 21 | mpark::variant v; 22 | v.emplace<1>(42); 23 | EXPECT_EQ(42, mpark::get<1>(v)); 24 | } 25 | 26 | TEST(Assign_Emplace, IndexConversion) { 27 | mpark::variant v; 28 | v.emplace<1>("42"); 29 | EXPECT_EQ("42", mpark::get<1>(v)); 30 | } 31 | 32 | TEST(Assign_Emplace, IndexConversionDuplicate) { 33 | mpark::variant v; 34 | v.emplace<1>(1.1); 35 | EXPECT_EQ(1, mpark::get<1>(v)); 36 | } 37 | 38 | TEST(Assign_Emplace, IndexInitializerList) { 39 | mpark::variant v; 40 | v.emplace<1>({'4', '2'}); 41 | EXPECT_EQ("42", mpark::get<1>(v)); 42 | } 43 | 44 | TEST(Assign_Emplace, TypeDirect) { 45 | mpark::variant v; 46 | v.emplace("42"); 47 | EXPECT_EQ("42", mpark::get(v)); 48 | } 49 | 50 | TEST(Assign_Emplace, TypeConversion) { 51 | mpark::variant v; 52 | v.emplace(1.1); 53 | EXPECT_EQ(1, mpark::get(v)); 54 | } 55 | 56 | TEST(Assign_Emplace, TypeInitializerList) { 57 | mpark::variant v; 58 | v.emplace({'4', '2'}); 59 | EXPECT_EQ("42", mpark::get(v)); 60 | } 61 | -------------------------------------------------------------------------------- /test/relops.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include "util.hpp" 17 | 18 | TEST(Rel, SameTypeSameValue) { 19 | mpark::variant v(0), w(0); 20 | // `v` op `w` 21 | EXPECT_TRUE(v == w); 22 | EXPECT_FALSE(v != w); 23 | EXPECT_FALSE(v < w); 24 | EXPECT_FALSE(v > w); 25 | EXPECT_TRUE(v <= w); 26 | EXPECT_TRUE(v >= w); 27 | // `w` op `v` 28 | EXPECT_TRUE(w == v); 29 | EXPECT_FALSE(w != v); 30 | EXPECT_FALSE(w < v); 31 | EXPECT_FALSE(w > v); 32 | EXPECT_TRUE(w <= v); 33 | EXPECT_TRUE(w >= v); 34 | 35 | #ifdef MPARK_CPP11_CONSTEXPR 36 | /* constexpr */ { 37 | constexpr mpark::variant cv(0), cw(0); 38 | // `cv` op `cw` 39 | static_assert(cv == cw, ""); 40 | static_assert(!(cv != cw), ""); 41 | static_assert(!(cv < cw), ""); 42 | static_assert(!(cv > cw), ""); 43 | static_assert(cv <= cw, ""); 44 | static_assert(cv >= cw, ""); 45 | // `cw` op `cv` 46 | static_assert(cw == cv, ""); 47 | static_assert(!(cw != cv), ""); 48 | static_assert(!(cw < cv), ""); 49 | static_assert(!(cw > cv), ""); 50 | static_assert(cw <= cv, ""); 51 | static_assert(cw >= cv, ""); 52 | } 53 | #endif 54 | } 55 | 56 | TEST(Rel, SameTypeDiffValue) { 57 | mpark::variant v(0), w(1); 58 | // `v` op `w` 59 | EXPECT_FALSE(v == w); 60 | EXPECT_TRUE(v != w); 61 | EXPECT_TRUE(v < w); 62 | EXPECT_FALSE(v > w); 63 | EXPECT_TRUE(v <= w); 64 | EXPECT_FALSE(v >= w); 65 | // `w` op `v` 66 | EXPECT_FALSE(w == v); 67 | EXPECT_TRUE(w != v); 68 | EXPECT_FALSE(w < v); 69 | EXPECT_TRUE(w > v); 70 | EXPECT_FALSE(w <= v); 71 | EXPECT_TRUE(w >= v); 72 | 73 | #ifdef MPARK_CPP11_CONSTEXPR 74 | /* constexpr */ { 75 | constexpr mpark::variant cv(0), cw(1); 76 | // `cv` op `cw` 77 | static_assert(!(cv == cw), ""); 78 | static_assert(cv != cw, ""); 79 | static_assert(cv < cw, ""); 80 | static_assert(!(cv > cw), ""); 81 | static_assert(cv <= cw, ""); 82 | static_assert(!(cv >= cw), ""); 83 | // `cw` op `cv` 84 | static_assert(!(cw == cv), ""); 85 | static_assert(cw != cv, ""); 86 | static_assert(!(cw < cv), ""); 87 | static_assert(cw > cv, ""); 88 | static_assert(!(cw <= cv), ""); 89 | static_assert(cw >= cv, ""); 90 | } 91 | #endif 92 | } 93 | 94 | TEST(Rel, DiffTypeSameValue) { 95 | mpark::variant v(0), w(0u); 96 | // `v` op `w` 97 | EXPECT_FALSE(v == w); 98 | EXPECT_TRUE(v != w); 99 | EXPECT_TRUE(v < w); 100 | EXPECT_FALSE(v > w); 101 | EXPECT_TRUE(v <= w); 102 | EXPECT_FALSE(v >= w); 103 | // `w` op `v` 104 | EXPECT_FALSE(w == v); 105 | EXPECT_TRUE(w != v); 106 | EXPECT_FALSE(w < v); 107 | EXPECT_TRUE(w > v); 108 | EXPECT_FALSE(w <= v); 109 | EXPECT_TRUE(w >= v); 110 | 111 | #ifdef MPARK_CPP11_CONSTEXPR 112 | /* constexpr */ { 113 | constexpr mpark::variant cv(0), cw(0u); 114 | // `cv` op `cw` 115 | static_assert(!(cv == cw), ""); 116 | static_assert(cv != cw, ""); 117 | static_assert(cv < cw, ""); 118 | static_assert(!(cv > cw), ""); 119 | static_assert(cv <= cw, ""); 120 | static_assert(!(cv >= cw), ""); 121 | // `cw` op `cv` 122 | static_assert(!(cw == cv), ""); 123 | static_assert(cw != cv, ""); 124 | static_assert(!(cw < cv), ""); 125 | static_assert(cw > cv, ""); 126 | static_assert(!(cw <= cv), ""); 127 | static_assert(cw >= cv, ""); 128 | } 129 | #endif 130 | } 131 | 132 | TEST(Rel, DiffTypeDiffValue) { 133 | mpark::variant v(0), w(1u); 134 | // `v` op `w` 135 | EXPECT_FALSE(v == w); 136 | EXPECT_TRUE(v != w); 137 | EXPECT_TRUE(v < w); 138 | EXPECT_FALSE(v > w); 139 | EXPECT_TRUE(v <= w); 140 | EXPECT_FALSE(v >= w); 141 | // `w` op `v` 142 | EXPECT_FALSE(w == v); 143 | EXPECT_TRUE(w != v); 144 | EXPECT_FALSE(w < v); 145 | EXPECT_TRUE(w > v); 146 | EXPECT_FALSE(w <= v); 147 | EXPECT_TRUE(w >= v); 148 | 149 | #ifdef MPARK_CPP11_CONSTEXPR 150 | /* constexpr */ { 151 | constexpr mpark::variant cv(0), cw(1u); 152 | // `cv` op `cw` 153 | static_assert(!(cv == cw), ""); 154 | static_assert(cv != cw, ""); 155 | static_assert(cv < cw, ""); 156 | static_assert(!(cv > cw), ""); 157 | static_assert(cv <= cw, ""); 158 | static_assert(!(cv >= cw), ""); 159 | // `cw` op `cv` 160 | static_assert(!(cw == cv), ""); 161 | static_assert(cw != cv, ""); 162 | static_assert(!(cw < cv), ""); 163 | static_assert(cw > cv, ""); 164 | static_assert(!(cw <= cv), ""); 165 | static_assert(cw >= cv, ""); 166 | } 167 | #endif 168 | } 169 | 170 | #ifdef MPARK_EXCEPTIONS 171 | TEST(Rel, OneValuelessByException) { 172 | // `v` normal, `w` corrupted. 173 | mpark::variant v(42), w(42); 174 | EXPECT_THROW(w = move_thrower_t{}, MoveConstruction); 175 | EXPECT_FALSE(v.valueless_by_exception()); 176 | EXPECT_TRUE(w.valueless_by_exception()); 177 | // `v` op `w` 178 | EXPECT_FALSE(v == w); 179 | EXPECT_TRUE(v != w); 180 | EXPECT_FALSE(v < w); 181 | EXPECT_TRUE(v > w); 182 | EXPECT_FALSE(v <= w); 183 | EXPECT_TRUE(v >= w); 184 | } 185 | 186 | TEST(Rel, BothValuelessByException) { 187 | // `v`, `w` both corrupted. 188 | mpark::variant v(42); 189 | EXPECT_THROW(v = move_thrower_t{}, MoveConstruction); 190 | mpark::variant w(v); 191 | EXPECT_TRUE(v.valueless_by_exception()); 192 | EXPECT_TRUE(w.valueless_by_exception()); 193 | // `v` op `w` 194 | EXPECT_TRUE(v == w); 195 | EXPECT_FALSE(v != w); 196 | EXPECT_FALSE(v < w); 197 | EXPECT_FALSE(v > w); 198 | EXPECT_TRUE(v <= w); 199 | EXPECT_TRUE(v >= w); 200 | } 201 | #endif 202 | -------------------------------------------------------------------------------- /test/swap.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include "util.hpp" 15 | 16 | TEST(Swap, Same) { 17 | mpark::variant v("hello"); 18 | mpark::variant w("world"); 19 | // Check `v`. 20 | EXPECT_EQ("hello", mpark::get(v)); 21 | // Check `w`. 22 | EXPECT_EQ("world", mpark::get(w)); 23 | // Swap. 24 | using std::swap; 25 | swap(v, w); 26 | // Check `v`. 27 | EXPECT_EQ("world", mpark::get(v)); 28 | // Check `w`. 29 | EXPECT_EQ("hello", mpark::get(w)); 30 | } 31 | 32 | TEST(Swap, Different) { 33 | mpark::variant v(42); 34 | mpark::variant w("hello"); 35 | // Check `v`. 36 | EXPECT_EQ(42, mpark::get(v)); 37 | // Check `w`. 38 | EXPECT_EQ("hello", mpark::get(w)); 39 | // Swap. 40 | using std::swap; 41 | swap(v, w); 42 | // Check `v`. 43 | EXPECT_EQ("hello", mpark::get(v)); 44 | // Check `w`. 45 | EXPECT_EQ(42, mpark::get(w)); 46 | } 47 | 48 | #ifdef MPARK_EXCEPTIONS 49 | TEST(Swap, OneValuelessByException) { 50 | // `v` normal, `w` corrupted. 51 | mpark::variant v(42), w(42); 52 | EXPECT_THROW(w = move_thrower_t{}, MoveConstruction); 53 | EXPECT_EQ(42, mpark::get(v)); 54 | EXPECT_TRUE(w.valueless_by_exception()); 55 | // Swap. 56 | using std::swap; 57 | swap(v, w); 58 | // Check `v`, `w`. 59 | EXPECT_TRUE(v.valueless_by_exception()); 60 | EXPECT_EQ(42, mpark::get(w)); 61 | } 62 | 63 | TEST(Swap, BothValuelessByException) { 64 | // `v`, `w` both corrupted. 65 | mpark::variant v(42); 66 | EXPECT_THROW(v = move_thrower_t{}, MoveConstruction); 67 | mpark::variant w(v); 68 | EXPECT_TRUE(v.valueless_by_exception()); 69 | EXPECT_TRUE(w.valueless_by_exception()); 70 | // Swap. 71 | using std::swap; 72 | swap(v, w); 73 | // Check `v`, `w`. 74 | EXPECT_TRUE(v.valueless_by_exception()); 75 | EXPECT_TRUE(w.valueless_by_exception()); 76 | } 77 | #endif 78 | 79 | TEST(Swap, DtorsSame) { 80 | struct Obj { 81 | Obj(size_t *dtor_count) : dtor_count_(dtor_count) {} 82 | Obj(const Obj &) = default; 83 | Obj(Obj &&) = default; 84 | ~Obj() { ++(*dtor_count_); } 85 | Obj &operator=(const Obj &) = default; 86 | Obj &operator=(Obj &&) = default; 87 | size_t *dtor_count_; 88 | }; // Obj 89 | size_t v_count = 0; 90 | size_t w_count = 0; 91 | { 92 | mpark::variant v{&v_count}, w{&w_count}; 93 | using std::swap; 94 | swap(v, w); 95 | // Calls `std::swap(Obj &lhs, Obj &rhs)`, with which we perform: 96 | // ``` 97 | // { 98 | // Obj temp(move(lhs)); 99 | // lhs = move(rhs); 100 | // rhs = move(temp); 101 | // } `++v_count` from `temp::~Obj()`. 102 | // ``` 103 | EXPECT_EQ(1u, v_count); 104 | EXPECT_EQ(0u, w_count); 105 | } 106 | EXPECT_EQ(2u, v_count); 107 | EXPECT_EQ(1u, w_count); 108 | } 109 | 110 | namespace detail { 111 | 112 | struct Obj { 113 | Obj(size_t *dtor_count) : dtor_count_(dtor_count) {} 114 | Obj(const Obj &) = default; 115 | Obj(Obj &&) = default; 116 | ~Obj() { ++(*dtor_count_); } 117 | Obj &operator=(const Obj &) = default; 118 | Obj &operator=(Obj &&) = default; 119 | size_t *dtor_count_; 120 | }; // Obj 121 | 122 | static void swap(Obj &lhs, Obj &rhs) noexcept { 123 | std::swap(lhs.dtor_count_, rhs.dtor_count_); 124 | } 125 | 126 | } // namespace detail 127 | 128 | TEST(Swap, DtorsSameWithSwap) { 129 | size_t v_count = 0; 130 | size_t w_count = 0; 131 | { 132 | mpark::variant v{&v_count}, w{&w_count}; 133 | using std::swap; 134 | swap(v, w); 135 | // Calls `detail::swap(Obj &lhs, Obj &rhs)`, with which doesn't call any destructors. 136 | EXPECT_EQ(0u, v_count); 137 | EXPECT_EQ(0u, w_count); 138 | } 139 | EXPECT_EQ(1u, v_count); 140 | EXPECT_EQ(1u, w_count); 141 | } 142 | 143 | TEST(Swap, DtorsDifferent) { 144 | struct V { 145 | V(size_t *dtor_count) : dtor_count_(dtor_count) {} 146 | V(const V &) = default; 147 | V(V &&) = default; 148 | ~V() { ++(*dtor_count_); } 149 | V &operator=(const V &) = default; 150 | V &operator=(V &&) = default; 151 | size_t *dtor_count_; 152 | }; // V 153 | struct W { 154 | W(size_t *dtor_count) : dtor_count_(dtor_count) {} 155 | W(const W &) = default; 156 | W(W &&) = default; 157 | ~W() { ++(*dtor_count_); } 158 | W &operator=(const W &) = default; 159 | W &operator=(W &&) = default; 160 | size_t *dtor_count_; 161 | }; // W 162 | size_t v_count = 0; 163 | size_t w_count = 0; 164 | { 165 | mpark::variant v{mpark::in_place_type_t{}, &v_count}; 166 | mpark::variant w{mpark::in_place_type_t{}, &w_count}; 167 | using std::swap; 168 | swap(v, w); 169 | EXPECT_EQ(1u, v_count); 170 | EXPECT_EQ(2u, w_count); 171 | } 172 | EXPECT_EQ(2u, v_count); 173 | EXPECT_EQ(3u, w_count); 174 | } 175 | -------------------------------------------------------------------------------- /test/util.hpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | enum Qual { Ptr, ConstPtr, LRef, ConstLRef, RRef, ConstRRef }; 11 | 12 | struct get_qual_t { 13 | constexpr Qual operator()(int *) const { return Ptr; } 14 | constexpr Qual operator()(const int *) const { return ConstPtr; } 15 | constexpr Qual operator()(int &) const { return LRef; } 16 | constexpr Qual operator()(const int &) const { return ConstLRef; } 17 | constexpr Qual operator()(int &&) const { return RRef; } 18 | constexpr Qual operator()(const int &&) const { return ConstRRef; } 19 | }; 20 | 21 | constexpr get_qual_t get_qual{}; 22 | 23 | #ifdef MPARK_EXCEPTIONS 24 | struct CopyConstruction : std::exception {}; 25 | struct CopyAssignment : std::exception {}; 26 | struct MoveConstruction : std::exception {}; 27 | struct MoveAssignment : std::exception {}; 28 | 29 | struct copy_thrower_t { 30 | constexpr copy_thrower_t() {} 31 | [[noreturn]] copy_thrower_t(const copy_thrower_t &) { 32 | throw CopyConstruction{}; 33 | } 34 | copy_thrower_t(copy_thrower_t &&) = default; 35 | copy_thrower_t &operator=(const copy_thrower_t &) { throw CopyAssignment{}; } 36 | copy_thrower_t &operator=(copy_thrower_t &&) = default; 37 | }; 38 | 39 | inline bool operator<(const copy_thrower_t &, 40 | const copy_thrower_t &) noexcept { 41 | return false; 42 | } 43 | 44 | inline bool operator>(const copy_thrower_t &, 45 | const copy_thrower_t &) noexcept { 46 | return false; 47 | } 48 | 49 | inline bool operator<=(const copy_thrower_t &, 50 | const copy_thrower_t &) noexcept { 51 | return true; 52 | } 53 | 54 | inline bool operator>=(const copy_thrower_t &, 55 | const copy_thrower_t &) noexcept { 56 | return true; 57 | } 58 | 59 | inline bool operator==(const copy_thrower_t &, 60 | const copy_thrower_t &) noexcept { 61 | return true; 62 | } 63 | 64 | inline bool operator!=(const copy_thrower_t &, 65 | const copy_thrower_t &) noexcept { 66 | return false; 67 | } 68 | 69 | struct move_thrower_t { 70 | constexpr move_thrower_t() {} 71 | move_thrower_t(const move_thrower_t &) = default; 72 | [[noreturn]] move_thrower_t(move_thrower_t &&) { throw MoveConstruction{}; } 73 | move_thrower_t &operator=(const move_thrower_t &) = default; 74 | move_thrower_t &operator=(move_thrower_t &&) { throw MoveAssignment{}; } 75 | }; 76 | 77 | inline bool operator<(const move_thrower_t &, 78 | const move_thrower_t &) noexcept { 79 | return false; 80 | } 81 | 82 | inline bool operator>(const move_thrower_t &, 83 | const move_thrower_t &) noexcept { 84 | return false; 85 | } 86 | 87 | inline bool operator<=(const move_thrower_t &, 88 | const move_thrower_t &) noexcept { 89 | return true; 90 | } 91 | 92 | inline bool operator>=(const move_thrower_t &, 93 | const move_thrower_t &) noexcept { 94 | return true; 95 | } 96 | 97 | inline bool operator==(const move_thrower_t &, 98 | const move_thrower_t &) noexcept { 99 | return true; 100 | } 101 | 102 | inline bool operator!=(const move_thrower_t &, 103 | const move_thrower_t &) noexcept { 104 | return false; 105 | } 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /test/visit.cpp: -------------------------------------------------------------------------------- 1 | // MPark.Variant 2 | // 3 | // Copyright Michael Park, 2015-2017 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "util.hpp" 18 | 19 | namespace lib = mpark::lib; 20 | 21 | TEST(Visit, MutVarMutType) { 22 | mpark::variant v(42); 23 | // Check `v`. 24 | EXPECT_EQ(42, mpark::get(v)); 25 | // Check qualifier. 26 | EXPECT_EQ(LRef, mpark::visit(get_qual, v)); 27 | EXPECT_EQ(RRef, mpark::visit(get_qual, lib::move(v))); 28 | } 29 | 30 | TEST(Visit, MutVarConstType) { 31 | mpark::variant v(42); 32 | EXPECT_EQ(42, mpark::get(v)); 33 | // Check qualifier. 34 | EXPECT_EQ(ConstLRef, mpark::visit(get_qual, v)); 35 | EXPECT_EQ(ConstRRef, mpark::visit(get_qual, lib::move(v))); 36 | } 37 | 38 | TEST(Visit, ConstVarMutType) { 39 | const mpark::variant v(42); 40 | EXPECT_EQ(42, mpark::get(v)); 41 | // Check qualifier. 42 | EXPECT_EQ(ConstLRef, mpark::visit(get_qual, v)); 43 | EXPECT_EQ(ConstRRef, mpark::visit(get_qual, lib::move(v))); 44 | 45 | #ifdef MPARK_CPP11_CONSTEXPR 46 | /* constexpr */ { 47 | constexpr mpark::variant cv(42); 48 | static_assert(42 == mpark::get(cv), ""); 49 | // Check qualifier. 50 | static_assert(ConstLRef == mpark::visit(get_qual, cv), ""); 51 | static_assert(ConstRRef == mpark::visit(get_qual, lib::move(cv)), ""); 52 | } 53 | #endif 54 | } 55 | 56 | TEST(Visit, ConstVarConstType) { 57 | const mpark::variant v(42); 58 | EXPECT_EQ(42, mpark::get(v)); 59 | // Check qualifier. 60 | EXPECT_EQ(ConstLRef, mpark::visit(get_qual, v)); 61 | EXPECT_EQ(ConstRRef, mpark::visit(get_qual, lib::move(v))); 62 | 63 | #ifdef MPARK_CPP11_CONSTEXPR 64 | /* constexpr */ { 65 | constexpr mpark::variant cv(42); 66 | static_assert(42 == mpark::get(cv), ""); 67 | // Check qualifier. 68 | static_assert(ConstLRef == mpark::visit(get_qual, cv), ""); 69 | static_assert(ConstRRef == mpark::visit(get_qual, lib::move(cv)), ""); 70 | } 71 | #endif 72 | } 73 | 74 | struct concat { 75 | template 76 | std::string operator()(const Args &... args) const { 77 | std::ostringstream strm; 78 | std::initializer_list({(strm << args, 0)...}); 79 | return lib::move(strm).str(); 80 | } 81 | }; 82 | 83 | TEST(Visit, Zero) { EXPECT_EQ("", mpark::visit(concat{})); } 84 | 85 | TEST(Visit_Homogeneous, Double) { 86 | mpark::variant v("hello"), w("world!"); 87 | EXPECT_EQ("helloworld!", mpark::visit(concat{}, v, w)); 88 | 89 | #ifdef MPARK_CPP11_CONSTEXPR 90 | /* constexpr */ { 91 | constexpr mpark::variant cv(101), cw(202), cx(3.3); 92 | struct add_ints { 93 | constexpr int operator()(int lhs, int rhs) const { return lhs + rhs; } 94 | constexpr int operator()(int lhs, double) const { return lhs; } 95 | constexpr int operator()(double, int rhs) const { return rhs; } 96 | constexpr int operator()(double, double) const { return 0; } 97 | }; // add 98 | static_assert(303 == mpark::visit(add_ints{}, cv, cw), ""); 99 | static_assert(202 == mpark::visit(add_ints{}, cw, cx), ""); 100 | static_assert(101 == mpark::visit(add_ints{}, cx, cv), ""); 101 | static_assert(0 == mpark::visit(add_ints{}, cx, cx), ""); 102 | } 103 | #endif 104 | } 105 | 106 | TEST(Visit_Homogeneous, Quintuple) { 107 | mpark::variant v(101), w("+"), x(202), y("="), z(303); 108 | EXPECT_EQ("101+202=303", mpark::visit(concat{}, v, w, x, y, z)); 109 | } 110 | 111 | TEST(Visit_Heterogeneous, Double) { 112 | mpark::variant v("hello"); 113 | mpark::variant w("world!"); 114 | EXPECT_EQ("helloworld!", mpark::visit(concat{}, v, w)); 115 | } 116 | 117 | TEST(Visit_Heterogenous, Quintuple) { 118 | mpark::variant v(101); 119 | mpark::variant w("+"); 120 | mpark::variant x(202); 121 | mpark::variant y('='); 122 | mpark::variant z(303L); 123 | EXPECT_EQ("101+202=303", mpark::visit(concat{}, v, w, x, y, z)); 124 | } 125 | --------------------------------------------------------------------------------