Compare commits

...

45 Commits

Author SHA1 Message Date
3ca95a65df Use boost::hash in hash_value, not std::hash (closes #27) 2021-03-13 05:08:03 +02:00
ae1f72671e Add test for types supported by boost::hash, but not by std::hash 2021-03-13 04:50:01 +02:00
a2dab8c7d3 Refactor detail::hash_value_L 2021-03-13 04:10:41 +02:00
8be0a4a5fe Update copyright 2021-03-12 23:42:32 +02:00
afb0aafd64 Change clangs to bionic 2021-03-12 20:18:24 +02:00
20b9175932 Add cxxstd=latest to Appveyor 2021-03-08 04:04:35 +02:00
fb3ce863ff Add MSVC workaround for monospace constexpr (refs #25) 2021-03-08 03:26:40 +02:00
8ec0bf448a Add monospace relational tests (refs #25) 2021-03-08 03:01:21 +02:00
6d19e6be68 Update revision history 2021-03-07 00:51:28 +02:00
d8552b23ae UBSan on clang 7 is broken on Ubuntu 2021-03-01 06:35:38 +02:00
f44aba09a2 Update .travis.yml 2021-03-01 00:26:43 +02:00
99cc1db385 Fix documentation for emplace effects 2021-01-25 03:49:42 +02:00
6d848c5af6 Update GCC workarounds in constexpr in-place construct tests 2021-01-25 03:44:24 +02:00
3c9f4e56bf Fix visit codegen regression when NDEBUG is not defined 2021-01-24 17:27:24 +02:00
3015e56bcb GCC bug 63707 has been fixed for GCC 11 2021-01-23 20:36:12 +02:00
7c37053950 Merge branch 'develop' into feature/double-opt 2021-01-13 05:06:00 +02:00
60995edb41 Remove g++ 4.7 from GHA 2021-01-13 05:01:44 +02:00
84a2c175d0 Use variant=release for variant_visit_r under g++/windows 2021-01-13 04:44:56 +02:00
ea3268feb4 Add .github/workflows 2021-01-13 04:19:15 +02:00
6de876954a Merge branch 'develop' into feature/double-opt 2021-01-13 02:32:32 +02:00
efc1d5acca Add more tests to variant_emplace_index.cpp 2021-01-13 02:32:05 +02:00
453b00dec8 Use (i+1)*2+j for the internal index in the double-buffered case, to avoid branches 2021-01-13 02:10:12 +02:00
c6186e0a95 Merge pull request #22 from eldiener/develop
Add "cxxstd" json field. The "cxxstd" json field is being added to ea…
2020-12-16 18:45:01 +02:00
24ccee2104 Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries whose minumum C++ standard compilation level is C++11 on up. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. 2020-12-16 01:45:24 -05:00
93b8618e94 Update maintainer e-mail 2020-12-12 01:08:09 +02:00
1ebc29aa02 Remove boost_install call from CMakeLists.txt 2020-06-11 17:21:57 +03:00
d3db874762 Document visit<R> 2020-06-03 18:01:57 +03:00
5586ebaa64 Add support for visit<R> 2020-06-03 17:00:13 +03:00
bede3777a8 Add test for nullary visit 2020-06-03 14:29:24 +03:00
b302dd5912 Update changelog 2020-05-22 17:57:29 +03:00
2ad6fed07a Update revision history 2020-05-10 19:34:12 +03:00
84ea994325 Add specialization for variant_storage_impl<mp_false, ...> 2020-05-09 19:56:27 +03:00
465e5bac3d Add specialization for variant_storage_impl<mp_true, ...> to reduce instantiations 2020-05-09 18:14:12 +03:00
41829b0fb1 test/variant_many_types: cosmetic fixes 2020-05-09 17:55:42 +03:00
b57d75ff80 Merge branch 'develop' into feature/many-types 2020-05-09 14:41:29 +03:00
03019860df Fix gcc-10 version check 2020-05-09 05:10:28 +03:00
8ec4720d2d Merge branch 'feature/clang-10' into feature/gcc-10 2020-05-09 05:09:11 +03:00
75f574fc48 Move warning suppression before the includes 2020-05-09 04:42:27 +03:00
1d79adfca0 Add gcc-10 to Travis 2020-05-09 04:32:11 +03:00
fa92e40b35 Disable failing constexpr tests on g++ 10.1 2020-05-09 04:31:26 +03:00
a403f82691 Disable -Wdeprecated-volatile 2020-05-09 03:57:27 +03:00
a7d0da59ad Add clang-10 to Travis 2020-05-09 03:50:20 +03:00
fa872cb835 test/variant_many_types: add a constructor to Y 2020-05-08 23:23:19 +03:00
93204676f5 Add test/variant_many_types 2020-05-08 22:22:49 +03:00
772ef0d312 Support derived types in visit 2020-05-06 20:11:03 +03:00
23 changed files with 1135 additions and 179 deletions

197
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,197 @@
name: CI
on:
pull_request:
push:
branches:
- master
- develop
- feature/**
env:
UBSAN_OPTIONS: print_stacktrace=1
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.8
- toolset: gcc-4.9
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.9
- toolset: gcc-5
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
- toolset: gcc-6
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
install: g++-6
- toolset: gcc-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
- toolset: clang
compiler: clang++-3.5
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.5
- toolset: clang
compiler: clang++-3.6
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.6
- toolset: clang
compiler: clang++-3.7
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.7
- toolset: clang
compiler: clang++-3.8
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.8
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "03,11,14,17"
os: ubuntu-18.04
- toolset: clang
compiler: clang++-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
- name: Create user-config.jam
if: matrix.compiler
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Run tests
run: |
cd ../boost-root
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release
windows:
strategy:
fail-fast: false
matrix:
include:
- toolset: msvc-14.1
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2016
- toolset: msvc-14.2
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2019
- toolset: gcc
cxxstd: "03,11,14,17,2a"
addrmd: 64
os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
- name: Run tests
shell: cmd
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release

View File

@ -1,4 +1,4 @@
# Copyright 2016-2019 Peter Dimov
# Copyright 2016-2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
@ -93,20 +93,16 @@ matrix:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-8
env: UBSAN=1 TOOLSET=gcc COMPILER=g++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold
dist: bionic
compiler: g++-10
env: UBSAN=1 TOOLSET=gcc COMPILER=g++-10 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold
addons:
apt:
packages:
- g++-8
- g++-10
sources:
- ubuntu-toolchain-r-test
- os: linux
dist: trusty
compiler: clang++
env: DIST=trusty TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: linux
compiler: clang++-3.5
env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=11,14,1z
@ -169,6 +165,7 @@ matrix:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-5.0
env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=11,14,1z
addons:
@ -179,6 +176,7 @@ matrix:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-6.0
env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=11,14,17
addons:
@ -189,6 +187,7 @@ matrix:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-7
env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=11,14,17,2a
addons:
@ -197,9 +196,10 @@ matrix:
- clang-7
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-7
- llvm-toolchain-bionic-7
- os: linux
dist: bionic
compiler: clang++-8
env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a
addons:
@ -208,10 +208,10 @@ matrix:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- llvm-toolchain-bionic-8
- os: linux
dist: xenial
dist: bionic
compiler: clang++-9
env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=11,14,17,2a
addons:
@ -220,19 +220,47 @@ matrix:
- clang-9
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
compiler: clang++-8
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
dist: bionic
compiler: clang++-10
env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-8
- clang-10
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: bionic
compiler: clang++-11
env: TOOLSET=clang COMPILER=clang++-11 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-11
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: bionic
compiler: clang++-12
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-12 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
addons:
apt:
packages:
- clang-12
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: trusty
@ -244,18 +272,14 @@ matrix:
- libc++-dev
- os: linux
dist: trusty
dist: bionic
compiler: clang++-libc++
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=11,14,1z UBSAN_OPTIONS=print_stacktrace=1
env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=11,14,17,2a
addons:
apt:
packages:
- libc++-dev
- os: osx
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: osx
compiler: clang++
env: UBSAN=1 TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z UBSAN_OPTIONS=print_stacktrace=1
@ -284,6 +308,7 @@ matrix:
- os: linux
env: CMAKE_INSTALL_TEST=1
script:
- pip install --user cmake
- mkdir __build__ && cd __build__
- cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=variant2 -DCMAKE_INSTALL_PREFIX=~/.local ..
- cmake --build . --target install

View File

@ -17,13 +17,6 @@ target_link_libraries(boost_variant2
Boost::mp11
)
if(BOOST_SUPERPROJECT_VERSION)
include(BoostInstall)
boost_install(TARGETS boost_variant2 HEADER_DIRECTORY include/)
endif()
if(BUILD_TESTING)
add_subdirectory(test)

View File

@ -20,15 +20,15 @@ environment:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc-14.1
ADDRMD: 32,64
CXXSTD: 14,17
CXXSTD: 14,17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: clang-win
ADDRMD: 64
CXXSTD: 14,17
CXXSTD: 14,17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: msvc-14.2
ADDRMD: 32,64
CXXSTD: 14,17
CXXSTD: 14,17,latest
install:
- set BOOST_BRANCH=develop

View File

@ -1,5 +1,5 @@
////
Copyright 2019, 2020 Peter Dimov
Copyright 2019-2021 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
@ -11,6 +11,16 @@ http://www.boost.org/LICENSE_1_0.txt
# Revision History
:idprefix: changelog_
## Changes in 1.76.0
* Improved generated code for the double buffered case.
## Changes in 1.74.0
* Added support for derived types in `visit`
* Improved compilation performance for many (hundreds of) alternatives.
* Added support for `visit<R>`
## Changes in 1.73.0
* Added support for `std::hash`, `boost::hash`.

View File

@ -134,7 +134,7 @@ template<class... T>
// visit
template<class F, class... V>
template<class R = /*unspecified*/, class F, class... V>
constexpr /*see below*/ visit(F&& f, V&&... v);
// monostate
@ -490,8 +490,8 @@ template<size_t I, class... A>
+
Requires: :: `I < sizeof...(T)`.
Effects: ::
Destroys the currently contained value, then initializes a new contained
value as if using the expression `Ti(std::forward<A>(a)...)`.
Initializes a new contained value as if using the expression
`Ti(std::forward<A>(a)...)`, then destroys the currently contained value.
Ensures: :: `index() == I`.
Returns: :: A reference to the new contained value.
Throws: ::
@ -511,8 +511,8 @@ template<size_t I, class V, class... A>
+
Requires: :: `I < sizeof...(T)`.
Effects: ::
Destroys the currently contained value, then initializes a new contained
value as if using the expression `Ti(il, std::forward<A>(a)...)`.
Initializes a new contained value as if using the expression
`Ti(il, std::forward<A>(a)...)`, then destroys the currently contained value.
Ensures: :: `index() == I`.
Returns: :: A reference to the new contained value.
Throws: ::
@ -838,7 +838,7 @@ Returns: ::
### visit
```
template<class F, class... V>
template<class R = /*unspecified*/, class F, class... V>
constexpr /*see below*/ visit(F&& f, V&&... v);
```
[none]
@ -846,6 +846,10 @@ template<class F, class... V>
+
Returns: :: `std::forward<F>(f)(get<I>(std::forward<V>(v))...)`, where
`I...` is `v.index()...`.
Remarks: :: If `R` is given explicitly, as in `visit<int>`, the return
type is `R`. Otherwise, it's deduced from `F`. All possible applications
of `F` to the variant alternatives must have the same return type for
this deduction to succeed.
### swap

View File

@ -26,6 +26,7 @@
#include <initializer_list>
#include <utility>
#include <functional> // std::hash
#include <cstdint>
//
@ -38,6 +39,8 @@ BOOST_NORETURN void throw_exception( std::exception const & e ); // user defined
#endif
template<class T> struct hash;
namespace variant2
{
@ -81,6 +84,8 @@ struct monostate
{
};
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1940)
constexpr bool operator<(monostate, monostate) noexcept { return false; }
constexpr bool operator>(monostate, monostate) noexcept { return false; }
constexpr bool operator<=(monostate, monostate) noexcept { return true; }
@ -88,6 +93,17 @@ constexpr bool operator>=(monostate, monostate) noexcept { return true; }
constexpr bool operator==(monostate, monostate) noexcept { return true; }
constexpr bool operator!=(monostate, monostate) noexcept { return false; }
#else
constexpr bool operator<(monostate const&, monostate const&) noexcept { return false; }
constexpr bool operator>(monostate const&, monostate const&) noexcept { return false; }
constexpr bool operator<=(monostate const&, monostate const&) noexcept { return true; }
constexpr bool operator>=(monostate const&, monostate const&) noexcept { return true; }
constexpr bool operator==(monostate const&, monostate const&) noexcept { return true; }
constexpr bool operator!=(monostate const&, monostate const&) noexcept { return false; }
#endif
// variant forward declaration
template<class... T> class variant;
@ -520,11 +536,11 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_false, T1, T.
T1 first_;
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
{
}
template<std::size_t I, class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
{
}
@ -549,17 +565,99 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_false, T1, T.
template<std::size_t I> constexpr mp11::mp_at_c<mp11::mp_list<T...>, I-1> const& get( mp11::mp_size_t<I> ) const noexcept { return rest_.get( mp11::mp_size_t<I-1>() ); }
};
template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class... T> union variant_storage_impl<mp11::mp_false, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T...>
{
T0 t0_;
T1 t1_;
T2 t2_;
T3 t3_;
T4 t4_;
T5 t5_;
T6 t6_;
T7 t7_;
T8 t8_;
T9 t9_;
variant_storage<T...> rest_;
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
~variant_storage_impl()
{
}
template<class... A> void emplace( mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<2>, A&&... a ) { ::new( &t2_ ) T2( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<3>, A&&... a ) { ::new( &t3_ ) T3( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<4>, A&&... a ) { ::new( &t4_ ) T4( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<5>, A&&... a ) { ::new( &t5_ ) T5( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<6>, A&&... a ) { ::new( &t6_ ) T6( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<7>, A&&... a ) { ::new( &t7_ ) T7( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<8>, A&&... a ) { ::new( &t8_ ) T8( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<9>, A&&... a ) { ::new( &t9_ ) T9( std::forward<A>(a)... ); }
template<std::size_t I, class... A> void emplace( mp11::mp_size_t<I>, A&&... a )
{
rest_.emplace( mp11::mp_size_t<I-10>(), std::forward<A>(a)... );
}
BOOST_CXX14_CONSTEXPR T0& get( mp11::mp_size_t<0> ) noexcept { return t0_; }
constexpr T0 const& get( mp11::mp_size_t<0> ) const noexcept { return t0_; }
BOOST_CXX14_CONSTEXPR T1& get( mp11::mp_size_t<1> ) noexcept { return t1_; }
constexpr T1 const& get( mp11::mp_size_t<1> ) const noexcept { return t1_; }
BOOST_CXX14_CONSTEXPR T2& get( mp11::mp_size_t<2> ) noexcept { return t2_; }
constexpr T2 const& get( mp11::mp_size_t<2> ) const noexcept { return t2_; }
BOOST_CXX14_CONSTEXPR T3& get( mp11::mp_size_t<3> ) noexcept { return t3_; }
constexpr T3 const& get( mp11::mp_size_t<3> ) const noexcept { return t3_; }
BOOST_CXX14_CONSTEXPR T4& get( mp11::mp_size_t<4> ) noexcept { return t4_; }
constexpr T4 const& get( mp11::mp_size_t<4> ) const noexcept { return t4_; }
BOOST_CXX14_CONSTEXPR T5& get( mp11::mp_size_t<5> ) noexcept { return t5_; }
constexpr T5 const& get( mp11::mp_size_t<5> ) const noexcept { return t5_; }
BOOST_CXX14_CONSTEXPR T6& get( mp11::mp_size_t<6> ) noexcept { return t6_; }
constexpr T6 const& get( mp11::mp_size_t<6> ) const noexcept { return t6_; }
BOOST_CXX14_CONSTEXPR T7& get( mp11::mp_size_t<7> ) noexcept { return t7_; }
constexpr T7 const& get( mp11::mp_size_t<7> ) const noexcept { return t7_; }
BOOST_CXX14_CONSTEXPR T8& get( mp11::mp_size_t<8> ) noexcept { return t8_; }
constexpr T8 const& get( mp11::mp_size_t<8> ) const noexcept { return t8_; }
BOOST_CXX14_CONSTEXPR T9& get( mp11::mp_size_t<9> ) noexcept { return t9_; }
constexpr T9 const& get( mp11::mp_size_t<9> ) const noexcept { return t9_; }
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<mp11::mp_list<T...>, I-10>& get( mp11::mp_size_t<I> ) noexcept { return rest_.get( mp11::mp_size_t<I-10>() ); }
template<std::size_t I> constexpr mp11::mp_at_c<mp11::mp_list<T...>, I-10> const& get( mp11::mp_size_t<I> ) const noexcept { return rest_.get( mp11::mp_size_t<I-10>() ); }
};
// all trivially destructible
template<class T1, class... T> union variant_storage_impl<mp11::mp_true, T1, T...>
{
T1 first_;
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
{
}
template<std::size_t I, class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
{
}
@ -590,6 +688,105 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_true, T1, T..
template<std::size_t I> constexpr mp11::mp_at_c<mp11::mp_list<T...>, I-1> const& get( mp11::mp_size_t<I> ) const noexcept { return rest_.get( mp11::mp_size_t<I-1>() ); }
};
template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class... T> union variant_storage_impl<mp11::mp_true, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T...>
{
T0 t0_;
T1 t1_;
T2 t2_;
T3 t3_;
T4 t4_;
T5 t5_;
T6 t6_;
T7 t7_;
T8 t8_;
T9 t9_;
variant_storage<T...> rest_;
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<2>, A&&... a ) { ::new( &t2_ ) T2( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<3>, A&&... a ) { ::new( &t3_ ) T3( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<4>, A&&... a ) { ::new( &t4_ ) T4( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<5>, A&&... a ) { ::new( &t5_ ) T5( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<6>, A&&... a ) { ::new( &t6_ ) T6( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<7>, A&&... a ) { ::new( &t7_ ) T7( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<8>, A&&... a ) { ::new( &t8_ ) T8( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<9>, A&&... a ) { ::new( &t9_ ) T9( std::forward<A>(a)... ); }
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<I>, A&&... a )
{
rest_.emplace( mp11::mp_size_t<I-10>(), std::forward<A>(a)... );
}
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, mp11::mp_size_t<I>, A&&... a )
{
*this = variant_storage_impl( mp11::mp_size_t<I>(), std::forward<A>(a)... );
}
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<I>, A&&... a )
{
this->emplace_impl( mp11::mp_all<
detail::is_trivially_move_assignable<T0>,
detail::is_trivially_move_assignable<T1>,
detail::is_trivially_move_assignable<T2>,
detail::is_trivially_move_assignable<T3>,
detail::is_trivially_move_assignable<T4>,
detail::is_trivially_move_assignable<T5>,
detail::is_trivially_move_assignable<T6>,
detail::is_trivially_move_assignable<T7>,
detail::is_trivially_move_assignable<T8>,
detail::is_trivially_move_assignable<T9>,
detail::is_trivially_move_assignable<T>...>(), mp11::mp_size_t<I>(), std::forward<A>(a)... );
}
BOOST_CXX14_CONSTEXPR T0& get( mp11::mp_size_t<0> ) noexcept { return t0_; }
constexpr T0 const& get( mp11::mp_size_t<0> ) const noexcept { return t0_; }
BOOST_CXX14_CONSTEXPR T1& get( mp11::mp_size_t<1> ) noexcept { return t1_; }
constexpr T1 const& get( mp11::mp_size_t<1> ) const noexcept { return t1_; }
BOOST_CXX14_CONSTEXPR T2& get( mp11::mp_size_t<2> ) noexcept { return t2_; }
constexpr T2 const& get( mp11::mp_size_t<2> ) const noexcept { return t2_; }
BOOST_CXX14_CONSTEXPR T3& get( mp11::mp_size_t<3> ) noexcept { return t3_; }
constexpr T3 const& get( mp11::mp_size_t<3> ) const noexcept { return t3_; }
BOOST_CXX14_CONSTEXPR T4& get( mp11::mp_size_t<4> ) noexcept { return t4_; }
constexpr T4 const& get( mp11::mp_size_t<4> ) const noexcept { return t4_; }
BOOST_CXX14_CONSTEXPR T5& get( mp11::mp_size_t<5> ) noexcept { return t5_; }
constexpr T5 const& get( mp11::mp_size_t<5> ) const noexcept { return t5_; }
BOOST_CXX14_CONSTEXPR T6& get( mp11::mp_size_t<6> ) noexcept { return t6_; }
constexpr T6 const& get( mp11::mp_size_t<6> ) const noexcept { return t6_; }
BOOST_CXX14_CONSTEXPR T7& get( mp11::mp_size_t<7> ) noexcept { return t7_; }
constexpr T7 const& get( mp11::mp_size_t<7> ) const noexcept { return t7_; }
BOOST_CXX14_CONSTEXPR T8& get( mp11::mp_size_t<8> ) noexcept { return t8_; }
constexpr T8 const& get( mp11::mp_size_t<8> ) const noexcept { return t8_; }
BOOST_CXX14_CONSTEXPR T9& get( mp11::mp_size_t<9> ) noexcept { return t9_; }
constexpr T9 const& get( mp11::mp_size_t<9> ) const noexcept { return t9_; }
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<mp11::mp_list<T...>, I-10>& get( mp11::mp_size_t<I> ) noexcept { return rest_.get( mp11::mp_size_t<I-10>() ); }
template<std::size_t I> constexpr mp11::mp_at_c<mp11::mp_list<T...>, I-10> const& get( mp11::mp_size_t<I> ) const noexcept { return rest_.get( mp11::mp_size_t<I-10>() ); }
};
// resolve_overload_*
template<class... T> struct overload;
@ -633,21 +830,21 @@ struct none {};
// trivially destructible, single buffered
template<class... T> struct variant_base_impl<true, true, T...>
{
int ix_;
variant_storage<none, T...> st1_;
unsigned ix_;
variant_storage<none, T...> st_;
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): ix_( 0 ), st_( mp11::mp_size_t<0>() )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
{
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
{
::new( &st1_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
::new( &st_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = I::value + 1;
}
@ -662,7 +859,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
assert( ix_ == J );
return st1_.get( mp11::mp_size_t<J>() );
return st_.get( mp11::mp_size_t<J>() );
}
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
@ -670,14 +867,14 @@ template<class... T> struct variant_base_impl<true, true, T...>
// size_t const J = I+1;
// assert( ix_ == I+1 );
return st1_.get( mp11::mp_size_t<I+1>() );
return st_.get( mp11::mp_size_t<I+1>() );
}
template<std::size_t J, class U, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, A&&... a )
{
static_assert( std::is_nothrow_constructible<U, A&&...>::value, "Logic error: U must be nothrow constructible from A&&..." );
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
st_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
ix_ = J;
}
@ -687,7 +884,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
U tmp( std::forward<A>(a)... );
st1_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
st_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
ix_ = J;
}
@ -703,84 +900,78 @@ template<class... T> struct variant_base_impl<true, true, T...>
// trivially destructible, double buffered
template<class... T> struct variant_base_impl<true, false, T...>
{
int ix_;
variant_storage<none, T...> st1_;
variant_storage<none, T...> st2_;
unsigned ix_;
variant_storage<none, T...> st_[ 2 ];
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): ix_( 0 ), st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), st2_( mp11::mp_size_t<0>() )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st_{ { mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... }, { mp11::mp_size_t<0>() } }
{
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
{
::new( &st1_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = I::value + 1;
::new( &st_[ 0 ] ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = ( I::value + 1 ) * 2;
}
constexpr std::size_t index() const noexcept
{
return ix_ >= 0? ix_ - 1: -ix_ - 1;
return ix_ / 2 - 1;
}
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<variant<T...>, I>& _get_impl( mp11::mp_size_t<I> ) noexcept
{
assert( index() == I );
size_t const J = I+1;
assert( ix_ == J || -ix_ == J );
constexpr mp11::mp_size_t<J> j{};
return ix_ >= 0? st1_.get( j ): st2_.get( j );
return st_[ ix_ & 1 ].get( j );
}
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
{
// assert( index() == I );
// size_t const J = I+1;
// assert( ix_ == J || -ix_ == J );
// constexpr mp_size_t<J> j{};
return ix_ >= 0? st1_.get( mp11::mp_size_t<I+1>() ): st2_.get( mp11::mp_size_t<I+1>() );
return st_[ ix_ & 1 ].get( mp11::mp_size_t<I+1>() );
}
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( A&&... a )
{
size_t const J = I+1;
if( ix_ >= 0 )
{
st2_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
ix_ = -static_cast<int>( J );
}
else
{
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
ix_ = J;
}
unsigned i2 = 1 - ( ix_ & 1 );
st_[ i2 ].emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
ix_ = J * 2 + i2;
}
};
// not trivially destructible, single buffered
template<class... T> struct variant_base_impl<false, true, T...>
{
int ix_;
variant_storage<none, T...> st1_;
unsigned ix_;
variant_storage<none, T...> st_;
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): ix_( 0 ), st_( mp11::mp_size_t<0>() )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
{
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
{
::new( &st1_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
::new( &st_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = I::value + 1;
}
@ -796,7 +987,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
template<class I> void operator()( I ) const noexcept
{
using U = mp11::mp_at<mp11::mp_list<none, T...>, I>;
this_->st1_.get( I() ).~U();
this_->st_.get( I() ).~U();
}
};
@ -824,7 +1015,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
assert( ix_ == J );
return st1_.get( mp11::mp_size_t<J>() );
return st_.get( mp11::mp_size_t<J>() );
}
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
@ -832,7 +1023,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
// size_t const J = I+1;
// assert( ix_ == J );
return st1_.get( mp11::mp_size_t<I+1>() );
return st_.get( mp11::mp_size_t<I+1>() );
}
template<std::size_t I, class... A> void emplace( A&&... a )
@ -847,7 +1038,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
_destroy();
st1_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
st_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
ix_ = J;
}
};
@ -855,23 +1046,61 @@ template<class... T> struct variant_base_impl<false, true, T...>
// not trivially destructible, double buffered
template<class... T> struct variant_base_impl<false, false, T...>
{
int ix_;
variant_storage<none, T...> st1_;
variant_storage<none, T...> st2_;
unsigned ix_;
#if defined(__GNUC__) && __GNUC__ < 11 && !defined(__clang__) && !defined(__INTEL_COMPILER)
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63707 :-(
variant_storage<none, T...> st1_, st2_;
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), st2_( mp11::mp_size_t<0>() )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), st2_( mp11::mp_size_t<0>() )
{
}
BOOST_CXX14_CONSTEXPR variant_storage<none, T...>& storage( unsigned i2 ) noexcept
{
return i2 == 0? st1_: st2_;
}
constexpr variant_storage<none, T...> const& storage( unsigned i2 ) const noexcept
{
return i2 == 0? st1_: st2_;
}
#else
variant_storage<none, T...> st_[ 2 ];
constexpr variant_base_impl(): ix_( 0 ), st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st_{ { mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... }, { mp11::mp_size_t<0>() } }
{
}
BOOST_CXX14_CONSTEXPR variant_storage<none, T...>& storage( unsigned i2 ) noexcept
{
return st_[ i2 ];
}
constexpr variant_storage<none, T...> const& storage( unsigned i2 ) const noexcept
{
return st_[ i2 ];
}
#endif
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
{
::new( &st1_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = I::value + 1;
::new( &storage( 0 ) ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = ( I::value + 1 ) * 2;
}
//[&]( auto I ){
@ -882,35 +1111,18 @@ template<class... T> struct variant_base_impl<false, false, T...>
struct _destroy_L1
{
variant_base_impl * this_;
unsigned i2_;
template<class I> void operator()( I ) const noexcept
{
using U = mp11::mp_at<mp11::mp_list<none, T...>, I>;
this_->st1_.get( I() ).~U();
}
};
struct _destroy_L2
{
variant_base_impl * this_;
template<class I> void operator()( I ) const noexcept
{
using U = mp11::mp_at<mp11::mp_list<none, T...>, I>;
this_->st2_.get( I() ).~U();
this_->storage( i2_ ).get( I() ).~U();
}
};
void _destroy() noexcept
{
if( ix_ > 0 )
{
mp11::mp_with_index<1 + sizeof...(T)>( ix_, _destroy_L1{ this } );
}
else if( ix_ < 0 )
{
mp11::mp_with_index<1 + sizeof...(T)>( -ix_, _destroy_L2{ this } );
}
mp11::mp_with_index<1 + sizeof...(T)>( ix_ / 2, _destroy_L1{ this, ix_ & 1 } );
}
~variant_base_impl() noexcept
@ -920,46 +1132,38 @@ template<class... T> struct variant_base_impl<false, false, T...>
constexpr std::size_t index() const noexcept
{
return ix_ >= 0? ix_ - 1: -ix_ - 1;
return ix_ / 2 - 1;
}
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<variant<T...>, I>& _get_impl( mp11::mp_size_t<I> ) noexcept
{
assert( index() == I );
size_t const J = I+1;
assert( ix_ == J || -ix_ == J );
constexpr mp11::mp_size_t<J> j{};
return ix_ >= 0? st1_.get( j ): st2_.get( j );
return storage( ix_ & 1 ).get( j );
}
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
{
// assert( index() == I );
// size_t const J = I+1;
// assert( ix_ == J || -ix_ == J );
// constexpr mp_size_t<J> j{};
return ix_ >= 0? st1_.get( mp11::mp_size_t<I+1>() ): st2_.get( mp11::mp_size_t<I+1>() );
return storage( ix_ & 1 ).get( mp11::mp_size_t<I+1>() );
}
template<std::size_t I, class... A> void emplace( A&&... a )
{
size_t const J = I+1;
if( ix_ >= 0 )
{
st2_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
_destroy();
unsigned i2 = 1 - ( ix_ & 1 );
ix_ = -static_cast<int>( J );
}
else
{
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
_destroy();
storage( i2 ).emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
_destroy();
ix_ = J;
}
ix_ = J * 2 + i2;
}
};
@ -1768,6 +1972,25 @@ namespace detail
template<class T> using remove_cv_ref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template<class... T> variant<T...> const & extract_variant_base_( variant<T...> const & );
#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
template<class V> struct extract_vbase_impl
{
using type = decltype( extract_variant_base_( std::declval<V>() ) );
};
template<class V> using extract_variant_base = remove_cv_ref_t< typename extract_vbase_impl<V>::type >;
#else
template<class V> using extract_variant_base = remove_cv_ref_t< decltype( extract_variant_base_( std::declval<V>() ) ) >;
#endif
template<class V> using variant_base_size = variant_size< extract_variant_base<V> >;
template<class T, class U> struct copy_cv_ref
{
using type = T;
@ -1807,13 +2030,28 @@ template<class F> struct Qret
template<class L> using front_if_same = mp11::mp_if<mp11::mp_apply<mp11::mp_same, L>, mp11::mp_front<L>>;
template<class V> using apply_cv_ref = mp11::mp_product<copy_cv_ref_t, remove_cv_ref_t<V>, mp11::mp_list<V>>;
template<class V> using apply_cv_ref = mp11::mp_product<copy_cv_ref_t, extract_variant_base<V>, mp11::mp_list<V>>;
template<class F, class... V> using Vret = front_if_same<mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...>>;
struct deduced {};
#if !BOOST_WORKAROUND( BOOST_MSVC, < 1920 )
template<class R, class F, class... V> using Vret = mp11::mp_eval_if_not< std::is_same<R, deduced>, R, front_if_same, mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...> >;
#else
template<class R, class F, class... V> struct Vret_impl
{
using type = mp11::mp_eval_if_not< std::is_same<R, deduced>, R, front_if_same, mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...> >;
};
template<class R, class F, class... V> using Vret = typename Vret_impl<R, F, V...>::type;
#endif
} // namespace detail
template<class F> constexpr auto visit( F&& f ) -> decltype(std::forward<F>(f)())
template<class R = detail::deduced, class F> constexpr auto visit( F&& f ) -> detail::Vret<R, F>
{
return std::forward<F>(f)();
}
@ -1821,12 +2059,12 @@ template<class F> constexpr auto visit( F&& f ) -> decltype(std::forward<F>(f)()
namespace detail
{
template<class F, class V1> struct visit_L1
template<class R, class F, class V1> struct visit_L1
{
F&& f;
V1&& v1;
template<class I> auto operator()( I ) const -> Vret<F, V1>
template<class I> auto operator()( I ) const -> Vret<R, F, V1>
{
return std::forward<F>(f)( unsafe_get<I::value>( std::forward<V1>(v1) ) );
}
@ -1834,9 +2072,9 @@ template<class F, class V1> struct visit_L1
} // namespace detail
template<class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret<F, V1>
template<class R = detail::deduced, class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret<R, F, V1>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L1<F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L1<R, F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
}
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) || BOOST_WORKAROUND( BOOST_MSVC, < 1920 )
@ -1860,31 +2098,31 @@ template<class F, class A> bind_front_<F, A> bind_front( F&& f, A&& a )
return bind_front_<F, A>{ std::forward<F>(f), std::forward<A>(a) };
}
template<class F, class V1, class V2> struct visit_L2
template<class R, class F, class V1, class V2> struct visit_L2
{
F&& f;
V1&& v1;
V2&& v2;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2) );
return visit<R>( f2, std::forward<V2>(v2) );
}
};
} // namespace detail
template<class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret<F, V1, V2>
template<class R = detail::deduced, class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret<R, F, V1, V2>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L2<F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L2<R, F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
}
namespace detail
{
template<class F, class V1, class V2, class V3> struct visit_L3
template<class R, class F, class V1, class V2, class V3> struct visit_L3
{
F&& f;
@ -1892,24 +2130,24 @@ template<class F, class V1, class V2, class V3> struct visit_L3
V2&& v2;
V3&& v3;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2, V3>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2, V3>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2), std::forward<V3>(v3) );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V3>(v3) );
}
};
} // namespace detail
template<class F, class V1, class V2, class V3> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> detail::Vret<F, V1, V2, V3>
template<class R = detail::deduced, class F, class V1, class V2, class V3> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> detail::Vret<R, F, V1, V2, V3>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L3<F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L3<R, F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
}
namespace detail
{
template<class F, class V1, class V2, class V3, class V4> struct visit_L4
template<class R, class F, class V1, class V2, class V3, class V4> struct visit_L4
{
F&& f;
@ -1918,28 +2156,28 @@ template<class F, class V1, class V2, class V3, class V4> struct visit_L4
V3&& v3;
V4&& v4;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2, V3, V4>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2, V3, V4>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) );
}
};
} // namespace detail
template<class F, class V1, class V2, class V3, class V4> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> detail::Vret<F, V1, V2, V3, V4>
template<class R = detail::deduced, class F, class V1, class V2, class V3, class V4> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> detail::Vret<R, F, V1, V2, V3, V4>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L4<F, V1, V2, V3, V4>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L4<R, F, V1, V2, V3, V4>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) } );
}
#else
template<class F, class V1, class V2, class... V> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> detail::Vret<F, V1, V2, V...>
template<class R = detail::deduced, class F, class V1, class V2, class... V> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> detail::Vret<R, F, V1, V2, V...>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), [&]( auto I ){
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), [&]( auto I ){
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( detail::unsafe_get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
return visit( f2, std::forward<V2>(v2), std::forward<V>(v)... );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V>(v)... );
});
}
@ -1960,31 +2198,59 @@ void swap( variant<T...> & v, variant<T...> & w )
namespace detail
{
template<class V> struct hash_value_L
inline std::size_t hash_value_impl_( mp11::mp_true, std::size_t index, std::size_t value )
{
boost::ulong_long_type hv = ( boost::ulong_long_type( 0xCBF29CE4 ) << 32 ) + 0x84222325;
boost::ulong_long_type const prime = ( boost::ulong_long_type( 0x00000100 ) << 32 ) + 0x000001B3;
hv ^= index;
hv *= prime;
hv ^= value;
hv *= prime;
return static_cast<std::size_t>( hv );
}
inline std::size_t hash_value_impl_( mp11::mp_false, std::size_t index, std::size_t value )
{
std::size_t hv = 0x811C9DC5;
std::size_t const prime = 0x01000193;
hv ^= index;
hv *= prime;
hv ^= value;
hv *= prime;
return hv;
}
inline std::size_t hash_value_impl( std::size_t index, std::size_t value )
{
return hash_value_impl_( mp11::mp_bool< (SIZE_MAX > UINT32_MAX) >(), index, value );
}
template<template<class> class H, class V> struct hash_value_L
{
V const & v;
template<class I> std::size_t operator()( I ) const
{
boost::ulong_long_type hv = ( boost::ulong_long_type( 0xCBF29CE4 ) << 32 ) + 0x84222325;
boost::ulong_long_type const prime = ( boost::ulong_long_type( 0x00000100 ) << 32 ) + 0x000001B3;
// index
hv ^= I::value;
hv *= prime;
// value
auto const & t = unsafe_get<I::value>( v );
hv ^= std::hash<remove_cv_ref_t<decltype(t)>>()( t );
hv *= prime;
std::size_t index = I::value;
std::size_t value = H<remove_cv_ref_t<decltype(t)>>()( t );
return static_cast<std::size_t>( hv );
return hash_value_impl( index, value );
}
};
template<class... T> std::size_t hash_value_std( variant<T...> const & v )
{
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< std::hash, variant<T...> >{ v } );
}
} // namespace detail
inline std::size_t hash_value( monostate const & )
@ -1994,7 +2260,7 @@ inline std::size_t hash_value( monostate const & )
template<class... T> std::size_t hash_value( variant<T...> const & v )
{
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< variant<T...> >{ v } );
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< boost::hash, variant<T...> >{ v } );
}
namespace detail
@ -2015,7 +2281,7 @@ template<class V> struct std_hash_impl<V, true>
{
std::size_t operator()( V const & v ) const
{
return hash_value( v );
return detail::hash_value_std( v );
}
};

