Compare commits

...

26 Commits

Author SHA1 Message Date
4153a535a0 Update .github/workflows 2021-04-19 20:37:12 +03:00
f374ad68a3 Add -DBUILD_TESTING=ON to .yml files; it's not default anymore 2021-03-19 04:18:08 +02:00
3bc9a57c9b Merge branch 'feature/issue-26' into develop 2021-03-13 18:23:39 +02:00
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
f39a71ed2f Merge branch 'feature/issue-26-nofix' into feature/issue-26 2021-03-13 01:09:46 +02:00
06dde96400 Merge branch 'develop' into feature/issue-26-nofix 2021-03-13 01:09:17 +02:00
8be0a4a5fe Update copyright 2021-03-12 23:42:32 +02:00
90cda5339f Disable U&& constructor for derived types 2021-03-12 23:40:14 +02:00
afb0aafd64 Change clangs to bionic 2021-03-12 20:18:24 +02:00
f586dc8848 Add test for inherited constructors (refs #26) 2021-03-12 20:15:09 +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
6de876954a Merge branch 'develop' into feature/double-opt 2021-01-13 02:32:32 +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
15 changed files with 317 additions and 179 deletions

View File

@ -17,10 +17,6 @@ jobs:
fail-fast: false
matrix:
include:
- toolset: gcc-4.7
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.7
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-16.04
@ -42,6 +38,7 @@ jobs:
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
install: g++-8
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
@ -87,6 +84,7 @@ jobs:
compiler: clang++-6.0
cxxstd: "03,11,14,17"
os: ubuntu-18.04
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "03,11,14,17"
@ -96,6 +94,7 @@ jobs:
compiler: clang++-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
@ -104,6 +103,10 @@ jobs:
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-10.15

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)
@ -95,7 +95,7 @@ matrix:
- os: linux
dist: bionic
compiler: g++-10
env: TOOLSET=gcc COMPILER=g++-10 CXXSTD=11,14,17,2a
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:
@ -103,21 +103,6 @@ matrix:
sources:
- 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
addons:
apt:
packages:
- g++-8
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
@ -180,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:
@ -190,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:
@ -200,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:
@ -208,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:
@ -219,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:
@ -231,11 +220,11 @@ 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
dist: xenial
dist: bionic
compiler: clang++-10
env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=11,14,17,2a
addons:
@ -244,19 +233,34 @@ matrix:
- clang-10
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main'
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 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++-11
env: TOOLSET=clang COMPILER=clang++-11 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-8
- clang-11
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- 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
@ -268,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
@ -288,7 +288,7 @@ matrix:
env: CMAKE_TEST=1
script:
- mkdir __build__ && cd __build__
- cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=variant2 ..
- cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=variant2 ..
- ctest --output-on-failure -R boost_variant2
- os: linux

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,10 @@ 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`

View File

@ -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: ::

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)... )
{
}
@ -564,18 +580,18 @@ template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, c
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
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 explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), 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()
{
@ -637,11 +653,11 @@ 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)... )
{
}
@ -687,18 +703,18 @@ template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, c
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
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 explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), 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)... ); }
@ -814,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;
}
@ -843,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
@ -851,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;
}
@ -868,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;
}
@ -884,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;
}
@ -977,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();
}
};
@ -1005,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
@ -1013,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 )
@ -1028,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;
}
};
@ -1036,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 ){
@ -1063,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
@ -1101,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;
}
};
@ -1561,7 +1584,7 @@ public:
template<class U,
class Ud = typename std::decay<U>::type,
class E1 = typename std::enable_if< !std::is_same<Ud, variant>::value && !detail::is_in_place_index<Ud>::value && !detail::is_in_place_type<Ud>::value >::type,
class E1 = typename std::enable_if< !std::is_same<Ud, variant>::value && !std::is_base_of<variant, Ud>::value && !detail::is_in_place_index<Ud>::value && !detail::is_in_place_type<Ud>::value >::type,
class V = detail::resolve_overload_type<U&&, T...>,
class E2 = typename std::enable_if<std::is_constructible<V, U&&>::value>::type
>
@ -2085,7 +2108,7 @@ template<class R, class F, class V1, class V2> struct visit_L2
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<R>( f2, std::forward<V2>(v2) );
return visit<R>( f2, std::forward<V2>(v2) );
}
};
@ -2175,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 & )
@ -2209,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
@ -2230,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

@ -119,3 +119,5 @@ run variant_visit_r.cpp : : :
<toolset>gcc,<target-os>windows:<variant>release
<toolset>gcc,<target-os>cygwin:<variant>release
;
compile variant_derived_construct.cpp ;

View File

@ -0,0 +1,33 @@
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
using namespace boost::variant2;
template<class... T> class X: variant<T...>
{
using base = variant<T...>;
using base::base;
};
struct Y
{
Y( Y const& rhs ) = default;
template<class T> Y( T const& t )
{
t.bar();
}
};
int main()
{
using W = X<int, double, Y>;
W a( 1 );
W b( a );
(void)b;
}

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

@ -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

@ -105,7 +105,7 @@ int main()
STATIC_ASSERT( v.index() == 4 );
}
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 100200)
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 110000)
// no idea why this fails on g++ 10

View File

@ -102,7 +102,7 @@ int main()
STATIC_ASSERT( holds_alternative<X>(v) );
}
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 100200)
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 110000)
// no idea why this fails on g++ 10

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