diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..1b1f780 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,225 @@ +# Copyright 2016 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) + +language: cpp + +sudo: false + +python: "2.7" + +os: + - linux + - osx + +branches: + only: + - master + - develop + +env: + matrix: + - BOGUS_JOB=true + +matrix: + + exclude: + - env: BOGUS_JOB=true + + include: + - os: linux + compiler: g++-5 + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=c++14 + addons: + apt: + packages: + - g++-5 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-5 + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=c++1z + addons: + apt: + packages: + - g++-5 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-6 + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=c++14 + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-6 + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=c++1z + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + dist: trusty + compiler: g++-7 + env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=c++14 + addons: + apt: + packages: + - g++-7 + sources: + - ubuntu-toolchain-r-test + + - os: linux + dist: trusty + compiler: g++-7 + env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=c++1z + addons: + apt: + packages: + - g++-7 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: clang++-3.5 + env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=c++14 + addons: + apt: + packages: + - clang-3.5 + - libstdc++-4.9-dev + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.5 + + - os: linux + compiler: clang++-3.6 + env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=c++14 + addons: + apt: + packages: + - clang-3.6 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + + - os: linux + compiler: clang++-3.7 + env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=c++14 + addons: + apt: + packages: + - clang-3.7 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + + - os: linux + compiler: clang++-3.8 + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=c++14 + addons: + apt: + packages: + - clang-3.8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + + - os: linux + compiler: clang++-3.8 + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=c++1z + addons: + apt: + packages: + - clang-3.8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + + - os: linux + compiler: clang++-3.9 + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=c++14 + addons: + apt: + packages: + - clang-3.9 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + + - os: linux + compiler: clang++-3.9 + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=c++1z + addons: + apt: + packages: + - clang-3.9 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + + - os: linux + dist: trusty + compiler: clang++-4.0 + env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=c++14 + addons: + apt: + packages: + - clang-4.0 + - libstdc++-4.9-dev + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-4.0 + + - os: linux + dist: trusty + compiler: clang++-4.0 + env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=c++1z + addons: + apt: + packages: + - clang-4.0 + - libstdc++-4.9-dev + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-4.0 + + - os: osx + compiler: clang++ + env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++14 + + - os: osx + compiler: clang++ + env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++1z + +install: + - cd .. + - git clone -b $TRAVIS_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule update --init tools/build + - git submodule update --init libs/config + - git submodule update --init tools/boostdep + - git clone -b $TRAVIS_BRANCH https://github.com/pdimov/mp11 libs/mp11 + - mkdir libs/variant2 + - cp -r $TRAVIS_BUILD_DIR/* libs/variant2 + - python tools/boostdep/depinst/depinst.py variant2 + - ./bootstrap.sh + - ./b2 headers + +script: + - |- + echo "using $TOOLSET : : $COMPILER : -std=$CXXSTD ;" > ~/user-config.jam + - ./b2 libs/variant2/test toolset=$TOOLSET + +notifications: + email: + on_success: always diff --git a/README.md b/README.md index 372c949..972145e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ # variant2 -A never-valueless implementation of std::variant + +A never-valueless C++14 implementation of [std::variant](http://en.cppreference.com/w/cpp/utility/variant). Requires [mp11](https://github.com/pdimov/mp11) and Boost.Config. Intended to be placed into the `libs/variant2` directory of a Boost clone or release, with mp11 in `libs/mp11`. + +To avoid the valueless state, this implementation falls back to using double storage unless + +* all the contained types are nothrow move constructible, or +* at least one contained type has a nothrow default constructor. + +Supported compilers: + +* g++ 5 or later with -std=c++14 or -std=c++1z +* clang++ 3.5 or later with -std=c++14 or -std=c++1z +* Visual Studio 2017 diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..152eb22 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,36 @@ +# Copyright 2016 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) + +version: 1.0.{build}-{branch} + +shallow_clone: true + +branches: + only: + - master + - develop + +environment: + matrix: + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + TOOLSET: msvc-14.1 + +install: + - cd .. + - git clone -b %APPVEYOR_REPO_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule update --init tools/build + - git submodule update --init libs/config + - git submodule update --init tools/boostdep + - git clone -b %APPVEYOR_REPO_BRANCH% https://github.com/pdimov/mp11 libs/mp11 + - mkdir libs\variant2 + - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\variant2 + - python tools/boostdep/depinst/depinst.py variant2 + - bootstrap + - b2 headers + +build: off + +test_script: + - b2 libs/variant2/test toolset=%TOOLSET% diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp new file mode 100644 index 0000000..4ce586e --- /dev/null +++ b/include/boost/variant2/variant.hpp @@ -0,0 +1,1154 @@ +#ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED +#define BOOST_VARIANT2_VARIANT_HPP_INCLUDED + +// Copyright 2015-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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// + +namespace boost +{ +namespace variant2 +{ + +using namespace boost::mp11; + +// bad_variant_access + +class bad_variant_access: public std::exception +{ +public: + + bad_variant_access() noexcept + { + } + + char const * what() const noexcept + { + return "bad_variant_access"; + } +}; + +// + +template class variant; + +// variant_size + +template struct variant_size +{ +}; + +template struct variant_size: variant_size +{ +}; + +template struct variant_size: variant_size +{ +}; + +template struct variant_size: variant_size +{ +}; + +template /*inline*/ constexpr std::size_t variant_size_v = variant_size::value; + +template struct variant_size>: mp_size> +{ +}; + +// variant_alternative + +template struct variant_alternative; + +template using variant_alternative_t = typename variant_alternative::type; + +namespace detail +{ + template using var_alt_t = mp_invoke>; +} // namespace detail + +template struct variant_alternative +{ +}; + +template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +{ +}; + +template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +{ +}; + +template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +{ +}; + +template struct variant_alternative>: mp_defer, mp_size_t> +{ +}; + +// holds_alternative + +template constexpr bool holds_alternative( variant const& v ) noexcept +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + return v.index() == mp_find, U>::value; +} + +// get + +template constexpr variant_alternative_t>& get(variant& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) + + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); + +#else + + if( v.index() != I ) throw bad_variant_access(); + return v._get_impl( mp_size_t() ); + +#endif +} + +template constexpr variant_alternative_t>&& get(variant&& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) + + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); + +#else + + if( v.index() != I ) throw bad_variant_access(); + return std::move( v._get_impl( mp_size_t() ) ); + +#endif +} + +template constexpr variant_alternative_t> const& get(variant const& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) + + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); + +#else + + if( v.index() != I ) throw bad_variant_access(); + return v._get_impl( mp_size_t() ); + +#endif +} + +template constexpr variant_alternative_t> const&& get(variant const&& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) + + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); + +#else + + if( v.index() != I ) throw bad_variant_access(); + return std::move( v._get_impl( mp_size_t() ) ); + +#endif +} + +// get + +template constexpr U& get(variant& v) +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + +#if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) + + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); + +#else + + if( v.index() != I ) throw bad_variant_access(); + return v._get_impl( mp_size_t() ); + +#endif +} + +template constexpr U&& get(variant&& v) +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + +#if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) + + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); + +#else + + if( v.index() != I ) throw bad_variant_access(); + return std::move( v._get_impl( mp_size_t() ) ); + +#endif +} + +template constexpr U const& get(variant const& v) +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + +#if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) + + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); + +#else + + if( v.index() != I ) throw bad_variant_access(); + return v._get_impl( mp_size_t() ); + +#endif +} + +template constexpr U const&& get(variant const&& v) +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + +#if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) + + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); + +#else + + if( v.index() != I ) throw bad_variant_access(); + return std::move( v._get_impl( mp_size_t() ) ); + +#endif +} + +// get_if + +template constexpr std::add_pointer_t>> get_if(variant* v) noexcept +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + return v->index() == I? &v->_get_impl( mp_size_t() ): 0; +} + +template constexpr std::add_pointer_t>> get_if(variant const * v) noexcept +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + return v->index() == I? &v->_get_impl( mp_size_t() ): 0; +} + +template constexpr std::add_pointer_t get_if(variant* v) noexcept +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + + return v->index() == I? &v->_get_impl( mp_size_t() ): 0; +} + +template constexpr std::add_pointer_t get_if(variant const * v) noexcept +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + + return v->index() == I? &v->_get_impl( mp_size_t() ): 0; +} + +// + +namespace detail +{ + +// variant_storage + +template union variant_storage_impl; + +template using variant_storage = variant_storage_impl...>, T...>; + +template union variant_storage_impl +{ +}; + +// not all trivially destructible +template union variant_storage_impl +{ + T1 first_; + variant_storage rest_; + + template constexpr explicit variant_storage_impl( mp_size_t<0>, A&&... a ): first_( std::forward(a)... ) + { + } + + template constexpr explicit variant_storage_impl( mp_size_t, A&&... a ): rest_( mp_size_t(), std::forward(a)... ) + { + } + + ~variant_storage_impl() + { + } + + template void emplace( mp_size_t<0>, A&&... a ) noexcept + { + ::new( &first_ ) T1( std::forward(a)... ); + } + + template void emplace( mp_size_t, A&&... a ) noexcept + { + rest_.emplace( mp_size_t(), std::forward(a)... ); + } + + constexpr T1& get( mp_size_t<0> ) noexcept { return first_; } + constexpr T1 const& get( mp_size_t<0> ) const noexcept { return first_; } + + template constexpr mp_at_c, I-1>& get( mp_size_t ) noexcept { return rest_.get( mp_size_t() ); } + template constexpr mp_at_c, I-1> const& get( mp_size_t ) const noexcept { return rest_.get( mp_size_t() ); } +}; + +// all trivially destructible +template union variant_storage_impl +{ + T1 first_; + variant_storage rest_; + + template constexpr explicit variant_storage_impl( mp_size_t<0>, A&&... a ): first_( std::forward(a)... ) + { + } + + template constexpr explicit variant_storage_impl( mp_size_t, A&&... a ): rest_( mp_size_t(), std::forward(a)... ) + { + } + + template void emplace( mp_size_t<0>, A&&... a ) noexcept + { + ::new( &first_ ) T1( std::forward(a)... ); + } + + template void emplace( mp_size_t, A&&... a ) noexcept + { + rest_.emplace( mp_size_t(), std::forward(a)... ); + } + + constexpr T1& get( mp_size_t<0> ) noexcept { return first_; } + constexpr T1 const& get( mp_size_t<0> ) const noexcept { return first_; } + + template constexpr mp_at_c, I-1>& get( mp_size_t ) noexcept { return rest_.get( mp_size_t() ); } + template constexpr mp_at_c, I-1> const& get( mp_size_t ) const noexcept { return rest_.get( mp_size_t() ); } +}; + +// resolve_overload_* + +template struct overload; + +template<> struct overload<> +{ + void operator()() const; +}; + +template struct overload: overload +{ + using overload::operator(); + mp_identity operator()(T1) const; +}; + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + +template struct resolve_overload_type_impl +{ + using type = decltype( overload()(std::declval()) ); +}; + +template using resolve_overload_type = typename resolve_overload_type_impl::type::type; + +#else + +template using resolve_overload_type = typename decltype( overload()(std::declval()) )::type; + +#endif + +template using resolve_overload_index = mp_find, resolve_overload_type>; + +// variant_base + +template struct variant_base_impl; // trivially destructible, single buffered +template using variant_base = variant_base_impl...>::value, mp_any...>, std::is_nothrow_default_constructible...>::value, T...>; + +struct none {}; + +// trivially destructible, single buffered +template struct variant_base_impl +{ + int ix_; + variant_storage st1_; + + constexpr variant_base_impl(): ix_( 0 ), st1_( mp_size_t<0>() ) + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp_size_t(), std::forward(a)... ) + { + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t ) noexcept + { + size_t const J = I+1; + + assert( ix_ == J ); + + return st1_.get( mp_size_t() ); + } + + template constexpr mp_at_c, I> const& _get_impl( mp_size_t ) const noexcept + { + size_t const J = I+1; + + assert( ix_ == J ); + + return st1_.get( mp_size_t() ); + } + + template void emplace( A&&... a ) + { + std::size_t const J = I+1; + + std::size_t const K = mp_find_if, std::is_nothrow_constructible>::value; + + using U = mp_at_c, I>; + + if( std::is_nothrow_constructible::value ) + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = J; + } + else if( K < sizeof...(T) ) // have nothrow destructible + { + try + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = J; + } + catch( ... ) + { + st1_.emplace( mp_size_t() ); + ix_ = K; + + throw; + } + } + else + { + assert( std::is_nothrow_move_constructible::value ); + + U tmp( std::forward(a)... ); + + st1_.emplace( mp_size_t(), std::move(tmp) ); + ix_ = J; + } + } +}; + +// trivially destructible, double buffered +template struct variant_base_impl +{ + int ix_; + variant_storage st1_; + variant_storage st2_; + + constexpr variant_base_impl(): ix_( 0 ), st1_( mp_size_t<0>() ), st2_( mp_size_t<0>() ) + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp_size_t(), std::forward(a)... ), st2_( mp_size_t<0>() ) + { + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t ) noexcept + { + size_t const J = I+1; + + assert( ix_ == J || -ix_ == J ); + + constexpr mp_size_t j{}; + return ix_ >= 0? st1_.get( j ): st2_.get( j ); + } + + template constexpr mp_at_c, I> const& _get_impl( mp_size_t ) const noexcept + { + size_t const J = I+1; + + assert( ix_ == J || -ix_ == J ); + + constexpr mp_size_t j{}; + return ix_ >= 0? st1_.get( j ): st2_.get( j ); + } + + template void emplace( A&&... a ) + { + size_t const J = I+1; + + if( ix_ >= 0 ) + { + st2_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = -static_cast( J ); + } + else + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = J; + } + } +}; + +// not trivially destructible, single buffered +template struct variant_base_impl +{ + int ix_; + variant_storage st1_; + + constexpr variant_base_impl(): ix_( 0 ), st1_( mp_size_t<0>() ) + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp_size_t(), std::forward(a)... ) + { + } + + void _destroy() noexcept + { + if( ix_ > 0 ) + { + mp_for_index<1 + sizeof...(T)>( ix_, [&]( auto I ){ + + using U = mp_at_c, I>; + st1_.get( I ).~U(); + + }); + } + } + + ~variant_base_impl() noexcept + { + _destroy(); + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t ) noexcept + { + size_t const J = I+1; + + assert( ix_ == J ); + + return st1_.get( mp_size_t() ); + } + + template constexpr mp_at_c, I> const& _get_impl( mp_size_t ) const noexcept + { + size_t const J = I+1; + + assert( ix_ == J ); + + return st1_.get( mp_size_t() ); + } + + template void emplace( A&&... a ) + { + size_t const J = I+1; + + std::size_t const K = mp_find_if, std::is_nothrow_constructible>::value; + + using U = mp_at_c, I>; + + if( std::is_nothrow_constructible::value ) + { + _destroy(); + + st1_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = J; + } + else if( K < sizeof...(T) ) // have nothrow destructible + { + _destroy(); + + try + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = J; + } + catch( ... ) + { + st1_.emplace( mp_size_t() ); + ix_ = K; + + throw; + } + } + else + { + assert( std::is_nothrow_move_constructible::value ); + + U tmp( std::forward(a)... ); + + _destroy(); + + st1_.emplace( mp_size_t(), std::move(tmp) ); + ix_ = J; + } + } +}; + +// not trivially destructible, double buffered +template struct variant_base_impl +{ + int ix_; + variant_storage st1_; + variant_storage st2_; + + constexpr variant_base_impl(): ix_( 0 ), st1_( mp_size_t<0>() ), st2_( mp_size_t<0>() ) + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp_size_t(), std::forward(a)... ), st2_( mp_size_t<0>() ) + { + } + + void _destroy() noexcept + { + if( ix_ > 0 ) + { + mp_for_index<1 + sizeof...(T)>( ix_, [&]( auto I ){ + + using U = mp_at_c, I>; + st1_.get( I ).~U(); + + }); + } + else if( ix_ < 0 ) + { + mp_for_index<1 + sizeof...(T)>( -ix_, [&]( auto I ){ + + using U = mp_at_c, I>; + st2_.get( I ).~U(); + + }); + } + } + + ~variant_base_impl() noexcept + { + _destroy(); + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t ) noexcept + { + size_t const J = I+1; + + assert( ix_ == J || -ix_ == J ); + + constexpr mp_size_t j{}; + return ix_ >= 0? st1_.get( j ): st2_.get( j ); + } + + template constexpr mp_at_c, I> const& _get_impl( mp_size_t ) const noexcept + { + size_t const J = I+1; + + assert( ix_ == J || -ix_ == J ); + + constexpr mp_size_t j{}; + return ix_ >= 0? st1_.get( j ): st2_.get( j ); + } + + template void emplace( A&&... a ) + { + size_t const J = I+1; + + if( ix_ >= 0 ) + { + st2_.emplace( mp_size_t(), std::forward(a)... ); + _destroy(); + + ix_ = -static_cast( J ); + } + else + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + _destroy(); + + ix_ = J; + } + } +}; + +} // namespace detail + +// in_place_type_t + +template struct in_place_type_t +{ +}; + +template constexpr in_place_type_t in_place_type{}; + +namespace detail +{ + +template struct is_in_place_type: std::false_type {}; +template struct is_in_place_type>: std::true_type {}; + +} // namespace detail + +// in_place_index_t + +template struct in_place_index_t +{ +}; + +template constexpr in_place_index_t in_place_index{}; + +namespace detail +{ + +template struct is_in_place_index: std::false_type {}; +template struct is_in_place_index>: std::true_type {}; + +} // namespace detail + +// is_nothrow_swappable + +namespace detail +{ + +namespace det2 +{ + +using std::swap; + +template using is_swappable_impl = decltype(swap(std::declval(), std::declval())); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + +template struct is_nothrow_swappable_impl_ +{ + static constexpr bool value = noexcept(swap(std::declval(), std::declval())); +}; + +template using is_nothrow_swappable_impl = mp_bool< is_nothrow_swappable_impl_::value >; + +#else + +template using is_nothrow_swappable_impl = std::enable_if_t(), std::declval()))>; + +#endif + +} // namespace det2 + +template struct is_swappable: mp_valid +{ +}; + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + +template struct is_nothrow_swappable: mp_eval_if>, mp_false, det2::is_nothrow_swappable_impl, T> +{ +}; + +#else + +template struct is_nothrow_swappable: mp_valid +{ +}; + +#endif + +} // namespace detail + +// variant + +template class variant: private variant2::detail::variant_base +{ +private: + + using variant_base = variant2::detail::variant_base; + +private: + + variant( variant const volatile& r ) = delete; + variant& operator=( variant const volatile& r ) = delete; + +public: + + // constructors + + template> >, E1>> + constexpr variant() + noexcept( std::is_nothrow_default_constructible< mp_first> >::value ) + : variant_base( mp_size_t<0>() ) + { + } + + template...>, E1>> + variant( variant const& r ) + noexcept( mp_all...>::value ) + { + mp_for_index( r.index(), [&]( auto I ){ + + ::new( static_cast(this) ) variant_base( I, r._get_impl( I ) ); + + }); + } + + template...>, E1>> + variant( variant && r ) + noexcept( mp_all...>::value ) + { + mp_for_index( r.index(), [&]( auto I ){ + + ::new( static_cast(this) ) variant_base( I, std::move( r._get_impl( I ) ) ); + + }); + } + + template, + class E1 = std::enable_if_t< !std::is_same::value && !variant2::detail::is_in_place_index::value && !variant2::detail::is_in_place_type::value >, + class V = variant2::detail::resolve_overload_type, + class E2 = std::enable_if_t::value> + > + constexpr variant( U&& u ) + noexcept( std::is_nothrow_constructible::value ) + : variant_base( variant2::detail::resolve_overload_index(), std::forward(u) ) + { + } + + template, U>, class E = std::enable_if_t::value>> + constexpr explicit variant( in_place_type_t, A&&... a ): variant_base( I(), std::forward(a)... ) + { + } + + template, U>, class E = std::enable_if_t&, A...>::value>> + constexpr explicit variant( in_place_type_t, std::initializer_list il, A&&... a ): variant_base( I(), il, std::forward(a)... ) + { + } + + template, I>, A...>::value>> + constexpr explicit variant( in_place_index_t, A&&... a ): variant_base( mp_size_t(), std::forward(a)... ) + { + } + + template, I>, std::initializer_list&, A...>::value>> + constexpr explicit variant( in_place_index_t, std::initializer_list il, A&&... a ): variant_base( mp_size_t(), il, std::forward(a)... ) + { + } + + // assignment + template..., std::is_copy_assignable...>, E1>> + variant& operator=( variant const & r ) + noexcept( mp_all..., std::is_nothrow_copy_assignable...>::value ) + { + mp_for_index( r.index(), [&]( auto I ){ + + if( this->index() == I ) + { + get(*this) = get(r); + } + else + { + this->variant_base::template emplace( get(r) ); + } + + }); + + return *this; + } + + template..., std::is_move_assignable...>, E1>> + variant& operator=( variant && r ) + noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) + { + mp_for_index( r.index(), [&]( auto I ){ + + if( this->index() == I ) + { + get(*this) = get(std::move(r)); + } + else + { + this->variant_base::template emplace( get(std::move(r)) ); + } + + }); + + return *this; + } + + template, variant>::value>, + class V = variant2::detail::resolve_overload_type, + class E2 = std::enable_if_t::value && std::is_constructible::value> + > + variant& operator=( U&& u ) + noexcept( std::is_nothrow_assignable::value && std::is_nothrow_constructible::value ) + { + std::size_t const I = variant2::detail::resolve_overload_index::value; + + if( index() == I ) + { + _get_impl( mp_size_t() ) = std::forward(u); + } + else + { + this->template emplace( std::forward(u) ); + } + + return *this; + } + + // modifiers + + template, U>, class E = std::enable_if_t::value>> + U& emplace( A&&... a ) + { + variant_base::template emplace( std::forward(a)... ); + return _get_impl( I() ); + } + + template, U>, class E = std::enable_if_t&, A...>::value>> + U& emplace( std::initializer_list il, A&&... a ) + { + variant_base::template emplace( il, std::forward(a)... ); + return _get_impl( I() ); + } + + template, I>, A...>::value>> + variant_alternative_t>& emplace( A&&... a ) + { + variant_base::template emplace( std::forward(a)... ); + return _get_impl( mp_size_t() ); + } + + template, I>, std::initializer_list&, A...>::value>> + variant_alternative_t>& emplace( std::initializer_list il, A&&... a ) + { + variant_base::template emplace( il, std::forward(a)... ); + return _get_impl( mp_size_t() ); + } + + // value status + + constexpr size_t index() const noexcept + { + return this->ix_ >= 0? this->ix_ - 1 : -this->ix_ - 1; + } + + // swap + + void swap( variant& r ) noexcept( mp_all..., variant2::detail::is_nothrow_swappable...>::value ) + { + if( index() == r.index() ) + { + mp_for_index( index(), [&]( auto I ){ + + using std::swap; + swap( get(*this), get(r) ); + + }); + } + else + { + variant tmp( std::move(*this) ); + *this = std::move( r ); + r = std::move( tmp ); + } + } + + // private accessors + + constexpr int _real_index() const noexcept + { + return this->ix_; + } + + using variant_base::_get_impl; +}; + +// relational operators +template constexpr bool operator==( variant const & v, variant const & w ) +{ + if( v.index() != w.index() ) return false; + + return mp_for_index( v.index(), [&]( auto I ){ + + return get(v) == get(w); + + }); +} + +template constexpr bool operator!=( variant const & v, variant const & w ) +{ + if( v.index() != w.index() ) return true; + + return mp_for_index( v.index(), [&]( auto I ){ + + return get(v) != get(w); + + }); +} + +template constexpr bool operator<( variant const & v, variant const & w ) +{ + if( v.index() < w.index() ) return true; + if( v.index() > w.index() ) return false; + + return mp_for_index( v.index(), [&]( auto I ){ + + return get(v) < get(w); + + }); +} + +template constexpr bool operator>( variant const & v, variant const & w ) +{ + if( v.index() > w.index() ) return true; + if( v.index() < w.index() ) return false; + + return mp_for_index( v.index(), [&]( auto I ){ + + return get(v) > get(w); + + }); +} + +template constexpr bool operator<=( variant const & v, variant const & w ) +{ + if( v.index() < w.index() ) return true; + if( v.index() > w.index() ) return false; + + return mp_for_index( v.index(), [&]( auto I ){ + + return get(v) <= get(w); + + }); +} + +template constexpr bool operator>=( variant const & v, variant const & w ) +{ + if( v.index() > w.index() ) return true; + if( v.index() < w.index() ) return false; + + return mp_for_index( v.index(), [&]( auto I ){ + + return get(v) >= get(w); + + }); +} + +// visitation +template constexpr auto visit( F&& f ) -> decltype(std::forward(f)()) +{ + return std::forward(f)(); +} + +namespace detail +{ + +template using remove_cv_ref = std::remove_cv_t>; + +template struct Qret +{ + template using fn = decltype( std::declval()( std::declval()... ) ); +}; + +template using front_if_same = mp_if, mp_front>; + +template using Vret = front_if_same, remove_cv_ref...>>; + +} // namespace detail + +template constexpr auto visit( F&& f, V1&& v1 ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + return std::forward(f)( get( std::forward(v1) ) ); + + }); +} + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + +template constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + auto f2 = [&]( auto&&... a ){ return std::forward(f)( get( std::forward(v1) ), std::forward(a)... ); }; + return visit( f2, std::forward(v2) ); + + }); +} + +template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + auto f2 = [&]( auto&&... a ){ return std::forward(f)( get( std::forward(v1) ), std::forward(a)... ); }; + return visit( f2, std::forward(v2), std::forward(v3) ); + + }); +} + +template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + auto f2 = [&]( auto&&... a ){ return std::forward(f)( get( std::forward(v1) ), std::forward(a)... ); }; + return visit( f2, std::forward(v2), std::forward(v3), std::forward(v4) ); + + }); +} + +#else + +template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + auto f2 = [&]( auto&&... a ){ return std::forward(f)( get( std::forward(v1) ), std::forward(a)... ); }; + return visit( f2, std::forward(v2), std::forward(v)... ); + + }); +} + +#endif + +// specialized algorithms +template..., variant2::detail::is_swappable...>::value>> +void swap( variant & v, variant & w ) + noexcept( noexcept(v.swap(w)) ) +{ + v.swap( w ); +} + +} // namespace variant2 +} // namespace boost + +#endif // #ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED diff --git a/meta/libraries.json b/meta/libraries.json new file mode 100644 index 0000000..50915a9 --- /dev/null +++ b/meta/libraries.json @@ -0,0 +1,14 @@ +{ + "key": "variant2", + "name": "Variant2", + "authors": [ + "Peter Dimov" + ], + "maintainers": [ + "Peter Dimov " + ], + "description": "A never-valueless implementation of std::variant.", + "category": [ + "Containers", "Data" + ] +} diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..4a68bfe --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,40 @@ +# Boost.Variant2 Library Test Jamfile +# +# Copyright 2015-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 + +import testing ; +import ../../config/checks/config : requires ; + +REQ = ; #[ requires cxx11_variadic_templates cxx11_template_aliases cxx11_decltype cxx11_hdr_type_traits ] ; + +run variant_size.cpp : : : $(REQ) ; +run variant_alternative.cpp : : : $(REQ) ; +run variant_holds_alternative.cpp : : : $(REQ) ; +compile variant_holds_alternative_cx.cpp : : : $(REQ) ; +run variant_get_by_index.cpp : : : $(REQ) ; +compile variant_get_by_index_cx.cpp : : : $(REQ) ; +run variant_get_by_type.cpp : : : $(REQ) ; +compile variant_get_by_type_cx.cpp : : : $(REQ) ; +run variant_default_construct.cpp : : : $(REQ) ; +compile variant_default_construct_cx.cpp : : : $(REQ) ; +run variant_copy_construct.cpp : : : $(REQ) ; +run variant_move_construct.cpp : : : $(REQ) ; +run variant_value_construct.cpp : : : $(REQ) ; +compile variant_value_construct_cx.cpp : : : $(REQ) ; +run variant_in_place_index_construct.cpp : : : $(REQ) ; +compile variant_in_place_index_construct_cx.cpp : : : $(REQ) ; +run variant_in_place_type_construct.cpp : : : $(REQ) ; +compile variant_in_place_type_construct_cx.cpp : : : $(REQ) ; +run variant_copy_assign.cpp : : : $(REQ) ; +run variant_move_assign.cpp : : : $(REQ) ; +run variant_value_assign.cpp : : : $(REQ) ; +run variant_emplace_index.cpp : : : $(REQ) ; +run variant_emplace_type.cpp : : : $(REQ) ; +run variant_swap.cpp : : : $(REQ) ; +run variant_eq_ne.cpp : : : $(REQ) ; +run variant_destroy.cpp : : : $(REQ) ; +run variant_visit.cpp : : : $(REQ) ; diff --git a/test/variant_alternative.cpp b/test/variant_alternative.cpp new file mode 100644 index 0000000..e5a9fa7 --- /dev/null +++ b/test/variant_alternative.cpp @@ -0,0 +1,89 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; +using namespace boost::mp11; + +template using var_alt_t = variant_alternative_t; + +int main() +{ + BOOST_TEST_TRAIT_TRUE((std::is_same>, void>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, void const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, void volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, void const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, void>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, void const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, void volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, void const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, int>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, int const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, int volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, int const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, void>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, void const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, void volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, void const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, int>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, int const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, int volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, int const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, float>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, float const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, float volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, float const volatile>)); + + variant_alternative<0, void>(); + variant_alternative<0, void const>(); + variant_alternative<0, void volatile>(); + variant_alternative<0, void const volatile>(); + + variant_alternative<0, variant<>>(); + variant_alternative<0, variant<> const>(); + variant_alternative<0, variant<> volatile>(); + variant_alternative<0, variant<> const volatile>(); + + variant_alternative<1, variant>(); + variant_alternative<1, variant const>(); + variant_alternative<1, variant volatile>(); + variant_alternative<1, variant const volatile>(); + + BOOST_TEST_TRAIT_FALSE((mp_valid, void>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, void const>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, void volatile>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, void const volatile>)); + + BOOST_TEST_TRAIT_FALSE((mp_valid, variant<>>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant<> const>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant<> volatile>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant<> const volatile>)); + + BOOST_TEST_TRAIT_TRUE((mp_valid, variant>)); + BOOST_TEST_TRAIT_TRUE((mp_valid, variant const>)); + BOOST_TEST_TRAIT_TRUE((mp_valid, variant volatile>)); + BOOST_TEST_TRAIT_TRUE((mp_valid, variant const volatile>)); + + BOOST_TEST_TRAIT_FALSE((mp_valid, variant>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant const>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant volatile>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant const volatile>)); + + return boost::report_errors(); +} diff --git a/test/variant_copy_assign.cpp b/test/variant_copy_assign.cpp new file mode 100644 index 0000000..c4ae80f --- /dev/null +++ b/test/variant_copy_assign.cpp @@ -0,0 +1,194 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + int v; + + X1(): v(0) {} + explicit X1(int v): v(v) {} + X1(X1 const& r): v(r.v) {} + X1(X1&& r): v(r.v) {} + X1& operator=( X1 const& r ) { v = r.v; return *this; } + X1& operator=( X1&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X1 const& a, X1 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +struct X2 +{ + int v; + + X2(): v(0) {} + explicit X2(int v): v(v) {} + X2(X2 const& r): v(r.v) {} + X2(X2&& r): v(r.v) {} + X2& operator=( X2 const& r ) { v = r.v; return *this; } + X2& operator=( X2&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X2 const& a, X2 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +struct Y +{ + Y& operator=( Y const& ) = delete; +}; + +int main() +{ + { + variant v; + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( 1 ); + + v = v2; + BOOST_TEST_EQ( get<0>(v), 1 ); + + variant const v3( 2 ); + + v = v3; + BOOST_TEST_EQ( get<0>(v), 2 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( 1 ); + + v = v2; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + variant v3( 3.14f ); + + v = v3; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + + variant const v4( 3.15f ); + + v = v4; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.15f ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( in_place_index<1>, 1 ); + + v = v2; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 1 ); + + variant v3( 3.14f ); + + v = v3; + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + + variant const v4( 3.15f ); + + v = v4; + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.15f ); + + variant v5( "s1" ); + + v = v5; + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s1") ); + + variant const v6( "s2" ); + + v = v6; + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s2") ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 0 ); + + variant v2( X1{1} ); + + v = v2; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 1 ); + + variant v3( in_place_index<1>, 2 ); + + v = v3; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 2 ); + + variant const v4( in_place_index<1>, 3 ); + + v = v4; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 3 ); + + variant const v5( in_place_index<0>, 4 ); + + v = v5; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + } + + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + + BOOST_TEST_TRAIT_TRUE((std::is_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_copy_assignable>)); + } + + return boost::report_errors(); +} diff --git a/test/variant_copy_construct.cpp b/test/variant_copy_construct.cpp new file mode 100644 index 0000000..473d8a2 --- /dev/null +++ b/test/variant_copy_construct.cpp @@ -0,0 +1,128 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + X1() {} + X1(X1 const&) {} + X1(X1&&) {} +}; + +inline bool operator==( X1, X1 ) { return true; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); + +struct X2 +{ + X2() {} + X2(X2 const&) {} + X2(X2&&) {} +}; + +inline bool operator==( X2, X2 ) { return true; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); + +struct Y +{ + Y( Y const& ) = delete; +}; + +template static void test( V const & v ) +{ + V v2( v ); + + BOOST_TEST_EQ( v.index(), v2.index() ); + BOOST_TEST( v == v2 ); +} + +int main() +{ + test( variant() ); + test( variant(1) ); + + test( variant() ); + test( variant(1) ); + + test( variant() ); + test( variant(1) ); + test( variant(3.14f) ); + + test( variant() ); + test( variant(1) ); + test( variant(3.14f) ); + test( variant("test") ); + + test( variant() ); + + test( variant() ); + test( variant(3.14f) ); + + test( variant() ); + + test( variant("test") ); + + test( variant() ); + + test( variant() ); + test( variant() ); + test( variant() ); + test( variant() ); + + { + variant v; + v.emplace(); + + test( v ); + } + + { + variant v; + v.emplace(); + + test( v ); + } + + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_copy_constructible>)); + } + + return boost::report_errors(); +} diff --git a/test/variant_default_construct.cpp b/test/variant_default_construct.cpp new file mode 100644 index 0000000..894934c --- /dev/null +++ b/test/variant_default_construct.cpp @@ -0,0 +1,103 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +struct X +{ + X(); +}; + +struct Y +{ + Y() = delete; +}; + +int main() +{ + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), std::string() ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), std::string() ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), std::string() ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), std::string() ); + } + + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_default_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_default_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_default_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_default_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_default_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_default_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_default_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_default_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_default_constructible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_default_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_default_constructible>)); + } + + return boost::report_errors(); +} diff --git a/test/variant_default_construct_cx.cpp b/test/variant_default_construct_cx.cpp new file mode 100644 index 0000000..d3325c6 --- /dev/null +++ b/test/variant_default_construct_cx.cpp @@ -0,0 +1,51 @@ + +// 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 + +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v; + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + } + + { + constexpr variant v; + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + } + + { + constexpr variant v; + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + } + + { + constexpr variant v; + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + } + + { + constexpr variant v; + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + } +} diff --git a/test/variant_destroy.cpp b/test/variant_destroy.cpp new file mode 100644 index 0000000..392a2d7 --- /dev/null +++ b/test/variant_destroy.cpp @@ -0,0 +1,205 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +struct X1 +{ + static int instances; + + int v; + + X1(): v(0) { ++instances; } + explicit X1(int v): v(v) { ++instances; } + X1(X1 const& r): v(r.v) { ++instances; } + X1(X1&& r): v(r.v) { ++instances; } + + ~X1() noexcept { --instances; } + + X1& operator=( X1 const& r ) { v = r.v; return *this; } + X1& operator=( X1&& r ) { v = r.v; return *this; } +}; + +int X1::instances = 0; + +struct X2 +{ + static int instances; + + int v; + + X2(): v(0) { ++instances; } + explicit X2(int v): v(v) { ++instances; } + X2(X2 const& r): v(r.v) { ++instances; } + X2(X2&& r): v(r.v) { ++instances; } + + ~X2() noexcept { --instances; } + + X2& operator=( X2 const& r ) { v = r.v; return *this; } + X2& operator=( X2&& r ) { v = r.v; return *this; } +}; + +int X2::instances = 0; + +struct Y1 +{ + static int instances; + + int v; + + Y1() noexcept: v(0) { ++instances; } + explicit Y1(int v) noexcept: v(v) { ++instances; } + Y1(Y1 const& r) noexcept: v(r.v) { ++instances; } + Y1(Y1&& r) noexcept: v(r.v) { ++instances; } + + ~Y1() noexcept { --instances; } + + Y1& operator=( Y1 const& r ) noexcept { v = r.v; return *this; } + Y1& operator=( Y1&& r ) noexcept { v = r.v; return *this; } +}; + +int Y1::instances = 0; + +struct Y2 +{ + static int instances; + + int v; + + Y2() noexcept: v(0) { ++instances; } + explicit Y2(int v) noexcept: v(v) { ++instances; } + Y2(Y2 const& r) noexcept: v(r.v) { ++instances; } + Y2(Y2&& r) noexcept: v(r.v) { ++instances; } + + ~Y2() noexcept { --instances; } + + Y2& operator=( Y2 const& r ) noexcept { v = r.v; return *this; } + Y2& operator=( Y2&& r ) noexcept { v = r.v; return *this; } +}; + +int Y2::instances = 0; + +int main() +{ + BOOST_TEST_EQ( Y1::instances, 0 ); + + { + variant v; + BOOST_TEST_EQ( Y1::instances, 1 ); + + { + variant v2; + BOOST_TEST_EQ( Y1::instances, 2 ); + + v = v2; + BOOST_TEST_EQ( Y1::instances, 2 ); + } + + BOOST_TEST_EQ( Y1::instances, 1 ); + + v = Y1{1}; + BOOST_TEST_EQ( Y1::instances, 1 ); + } + + BOOST_TEST_EQ( Y1::instances, 0 ); + BOOST_TEST_EQ( Y2::instances, 0 ); + + { + variant v; + + BOOST_TEST_EQ( Y1::instances, 1 ); + BOOST_TEST_EQ( Y2::instances, 0 ); + + { + variant v2; + BOOST_TEST_EQ( Y1::instances, 2 ); + BOOST_TEST_EQ( Y2::instances, 0 ); + + v = v2; + BOOST_TEST_EQ( Y1::instances, 2 ); + BOOST_TEST_EQ( Y2::instances, 0 ); + + v2 = Y2{1}; + BOOST_TEST_EQ( Y1::instances, 1 ); + BOOST_TEST_EQ( Y2::instances, 1 ); + + v = v2; + BOOST_TEST_EQ( Y1::instances, 0 ); + BOOST_TEST_EQ( Y2::instances, 2 ); + } + + BOOST_TEST_EQ( Y1::instances, 0 ); + BOOST_TEST_EQ( Y2::instances, 1 ); + + v.emplace<0>(); + + BOOST_TEST_EQ( Y1::instances, 1 ); + BOOST_TEST_EQ( Y2::instances, 0 ); + + v.emplace(); + + BOOST_TEST_EQ( Y1::instances, 0 ); + BOOST_TEST_EQ( Y2::instances, 1 ); + } + + BOOST_TEST_EQ( Y1::instances, 0 ); + BOOST_TEST_EQ( Y2::instances, 0 ); + + BOOST_TEST_EQ( X1::instances, 0 ); + BOOST_TEST_EQ( X2::instances, 0 ); + + { + variant v; + + BOOST_TEST_EQ( X1::instances, 1 ); + BOOST_TEST_EQ( X2::instances, 0 ); + + { + variant v2; + BOOST_TEST_EQ( X1::instances, 2 ); + BOOST_TEST_EQ( X2::instances, 0 ); + + v = v2; + BOOST_TEST_EQ( X1::instances, 2 ); + BOOST_TEST_EQ( X2::instances, 0 ); + + v2 = X2{1}; + BOOST_TEST_EQ( X1::instances, 1 ); + BOOST_TEST_EQ( X2::instances, 1 ); + + v = v2; + BOOST_TEST_EQ( X1::instances, 0 ); + BOOST_TEST_EQ( X2::instances, 2 ); + } + + BOOST_TEST_EQ( X1::instances, 0 ); + BOOST_TEST_EQ( X2::instances, 1 ); + + v.emplace<0>(); + + BOOST_TEST_EQ( X1::instances, 1 ); + BOOST_TEST_EQ( X2::instances, 0 ); + + v.emplace(); + + BOOST_TEST_EQ( X1::instances, 0 ); + BOOST_TEST_EQ( X2::instances, 1 ); + } + + BOOST_TEST_EQ( X1::instances, 0 ); + BOOST_TEST_EQ( X2::instances, 0 ); + + return boost::report_errors(); +} diff --git a/test/variant_emplace_index.cpp b/test/variant_emplace_index.cpp new file mode 100644 index 0000000..7fa30b7 --- /dev/null +++ b/test/variant_emplace_index.cpp @@ -0,0 +1,181 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + int v; + + X1(): v(0) {} + explicit X1(int v): v(v) {} + X1(X1 const& r): v(r.v) {} + X1(X1&& r): v(r.v) {} + X1& operator=( X1 const& r ) { v = r.v; return *this; } + X1& operator=( X1&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X1 const& a, X1 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +struct X2 +{ + int v; + + X2(): v(0) {} + explicit X2(int v): v(v) {} + X2(X2 const& r): v(r.v) {} + X2(X2&& r): v(r.v) {} + X2& operator=( X2 const& r ) { v = r.v; return *this; } + X2& operator=( X2&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X2 const& a, X2 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +int main() +{ + { + variant v; + BOOST_TEST_EQ( get<0>(v), 0 ); + + v.emplace<0>( 1 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + v.emplace<0>(); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + v.emplace<0>( 1 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + v.emplace<1>( 3.14f ); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + + v.emplace<1>(); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 0 ); + + v.emplace<0>(); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + v.emplace<0>( 1 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + v.emplace<1>(); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 0 ); + + v.emplace<1>( 1 ); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 1 ); + + v.emplace<2>( 3.14f ); + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + + v.emplace<2>(); + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 0 ); + + v.emplace<3>( "s1" ); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s1") ); + + v.emplace<3>( "s2" ); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s2") ); + + v.emplace<3>(); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string() ); + + v.emplace<3>( { 'a', 'b' } ); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), (std::string{ 'a', 'b'}) ); + + v.emplace<3>( { 'c', 'd' }, std::allocator() ); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), (std::string{ 'c', 'd'}) ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 0 ); + + v.emplace<0>( 1 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 1 ); + + v.emplace<1>( 2 ); + 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, 0 ); + + v.emplace<0>( 4 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + + v.emplace<1>(); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 0 ); + + v.emplace<1>( 6 ); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 6 ); + + v.emplace<0>( 3 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 3 ); + + v.emplace<0>( 4 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + } + + return boost::report_errors(); +} diff --git a/test/variant_emplace_type.cpp b/test/variant_emplace_type.cpp new file mode 100644 index 0000000..4189bbb --- /dev/null +++ b/test/variant_emplace_type.cpp @@ -0,0 +1,169 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + int v; + + X1(): v(0) {} + explicit X1(int v): v(v) {} + X1(X1 const& r): v(r.v) {} + X1(X1&& r): v(r.v) {} + X1& operator=( X1 const& r ) { v = r.v; return *this; } + X1& operator=( X1&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X1 const& a, X1 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +struct X2 +{ + int v; + + X2(): v(0) {} + explicit X2(int v): v(v) {} + X2(X2 const& r): v(r.v) {} + X2(X2&& r): v(r.v) {} + X2& operator=( X2 const& r ) { v = r.v; return *this; } + X2& operator=( X2&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X2 const& a, X2 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +int main() +{ + { + variant v; + BOOST_TEST_EQ( get<0>(v), 0 ); + + v.emplace( 1 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + v.emplace(); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + v.emplace( 1 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + v.emplace( 3.14f ); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + + v.emplace(); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 0 ); + + v.emplace(); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + v.emplace( 3.14f ); + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + + v.emplace(); + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 0 ); + + v.emplace( "s1" ); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s1") ); + + v.emplace( "s2" ); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s2") ); + + v.emplace(); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string() ); + + v.emplace( { 'a', 'b' } ); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), (std::string{ 'a', 'b' }) ); + + v.emplace( { 'c', 'd' }, std::allocator() ); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), (std::string{ 'c', 'd' }) ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 0 ); + + v.emplace( 1 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 1 ); + + v.emplace( 2 ); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 2 ); + + v.emplace(); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 0 ); + + v.emplace( 4 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + + v.emplace(); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 0 ); + + v.emplace( 6 ); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 6 ); + + v.emplace( 3 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 3 ); + + v.emplace( 4 ); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + } + + return boost::report_errors(); +} diff --git a/test/variant_eq_ne.cpp b/test/variant_eq_ne.cpp new file mode 100644 index 0000000..47b3873 --- /dev/null +++ b/test/variant_eq_ne.cpp @@ -0,0 +1,92 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +struct X +{ +}; + +inline bool operator==( X const&, X const& ) { return false; } +inline bool operator!=( X const&, X const& ) { return false; } + +int main() +{ + { + variant v1, v2, v3( 1 ), v4( 1 ); + + BOOST_TEST( v1 == v2 ); + BOOST_TEST_NOT( v1 != v2 ); + + BOOST_TEST( v1 != v3 ); + BOOST_TEST_NOT( v1 == v3 ); + + BOOST_TEST( v3 == v4 ); + BOOST_TEST_NOT( v3 != v4 ); + } + + { + variant v1, v2, v3( 1 ), v4( 1 ), v5( 3.14f ), v6( 3.14f ); + + BOOST_TEST( v1 == v2 ); + BOOST_TEST_NOT( v1 != v2 ); + + BOOST_TEST( v1 != v3 ); + BOOST_TEST_NOT( v1 == v3 ); + + BOOST_TEST( v3 == v4 ); + BOOST_TEST_NOT( v3 != v4 ); + + BOOST_TEST( v1 != v5 ); + BOOST_TEST_NOT( v1 == v5 ); + + BOOST_TEST( v3 != v5 ); + BOOST_TEST_NOT( v3 == v5 ); + + BOOST_TEST( v5 == v6 ); + BOOST_TEST_NOT( v5 != v6 ); + } + + { + variant v1, v2, v3( in_place_index<1> ), v4( in_place_index<1> ), v5( 3.14f ), v6( 3.14f ); + + BOOST_TEST( v1 == v2 ); + BOOST_TEST_NOT( v1 != v2 ); + + BOOST_TEST( v1 != v3 ); + BOOST_TEST_NOT( v1 == v3 ); + + BOOST_TEST( v3 == v4 ); + BOOST_TEST_NOT( v3 != v4 ); + + BOOST_TEST( v1 != v5 ); + BOOST_TEST_NOT( v1 == v5 ); + + BOOST_TEST( v3 != v5 ); + BOOST_TEST_NOT( v3 == v5 ); + + BOOST_TEST( v5 == v6 ); + BOOST_TEST_NOT( v5 != v6 ); + } + + { + variant v1, v2; + + BOOST_TEST_NOT( v1 == v2 ); + BOOST_TEST_NOT( v1 != v2 ); + } + + return boost::report_errors(); +} diff --git a/test/variant_get_by_index.cpp b/test/variant_get_by_index.cpp new file mode 100644 index 0000000..b55313e --- /dev/null +++ b/test/variant_get_by_index.cpp @@ -0,0 +1,200 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +int main() +{ + { + variant v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int*>)); + } + + { + variant const v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + } + + { + variant v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + } + + { + variant const v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const volatile&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const volatile&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const volatile*>)); + } + + { + variant v; + + BOOST_TEST_EQ( get<0>(v), 0 ); + BOOST_TEST_EQ( get_if<0>(&v), &get<0>(v) ); + + BOOST_TEST_EQ( get<0>(std::move(v)), 0 ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( get<0>(v), 1 ); + BOOST_TEST_EQ( get_if<0>(&v), &get<0>(v) ); + + BOOST_TEST_EQ( get<0>(std::move(v)), 1 ); + } + + { + variant v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int*>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), float&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), float&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), float*>)); + } + + { + variant const v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), float const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), float const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), float const*>)); + } + + { + variant v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), float volatile&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), float volatile&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), float volatile*>)); + } + + { + variant const v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), float const volatile&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), float const volatile&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), float const volatile*>)); + } + + { + variant v; + + BOOST_TEST_EQ( get<0>(v), 0 ); + BOOST_TEST_EQ( get_if<0>(&v), &get<0>(v) ); + + BOOST_TEST_THROWS( get<1>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<1>(&v), nullptr ); + + BOOST_TEST_EQ( get<0>(std::move(v)), 0 ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( get<0>(v), 1 ); + BOOST_TEST_EQ( get_if<0>(&v), &get<0>(v) ); + + BOOST_TEST_THROWS( get<1>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<1>(&v), nullptr ); + + BOOST_TEST_EQ( get<0>(std::move(v)), 1 ); + } + + { + variant v( 3.14f ); + + BOOST_TEST_THROWS( get<0>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<0>(&v), nullptr ); + + BOOST_TEST_EQ( get<1>(v), 3.14f ); + BOOST_TEST_EQ( get_if<1>(&v), &get<1>(v) ); + + BOOST_TEST_EQ( get<1>(std::move(v)), 3.14f ); + } + + { + variant v; + + BOOST_TEST_EQ( get<0>(v), 0 ); + BOOST_TEST_EQ( get_if<0>(&v), &get<0>(v) ); + + BOOST_TEST_THROWS( get<1>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<1>(&v), nullptr ); + + BOOST_TEST_THROWS( get<2>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<2>(&v), nullptr ); + + BOOST_TEST_EQ( get<0>(std::move(v)), 0 ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( get<0>(v), 1 ); + BOOST_TEST_EQ( get_if<0>(&v), &get<0>(v) ); + + BOOST_TEST_THROWS( get<1>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<1>(&v), nullptr ); + + BOOST_TEST_THROWS( get<2>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<2>(&v), nullptr ); + + BOOST_TEST_EQ( get<0>(std::move(v)), 1 ); + } + + { + variant v( 3.14f ); + + BOOST_TEST_THROWS( get<0>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<0>(&v), nullptr ); + + BOOST_TEST_THROWS( get<1>(v), bad_variant_access ); + BOOST_TEST_EQ( get_if<1>(&v), nullptr ); + + BOOST_TEST_EQ( get<2>(v), 3.14f ); + BOOST_TEST_EQ( get_if<2>(&v), &get<2>(v) ); + + BOOST_TEST_EQ( get<2>(std::move(v)), 3.14f ); + } + + return boost::report_errors(); +} diff --git a/test/variant_get_by_index_cx.cpp b/test/variant_get_by_index_cx.cpp new file mode 100644 index 0000000..ae1b99f --- /dev/null +++ b/test/variant_get_by_index_cx.cpp @@ -0,0 +1,90 @@ + +// 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 + +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v; + + STATIC_ASSERT( get<0>(v) == 0 ); + STATIC_ASSERT( get_if<0>(&v) == &get<0>(v) ); + } + + { + constexpr variant v( 1 ); + + STATIC_ASSERT( get<0>(v) == 1 ); + STATIC_ASSERT( get_if<0>(&v) == &get<0>(v) ); + } + + { + constexpr variant v; + + STATIC_ASSERT( get<0>(v) == 0 ); + STATIC_ASSERT( get_if<0>(&v) == &get<0>(v) ); + + STATIC_ASSERT( get_if<1>(&v) == nullptr ); + } + + { + constexpr variant v( 1 ); + + STATIC_ASSERT( get<0>(v) == 1 ); + STATIC_ASSERT( get_if<0>(&v) == &get<0>(v) ); + + STATIC_ASSERT( get_if<1>(&v) == nullptr ); + } + + { + constexpr variant v( 3.14f ); + + STATIC_ASSERT( get_if<0>(&v) == nullptr ); + + STATIC_ASSERT( get<1>(v) == 3.14f ); + STATIC_ASSERT( get_if<1>(&v) == &get<1>(v) ); + } + + { + constexpr variant v; + + STATIC_ASSERT( get<0>(v) == 0 ); + STATIC_ASSERT( get_if<0>(&v) == &get<0>(v) ); + + STATIC_ASSERT( get_if<1>(&v) == nullptr ); + + STATIC_ASSERT( get_if<2>(&v) == nullptr ); + } + + { + constexpr variant v( 1 ); + + STATIC_ASSERT( get<0>(v) == 1 ); + STATIC_ASSERT( get_if<0>(&v) == &get<0>(v) ); + + STATIC_ASSERT( get_if<1>(&v) == nullptr ); + + STATIC_ASSERT( get_if<2>(&v) == nullptr ); + } + + { + constexpr variant v( 3.14f ); + + STATIC_ASSERT( get_if<0>(&v) == nullptr ); + + STATIC_ASSERT( get_if<1>(&v) == nullptr ); + + STATIC_ASSERT( get<2>(v) == 3.14f ); + STATIC_ASSERT( get_if<2>(&v) == &get<2>(v) ); + } +} diff --git a/test/variant_get_by_type.cpp b/test/variant_get_by_type.cpp new file mode 100644 index 0000000..82b18c7 --- /dev/null +++ b/test/variant_get_by_type.cpp @@ -0,0 +1,166 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +int main() +{ + { + variant v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int*>)); + } + + { + variant const v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + } + + { + variant v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + } + + { + variant const v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const volatile&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const volatile&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const volatile*>)); + } + + { + variant v; + + BOOST_TEST_EQ( get(v), 0 ); + BOOST_TEST_EQ( get_if(&v), &get(v) ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( get(v), 1 ); + BOOST_TEST_EQ( get_if(&v), &get(v) ); + } + + { + variant v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int*>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), float&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), float&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), float*>)); + } + + { + variant const v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), float const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), float const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), float const*>)); + } + + { + variant v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), float volatile&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), float volatile&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), float volatile*>)); + } + + { + variant const v; + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), int const&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), int const*>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same(v)), float const volatile&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(std::move(v))), float const volatile&&>)); + BOOST_TEST_TRAIT_TRUE((std::is_same(&v)), float const volatile*>)); + } + + { + variant v; + + BOOST_TEST_EQ( get(v), 0 ); + BOOST_TEST_EQ( get_if(&v), &get(v) ); + + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( get(v), 1 ); + BOOST_TEST_EQ( get_if(&v), &get(v) ); + + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + } + + { + variant v( 3.14f ); + + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + + BOOST_TEST_EQ( get(v), 3.14f ); + BOOST_TEST_EQ( get_if(&v), &get(v) ); + } + + { + variant v; + + BOOST_TEST_EQ( get(v), 0 ); + BOOST_TEST_EQ( get_if(&v), &get(v) ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( get(v), 1 ); + BOOST_TEST_EQ( get_if(&v), &get(v) ); + } + + { + variant v( 3.14f ); + + BOOST_TEST_EQ( get(v), 3.14f ); + BOOST_TEST_EQ( get_if(&v), &get(v) ); + } + + return boost::report_errors(); +} diff --git a/test/variant_get_by_type_cx.cpp b/test/variant_get_by_type_cx.cpp new file mode 100644 index 0000000..b4995fe --- /dev/null +++ b/test/variant_get_by_type_cx.cpp @@ -0,0 +1,78 @@ + +// 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 + +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v; + + STATIC_ASSERT( get(v) == 0 ); + STATIC_ASSERT( get_if(&v) == &get(v) ); + } + + { + constexpr variant v( 1 ); + + STATIC_ASSERT( get(v) == 1 ); + STATIC_ASSERT( get_if(&v) == &get(v) ); + } + + { + constexpr variant v; + + STATIC_ASSERT( get(v) == 0 ); + STATIC_ASSERT( get_if(&v) == &get(v) ); + + STATIC_ASSERT( get_if(&v) == nullptr ); + } + + { + constexpr variant v( 1 ); + + STATIC_ASSERT( get(v) == 1 ); + STATIC_ASSERT( get_if(&v) == &get(v) ); + + STATIC_ASSERT( get_if(&v) == nullptr ); + } + + { + constexpr variant v( 3.14f ); + + STATIC_ASSERT( get_if(&v) == nullptr ); + + STATIC_ASSERT( get(v) == 3.14f ); + STATIC_ASSERT( get_if(&v) == &get(v) ); + } + + { + constexpr variant v; + + STATIC_ASSERT( get(v) == 0 ); + STATIC_ASSERT( get_if(&v) == &get(v) ); + } + + { + constexpr variant v( 1 ); + + STATIC_ASSERT( get(v) == 1 ); + STATIC_ASSERT( get_if(&v) == &get(v) ); + } + + { + constexpr variant v( 3.14f ); + + STATIC_ASSERT( get(v) == 3.14f ); + STATIC_ASSERT( get_if(&v) == &get(v) ); + } +} diff --git a/test/variant_holds_alternative.cpp b/test/variant_holds_alternative.cpp new file mode 100644 index 0000000..4931f40 --- /dev/null +++ b/test/variant_holds_alternative.cpp @@ -0,0 +1,78 @@ + +// 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 + +#include +#include +#include + +using namespace boost::variant2; + +int main() +{ + { + variant v; + BOOST_TEST( holds_alternative( v ) ); + } + + { + variant v; + BOOST_TEST( holds_alternative( v ) ); + BOOST_TEST( !holds_alternative( v ) ); + } + + { + variant v( 3.14f ); + BOOST_TEST( !holds_alternative( v ) ); + BOOST_TEST( holds_alternative( v ) ); + } + + { + variant v; + BOOST_TEST( holds_alternative( v ) ); + } + + { + variant v( 3.14f ); + BOOST_TEST( holds_alternative( v ) ); + } + + { + variant v; + BOOST_TEST( holds_alternative( v ) ); + BOOST_TEST( !holds_alternative( v ) ); + BOOST_TEST( !holds_alternative( v ) ); + } + + { + variant v( 3.14f ); + BOOST_TEST( !holds_alternative( v ) ); + BOOST_TEST( holds_alternative( v ) ); + BOOST_TEST( !holds_alternative( v ) ); + } + + { + variant v( "text" ); + BOOST_TEST( !holds_alternative( v ) ); + BOOST_TEST( !holds_alternative( v ) ); + BOOST_TEST( holds_alternative( v ) ); + } + + { + variant v( 3.14f ); + BOOST_TEST( holds_alternative( v ) ); + BOOST_TEST( !holds_alternative( v ) ); + } + + { + variant v( "text" ); + BOOST_TEST( !holds_alternative( v ) ); + BOOST_TEST( holds_alternative( v ) ); + } + + return boost::report_errors(); +} diff --git a/test/variant_holds_alternative_cx.cpp b/test/variant_holds_alternative_cx.cpp new file mode 100644 index 0000000..c2bdc0a --- /dev/null +++ b/test/variant_holds_alternative_cx.cpp @@ -0,0 +1,43 @@ + +// 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 + +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v; + STATIC_ASSERT( holds_alternative( v ) ); + } + + { + constexpr variant v; + STATIC_ASSERT( holds_alternative( v ) ); + STATIC_ASSERT( !holds_alternative( v ) ); + } + + { + constexpr variant v( 3.14f ); + STATIC_ASSERT( !holds_alternative( v ) ); + STATIC_ASSERT( holds_alternative( v ) ); + } + + { + constexpr variant v; + STATIC_ASSERT( holds_alternative( v ) ); + } + + { + constexpr variant v( 3.14f ); + STATIC_ASSERT( holds_alternative( v ) ); + } +} diff --git a/test/variant_in_place_index_construct.cpp b/test/variant_in_place_index_construct.cpp new file mode 100644 index 0000000..4e87b3f --- /dev/null +++ b/test/variant_in_place_index_construct.cpp @@ -0,0 +1,138 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +struct X +{ + X() = default; + X( in_place_index_t<0> ) = delete; +}; + +int main() +{ + { + variant v( in_place_index<0> ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v( in_place_index<0> ); + + BOOST_TEST_EQ( v.index(), 0 ); + } + + { + variant v( in_place_index<0>, 1 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + } + + { + variant v( in_place_index<0> ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + } + + { + variant v( in_place_index<0>, 1 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + } + + { + variant v( in_place_index<1> ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 0 ); + } + + { + variant v( in_place_index<1>, 3.14f ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + } + + { + variant v( in_place_index<0>, 1 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + } + + { + variant v( in_place_index<1>, 1 ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 1 ); + } + + { + variant v( in_place_index<2>, 3.14f ); + + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + } + + { + variant v( in_place_index<3>, 3.14f ); + + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), 3.14f ); + } + + { + variant v( in_place_index<4>, "text" ); + + BOOST_TEST_EQ( v.index(), 4 ); + BOOST_TEST_EQ( get<4>(v), std::string("text") ); + } + + { + variant v( in_place_index<5>, "text" ); + + BOOST_TEST_EQ( v.index(), 5 ); + BOOST_TEST_EQ( get<5>(v), std::string("text") ); + } + + { + variant v( in_place_index<5>, 4, 'a' ); + + BOOST_TEST_EQ( v.index(), 5 ); + BOOST_TEST_EQ( get<5>(v), std::string( 4, 'a' ) ); + } + + { + variant v( in_place_index<4>, { 'a', 'b', 'c' } ); + + BOOST_TEST_EQ( v.index(), 4 ); + BOOST_TEST_EQ( get<4>(v), (std::string{ 'a', 'b', 'c' }) ); + } + + { + variant v( in_place_index<5>, { 'a', 'b', 'c' }, std::allocator() ); + + BOOST_TEST_EQ( v.index(), 5 ); + BOOST_TEST_EQ( get<5>(v), (std::string{ 'a', 'b', 'c' }) ); + } + + return boost::report_errors(); +} diff --git a/test/variant_in_place_index_construct_cx.cpp b/test/variant_in_place_index_construct_cx.cpp new file mode 100644 index 0000000..e9c771f --- /dev/null +++ b/test/variant_in_place_index_construct_cx.cpp @@ -0,0 +1,116 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +struct X +{ + constexpr X() = default; + constexpr explicit X(int, int) {} + X( in_place_index_t<0> ) = delete; +}; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v( in_place_index<0> ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + } + + { + constexpr variant v( in_place_index<0> ); + + STATIC_ASSERT( v.index() == 0 ); + } + + { + constexpr variant v( in_place_index<0>, 1 ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 1 ); + } + + { + constexpr variant v( in_place_index<0> ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + } + + { + constexpr variant v( in_place_index<0>, 1 ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 1 ); + } + + { + constexpr variant v( in_place_index<1> ); + + STATIC_ASSERT( v.index() == 1 ); + STATIC_ASSERT( get<1>(v) == 0 ); + } + + { + constexpr variant v( in_place_index<1>, 3.14f ); + + STATIC_ASSERT( v.index() == 1 ); + STATIC_ASSERT( get<1>(v) == 3.14f ); + } + + { + constexpr variant v( in_place_index<0>, 1 ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 1 ); + } + + { + constexpr variant v( in_place_index<1>, 1 ); + + STATIC_ASSERT( v.index() == 1 ); + STATIC_ASSERT( get<1>(v) == 1 ); + } + + { + constexpr variant v( in_place_index<2>, 3.14f ); + + STATIC_ASSERT( v.index() == 2 ); + STATIC_ASSERT( get<2>(v) == 3.14f ); + } + + { + constexpr variant v( in_place_index<3>, 3.14f ); + + STATIC_ASSERT( v.index() == 3 ); + STATIC_ASSERT( get<3>(v) == 3.14f ); + } + + { + constexpr variant v( in_place_index<4> ); + + STATIC_ASSERT( v.index() == 4 ); + } + + { + constexpr variant v( in_place_index<5>, 0, 0 ); + + STATIC_ASSERT( v.index() == 5 ); + } +} diff --git a/test/variant_in_place_type_construct.cpp b/test/variant_in_place_type_construct.cpp new file mode 100644 index 0000000..dc956eb --- /dev/null +++ b/test/variant_in_place_type_construct.cpp @@ -0,0 +1,134 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +struct X +{ + X() = default; + template X( in_place_type_t ) = delete; +}; + +int main() +{ + { + variant v( in_place_type ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type ); + + BOOST_TEST_EQ( v.index(), 0 ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type, 1 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type, 1 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 0 ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type, 3.14f ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type, 3.14f ); + + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type, "text" ); + + BOOST_TEST_EQ( v.index(), 4 ); + BOOST_TEST_EQ( get<4>(v), std::string("text") ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type, 4, 'a' ); + + BOOST_TEST_EQ( v.index(), 4 ); + BOOST_TEST_EQ( get<4>(v), std::string( 4, 'a' ) ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type, { 'a', 'b', 'c' } ); + + BOOST_TEST_EQ( v.index(), 4 ); + BOOST_TEST_EQ( get<4>(v), (std::string{ 'a', 'b', 'c' }) ); + + BOOST_TEST( holds_alternative(v) ); + } + + { + variant v( in_place_type, { 'a', 'b', 'c' }, std::allocator() ); + + BOOST_TEST_EQ( v.index(), 4 ); + BOOST_TEST_EQ( get<4>(v), (std::string{ 'a', 'b', 'c' }) ); + + BOOST_TEST( holds_alternative(v) ); + } + + return boost::report_errors(); +} diff --git a/test/variant_in_place_type_construct_cx.cpp b/test/variant_in_place_type_construct_cx.cpp new file mode 100644 index 0000000..054159b --- /dev/null +++ b/test/variant_in_place_type_construct_cx.cpp @@ -0,0 +1,110 @@ + +// 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 + +#include + +using namespace boost::variant2; + +struct X +{ + constexpr X() = default; + constexpr explicit X(int, int) {} + template X( in_place_type_t ) = delete; +}; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v( in_place_type ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type ); + + STATIC_ASSERT( v.index() == 0 ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type, 1 ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 1 ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 0 ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type, 1 ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 1 ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type ); + + STATIC_ASSERT( v.index() == 1 ); + STATIC_ASSERT( get<1>(v) == 0 ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type, 3.14f ); + + STATIC_ASSERT( v.index() == 1 ); + STATIC_ASSERT( get<1>(v) == 3.14f ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type, 3.14f ); + + STATIC_ASSERT( v.index() == 2 ); + STATIC_ASSERT( get<2>(v) == 3.14f ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type ); + + STATIC_ASSERT( v.index() == 4 ); + + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( in_place_type, 0, 0 ); + + STATIC_ASSERT( v.index() == 4 ); + + STATIC_ASSERT( holds_alternative(v) ); + } +} diff --git a/test/variant_move_assign.cpp b/test/variant_move_assign.cpp new file mode 100644 index 0000000..9c87718 --- /dev/null +++ b/test/variant_move_assign.cpp @@ -0,0 +1,194 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + int v; + + X1(): v(0) {} + explicit X1(int v): v(v) {} + X1(X1 const& r): v(r.v) {} + X1(X1&& r): v(r.v) {} + X1& operator=( X1 const& r ) { v = r.v; return *this; } + X1& operator=( X1&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X1 const& a, X1 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +struct X2 +{ + int v; + + X2(): v(0) {} + explicit X2(int v): v(v) {} + X2(X2 const& r): v(r.v) {} + X2(X2&& r): v(r.v) {} + X2& operator=( X2 const& r ) { v = r.v; return *this; } + X2& operator=( X2&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X2 const& a, X2 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +struct Y +{ + Y& operator=( Y&& ) = delete; +}; + +int main() +{ + { + variant v; + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( 1 ); + + v = std::move(v2); + BOOST_TEST_EQ( get<0>(v), 1 ); + + variant v3( 2 ); + + v = std::move(v3); + BOOST_TEST_EQ( get<0>(v), 2 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( 1 ); + + v = std::move(v2); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + variant v3( 3.14f ); + + v = std::move(v3); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + + variant v4( 3.15f ); + + v = std::move(v4); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.15f ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( in_place_index<1>, 1 ); + + v = std::move(v2); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 1 ); + + variant v3( 3.14f ); + + v = std::move(v3); + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + + variant v4( 3.15f ); + + v = std::move(v4); + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.15f ); + + variant v5( "s1" ); + + v = std::move(v5); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s1") ); + + variant v6( "s2" ); + + v = std::move(v6); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s2") ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 0 ); + + variant v2( X1{1} ); + + v = std::move(v2); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 1 ); + + variant v3( in_place_index<1>, 2 ); + + v = std::move(v3); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 2 ); + + variant v4( in_place_index<1>, 3 ); + + v = std::move(v4); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 3 ); + + variant v5( in_place_index<0>, 4 ); + + v = std::move(v5); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + } + + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + + BOOST_TEST_TRAIT_TRUE((std::is_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_move_assignable>)); + } + + return boost::report_errors(); +} diff --git a/test/variant_move_construct.cpp b/test/variant_move_construct.cpp new file mode 100644 index 0000000..e3d8e98 --- /dev/null +++ b/test/variant_move_construct.cpp @@ -0,0 +1,129 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + X1() {} + X1(X1 const&) {} + X1(X1&&) {} +}; + +inline bool operator==( X1, X1 ) { return true; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); + +struct X2 +{ + X2() {} + X2(X2 const&) {} + X2(X2&&) {} +}; + +inline bool operator==( X2, X2 ) { return true; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); + +struct Y +{ + Y( Y&& ) = delete; +}; + +template static void test( V&& v ) +{ + V v2( v ); + V v3( std::move(v) ); + + BOOST_TEST_EQ( v2.index(), v3.index() ); + BOOST_TEST( v2 == v3 ); +} + +int main() +{ + test( variant() ); + test( variant(1) ); + + test( variant() ); + test( variant(1) ); + + test( variant() ); + test( variant(1) ); + test( variant(3.14f) ); + + test( variant() ); + test( variant(1) ); + test( variant(3.14f) ); + test( variant("test") ); + + test( variant() ); + + test( variant() ); + test( variant(3.14f) ); + + test( variant() ); + + test( variant("test") ); + + test( variant() ); + + test( variant() ); + test( variant() ); + test( variant() ); + test( variant() ); + + { + variant v; + v.emplace(); + + test( std::move(v) ); + } + + { + variant v; + v.emplace(); + + test( std::move(v) ); + } + + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_move_constructible>)); + } + + return boost::report_errors(); +} diff --git a/test/variant_size.cpp b/test/variant_size.cpp new file mode 100644 index 0000000..b348418 --- /dev/null +++ b/test/variant_size.cpp @@ -0,0 +1,64 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; +using namespace boost::mp11; + +template using var_size_t = mp_size_t::value>; + +int main() +{ + BOOST_TEST_EQ( (variant_size>::value), 0 ); + BOOST_TEST_EQ( (variant_size const>::value), 0 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 0 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 0 ); + + BOOST_TEST_EQ( (variant_size>::value), 1 ); + BOOST_TEST_EQ( (variant_size const>::value), 1 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 1 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 1 ); + + BOOST_TEST_EQ( (variant_size>::value), 2 ); + BOOST_TEST_EQ( (variant_size const>::value), 2 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 2 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 2 ); + + BOOST_TEST_EQ( (variant_size>::value), 3 ); + BOOST_TEST_EQ( (variant_size const>::value), 3 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 3 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 3 ); + + BOOST_TEST_EQ( (variant_size>::value), 4 ); + BOOST_TEST_EQ( (variant_size const>::value), 4 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 4 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 4 ); + + variant_size(); + variant_size(); + variant_size(); + variant_size(); + + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + + BOOST_TEST_TRAIT_TRUE((mp_valid>)); + BOOST_TEST_TRAIT_TRUE((mp_valid const>)); + BOOST_TEST_TRAIT_TRUE((mp_valid volatile>)); + BOOST_TEST_TRAIT_TRUE((mp_valid const volatile>)); + + return boost::report_errors(); +} diff --git a/test/variant_swap.cpp b/test/variant_swap.cpp new file mode 100644 index 0000000..679f5f8 --- /dev/null +++ b/test/variant_swap.cpp @@ -0,0 +1,259 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + int v; + + X1(): v(0) {} + explicit X1(int v): v(v) {} + X1(X1 const& r): v(r.v) {} + X1(X1&& r): v(r.v) {} + X1& operator=( X1 const& r ) { v = r.v; return *this; } + X1& operator=( X1&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X1 const& a, X1 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +struct X2 +{ + int v; + + X2(): v(0) {} + explicit X2(int v): v(v) {} + X2(X2 const& r): v(r.v) {} + X2(X2&& r): v(r.v) {} + X2& operator=( X2 const& r ) { v = r.v; return *this; } + X2& operator=( X2&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X2 const& a, X2 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +int main() +{ + { + variant v; + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( 1 ); + BOOST_TEST_EQ( get<0>(v2), 1 ); + + swap( v, v2 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + BOOST_TEST_EQ( get<0>(v2), 0 ); + + variant v3( 2 ); + BOOST_TEST_EQ( get<0>(v3), 2 ); + + swap( v, v3 ); + BOOST_TEST_EQ( get<0>(v), 2 ); + BOOST_TEST_EQ( get<0>(v3), 1 ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( 1 ); + + BOOST_TEST_EQ( v2.index(), 0 ); + BOOST_TEST_EQ( get<0>(v2), 1 ); + + swap( v, v2 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + BOOST_TEST_EQ( v2.index(), 0 ); + BOOST_TEST_EQ( get<0>(v2), 0 ); + + variant v3( 3.14f ); + + BOOST_TEST_EQ( v3.index(), 1 ); + BOOST_TEST_EQ( get<1>(v3), 3.14f ); + + swap( v, v3 ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + + BOOST_TEST_EQ( v3.index(), 0 ); + BOOST_TEST_EQ( get<0>(v3), 1 ); + + variant v4( 3.15f ); + + BOOST_TEST_EQ( v4.index(), 1 ); + BOOST_TEST_EQ( get<1>(v4), 3.15f ); + + swap( v, v4 ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.15f ); + + BOOST_TEST_EQ( v4.index(), 1 ); + BOOST_TEST_EQ( get<1>(v4), 3.14f ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + variant v2( in_place_index<1>, 1 ); + + BOOST_TEST_EQ( v2.index(), 1 ); + BOOST_TEST_EQ( get<1>(v2), 1 ); + + swap( v, v2 ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 1 ); + + BOOST_TEST_EQ( v2.index(), 0 ); + BOOST_TEST_EQ( get<0>(v2), 0 ); + + variant v3( 3.14f ); + + BOOST_TEST_EQ( v3.index(), 2 ); + BOOST_TEST_EQ( get<2>(v3), 3.14f ); + + swap( v, v3 ); + + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + + BOOST_TEST_EQ( v3.index(), 1 ); + BOOST_TEST_EQ( get<1>(v3), 1 ); + + variant v4( 3.15f ); + + BOOST_TEST_EQ( v4.index(), 2 ); + BOOST_TEST_EQ( get<2>(v4), 3.15f ); + + swap( v, v4 ); + + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.15f ); + + BOOST_TEST_EQ( v4.index(), 2 ); + BOOST_TEST_EQ( get<2>(v4), 3.14f ); + + variant v5( "s1" ); + + BOOST_TEST_EQ( v5.index(), 3 ); + BOOST_TEST_EQ( get<3>(v5), std::string("s1") ); + + swap( v, v5 ); + + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s1") ); + + BOOST_TEST_EQ( v5.index(), 2 ); + BOOST_TEST_EQ( get<2>(v5), 3.15f ); + + variant v6( "s2" ); + + BOOST_TEST_EQ( v6.index(), 3 ); + BOOST_TEST_EQ( get<3>(v6), std::string("s2") ); + + swap( v, v6 ); + + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s2") ); + + BOOST_TEST_EQ( v6.index(), 3 ); + BOOST_TEST_EQ( get<3>(v6), std::string("s1") ); + } + + { + variant v; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 0 ); + + variant v2( X1{1} ); + + BOOST_TEST_EQ( v2.index(), 0 ); + BOOST_TEST_EQ( get<0>(v2).v, 1 ); + + swap( v, v2 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 1 ); + + BOOST_TEST_EQ( v2.index(), 0 ); + BOOST_TEST_EQ( get<0>(v2).v, 0 ); + + variant v3( in_place_index<1>, 2 ); + + BOOST_TEST_EQ( v3.index(), 1 ); + BOOST_TEST_EQ( get<1>(v3).v, 2 ); + + swap( v, v3 ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 2 ); + + BOOST_TEST_EQ( v3.index(), 0 ); + BOOST_TEST_EQ( get<0>(v3).v, 1 ); + + variant v4( in_place_index<1>, 3 ); + + BOOST_TEST_EQ( v4.index(), 1 ); + BOOST_TEST_EQ( get<1>(v4).v, 3 ); + + swap( v, v4 ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 3 ); + + BOOST_TEST_EQ( v4.index(), 1 ); + BOOST_TEST_EQ( get<1>(v4).v, 2 ); + + variant v5( in_place_index<0>, 4 ); + + BOOST_TEST_EQ( v5.index(), 0 ); + BOOST_TEST_EQ( get<0>(v5).v, 4 ); + + swap( v, v5 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + + BOOST_TEST_EQ( v5.index(), 1 ); + BOOST_TEST_EQ( get<1>(v5).v, 3 ); + } + + return boost::report_errors(); +} diff --git a/test/variant_value_assign.cpp b/test/variant_value_assign.cpp new file mode 100644 index 0000000..2519adc --- /dev/null +++ b/test/variant_value_assign.cpp @@ -0,0 +1,206 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + int v; + + X1(): v(0) {} + explicit X1(int v): v(v) {} + X1(X1 const& r): v(r.v) {} + X1(X1&& r): v(r.v) {} + X1& operator=( X1 const& r ) { v = r.v; return *this; } + X1& operator=( X1&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X1 const& a, X1 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +struct X2 +{ + int v; + + X2(): v(0) {} + explicit X2(int v): v(v) {} + X2(X2 const& r): v(r.v) {} + X2(X2&& r): v(r.v) {} + X2& operator=( X2 const& r ) { v = r.v; return *this; } + X2& operator=( X2&& r ) { v = r.v; return *this; } +}; + +inline bool operator==( X2 const& a, X2 const& b ) { return a.v == b.v; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); +STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); + +int main() +{ + { + variant v; + BOOST_TEST_EQ( get<0>(v), 0 ); + + v = 1; + BOOST_TEST_EQ( get<0>(v), 1 ); + + v = 2; + BOOST_TEST_EQ( get<0>(v), 2 ); + + int w1 = 3; + + v = w1; + BOOST_TEST_EQ( get<0>(v), 3 ); + + int const w2 = 4; + + v = w2; + BOOST_TEST_EQ( get<0>(v), 4 ); + + v = std::move( w1 ); + BOOST_TEST_EQ( get<0>(v), 3 ); + + v = std::move( w2 ); + BOOST_TEST_EQ( get<0>(v), 4 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + v = 1; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + + v = 3.14f; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + + float w1 = 3.15f; + + v = w1; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.15f ); + + int const w2 = 2; + + v = w2; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 2 ); + + v = std::move(w1); + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 3.15f ); + + v = std::move(w2); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 2 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 0 ); + + v = 3.14f; + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + + float const w1 = 3.15f; + + v = w1; + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.15f ); + + variant v5( "s1" ); + + v = "s1"; + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s1") ); + + std::string w2( "s2" ); + + v = w2; + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s2") ); + + v = std::move(w1); + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.15f ); + + v = std::move(w2); + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST_EQ( get<3>(v), std::string("s2") ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 0 ); + + v = X1{1}; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 1 ); + + v = X2{2}; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 2 ); + + X1 w1{3}; + + v = w1; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 3 ); + + X1 const w2{4}; + + v = w2; + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + + X2 w3{5}; + + v = w3; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 5 ); + + X2 const w4{6}; + + v = w4; + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v).v, 6 ); + + v = std::move(w1); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 3 ); + + v = std::move(w2); + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v).v, 4 ); + } + + return boost::report_errors(); +} diff --git a/test/variant_value_construct.cpp b/test/variant_value_construct.cpp new file mode 100644 index 0000000..56df896 --- /dev/null +++ b/test/variant_value_construct.cpp @@ -0,0 +1,124 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +struct X +{ + operator int() const { return 2; } +}; + +int main() +{ + { + variant v( 1 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + } + + { + variant v( 'a' ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 'a' ); + } + + { + variant v( X{} ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 2 ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 1 ); + } + + { + variant v( 'a' ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 'a' ); + } + + { + variant v( X{} ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), 2 ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST( holds_alternative(v) ); + BOOST_TEST_EQ( get<0>(v), 1 ); + } + + { + variant v( 'a' ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST( holds_alternative(v) ); + BOOST_TEST_EQ( get<0>(v), 'a' ); + } + + { + variant v( X{} ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST( holds_alternative(v) ); + BOOST_TEST_EQ( get<0>(v), 2 ); + } + + { + variant v( 3.14f ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST( holds_alternative(v) ); + BOOST_TEST_EQ( get<1>(v), 3.14f ); + } + + { + variant v( "text" ); + + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST( holds_alternative(v) ); + BOOST_TEST_EQ( get<2>(v), std::string("text") ); + } + + { + variant v( 3.14f ); + + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST( holds_alternative(v) ); + BOOST_TEST_EQ( get<2>(v), 3.14f ); + } + + { + variant v( "text" ); + + BOOST_TEST_EQ( v.index(), 3 ); + BOOST_TEST( holds_alternative(v) ); + BOOST_TEST_EQ( get<3>(v), std::string("text") ); + } + + return boost::report_errors(); +} diff --git a/test/variant_value_construct_cx.cpp b/test/variant_value_construct_cx.cpp new file mode 100644 index 0000000..5ffad25 --- /dev/null +++ b/test/variant_value_construct_cx.cpp @@ -0,0 +1,109 @@ + +// 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 + +#include + +using namespace boost::variant2; + +struct X +{ + constexpr operator int() const { return 2; } +}; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v( 1 ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 1 ); + } + + { + constexpr variant v( 'a' ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 'a' ); + } + + { + constexpr variant v( X{} ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 2 ); + } + + { + constexpr variant v( 1 ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 1 ); + } + + { + constexpr variant v( 'a' ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 'a' ); + } + + { + constexpr variant v( X{} ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( get<0>(v) == 2 ); + } + + { + constexpr variant v( 1 ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( holds_alternative(v) ); + STATIC_ASSERT( get<0>(v) == 1 ); + } + + { + constexpr variant v( 'a' ); + + STATIC_ASSERT( v.index() == 0 ); + STATIC_ASSERT( holds_alternative(v) ); + STATIC_ASSERT( get<0>(v) == 'a' ); + } + + { + constexpr variant v( 3.14f ); + + STATIC_ASSERT( v.index() == 1 ); + STATIC_ASSERT( holds_alternative(v) ); + STATIC_ASSERT( get<1>(v) == 3.14f ); + } + + { + constexpr variant v( X{} ); + + STATIC_ASSERT( v.index() == 2 ); + STATIC_ASSERT( holds_alternative(v) ); + } + + { + constexpr variant v( 3.14f ); + + STATIC_ASSERT( v.index() == 2 ); + STATIC_ASSERT( holds_alternative(v) ); + STATIC_ASSERT( get<2>(v) == 3.14f ); + } + + { + constexpr variant v( X{} ); + + STATIC_ASSERT( v.index() == 3 ); + STATIC_ASSERT( holds_alternative(v) ); + } +} diff --git a/test/variant_visit.cpp b/test/variant_visit.cpp new file mode 100644 index 0000000..5058e3e --- /dev/null +++ b/test/variant_visit.cpp @@ -0,0 +1,91 @@ + +// 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 + +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +int main() +{ + { + variant v( 1 ); + + BOOST_TEST_EQ( (visit( []( auto x ){ return x; }, v )), 1 ); + + visit( []( auto x ){ BOOST_TEST_EQ( x, 1 ); }, v ); + visit( []( auto x ){ BOOST_TEST_EQ( x, 1 ); }, std::move(v) ); + } + + { + variant const v( 2 ); + + BOOST_TEST_EQ( (visit( []( auto x ){ return x; }, v )), 2 ); + + visit( []( auto x ){ BOOST_TEST_EQ( x, 2 ); }, v ); + visit( []( auto x ){ BOOST_TEST_EQ( x, 2 ); }, std::move(v) ); + } + + { + variant v( 3 ); + + BOOST_TEST_EQ( (visit( []( auto x ){ return x; }, v )), 3 ); + + visit( []( auto x ){ BOOST_TEST_EQ( x, 3 ); }, v ); + visit( []( auto x ){ BOOST_TEST_EQ( x, 3 ); }, std::move(v) ); + } + + { + variant const v( 4 ); + + BOOST_TEST_EQ( (visit( []( auto x ){ return x; }, v )), 4 ); + + visit( []( auto x ){ BOOST_TEST_EQ( x, 4 ); }, v ); + visit( []( auto x ){ BOOST_TEST_EQ( x, 4 ); }, std::move(v) ); + } + + { + variant v1( 1 ); + variant const v2( 3.14f ); + + BOOST_TEST_EQ( (visit( []( auto x1, auto x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 ); + + visit( []( auto x1, auto x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 ); + visit( []( auto x1, auto x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) ); + } + + { + variant v1( 1 ); + variant const v2( 3.14f ); + variant v3( 6.28 ); + + BOOST_TEST_EQ( (visit( []( auto x1, auto x2, auto x3 ){ return (int)(x1 * 100) * 1000000 + (int)(x2 * 100) * 1000 + (int)(x3 * 100); }, v1, v2, v3 )), 100314628 ); + + visit( []( auto x1, auto x2, auto x3 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); BOOST_TEST_EQ( x3, 6.28 ); }, v1, v2, v3 ); + visit( []( auto x1, auto x2, auto x3 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); BOOST_TEST_EQ( x3, 6.28 ); }, std::move(v1), std::move(v2), std::move(v3) ); + } + + { + variant v1( 1 ); + variant const v2( 3.14f ); + variant v3( 6.28 ); + variant const v4( 'A' ); + + BOOST_TEST_EQ( (visit( []( auto x1, auto x2, auto x3, auto x4 ){ return (long long)(x1 * 100) * 100000000 + (long long)(x2 * 100) * 100000 + (long long)(x3 * 10000) + (int)x4; }, v1, v2, v3, v4 )), 10031462800 + 'A' ); + + visit( []( auto x1, auto x2, auto x3, auto x4 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); BOOST_TEST_EQ( x3, 6.28 ); BOOST_TEST_EQ( x4, 'A' ); }, v1, v2, v3, v4 ); + visit( []( auto x1, auto x2, auto x3, auto x4 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); BOOST_TEST_EQ( x3, 6.28 ); BOOST_TEST_EQ( x4, 'A' ); }, std::move(v1), std::move(v2), std::move(v3), std::move(v4) ); + } + + return boost::report_errors(); +}