View File

@ -5,10 +5,11 @@
"Peter Dimov"
],
"maintainers": [
"Peter Dimov <pdimov -at- pdimov.com>"
"Peter Dimov <pdimov -at- gmail.com>"
],
"description": "A never-valueless, strong guarantee implementation of std::variant.",
"category": [
"Containers", "Data"
]
],
"cxxstd": "11"
}

View File

@ -110,3 +110,12 @@ run variant_hash.cpp ;
run variant_trivial.cpp ;
run variant_special.cpp ;
run variant_visit_derived.cpp ;
run variant_many_types.cpp ;
run variant_visit_r.cpp : : :
<toolset>gcc,<target-os>windows:<variant>release
<toolset>gcc,<target-os>cygwin:<variant>release
;

View File

@ -57,6 +57,60 @@ STATIC_ASSERT( !std::is_nothrow_move_constructible<X2>::value );
STATIC_ASSERT( !std::is_nothrow_copy_assignable<X2>::value );
STATIC_ASSERT( !std::is_nothrow_move_assignable<X2>::value );
struct Y1
{
int v = 1;
Y1() = default;
Y1(Y1 const&) = delete;
Y1(Y1&&) = delete;
};
STATIC_ASSERT( !std::is_copy_constructible<Y1>::value );
STATIC_ASSERT( !std::is_move_constructible<Y1>::value );
struct Y2
{
int v = 2;
Y2() = default;
Y2(Y2 const&) = delete;
Y2(Y2&&) = delete;
};
STATIC_ASSERT( !std::is_copy_constructible<Y2>::value );
STATIC_ASSERT( !std::is_move_constructible<Y2>::value );
struct Z1
{
static int instances;
int v = 1;
Z1() { ++instances; }
~Z1() { --instances; }
Z1(Z1 const&) = delete;
Z1(Z1&&) = delete;
};
int Z1::instances = 0;
struct Z2
{
static int instances;
int v = 2;
Z2() { ++instances; }
~Z2() { --instances; }
Z2(Z2 const&) = delete;
Z2(Z2&&) = delete;
};
int Z2::instances = 0;
int main()
{
{
@ -177,5 +231,62 @@ int main()
BOOST_TEST_EQ( get<0>(v).v, 4 );
}
{
variant<Y1, Y2> v;
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
v.emplace<0>();
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
v.emplace<1>();
BOOST_TEST_EQ( v.index(), 1 );
BOOST_TEST_EQ( get<1>(v).v, 2 );
v.emplace<1>();
BOOST_TEST_EQ( v.index(), 1 );
BOOST_TEST_EQ( get<1>(v).v, 2 );
v.emplace<0>();
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
}
{
variant<Z1, Z2> v;
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
BOOST_TEST_EQ( Z1::instances, 1 );
BOOST_TEST_EQ( Z2::instances, 0 );
v.emplace<0>();
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
BOOST_TEST_EQ( Z1::instances, 1 );
BOOST_TEST_EQ( Z2::instances, 0 );
v.emplace<1>();
BOOST_TEST_EQ( v.index(), 1 );
BOOST_TEST_EQ( get<1>(v).v, 2 );
BOOST_TEST_EQ( Z1::instances, 0 );
BOOST_TEST_EQ( Z2::instances, 1 );
v.emplace<1>();
BOOST_TEST_EQ( v.index(), 1 );
BOOST_TEST_EQ( get<1>(v).v, 2 );
BOOST_TEST_EQ( Z1::instances, 0 );
BOOST_TEST_EQ( Z2::instances, 1 );
v.emplace<0>();
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
BOOST_TEST_EQ( Z1::instances, 1 );
BOOST_TEST_EQ( Z2::instances, 0 );
}
BOOST_TEST_EQ( Z1::instances, 0 );
BOOST_TEST_EQ( Z2::instances, 0 );
return boost::report_errors();
}

