From fc2aa96acb96a8bbc8c72459a0770a8374cc694c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 29 May 2017 17:31:05 +0300 Subject: [PATCH 01/30] Initial commit --- include/boost/variant2/variant.hpp | 908 +++++++++++++++++++++++++++++ meta/libraries.json | 14 + test/Jamfile | 15 + test/variant_alternative.cpp | 90 +++ test/variant_size.cpp | 65 +++ 5 files changed, 1092 insertions(+) create mode 100644 include/boost/variant2/variant.hpp create mode 100644 meta/libraries.json create mode 100644 test/Jamfile create mode 100644 test/variant_alternative.cpp create mode 100644 test/variant_size.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp new file mode 100644 index 0000000..1da500e --- /dev/null +++ b/include/boost/variant2/variant.hpp @@ -0,0 +1,908 @@ +#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 + +// + +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_MSVC, <= 1910 ) + + return v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ); + +#else + + return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); + +#endif +} + +template constexpr variant_alternative_t>&& get(variant&& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + + return std::move( v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ) ); + +#else + + return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); + +#endif +} + +template constexpr variant_alternative_t const>& get(variant const& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + + return v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ); + +#else + + return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); + +#endif +} + +template constexpr variant_alternative_t const>&& get(variant const&& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + + return std::move( v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ) ); + +#else + + return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); + +#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; + + return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); +} + +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; + + return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); +} + +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; + + return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); +} + +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; + + return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); +} + +// 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...>, mp_all...>, 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 i ) 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 i ) 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; + + using U = mp_at_c, I>; + + if( std::is_nothrow_constructible::value ) + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = J; + } + else + { + 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 i ) 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 i ) 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 + { + mp_for_each>([&]( auto I ){ + + using U = mp_at_c, I>; + constexpr auto J = decltype(I)::value + 1; + + if( J == ix_ ) + { + st1_.get( mp_size_t() ).~U(); + } + + }); + } + + ~variant_base_impl() noexcept + { + _destroy(); + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) 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 i ) 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; + + using U = mp_at_c, I>; + + if( std::is_nothrow_constructible::value ) + { + _destroy(); + st1_.emplace( mp_size_t(), std::forward(a)... ); + + ix_ = J; + } + 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 + { + mp_for_each>([&]( auto I ){ + + using U = mp_at_c, I>; + constexpr auto J = decltype(I)::value + 1; + + if( ix_ > 0 && J == ix_ ) + { + st1_.get( mp_size_t() ).~U(); + } + + if( ix_ < 0 && J == -ix_ ) + { + st2_.get( mp_size_t() ).~U(); + } + + }); + } + + ~variant_base_impl() noexcept + { + _destroy(); + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) 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 i ) 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 +{ +}; + +// in_place_index_t + +template struct in_place_index_t +{ +}; + +// variant + +template class variant: private variant2::detail::variant_base +{ +private: + + using variant_base = variant2::detail::variant_base; + +public: + + // constructors + + constexpr variant() + noexcept( std::is_nothrow_default_constructible< mp_first> >::value ) + : variant_base( mp_size_t<0>() ) + { + } + + variant( variant const& r ) + noexcept( mp_all...>::value ) + { + mp_for_each>([&]( auto I ){ + + if( I == r.index() ) + { + ::new( static_cast(this) ) variant_base( I, r._get_impl( I ) ); + } + + }); + } + + variant( variant && r ) + noexcept( mp_all...>::value ) + { + mp_for_each>([&]( auto I ){ + + if( I == r.index() ) + { + ::new( static_cast(this) ) variant_base( I, std::move( r._get_impl( I ) ) ); + } + + }); + } + + template constexpr variant( U&& u ) + noexcept( std::is_nothrow_constructible< variant2::detail::resolve_overload_type, U >::value ) + : variant_base( variant2::detail::resolve_overload_index(), std::forward(u) ) + { + } + + template, U>> + constexpr explicit variant( in_place_type_t, A&&... a ): variant_base( I(), std::forward(a)... ) + { + } + + template + constexpr explicit variant( in_place_type_t, std::initializer_list, A&&... a ); + + template + constexpr explicit variant( in_place_index_t, A&&... a ): variant_base( mp_size_t(), std::forward(a)... ) + { + } + + template + constexpr explicit variant( in_place_index_t, std::initializer_list, A&&... ); + + // assignment + variant& operator=( variant const & r ) + { + mp_for_each>([&]( auto I ){ + + constexpr auto J = decltype(I)::value; + + if( J == r.index() ) + { + if( index() == J ) + { + get(*this) = get(r); + } + else + { + variant_base::template emplace( get(r) ); + } + } + + }); + + return *this; + } + + variant& operator=( variant&& r ) noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) + { + mp_for_each>([&]( auto I ){ + + constexpr auto J = decltype(I)::type::value; + + if( J == r.index() ) + { + if( index() == J ) + { + get(*this) = get(std::move(r)); + } + else + { + 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(see below ); + { + 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 + // using variant_base::emplace; + + template, U>> U& emplace( A&&... a ) + { + variant_base::template emplace( std::forward(a)... ); + return _get_impl( I() ); + } + + template U& emplace( std::initializer_list il, A&&... a ); + + template variant_alternative_t>& emplace( A&&... a ) + { + variant_base::template emplace( std::forward(a)... ); + return _get_impl( mp_size_t() ); + } + + template variant_alternative_t>& emplace( std::initializer_list il, A&&... a ); + + // value status + + constexpr size_t index() const noexcept + { + return this->ix_ >= 0? this->ix_ - 1 : -this->ix_ - 1; + } + + // swap + + void swap( variant& r ); // noexcept( ... ) + + // 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; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) == get(w); + + }); + + assert( false ); + return false; +} + +template constexpr bool operator!=( variant const & v, variant const & w ) +{ + if( v.index() != w.index() ) return true; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) != get(w); + + }); + + assert( false ); + return true; +} + +template constexpr bool operator<( variant const & v, variant const & w ) +{ + if( v.index() < w.index() ) return true; + if( v.index() > w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) < get(w); + + }); + + assert( false ); + return false; +} + +template constexpr bool operator>( variant const & v, variant const & w ) +{ + if( v.index() > w.index() ) return true; + if( v.index() < w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) > get(w); + + }); + + assert( false ); + return false; +} + +template constexpr bool operator<=( variant const & v, variant const & w ) +{ + if( v.index() < w.index() ) return true; + if( v.index() > w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) <= get(w); + + }); + + assert( false ); + return false; +} + +template constexpr bool operator>=( variant const & v, variant const & w ) +{ + if( v.index() > w.index() ) return true; + if( v.index() < w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) >= get(w); + + }); + + assert( false ); + return false; +} + +// visitation +template constexpr void visit( Visitor&&, Variants&&... ); + +// specialized algorithms +template void swap( variant & v, variant & w ); // noexcept(see below ); + +} // 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..f114533 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,15 @@ +# 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) ; diff --git a/test/variant_alternative.cpp b/test/variant_alternative.cpp new file mode 100644 index 0000000..44e2a7a --- /dev/null +++ b/test/variant_alternative.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 +#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_size.cpp b/test/variant_size.cpp new file mode 100644 index 0000000..3d59682 --- /dev/null +++ b/test/variant_size.cpp @@ -0,0 +1,65 @@ + +// 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(); +} From ae2594419a50099ef6452df08b5b5c84edb56060 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 29 May 2017 17:38:03 +0300 Subject: [PATCH 02/30] Add .travis.yml, appveyor.yml --- .travis.yml | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 36 +++++++++ 2 files changed, 256 insertions(+) create mode 100644 .travis.yml create mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c1478bb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,220 @@ +# 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 + 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 + compiler: clang++-4.0 + env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=c++14 + addons: + apt: + packages: + - clang-4.0 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-4.0 + + - os: linux + compiler: clang++-4.0 + env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=c++1z + addons: + apt: + packages: + - clang-4.0 + 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 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/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..aa33f0e --- /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 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% From abd7a5ffe3291b89d678d3957054428f1e7fce8d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 29 May 2017 17:58:13 +0300 Subject: [PATCH 03/30] Remove clang-3.5; move clang-4.0 to trusty; include --- .travis.yml | 13 ++----------- include/boost/variant2/variant.hpp | 1 + 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index c1478bb..03c450b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -89,17 +89,6 @@ matrix: 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 - 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 @@ -167,6 +156,7 @@ matrix: - llvm-toolchain-precise-3.9 - os: linux + dist: trusty compiler: clang++-4.0 env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=c++14 addons: @@ -178,6 +168,7 @@ matrix: - llvm-toolchain-trusty-4.0 - os: linux + dist: trusty compiler: clang++-4.0 env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=c++1z addons: diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 1da500e..29991c1 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -15,6 +15,7 @@ #include #include #include +#include // From 6f0a3029f4a39b73df4b7da133577bf35c403d71 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 29 May 2017 18:35:42 +0300 Subject: [PATCH 04/30] Restore clang-3.5; add libstdc++ 4.9 to it and 4.0 --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.travis.yml b/.travis.yml index 03c450b..ef3c1bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -89,6 +89,18 @@ matrix: 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 @@ -163,6 +175,7 @@ matrix: apt: packages: - clang-4.0 + - libstdc++-4.9-dev sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-4.0 @@ -175,6 +188,7 @@ matrix: apt: packages: - clang-4.0 + - libstdc++-4.9-dev sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-4.0 From 99747c78076639ef4362d72cff8ec4b2aaa51cbe Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 29 May 2017 20:07:42 +0300 Subject: [PATCH 05/30] Add tests for holds_alternative --- test/Jamfile | 2 + test/holds_alternative.cpp | 78 +++++++++++++++++++++++++++++++++++ test/holds_alternative_cx.cpp | 43 +++++++++++++++++++ test/variant_alternative.cpp | 1 - test/variant_size.cpp | 1 - 5 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 test/holds_alternative.cpp create mode 100644 test/holds_alternative_cx.cpp diff --git a/test/Jamfile b/test/Jamfile index f114533..766c254 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -13,3 +13,5 @@ REQ = ; #[ requires cxx11_variadic_templates cxx11_template_aliases cxx11_declty run variant_size.cpp : : : $(REQ) ; run variant_alternative.cpp : : : $(REQ) ; +run holds_alternative.cpp : : : $(REQ) ; +run holds_alternative_cx.cpp : : : $(REQ) ; diff --git a/test/holds_alternative.cpp b/test/holds_alternative.cpp new file mode 100644 index 0000000..4931f40 --- /dev/null +++ b/test/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/holds_alternative_cx.cpp b/test/holds_alternative_cx.cpp new file mode 100644 index 0000000..c2bdc0a --- /dev/null +++ b/test/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_alternative.cpp b/test/variant_alternative.cpp index 44e2a7a..e5a9fa7 100644 --- a/test/variant_alternative.cpp +++ b/test/variant_alternative.cpp @@ -20,7 +20,6 @@ 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>)); diff --git a/test/variant_size.cpp b/test/variant_size.cpp index 3d59682..b348418 100644 --- a/test/variant_size.cpp +++ b/test/variant_size.cpp @@ -20,7 +20,6 @@ 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 ); From 781977a23751c6a9ec07a387fc54c32cf5190e47 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 29 May 2017 21:38:04 +0300 Subject: [PATCH 06/30] Add test/get_by_index.cpp --- include/boost/variant2/variant.hpp | 44 +------ test/Jamfile | 1 + test/get_by_index.cpp | 184 +++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 40 deletions(-) create mode 100644 test/get_by_index.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 29991c1..28079b6 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -114,61 +114,25 @@ template constexpr bool holds_alternative( variant co template constexpr variant_alternative_t>& get(variant& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); - -#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) - - return v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ); - -#else - - return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); - -#endif + return ( v.index() == I? (void)0: throw bad_variant_access() ), v._get_impl( mp_size_t() ); } template constexpr variant_alternative_t>&& get(variant&& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); - -#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) - - return std::move( v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ) ); - -#else - - return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); - -#endif + return ( v.index() == I? (void)0: throw bad_variant_access() ), std::move( v._get_impl( mp_size_t() ) ); } template constexpr variant_alternative_t const>& get(variant const& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); - -#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) - - return v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ); - -#else - - return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); - -#endif + return ( v.index() == I? (void)0: throw bad_variant_access() ), v._get_impl( mp_size_t() ); } template constexpr variant_alternative_t const>&& get(variant const&& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); - -#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) - - return std::move( v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ) ); - -#else - - return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); - -#endif + return ( v.index() == I? (void)0: throw bad_variant_access() ), std::move( v._get_impl( mp_size_t() ) ); } // get diff --git a/test/Jamfile b/test/Jamfile index 766c254..3a35203 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -15,3 +15,4 @@ run variant_size.cpp : : : $(REQ) ; run variant_alternative.cpp : : : $(REQ) ; run holds_alternative.cpp : : : $(REQ) ; run holds_alternative_cx.cpp : : : $(REQ) ; +run get_by_index.cpp : : : $(REQ) ; diff --git a/test/get_by_index.cpp b/test/get_by_index.cpp new file mode 100644 index 0000000..7491d9b --- /dev/null +++ b/test/get_by_index.cpp @@ -0,0 +1,184 @@ + +// 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) ); + } + + { + variant v( 1 ); + + BOOST_TEST_EQ( get<0>(v), 1 ); + BOOST_TEST_EQ( get_if<0>(&v), &get<0>(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<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 ); + } + + { + 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 ); + } + + { + 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) ); + } + + { + 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 ); + } + + { + 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 ); + } + + { + 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) ); + } + + return boost::report_errors(); +} From 07be071794b4af106b376ec8fa2d38b94e648180 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 30 May 2017 02:08:31 +0300 Subject: [PATCH 07/30] Add test/get_by_type(_cx).cpp, get_by_index_cx.cpp --- include/boost/variant2/variant.hpp | 8 +- test/Jamfile | 5 +- test/get_by_index_cx.cpp | 90 ++++++++++++++++ test/get_by_type.cpp | 166 +++++++++++++++++++++++++++++ test/get_by_type_cx.cpp | 78 ++++++++++++++ 5 files changed, 342 insertions(+), 5 deletions(-) create mode 100644 test/get_by_index_cx.cpp create mode 100644 test/get_by_type.cpp create mode 100644 test/get_by_type_cx.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 28079b6..fbd2628 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -142,7 +142,7 @@ 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; - return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); + return ( v.index() == I? (void)0: throw bad_variant_access() ), v._get_impl( mp_size_t() ); } template constexpr U&& get(variant&& v) @@ -150,7 +150,7 @@ 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; - return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); + return ( v.index() == I? (void)0: throw bad_variant_access() ), std::move( v._get_impl( mp_size_t() ) ); } template constexpr U const& get(variant const& v) @@ -158,7 +158,7 @@ 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; - return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); + return ( v.index() == I? (void)0: throw bad_variant_access() ), v._get_impl( mp_size_t() ); } template constexpr U const&& get(variant const&& v) @@ -166,7 +166,7 @@ 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; - return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); + return ( v.index() == I? (void)0: throw bad_variant_access() ), std::move( v._get_impl( mp_size_t() ) ); } // get_if diff --git a/test/Jamfile b/test/Jamfile index 3a35203..78a822a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -14,5 +14,8 @@ REQ = ; #[ requires cxx11_variadic_templates cxx11_template_aliases cxx11_declty run variant_size.cpp : : : $(REQ) ; run variant_alternative.cpp : : : $(REQ) ; run holds_alternative.cpp : : : $(REQ) ; -run holds_alternative_cx.cpp : : : $(REQ) ; +compile holds_alternative_cx.cpp : : : $(REQ) ; run get_by_index.cpp : : : $(REQ) ; +compile get_by_index_cx.cpp : : : $(REQ) ; +run get_by_type.cpp : : : $(REQ) ; +compile get_by_type_cx.cpp : : : $(REQ) ; diff --git a/test/get_by_index_cx.cpp b/test/get_by_index_cx.cpp new file mode 100644 index 0000000..ae1b99f --- /dev/null +++ b/test/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/get_by_type.cpp b/test/get_by_type.cpp new file mode 100644 index 0000000..82b18c7 --- /dev/null +++ b/test/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/get_by_type_cx.cpp b/test/get_by_type_cx.cpp new file mode 100644 index 0000000..b4995fe --- /dev/null +++ b/test/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) ); + } +} From 084712cab345496f140c9a055f30981ab7c24b8d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 30 May 2017 02:28:39 +0300 Subject: [PATCH 08/30] Add test/variant_default_construct(_cx) --- test/Jamfile | 2 + test/variant_default_construct.cpp | 95 +++++++++++++++++++++++++++ test/variant_default_construct_cx.cpp | 51 ++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 test/variant_default_construct.cpp create mode 100644 test/variant_default_construct_cx.cpp diff --git a/test/Jamfile b/test/Jamfile index 78a822a..5996a29 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -19,3 +19,5 @@ run get_by_index.cpp : : : $(REQ) ; compile get_by_index_cx.cpp : : : $(REQ) ; run get_by_type.cpp : : : $(REQ) ; compile get_by_type_cx.cpp : : : $(REQ) ; +run variant_default_construct.cpp : : : $(REQ) ; +compile variant_default_construct_cx.cpp : : : $(REQ) ; diff --git a/test/variant_default_construct.cpp b/test/variant_default_construct.cpp new file mode 100644 index 0000000..c766345 --- /dev/null +++ b/test/variant_default_construct.cpp @@ -0,0 +1,95 @@ + +// 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(); +}; + +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>)); + } + + 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 ); + } +} From 5aa16c5bf73252c85385ba84f0f6e5600e84c61d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 30 May 2017 03:45:55 +0300 Subject: [PATCH 09/30] Add test/variant_copy_construct, variant_move_construct --- include/boost/variant2/variant.hpp | 56 +++++++------ test/Jamfile | 2 + test/variant_copy_construct.cpp | 120 ++++++++++++++++++++++++++++ test/variant_move_construct.cpp | 121 +++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 23 deletions(-) create mode 100644 test/variant_copy_construct.cpp create mode 100644 test/variant_move_construct.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index fbd2628..bb44f3d 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -642,8 +642,13 @@ public: }); } - template constexpr variant( U&& u ) - noexcept( std::is_nothrow_constructible< variant2::detail::resolve_overload_type, U >::value ) + template, variant>::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) ) { } @@ -714,9 +719,9 @@ public: template, variant>::value>, class V = variant2::detail::resolve_overload_type, - class E2 = std::enable_if_t::value && std::is_constructible::value> + class E2 = std::enable_if_t::value && std::is_constructible::value> > - variant& operator=( U&& u ) // noexcept(see below ); + 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; @@ -733,7 +738,6 @@ public: } // modifiers - // using variant_base::emplace; template, U>> U& emplace( A&&... a ) { @@ -777,28 +781,30 @@ template constexpr bool operator==( variant const & v, variant { if( v.index() != w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) == get(w); + if( I == v.index() ) r = get(v) == get(w); }); - assert( false ); - return false; + return r; } template constexpr bool operator!=( variant const & v, variant const & w ) { if( v.index() != w.index() ) return true; + bool r = true; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) != get(w); + if( I == v.index() ) r = get(v) != get(w); }); - assert( false ); - return true; + return r; } template constexpr bool operator<( variant const & v, variant const & w ) @@ -806,14 +812,15 @@ template constexpr bool operator<( variant const & v, variant< if( v.index() < w.index() ) return true; if( v.index() > w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) < get(w); + if( I == v.index() ) r = get(v) < get(w); }); - assert( false ); - return false; + return r; } template constexpr bool operator>( variant const & v, variant const & w ) @@ -821,14 +828,15 @@ template constexpr bool operator>( variant const & v, variant if( v.index() > w.index() ) return true; if( v.index() < w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) > get(w); + if( I == v.index() ) r = get(v) > get(w); }); - assert( false ); - return false; + return r; } template constexpr bool operator<=( variant const & v, variant const & w ) @@ -836,14 +844,15 @@ template constexpr bool operator<=( variant const & v, variant if( v.index() < w.index() ) return true; if( v.index() > w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) <= get(w); + if( I == v.index() ) r = get(v) <= get(w); }); - assert( false ); - return false; + return r; } template constexpr bool operator>=( variant const & v, variant const & w ) @@ -851,14 +860,15 @@ template constexpr bool operator>=( variant const & v, variant if( v.index() > w.index() ) return true; if( v.index() < w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) >= get(w); + if( I == v.index() ) r = get(v) >= get(w); }); - assert( false ); - return false; + return r; } // visitation diff --git a/test/Jamfile b/test/Jamfile index 5996a29..8ce5517 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -21,3 +21,5 @@ run get_by_type.cpp : : : $(REQ) ; compile 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) ; diff --git a/test/variant_copy_construct.cpp b/test/variant_copy_construct.cpp new file mode 100644 index 0000000..bf060f8 --- /dev/null +++ b/test/variant_copy_construct.cpp @@ -0,0 +1,120 @@ + +// 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 ); + +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>)); + } + + return boost::report_errors(); +} diff --git a/test/variant_move_construct.cpp b/test/variant_move_construct.cpp new file mode 100644 index 0000000..bee71e6 --- /dev/null +++ b/test/variant_move_construct.cpp @@ -0,0 +1,121 @@ + +// 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 ); + +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>)); + } + + return boost::report_errors(); +} From a99b5f8e2ebf615d993932d60354675b6918a134 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 30 May 2017 16:05:55 +0300 Subject: [PATCH 10/30] Add test/variant_value_construct(_cx) --- test/Jamfile | 2 + test/variant_value_construct.cpp | 124 ++++++++++++++++++++++++++++ test/variant_value_construct_cx.cpp | 109 ++++++++++++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 test/variant_value_construct.cpp create mode 100644 test/variant_value_construct_cx.cpp diff --git a/test/Jamfile b/test/Jamfile index 8ce5517..9495081 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -23,3 +23,5 @@ 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) ; 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) ); + } +} From 2357f4d2f4511b41a7f868d19295555da1d4f930 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 30 May 2017 16:57:48 +0300 Subject: [PATCH 11/30] Add test/variant_in_place_index_construct(_cx) --- include/boost/variant2/variant.hpp | 23 +++- test/Jamfile | 2 + test/variant_in_place_index_construct.cpp | 124 +++++++++++++++++++ test/variant_in_place_index_construct_cx.cpp | 116 +++++++++++++++++ 4 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 test/variant_in_place_index_construct.cpp create mode 100644 test/variant_in_place_index_construct_cx.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index bb44f3d..7b62e81 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -592,12 +592,32 @@ 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 + // variant template class variant: private variant2::detail::variant_base @@ -643,7 +663,8 @@ public: } template, variant>::value>, + class Ud = std::decay_t, + 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> > diff --git a/test/Jamfile b/test/Jamfile index 9495081..2c89a2f 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -25,3 +25,5 @@ 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) ; diff --git a/test/variant_in_place_index_construct.cpp b/test/variant_in_place_index_construct.cpp new file mode 100644 index 0000000..8f6c58f --- /dev/null +++ b/test/variant_in_place_index_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 +{ + 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' ) ); + } + + 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 ); + } +} From 21acb2bda0d4d6d80ddf4e9582a46b600de84b50 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 30 May 2017 17:12:26 +0300 Subject: [PATCH 12/30] Add test/variant_in_place_type_construct(_cx) --- test/Jamfile | 2 + test/variant_in_place_type_construct.cpp | 116 ++++++++++++++++++++ test/variant_in_place_type_construct_cx.cpp | 110 +++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 test/variant_in_place_type_construct.cpp create mode 100644 test/variant_in_place_type_construct_cx.cpp diff --git a/test/Jamfile b/test/Jamfile index 2c89a2f..6192882 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -27,3 +27,5 @@ 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) ; diff --git a/test/variant_in_place_type_construct.cpp b/test/variant_in_place_type_construct.cpp new file mode 100644 index 0000000..7a04cae --- /dev/null +++ b/test/variant_in_place_type_construct.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 +{ + 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) ); + } + + 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) ); + } +} From e0e48d365ce4a48d1c24f3c9f05ed42c210e6f6d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 30 May 2017 18:00:07 +0300 Subject: [PATCH 13/30] Add test/variant_copy_assign, variant_move_assign --- include/boost/variant2/variant.hpp | 44 +++++--- test/Jamfile | 2 + test/get_by_index.cpp | 16 +++ test/variant_copy_assign.cpp | 168 +++++++++++++++++++++++++++++ test/variant_move_assign.cpp | 168 +++++++++++++++++++++++++++++ 5 files changed, 386 insertions(+), 12 deletions(-) create mode 100644 test/variant_copy_assign.cpp create mode 100644 test/variant_move_assign.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 7b62e81..8f6a223 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -114,25 +114,37 @@ template constexpr bool holds_alternative( variant co template constexpr variant_alternative_t>& get(variant& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); - return ( v.index() == I? (void)0: throw bad_variant_access() ), v._get_impl( mp_size_t() ); + + if( v.index() != I ) throw bad_variant_access(); + + return v._get_impl( mp_size_t() ); } template constexpr variant_alternative_t>&& get(variant&& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); - return ( v.index() == I? (void)0: throw bad_variant_access() ), std::move( v._get_impl( mp_size_t() ) ); + + if( v.index() != I ) throw bad_variant_access(); + + return std::move( v._get_impl( mp_size_t() ) ); } template constexpr variant_alternative_t const>& get(variant const& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); - return ( v.index() == I? (void)0: throw bad_variant_access() ), v._get_impl( mp_size_t() ); + + if( v.index() != I ) throw bad_variant_access(); + + return v._get_impl( mp_size_t() ); } template constexpr variant_alternative_t const>&& get(variant const&& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); - return ( v.index() == I? (void)0: throw bad_variant_access() ), std::move( v._get_impl( mp_size_t() ) ); + + if( v.index() != I ) throw bad_variant_access(); + + return std::move( v._get_impl( mp_size_t() ) ); } // get @@ -142,7 +154,9 @@ 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; - return ( v.index() == I? (void)0: throw bad_variant_access() ), v._get_impl( mp_size_t() ); + if( v.index() != I ) throw bad_variant_access(); + + return v._get_impl( mp_size_t() ); } template constexpr U&& get(variant&& v) @@ -150,7 +164,9 @@ 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; - return ( v.index() == I? (void)0: throw bad_variant_access() ), std::move( v._get_impl( mp_size_t() ) ); + if( v.index() != I ) throw bad_variant_access(); + + return std::move( v._get_impl( mp_size_t() ) ); } template constexpr U const& get(variant const& v) @@ -158,7 +174,9 @@ 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; - return ( v.index() == I? (void)0: throw bad_variant_access() ), v._get_impl( mp_size_t() ); + if( v.index() != I ) throw bad_variant_access(); + + return v._get_impl( mp_size_t() ); } template constexpr U const&& get(variant const&& v) @@ -166,7 +184,9 @@ 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; - return ( v.index() == I? (void)0: throw bad_variant_access() ), std::move( v._get_impl( mp_size_t() ) ); + if( v.index() != I ) throw bad_variant_access(); + + return std::move( v._get_impl( mp_size_t() ) ); } // get_if @@ -699,13 +719,13 @@ public: if( J == r.index() ) { - if( index() == J ) + if( this->index() == J ) { get(*this) = get(r); } else { - variant_base::template emplace( get(r) ); + this->variant_base::template emplace( get(r) ); } } @@ -722,13 +742,13 @@ public: if( J == r.index() ) { - if( index() == J ) + if( this->index() == J ) { get(*this) = get(std::move(r)); } else { - variant_base::template emplace( get(std::move(r)) ); + this->variant_base::template emplace( get(std::move(r)) ); } } diff --git a/test/Jamfile b/test/Jamfile index 6192882..d38728a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -29,3 +29,5 @@ 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) ; diff --git a/test/get_by_index.cpp b/test/get_by_index.cpp index 7491d9b..b55313e 100644 --- a/test/get_by_index.cpp +++ b/test/get_by_index.cpp @@ -54,6 +54,8 @@ int main() 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 ); } { @@ -61,6 +63,8 @@ int main() 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 ); } { @@ -119,6 +123,8 @@ int main() 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 ); } { @@ -129,6 +135,8 @@ int main() 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 ); } { @@ -139,6 +147,8 @@ int main() 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 ); } { @@ -152,6 +162,8 @@ int main() 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 ); } { @@ -165,6 +177,8 @@ int main() 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 ); } { @@ -178,6 +192,8 @@ int main() 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_copy_assign.cpp b/test/variant_copy_assign.cpp new file mode 100644 index 0000000..eec88c7 --- /dev/null +++ b/test/variant_copy_assign.cpp @@ -0,0 +1,168 @@ + +// 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 ); + + 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 ); + } + + return boost::report_errors(); +} diff --git a/test/variant_move_assign.cpp b/test/variant_move_assign.cpp new file mode 100644 index 0000000..044428c --- /dev/null +++ b/test/variant_move_assign.cpp @@ -0,0 +1,168 @@ + +// 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 ); + + 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 ); + } + + return boost::report_errors(); +} From 77fe0372093eb538f4f779e362ce8bfc625ad7ba Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 01:31:46 +0300 Subject: [PATCH 14/30] Add test/variant_value_assign --- test/Jamfile | 1 + test/variant_value_assign.cpp | 206 ++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 test/variant_value_assign.cpp diff --git a/test/Jamfile b/test/Jamfile index d38728a..4fb2515 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -31,3 +31,4 @@ 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) ; 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(); +} From fd848a869836c842bc258c49ce97349752b96a9f Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 02:27:20 +0300 Subject: [PATCH 15/30] Add test/variant_emplace_index, _type --- test/Jamfile | 2 + test/variant_emplace_index.cpp | 173 +++++++++++++++++++++++++++++++++ test/variant_emplace_type.cpp | 161 ++++++++++++++++++++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 test/variant_emplace_index.cpp create mode 100644 test/variant_emplace_type.cpp diff --git a/test/Jamfile b/test/Jamfile index 4fb2515..07e9465 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -32,3 +32,5 @@ 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) ; diff --git a/test/variant_emplace_index.cpp b/test/variant_emplace_index.cpp new file mode 100644 index 0000000..c8dc55e --- /dev/null +++ b/test/variant_emplace_index.cpp @@ -0,0 +1,173 @@ + +// 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() ); + } + + { + 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..37b3eff --- /dev/null +++ b/test/variant_emplace_type.cpp @@ -0,0 +1,161 @@ + +// 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() ); + } + + { + 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(); +} From 4bb5cdab60112cd5bf71dc621866b5cebdd6ca1d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 03:36:08 +0300 Subject: [PATCH 16/30] Add test/variant_swap --- include/boost/variant2/variant.hpp | 99 +++++++++-- test/Jamfile | 1 + test/variant_swap.cpp | 259 +++++++++++++++++++++++++++++ 3 files changed, 347 insertions(+), 12 deletions(-) create mode 100644 test/variant_swap.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 8f6a223..0155de9 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -16,6 +16,7 @@ #include #include #include +#include // @@ -353,7 +354,7 @@ template struct variant_base_impl { } - template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) noexcept + template constexpr mp_at_c, I>& _get_impl( mp_size_t ) noexcept { size_t const J = I+1; @@ -362,7 +363,7 @@ template struct variant_base_impl return st1_.get( mp_size_t() ); } - template constexpr mp_at_c, I> const& _get_impl( mp_size_t i ) const noexcept + template constexpr mp_at_c, I> const& _get_impl( mp_size_t ) const noexcept { size_t const J = I+1; @@ -407,7 +408,7 @@ template struct variant_base_impl { } - template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) noexcept + template constexpr mp_at_c, I>& _get_impl( mp_size_t ) noexcept { size_t const J = I+1; @@ -417,7 +418,7 @@ template struct variant_base_impl return ix_ >= 0? st1_.get( j ): st2_.get( j ); } - template constexpr mp_at_c, I> const& _get_impl( mp_size_t i ) const noexcept + template constexpr mp_at_c, I> const& _get_impl( mp_size_t ) const noexcept { size_t const J = I+1; @@ -478,7 +479,7 @@ template struct variant_base_impl _destroy(); } - template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) noexcept + template constexpr mp_at_c, I>& _get_impl( mp_size_t ) noexcept { size_t const J = I+1; @@ -487,7 +488,7 @@ template struct variant_base_impl return st1_.get( mp_size_t() ); } - template constexpr mp_at_c, I> const& _get_impl( mp_size_t i ) const noexcept + template constexpr mp_at_c, I> const& _get_impl( mp_size_t ) const noexcept { size_t const J = I+1; @@ -563,7 +564,7 @@ template struct variant_base_impl _destroy(); } - template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) noexcept + template constexpr mp_at_c, I>& _get_impl( mp_size_t ) noexcept { size_t const J = I+1; @@ -573,7 +574,7 @@ template struct variant_base_impl return ix_ >= 0? st1_.get( j ): st2_.get( j ); } - template constexpr mp_at_c, I> const& _get_impl( mp_size_t i ) const noexcept + template constexpr mp_at_c, I> const& _get_impl( mp_size_t ) const noexcept { size_t const J = I+1; @@ -638,6 +639,55 @@ template struct is_in_place_index>: std::true } // 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 @@ -715,7 +765,7 @@ public: { mp_for_each>([&]( auto I ){ - constexpr auto J = decltype(I)::value; + constexpr auto J = I.value; if( J == r.index() ) { @@ -738,7 +788,7 @@ public: { mp_for_each>([&]( auto I ){ - constexpr auto J = decltype(I)::type::value; + constexpr auto J = I.value; if( J == r.index() ) { @@ -805,7 +855,29 @@ public: // swap - void swap( variant& r ); // noexcept( ... ) + void swap( variant& r ) noexcept( mp_all..., variant2::detail::is_nothrow_swappable...>::value ) + { + if( index() == r.index() ) + { + mp_for_each>([&]( auto I ){ + + constexpr auto J = I.value; + + if( J == this->index() ) + { + using std::swap; + swap( get(*this), get(r) ); + } + + }); + } + else + { + variant tmp( std::move(*this) ); + *this = std::move( r ); + r = std::move( tmp ); + } + } // private accessors @@ -916,7 +988,10 @@ template constexpr bool operator>=( variant const & v, variant template constexpr void visit( Visitor&&, Variants&&... ); // specialized algorithms -template void swap( variant & v, variant & w ); // noexcept(see below ); +template void swap( variant & v, variant & w ) noexcept( noexcept(v.swap(w)) ) +{ + v.swap( w ); +} } // namespace variant2 } // namespace boost diff --git a/test/Jamfile b/test/Jamfile index 07e9465..1670e6a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -34,3 +34,4 @@ 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) ; 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(); +} From 8301228e22c8c41e20cbaedcd1a3e2e23689f5d2 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 04:02:23 +0300 Subject: [PATCH 17/30] Add test/variant_eq_ne --- test/Jamfile | 1 + test/variant_eq_ne.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 test/variant_eq_ne.cpp diff --git a/test/Jamfile b/test/Jamfile index 1670e6a..771cbf9 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -35,3 +35,4 @@ 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) ; 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(); +} From 755bc60c2be8d65b61a3170fb8c28e950574f95f Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 04:19:40 +0300 Subject: [PATCH 18/30] Add initializer list support --- include/boost/variant2/variant.hpp | 22 +++++++++++++++++----- test/variant_emplace_index.cpp | 8 ++++++++ test/variant_emplace_type.cpp | 8 ++++++++ test/variant_in_place_index_construct.cpp | 18 ++++++++++++++++-- test/variant_in_place_type_construct.cpp | 18 ++++++++++++++++++ 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 0155de9..c2f23a4 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -749,8 +749,10 @@ public: { } - template - constexpr explicit variant( in_place_type_t, std::initializer_list, A&&... a ); + template, U>> + constexpr explicit variant( in_place_type_t, std::initializer_list il, A&&... a ): variant_base( I(), il, std::forward(a)... ) + { + } template constexpr explicit variant( in_place_index_t, A&&... a ): variant_base( mp_size_t(), std::forward(a)... ) @@ -758,7 +760,9 @@ public: } template - constexpr explicit variant( in_place_index_t, std::initializer_list, A&&... ); + constexpr explicit variant( in_place_index_t, std::initializer_list il, A&&... a ): variant_base( mp_size_t(), il, std::forward(a)... ) + { + } // assignment variant& operator=( variant const & r ) @@ -836,7 +840,11 @@ public: return _get_impl( I() ); } - template U& emplace( std::initializer_list il, A&&... a ); + template, U>> U& emplace( std::initializer_list il, A&&... a ) + { + variant_base::template emplace( il, std::forward(a)... ); + return _get_impl( I() ); + } template variant_alternative_t>& emplace( A&&... a ) { @@ -844,7 +852,11 @@ public: return _get_impl( mp_size_t() ); } - template variant_alternative_t>& emplace( std::initializer_list il, A&&... a ); + template 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 diff --git a/test/variant_emplace_index.cpp b/test/variant_emplace_index.cpp index c8dc55e..7fa30b7 100644 --- a/test/variant_emplace_index.cpp +++ b/test/variant_emplace_index.cpp @@ -128,6 +128,14 @@ int main() 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'}) ); } { diff --git a/test/variant_emplace_type.cpp b/test/variant_emplace_type.cpp index 37b3eff..4189bbb 100644 --- a/test/variant_emplace_type.cpp +++ b/test/variant_emplace_type.cpp @@ -116,6 +116,14 @@ int main() 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' }) ); } { diff --git a/test/variant_in_place_index_construct.cpp b/test/variant_in_place_index_construct.cpp index 8f6c58f..4e87b3f 100644 --- a/test/variant_in_place_index_construct.cpp +++ b/test/variant_in_place_index_construct.cpp @@ -17,8 +17,8 @@ using namespace boost::variant2; struct X { - X() = default; - X( in_place_index_t<0> ) = delete; + X() = default; + X( in_place_index_t<0> ) = delete; }; int main() @@ -120,5 +120,19 @@ int main() 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_type_construct.cpp b/test/variant_in_place_type_construct.cpp index 7a04cae..dc956eb 100644 --- a/test/variant_in_place_type_construct.cpp +++ b/test/variant_in_place_type_construct.cpp @@ -112,5 +112,23 @@ int main() 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(); } From 4f241bd8b071a4a72e6e82e9b2774c766cdb6121 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 04:55:30 +0300 Subject: [PATCH 19/30] Try a fix for g++ 5 --- include/boost/variant2/variant.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index c2f23a4..efd33ab 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -130,7 +130,7 @@ template constexpr variant_alternative_t() ) ); } -template constexpr variant_alternative_t const>& get(variant const& v) +template constexpr variant_alternative_t> const& get(variant const& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); @@ -139,7 +139,7 @@ template constexpr variant_alternative_t() ); } -template constexpr variant_alternative_t const>&& get(variant const&& v) +template constexpr variant_alternative_t> const&& get(variant const&& v) { static_assert( I < sizeof...(T), "Index out of bounds" ); From 08bfd69387df20507b7c0e2956cc43a8a877a4d6 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 04:59:59 +0300 Subject: [PATCH 20/30] Single buffer when a type is nothrow default constructible --- include/boost/variant2/variant.hpp | 56 +++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index efd33ab..3506524 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -335,13 +335,13 @@ template using resolve_overload_index = mp_find struct variant_base_impl; // trivially destructible, single buffered -template using variant_base = variant_base_impl...>, mp_all...>, T...>; +template struct variant_base_impl; // trivially destructible, single buffered +template using variant_base = variant_base_impl...>::value, mp_all...>::value || mp_any...>::value, T...>; struct none {}; // trivially destructible, single buffered -template struct variant_base_impl +template struct variant_base_impl { int ix_; variant_storage st1_; @@ -374,7 +374,9 @@ template struct variant_base_impl template void emplace( A&&... a ) { - size_t const J = I+1; + 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>; @@ -383,8 +385,25 @@ template struct variant_base_impl 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) ); @@ -394,7 +413,7 @@ template struct variant_base_impl }; // trivially destructible, double buffered -template struct variant_base_impl +template struct variant_base_impl { int ix_; variant_storage st1_; @@ -446,7 +465,7 @@ template struct variant_base_impl }; // not trivially destructible, single buffered -template struct variant_base_impl +template struct variant_base_impl { int ix_; variant_storage st1_; @@ -501,15 +520,34 @@ template struct variant_base_impl { 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)... ); + 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 ); @@ -517,15 +555,15 @@ template struct variant_base_impl U tmp( std::forward(a)... ); _destroy(); - st1_.emplace( mp_size_t(), std::move(tmp) ); + st1_.emplace( mp_size_t(), std::move(tmp) ); ix_ = J; } } }; // not trivially destructible, double buffered -template struct variant_base_impl +template struct variant_base_impl { int ix_; variant_storage st1_; From ab0d8674114f0c1006d6e0566355549cc68414d1 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 05:36:35 +0300 Subject: [PATCH 21/30] Another attempt at g+ 5 fix --- include/boost/variant2/variant.hpp | 36 ++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 3506524..5b3fc76 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -116,9 +116,16 @@ template constexpr variant_alternative_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) @@ -134,9 +141,16 @@ template constexpr variant_alternative_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) @@ -155,9 +169,16 @@ 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( v.index() != I ) throw bad_variant_access(); +#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) @@ -175,9 +196,16 @@ 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( v.index() != I ) throw bad_variant_access(); +#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) From abb7b551cc440f0fcd177ca07a0476ea57bf26c3 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 05:46:34 +0300 Subject: [PATCH 22/30] Extend g++5 workaround for consistency to rvalue overloads --- include/boost/variant2/variant.hpp | 38 ++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 5b3fc76..145df70 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -122,7 +122,7 @@ template constexpr variant_alternative_t() ); #endif @@ -132,9 +132,16 @@ template constexpr variant_alternative_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) @@ -157,9 +164,16 @@ template constexpr variant_alternative_t() ) ); + +#else + + if( v.index() != I ) throw bad_variant_access(); return std::move( v._get_impl( mp_size_t() ) ); + +#endif } // get @@ -186,9 +200,16 @@ 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( v.index() != I ) throw bad_variant_access(); +#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) @@ -213,9 +234,16 @@ 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( v.index() != I ) throw bad_variant_access(); +#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 From 7d25e131bebe77ad9915bbeeb209a35f69ab8de3 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 07:42:45 +0300 Subject: [PATCH 23/30] Add SFINAE conditions --- include/boost/variant2/variant.hpp | 60 +++++++++++++++++++----------- test/variant_copy_assign.cpp | 26 +++++++++++++ test/variant_copy_construct.cpp | 8 ++++ test/variant_default_construct.cpp | 8 ++++ test/variant_move_assign.cpp | 26 +++++++++++++ test/variant_move_construct.cpp | 8 ++++ 6 files changed, 115 insertions(+), 21 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 145df70..b79f1fe 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -118,7 +118,7 @@ template constexpr variant_alternative_t() ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); #else @@ -134,7 +134,7 @@ template constexpr variant_alternative_t() ) ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); #else @@ -150,7 +150,7 @@ template constexpr variant_alternative_t() ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); #else @@ -166,7 +166,7 @@ template constexpr variant_alternative_t() ) ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); #else @@ -185,7 +185,7 @@ template constexpr U& get(variant& v) #if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) - return (void)( v.index() != I? throw bad_variant_access(): 0), v._get_impl( mp_size_t() ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); #else @@ -202,7 +202,7 @@ template constexpr U&& get(variant&& v) #if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) - return (void)( v.index() != I? throw bad_variant_access(): 0), std::move( v._get_impl( mp_size_t() ) ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); #else @@ -219,7 +219,7 @@ template constexpr U const& get(variant const& v) #if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) - return (void)( v.index() != I? throw bad_variant_access(): 0), v._get_impl( mp_size_t() ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); #else @@ -236,7 +236,7 @@ template constexpr U const&& get(variant const&& v) #if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) - return (void)( v.index() != I? throw bad_variant_access(): 0), std::move( v._get_impl( mp_size_t() ) ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); #else @@ -392,7 +392,7 @@ template using resolve_overload_index = mp_find struct variant_base_impl; // trivially destructible, single buffered -template using variant_base = variant_base_impl...>::value, mp_all...>::value || mp_any...>::value, T...>; +template using variant_base = variant_base_impl...>::value, mp_any...>, std::is_nothrow_default_constructible...>::value, T...>; struct none {}; @@ -790,16 +790,23 @@ 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 ) { @@ -813,6 +820,7 @@ public: }); } + template...>, E1>> variant( variant && r ) noexcept( mp_all...>::value ) { @@ -838,28 +846,30 @@ public: { } - template, 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>> + 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 + template, I>, A...>::value>> constexpr explicit variant( in_place_index_t, A&&... a ): variant_base( mp_size_t(), std::forward(a)... ) { } - template + 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_each>([&]( auto I ){ @@ -882,7 +892,9 @@ public: return *this; } - variant& operator=( variant&& r ) noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) + template..., std::is_move_assignable...>, E1>> + variant& operator=( variant && r ) + noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) { mp_for_each>([&]( auto I ){ @@ -909,8 +921,9 @@ public: class E1 = std::enable_if_t, 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 ) + > + 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; @@ -928,25 +941,29 @@ public: // modifiers - template, U>> U& emplace( A&&... a ) + 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>> U& emplace( std::initializer_list il, A&&... a ) + 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 variant_alternative_t>& emplace( A&&... a ) + template, I>, A...>::value>> + variant_alternative_t>& emplace( A&&... a ) { variant_base::template emplace( std::forward(a)... ); return _get_impl( mp_size_t() ); } - template variant_alternative_t>& emplace( std::initializer_list il, A&&... a ) + 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() ); @@ -1094,7 +1111,8 @@ template constexpr bool operator>=( variant const & v, variant template constexpr void visit( Visitor&&, Variants&&... ); // specialized algorithms -template void swap( variant & v, variant & w ) noexcept( noexcept(v.swap(w)) ) +template..., variant2::detail::is_swappable...>::value>> +void swap( variant & v, variant & w ) noexcept( noexcept(v.swap(w)) ) { v.swap( w ); } diff --git a/test/variant_copy_assign.cpp b/test/variant_copy_assign.cpp index eec88c7..c4ae80f 100644 --- a/test/variant_copy_assign.cpp +++ b/test/variant_copy_assign.cpp @@ -57,6 +57,11 @@ 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() { { @@ -164,5 +169,26 @@ int main() 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 index bf060f8..473d8a2 100644 --- a/test/variant_copy_construct.cpp +++ b/test/variant_copy_construct.cpp @@ -43,6 +43,11 @@ 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 ); @@ -114,6 +119,9 @@ int main() 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 index c766345..894934c 100644 --- a/test/variant_default_construct.cpp +++ b/test/variant_default_construct.cpp @@ -20,6 +20,11 @@ struct X X(); }; +struct Y +{ + Y() = delete; +}; + int main() { { @@ -89,6 +94,9 @@ int main() 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_move_assign.cpp b/test/variant_move_assign.cpp index 044428c..9c87718 100644 --- a/test/variant_move_assign.cpp +++ b/test/variant_move_assign.cpp @@ -57,6 +57,11 @@ 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() { { @@ -164,5 +169,26 @@ int main() 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 index bee71e6..e3d8e98 100644 --- a/test/variant_move_construct.cpp +++ b/test/variant_move_construct.cpp @@ -43,6 +43,11 @@ 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 ); @@ -115,6 +120,9 @@ int main() 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(); From b7d039e30f622587ca3e33849072fbdc954b5835 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 07:59:35 +0300 Subject: [PATCH 24/30] Test develop against mp11 develop --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef3c1bc..1b1f780 100644 --- a/.travis.yml +++ b/.travis.yml @@ -208,7 +208,7 @@ install: - git submodule update --init tools/build - git submodule update --init libs/config - git submodule update --init tools/boostdep - - git clone https://github.com/pdimov/mp11 libs/mp11 + - 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 diff --git a/appveyor.yml b/appveyor.yml index aa33f0e..152eb22 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,7 +23,7 @@ install: - git submodule update --init tools/build - git submodule update --init libs/config - git submodule update --init tools/boostdep - - git clone https://github.com/pdimov/mp11 libs/mp11 + - 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 From ef849a0febc98d377b268ae421730122e6b2fec5 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 20:29:57 +0300 Subject: [PATCH 25/30] Use mp_for_index_c --- include/boost/variant2/variant.hpp | 153 ++++++++++------------------- 1 file changed, 54 insertions(+), 99 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index b79f1fe..76ab756 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -536,17 +536,15 @@ template struct variant_base_impl void _destroy() noexcept { - mp_for_each>([&]( auto I ){ + if( ix_ > 0 ) + { + mp_for_index_c<1 + sizeof...(T)>( ix_, [&]( auto I ){ - using U = mp_at_c, I>; - constexpr auto J = decltype(I)::value + 1; + using U = mp_at_c, I>; + st1_.get( I ).~U(); - if( J == ix_ ) - { - st1_.get( mp_size_t() ).~U(); - } - - }); + }); + } } ~variant_base_impl() noexcept @@ -635,22 +633,24 @@ template struct variant_base_impl void _destroy() noexcept { - mp_for_each>([&]( auto I ){ + if( ix_ > 0 ) + { + mp_for_index_c<1 + sizeof...(T)>( ix_, [&]( auto I ){ - using U = mp_at_c, I>; - constexpr auto J = decltype(I)::value + 1; + using U = mp_at_c, I>; + st1_.get( I ).~U(); - if( ix_ > 0 && J == ix_ ) - { - st1_.get( mp_size_t() ).~U(); - } + }); + } + else if( ix_ < 0 ) + { + mp_for_index_c<1 + sizeof...(T)>( -ix_, [&]( auto I ){ - if( ix_ < 0 && J == -ix_ ) - { - st2_.get( mp_size_t() ).~U(); - } + using U = mp_at_c, I>; + st2_.get( I ).~U(); - }); + }); + } } ~variant_base_impl() noexcept @@ -810,12 +810,9 @@ public: variant( variant const& r ) noexcept( mp_all...>::value ) { - mp_for_each>([&]( auto I ){ + mp_for_index_c( r.index(), [&]( auto I ){ - if( I == r.index() ) - { - ::new( static_cast(this) ) variant_base( I, r._get_impl( I ) ); - } + ::new( static_cast(this) ) variant_base( I, r._get_impl( I ) ); }); } @@ -824,12 +821,9 @@ public: variant( variant && r ) noexcept( mp_all...>::value ) { - mp_for_each>([&]( auto I ){ + mp_for_index_c( r.index(), [&]( auto I ){ - if( I == r.index() ) - { - ::new( static_cast(this) ) variant_base( I, std::move( r._get_impl( I ) ) ); - } + ::new( static_cast(this) ) variant_base( I, std::move( r._get_impl( I ) ) ); }); } @@ -871,20 +865,15 @@ public: variant& operator=( variant const & r ) noexcept( mp_all..., std::is_nothrow_copy_assignable...>::value ) { - mp_for_each>([&]( auto I ){ + mp_for_index_c( r.index(), [&]( auto I ){ - constexpr auto J = I.value; - - if( J == r.index() ) + if( this->index() == I ) { - if( this->index() == J ) - { - get(*this) = get(r); - } - else - { - this->variant_base::template emplace( get(r) ); - } + get(*this) = get(r); + } + else + { + this->variant_base::template emplace( get(r) ); } }); @@ -896,20 +885,15 @@ public: variant& operator=( variant && r ) noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) { - mp_for_each>([&]( auto I ){ + mp_for_index_c( r.index(), [&]( auto I ){ - constexpr auto J = I.value; - - if( J == r.index() ) + if( this->index() == I ) { - if( this->index() == J ) - { - get(*this) = get(std::move(r)); - } - else - { - this->variant_base::template emplace( get(std::move(r)) ); - } + get(*this) = get(std::move(r)); + } + else + { + this->variant_base::template emplace( get(std::move(r)) ); } }); @@ -982,15 +966,10 @@ public: { if( index() == r.index() ) { - mp_for_each>([&]( auto I ){ + mp_for_index_c( index(), [&]( auto I ){ - constexpr auto J = I.value; - - if( J == this->index() ) - { - using std::swap; - swap( get(*this), get(r) ); - } + using std::swap; + swap( get(*this), get(r) ); }); } @@ -1017,30 +996,22 @@ template constexpr bool operator==( variant const & v, variant { if( v.index() != w.index() ) return false; - bool r = false; + return mp_for_index_c( v.index(), [&]( auto I ){ - mp_for_each>([&]( auto I ){ - - if( I == v.index() ) r = get(v) == get(w); + return get(v) == get(w); }); - - return r; } template constexpr bool operator!=( variant const & v, variant const & w ) { if( v.index() != w.index() ) return true; - bool r = true; + return mp_for_index_c( v.index(), [&]( auto I ){ - mp_for_each>([&]( auto I ){ - - if( I == v.index() ) r = get(v) != get(w); + return get(v) != get(w); }); - - return r; } template constexpr bool operator<( variant const & v, variant const & w ) @@ -1048,15 +1019,11 @@ template constexpr bool operator<( variant const & v, variant< if( v.index() < w.index() ) return true; if( v.index() > w.index() ) return false; - bool r = false; + return mp_for_index_c( v.index(), [&]( auto I ){ - mp_for_each>([&]( auto I ){ - - if( I == v.index() ) r = get(v) < get(w); + return get(v) < get(w); }); - - return r; } template constexpr bool operator>( variant const & v, variant const & w ) @@ -1064,15 +1031,11 @@ template constexpr bool operator>( variant const & v, variant if( v.index() > w.index() ) return true; if( v.index() < w.index() ) return false; - bool r = false; + return mp_for_index_c( v.index(), [&]( auto I ){ - mp_for_each>([&]( auto I ){ - - if( I == v.index() ) r = get(v) > get(w); + return get(v) > get(w); }); - - return r; } template constexpr bool operator<=( variant const & v, variant const & w ) @@ -1080,15 +1043,11 @@ template constexpr bool operator<=( variant const & v, variant if( v.index() < w.index() ) return true; if( v.index() > w.index() ) return false; - bool r = false; + return mp_for_index_c( v.index(), [&]( auto I ){ - mp_for_each>([&]( auto I ){ - - if( I == v.index() ) r = get(v) <= get(w); + return get(v) <= get(w); }); - - return r; } template constexpr bool operator>=( variant const & v, variant const & w ) @@ -1096,15 +1055,11 @@ template constexpr bool operator>=( variant const & v, variant if( v.index() > w.index() ) return true; if( v.index() < w.index() ) return false; - bool r = false; + return mp_for_index_c( v.index(), [&]( auto I ){ - mp_for_each>([&]( auto I ){ - - if( I == v.index() ) r = get(v) >= get(w); + return get(v) >= get(w); }); - - return r; } // visitation From 89e3588c9b1bd04129ffae96b884763f53fa242d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 20:48:17 +0300 Subject: [PATCH 26/30] Add test/variant_destroy --- test/Jamfile | 1 + test/variant_destroy.cpp | 205 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 test/variant_destroy.cpp diff --git a/test/Jamfile b/test/Jamfile index 771cbf9..323ec4d 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -36,3 +36,4 @@ 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) ; 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(); +} From f74da6d38287608a34a2df6645b3165568fbcb4e Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 23:18:37 +0300 Subject: [PATCH 27/30] Rename mp_for_index_c to mp_for_index --- include/boost/variant2/variant.hpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 76ab756..0f64f42 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -538,7 +538,7 @@ template struct variant_base_impl { if( ix_ > 0 ) { - mp_for_index_c<1 + sizeof...(T)>( ix_, [&]( auto I ){ + mp_for_index<1 + sizeof...(T)>( ix_, [&]( auto I ){ using U = mp_at_c, I>; st1_.get( I ).~U(); @@ -635,7 +635,7 @@ template struct variant_base_impl { if( ix_ > 0 ) { - mp_for_index_c<1 + sizeof...(T)>( ix_, [&]( auto I ){ + mp_for_index<1 + sizeof...(T)>( ix_, [&]( auto I ){ using U = mp_at_c, I>; st1_.get( I ).~U(); @@ -644,7 +644,7 @@ template struct variant_base_impl } else if( ix_ < 0 ) { - mp_for_index_c<1 + sizeof...(T)>( -ix_, [&]( auto I ){ + mp_for_index<1 + sizeof...(T)>( -ix_, [&]( auto I ){ using U = mp_at_c, I>; st2_.get( I ).~U(); @@ -810,7 +810,7 @@ public: variant( variant const& r ) noexcept( mp_all...>::value ) { - mp_for_index_c( r.index(), [&]( auto I ){ + mp_for_index( r.index(), [&]( auto I ){ ::new( static_cast(this) ) variant_base( I, r._get_impl( I ) ); @@ -821,7 +821,7 @@ public: variant( variant && r ) noexcept( mp_all...>::value ) { - mp_for_index_c( r.index(), [&]( auto I ){ + mp_for_index( r.index(), [&]( auto I ){ ::new( static_cast(this) ) variant_base( I, std::move( r._get_impl( I ) ) ); @@ -865,7 +865,7 @@ public: variant& operator=( variant const & r ) noexcept( mp_all..., std::is_nothrow_copy_assignable...>::value ) { - mp_for_index_c( r.index(), [&]( auto I ){ + mp_for_index( r.index(), [&]( auto I ){ if( this->index() == I ) { @@ -885,7 +885,7 @@ public: variant& operator=( variant && r ) noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) { - mp_for_index_c( r.index(), [&]( auto I ){ + mp_for_index( r.index(), [&]( auto I ){ if( this->index() == I ) { @@ -966,7 +966,7 @@ public: { if( index() == r.index() ) { - mp_for_index_c( index(), [&]( auto I ){ + mp_for_index( index(), [&]( auto I ){ using std::swap; swap( get(*this), get(r) ); @@ -996,7 +996,7 @@ template constexpr bool operator==( variant const & v, variant { if( v.index() != w.index() ) return false; - return mp_for_index_c( v.index(), [&]( auto I ){ + return mp_for_index( v.index(), [&]( auto I ){ return get(v) == get(w); @@ -1007,7 +1007,7 @@ template constexpr bool operator!=( variant const & v, variant { if( v.index() != w.index() ) return true; - return mp_for_index_c( v.index(), [&]( auto I ){ + return mp_for_index( v.index(), [&]( auto I ){ return get(v) != get(w); @@ -1019,7 +1019,7 @@ template constexpr bool operator<( variant const & v, variant< if( v.index() < w.index() ) return true; if( v.index() > w.index() ) return false; - return mp_for_index_c( v.index(), [&]( auto I ){ + return mp_for_index( v.index(), [&]( auto I ){ return get(v) < get(w); @@ -1031,7 +1031,7 @@ template constexpr bool operator>( variant const & v, variant if( v.index() > w.index() ) return true; if( v.index() < w.index() ) return false; - return mp_for_index_c( v.index(), [&]( auto I ){ + return mp_for_index( v.index(), [&]( auto I ){ return get(v) > get(w); @@ -1043,7 +1043,7 @@ template constexpr bool operator<=( variant const & v, variant if( v.index() < w.index() ) return true; if( v.index() > w.index() ) return false; - return mp_for_index_c( v.index(), [&]( auto I ){ + return mp_for_index( v.index(), [&]( auto I ){ return get(v) <= get(w); @@ -1055,7 +1055,7 @@ template constexpr bool operator>=( variant const & v, variant if( v.index() > w.index() ) return true; if( v.index() < w.index() ) return false; - return mp_for_index_c( v.index(), [&]( auto I ){ + return mp_for_index( v.index(), [&]( auto I ){ return get(v) >= get(w); From db565aaa73f2f218c6e369282cb3095db9d1253d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 1 Jun 2017 01:48:38 +0300 Subject: [PATCH 28/30] Implement visit --- include/boost/variant2/variant.hpp | 82 ++++++++++++++++++++++++++- test/Jamfile | 1 + test/variant_visit.cpp | 91 ++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 test/variant_visit.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 0f64f42..4ce586e 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -1063,11 +1063,87 @@ template constexpr bool operator>=( variant const & v, variant } // visitation -template constexpr void visit( Visitor&&, Variants&&... ); +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)) ) +template..., variant2::detail::is_swappable...>::value>> +void swap( variant & v, variant & w ) + noexcept( noexcept(v.swap(w)) ) { v.swap( w ); } diff --git a/test/Jamfile b/test/Jamfile index 323ec4d..ab1fd9a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -37,3 +37,4 @@ 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_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(); +} From 6ad3e2fd12ee7ef4aa2d5570fdf264fb0e130dbd Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 1 Jun 2017 02:03:35 +0300 Subject: [PATCH 29/30] Rename tests --- test/Jamfile | 12 ++++++------ test/{get_by_index.cpp => variant_get_by_index.cpp} | 0 ...t_by_index_cx.cpp => variant_get_by_index_cx.cpp} | 0 test/{get_by_type.cpp => variant_get_by_type.cpp} | 0 ...get_by_type_cx.cpp => variant_get_by_type_cx.cpp} | 0 ...alternative.cpp => variant_holds_alternative.cpp} | 0 ...ative_cx.cpp => variant_holds_alternative_cx.cpp} | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename test/{get_by_index.cpp => variant_get_by_index.cpp} (100%) rename test/{get_by_index_cx.cpp => variant_get_by_index_cx.cpp} (100%) rename test/{get_by_type.cpp => variant_get_by_type.cpp} (100%) rename test/{get_by_type_cx.cpp => variant_get_by_type_cx.cpp} (100%) rename test/{holds_alternative.cpp => variant_holds_alternative.cpp} (100%) rename test/{holds_alternative_cx.cpp => variant_holds_alternative_cx.cpp} (100%) diff --git a/test/Jamfile b/test/Jamfile index ab1fd9a..4a68bfe 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -13,12 +13,12 @@ REQ = ; #[ requires cxx11_variadic_templates cxx11_template_aliases cxx11_declty run variant_size.cpp : : : $(REQ) ; run variant_alternative.cpp : : : $(REQ) ; -run holds_alternative.cpp : : : $(REQ) ; -compile holds_alternative_cx.cpp : : : $(REQ) ; -run get_by_index.cpp : : : $(REQ) ; -compile get_by_index_cx.cpp : : : $(REQ) ; -run get_by_type.cpp : : : $(REQ) ; -compile get_by_type_cx.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) ; diff --git a/test/get_by_index.cpp b/test/variant_get_by_index.cpp similarity index 100% rename from test/get_by_index.cpp rename to test/variant_get_by_index.cpp diff --git a/test/get_by_index_cx.cpp b/test/variant_get_by_index_cx.cpp similarity index 100% rename from test/get_by_index_cx.cpp rename to test/variant_get_by_index_cx.cpp diff --git a/test/get_by_type.cpp b/test/variant_get_by_type.cpp similarity index 100% rename from test/get_by_type.cpp rename to test/variant_get_by_type.cpp diff --git a/test/get_by_type_cx.cpp b/test/variant_get_by_type_cx.cpp similarity index 100% rename from test/get_by_type_cx.cpp rename to test/variant_get_by_type_cx.cpp diff --git a/test/holds_alternative.cpp b/test/variant_holds_alternative.cpp similarity index 100% rename from test/holds_alternative.cpp rename to test/variant_holds_alternative.cpp diff --git a/test/holds_alternative_cx.cpp b/test/variant_holds_alternative_cx.cpp similarity index 100% rename from test/holds_alternative_cx.cpp rename to test/variant_holds_alternative_cx.cpp From bcf20069eee56c894241ae5196bef0ab74a64161 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 1 Jun 2017 02:48:27 +0300 Subject: [PATCH 30/30] Update README.md --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) 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