View File

@ -88,5 +88,12 @@ int main()
BOOST_TEST_NOT( v1 != v2 );
}
{
variant<monostate> v1, v2;
BOOST_TEST( v1 == v2 );
BOOST_TEST_NOT( v1 != v2 );
}
return boost::report_errors();
}

View File

@ -93,6 +93,13 @@ int main()
STATIC_ASSERT( !(v1 == v2) );
STATIC_ASSERT( !(v1 != v2) );
}
{
constexpr variant<monostate> v1, v2;
STATIC_ASSERT( v1 == v2 );
STATIC_ASSERT( !(v1 != v2) );
}
}
#endif

View File

@ -6,6 +6,12 @@
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#if defined( __clang__ ) && defined( __has_warning )
# if __has_warning( "-Wdeprecated-volatile" )
# pragma clang diagnostic ignored "-Wdeprecated-volatile"
# endif
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>

View File

@ -6,6 +6,12 @@
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#if defined( __clang__ ) && defined( __has_warning )
# if __has_warning( "-Wdeprecated-volatile" )
# pragma clang diagnostic ignored "-Wdeprecated-volatile"
# endif
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>

View File

@ -12,6 +12,7 @@
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/config/workaround.hpp>
#include <vector>
using namespace boost::variant2;
@ -47,7 +48,17 @@ template<template<class...> class Hash, class T> void test2()
BOOST_TEST_NE( h2, h3 );
}
struct X {};
struct X
{
int m = 0;
};
std::size_t hash_value( X const& x )
{
return boost::hash<int>()( x.m );
}
struct Y {}; // no hash support
int main()
{
@ -57,6 +68,8 @@ int main()
test<boost::hash, monostate, monostate, monostate>();
test<boost::hash, int, int, float>();
test<boost::hash, monostate, X, std::vector<X>>();
test2<std::hash, int>();
test2<std::hash, float>();
@ -65,7 +78,7 @@ int main()
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910) && ( !defined(_LIBCPP_STD_VER) || _LIBCPP_STD_VER > 11 )
BOOST_TEST_TRAIT_FALSE(( detail::is_hash_enabled<X> ));
BOOST_TEST_TRAIT_FALSE(( detail::is_hash_enabled<Y> ));
#endif

View File

@ -7,11 +7,8 @@
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <utility>
#include <string>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
using namespace boost::variant2;
@ -108,9 +105,17 @@ int main()
STATIC_ASSERT( v.index() == 4 );
}
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 110000)
// no idea why this fails on g++ 10
#else
{
constexpr variant<int, int, float, float, X, X> v( in_place_index_t<5>{}, 0, 0 );
STATIC_ASSERT( v.index() == 5 );
}
#endif
}

View File

@ -7,6 +7,8 @@
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
using namespace boost::variant2;
@ -100,6 +102,12 @@ int main()
STATIC_ASSERT( holds_alternative<X>(v) );
}
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 110000)
// no idea why this fails on g++ 10
#else
{
constexpr variant<int, int, float, float, X> v( in_place_type_t<X>{}, 0, 0 );
@ -107,4 +115,6 @@ int main()
STATIC_ASSERT( holds_alternative<X>(v) );
}
#endif
}

View File

@ -81,5 +81,14 @@ int main()
BOOST_TEST_NOT( v1 >= v2 );
}
{
variant<monostate> v1, v2;
BOOST_TEST_NOT( v1 < v2 );
BOOST_TEST_NOT( v1 > v2 );
BOOST_TEST( v1 <= v2 );
BOOST_TEST( v1 >= v2 );
}
return boost::report_errors();
}

View File

@ -86,6 +86,15 @@ int main()
STATIC_ASSERT( !(v1 <= v2) );
STATIC_ASSERT( !(v1 >= v2) );
}
{
constexpr variant<monostate> v1, v2;
STATIC_ASSERT( !(v1 < v2) );
STATIC_ASSERT( !(v1 > v2) );
STATIC_ASSERT( v1 <= v2 );
STATIC_ASSERT( v1 >= v2 );
}
}
#endif

109
test/variant_many_types.cpp Normal file
View File

@ -0,0 +1,109 @@
// Copyright 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning( disable: 4503 ) // decorated name length exceeded
#endif
#include <boost/variant2/variant.hpp>
#include <boost/mp11.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::mp11;
template<class I> struct X
{
static int const value = I::value;
int v_;
};
template<class I> int const X<I>::value;
template<class I> struct Y
{
static int const value = I::value;
int v_;
Y() = default;
Y( Y const& ) = default;
explicit Y( int v ): v_( v ) {}
Y& operator=( Y const& ) noexcept = default;
Y& operator=( Y&& r ) noexcept
{
v_ = r.v_;
return *this;
}
};
template<class I> int const Y<I>::value;
template<class I> struct Z
{
static int const value = I::value;
int v_;
~Z() {}
};
template<class I> int const Z<I>::value;
template<class V> struct F1
{
template<class T> void operator()( T ) const
{
int const i = T::value;
T t{ i * 2 };
using boost::variant2::get;
{
V v( t );
BOOST_TEST_EQ( v.index(), i );
BOOST_TEST_EQ( get<i>( v ).v_, t.v_ );
BOOST_TEST_EQ( get<T>( v ).v_, t.v_ );
}
{
V const v( t );
BOOST_TEST_EQ( v.index(), i );
BOOST_TEST_EQ( get<i>( v ).v_, t.v_ );
BOOST_TEST_EQ( get<T>( v ).v_, t.v_ );
}
{
V v;
v = t;
BOOST_TEST_EQ( v.index(), i );
BOOST_TEST_EQ( get<i>( v ).v_, t.v_ );
BOOST_TEST_EQ( get<T>( v ).v_, t.v_ );
}
}
};
template<class V> void test()
{
mp_for_each<V>( F1<V>() );
}
int main()
{
int const N = 32;
using V = mp_rename<mp_iota_c<N>, boost::variant2::variant>;
test< mp_transform<X, V> >();
test< mp_transform<Y, V> >();
test< mp_transform<Z, V> >();
return boost::report_errors();
}

View File

@ -37,6 +37,10 @@ struct F
int main()
{
{
BOOST_TEST_EQ( (visit( []{ return 5; } )), 5 );
}
{
variant<int> v( 1 );

View File

@ -0,0 +1,57 @@
// Copyright 2017, 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning( disable: 4244 ) // conversion from float to int, possible loss of data
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <utility>
struct X: boost::variant2::variant<int, float>
{
#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
template<class T> explicit X( T&& t ): variant( std::forward<T>( t ) ) {};
#else
using variant::variant;
#endif
};
template<class... T> struct Y: boost::variant2::variant<T...>
{
using boost::variant2::variant<T...>::variant;
};
int main()
{
{
X v1( 1 );
X const v2( 3.14f );
BOOST_TEST_EQ( (visit( []( int x1, float x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 );
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 );
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) );
}
{
Y<int, float> v1( 1 );
Y<int, float> const v2( 3.14f );
BOOST_TEST_EQ( (visit( []( int x1, float x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 );
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 );
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) );
}
return boost::report_errors();
}

98
test/variant_visit_r.cpp Normal file
View File

@ -0,0 +1,98 @@
// Copyright 2017 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning( disable: 4244 ) // conversion from float to int, possible loss of data
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::variant2;
struct F1
{
template<class T1> T1 operator()( T1 t1 ) const
{
return t1;
}
};
struct F2
{
template<class T1, class T2> auto operator()( T1 t1, T2 t2 ) const -> decltype( t1 + t2 )
{
return t1 + t2;
}
};
struct F3
{
template<class T1, class T2, class T3> auto operator()( T1 t1, T2 t2, T3 t3 ) const -> decltype( t1 + t2 + t3 )
{
return t1 + t2 + t3;
}
};
struct F4
{
template<class T1, class T2, class T3, class T4> auto operator()( T1 t1, T2 t2, T3 t3, T4 t4 ) const -> decltype( t1 + t2 + t3 + t4 )
{
return t1 + t2 + t3 + t4;
}
};
int main()
{
{
BOOST_TEST_EQ( (visit<int>( []{ return 3.14f; } )), 3 );
}
{
variant<int, float> v( 1 );
BOOST_TEST_EQ( visit<int>( F1(), v ), 1 );
BOOST_TEST_EQ( visit<float>( F1(), v ), 1.0f );
}
{
variant<int, float> const v( 3.14f );
BOOST_TEST_EQ( visit<int>( F1(), v ), 3 );
BOOST_TEST_EQ( visit<float>( F1(), v ), 3.14f );
}
{
variant<int, float> v1( 1 );
variant<int, float> const v2( 3.14f );
BOOST_TEST_EQ( visit<int>( F2(), v1, v2 ), 4 );
BOOST_TEST_EQ( visit<float>( F2(), v1, v2 ), 1 + 3.14f );
}
{
variant<int, float, double> v1( 1 );
variant<int, float, double> const v2( 3.14f );
variant<int, float, double> v3( 6.28 );
BOOST_TEST_EQ( visit<int>( F3(), v1, v2, v3 ), 10 );
BOOST_TEST_EQ( visit<float>( F3(), v1, v2, v3 ), static_cast<float>( 1 + 3.14f + 6.28 ) );
}
{
variant<int, float, double, char> v1( 1 );
variant<int, float, double, char> const v2( 3.14f );
variant<int, float, double, char> v3( 6.28 );
variant<int, float, double, char> const v4( 'A' );
BOOST_TEST_EQ( visit<int>( F4(), v1, v2, v3, v4 ), 10 + 'A' );
BOOST_TEST_EQ( visit<float>( F4(), v1, v2, v3, v4 ), static_cast<float>( 1 + 3.14f + 6.28 + 'A' ) );
}
return boost::report_errors();
}