// MPark.Variant // // Copyright Michael Park, 2015-2017 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #ifndef MPARK_VARIANT_HPP #define MPARK_VARIANT_HPP /* variant synopsis namespace std { // 20.7.2, class template variant template class variant { public: // 20.7.2.1, constructors constexpr variant() noexcept(see below); variant(const variant&); variant(variant&&) noexcept(see below); template constexpr variant(T&&) noexcept(see below); template constexpr explicit variant(in_place_type_t, Args&&...); template constexpr explicit variant( in_place_type_t, initializer_list, Args&&...); template constexpr explicit variant(in_place_index_t, Args&&...); template constexpr explicit variant( in_place_index_t, initializer_list, Args&&...); // 20.7.2.2, destructor ~variant(); // 20.7.2.3, assignment variant& operator=(const variant&); variant& operator=(variant&&) noexcept(see below); template variant& operator=(T&&) noexcept(see below); // 20.7.2.4, modifiers template T& emplace(Args&&...); template T& emplace(initializer_list, Args&&...); template variant_alternative& emplace(Args&&...); template variant_alternative& emplace(initializer_list, Args&&...); // 20.7.2.5, value status constexpr bool valueless_by_exception() const noexcept; constexpr size_t index() const noexcept; // 20.7.2.6, swap void swap(variant&) noexcept(see below); }; // 20.7.3, variant helper classes template struct variant_size; // undefined template constexpr size_t variant_size_v = variant_size::value; template struct variant_size; template struct variant_size; template struct variant_size; template struct variant_size>; template struct variant_alternative; // undefined template using variant_alternative_t = typename variant_alternative::type; template struct variant_alternative; template struct variant_alternative; template struct variant_alternative; template struct variant_alternative>; constexpr size_t variant_npos = -1; // 20.7.4, value access template constexpr bool holds_alternative(const variant&) noexcept; template constexpr variant_alternative_t>& get(variant&); template constexpr variant_alternative_t>&& get(variant&&); template constexpr variant_alternative_t> const& get(const variant&); template constexpr variant_alternative_t> const&& get(const variant&&); template constexpr T& get(variant&); template constexpr T&& get(variant&&); template constexpr const T& get(const variant&); template constexpr const T&& get(const variant&&); template constexpr add_pointer_t>> get_if(variant*) noexcept; template constexpr add_pointer_t>> get_if(const variant*) noexcept; template constexpr add_pointer_t get_if(variant*) noexcept; template constexpr add_pointer_t get_if(const variant*) noexcept; // 20.7.5, relational operators template constexpr bool operator==(const variant&, const variant&); template constexpr bool operator!=(const variant&, const variant&); template constexpr bool operator<(const variant&, const variant&); template constexpr bool operator>(const variant&, const variant&); template constexpr bool operator<=(const variant&, const variant&); template constexpr bool operator>=(const variant&, const variant&); // 20.7.6, visitation template constexpr see below visit(Visitor&&, Variants&&...); // 20.7.7, class monostate struct monostate; // 20.7.8, monostate relational operators constexpr bool operator<(monostate, monostate) noexcept; constexpr bool operator>(monostate, monostate) noexcept; constexpr bool operator<=(monostate, monostate) noexcept; constexpr bool operator>=(monostate, monostate) noexcept; constexpr bool operator==(monostate, monostate) noexcept; constexpr bool operator!=(monostate, monostate) noexcept; // 20.7.9, specialized algorithms template void swap(variant&, variant&) noexcept(see below); // 20.7.10, class bad_variant_access class bad_variant_access; // 20.7.11, hash support template struct hash; template struct hash>; template <> struct hash; } // namespace std */ #include #include #include #include #include #include #include #include "config.hpp" #include "in_place.hpp" #include "lib.hpp" namespace mpark { #ifdef MPARK_RETURN_TYPE_DEDUCTION #define AUTO auto #define AUTO_RETURN(...) { return __VA_ARGS__; } #define AUTO_REFREF auto && #define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } #define DECLTYPE_AUTO decltype(auto) #define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } #else #define AUTO auto #define AUTO_RETURN(...) \ -> lib::decay_t { return __VA_ARGS__; } #define AUTO_REFREF auto #define AUTO_REFREF_RETURN(...) \ -> decltype((__VA_ARGS__)) { \ static_assert(std::is_reference::value, ""); \ return __VA_ARGS__; \ } #define DECLTYPE_AUTO auto #define DECLTYPE_AUTO_RETURN(...) \ -> decltype(__VA_ARGS__) { return __VA_ARGS__; } #endif class bad_variant_access : public std::exception { public: virtual const char *what() const noexcept { return "bad_variant_access"; } }; [[noreturn]] inline void throw_bad_variant_access() { #ifdef MPARK_EXCEPTIONS throw bad_variant_access{}; #else std::terminate(); #endif } template class variant; template struct variant_size; #ifdef MPARK_VARIABLE_TEMPLATES template constexpr std::size_t variant_size_v = variant_size::value; #endif template struct variant_size : variant_size {}; template struct variant_size : variant_size {}; template struct variant_size : variant_size {}; template struct variant_size> : lib::size_constant {}; template struct variant_alternative; template using variant_alternative_t = typename variant_alternative::type; template struct variant_alternative : std::add_const> {}; template struct variant_alternative : std::add_volatile> {}; template struct variant_alternative : std::add_cv> {}; template struct variant_alternative> { static_assert(I < sizeof...(Ts), "Index out of bounds in std::variant_alternative<>"); using type = lib::type_pack_element_t; }; constexpr std::size_t variant_npos = static_cast(-1); namespace detail { inline constexpr bool all() { return true; } template inline constexpr bool all(bool b, Bs... bs) { return b && all(bs...); } constexpr std::size_t not_found = static_cast(-1); constexpr std::size_t ambiguous = static_cast(-2); #ifdef MPARK_CPP14_CONSTEXPR template inline constexpr std::size_t find_index() { constexpr lib::array matches = { {std::is_same::value...} }; std::size_t result = not_found; for (std::size_t i = 0; i < sizeof...(Ts); ++i) { if (matches[i]) { if (result != not_found) { return ambiguous; } result = i; } } return result; } #else inline constexpr std::size_t find_index_impl(std::size_t result, std::size_t) { return result; } template inline constexpr std::size_t find_index_impl(std::size_t result, std::size_t idx, bool b, Bs... bs) { return b ? (result != not_found ? ambiguous : find_index_impl(idx, idx + 1, bs...)) : find_index_impl(result, idx + 1, bs...); } template inline constexpr std::size_t find_index() { return find_index_impl(not_found, 0, std::is_same::value...); } #endif template using find_index_sfinae_impl = lib::enable_if_t>; template using find_index_sfinae = find_index_sfinae_impl()>; template struct find_index_checked_impl : lib::size_constant { static_assert(I != not_found, "the specified type is not found."); static_assert(I != ambiguous, "the specified type is ambiguous."); }; template using find_index_checked = find_index_checked_impl()>; struct valueless_t {}; enum class Trait { TriviallyAvailable, Available, Unavailable }; template class IsTriviallyAvailable, template class IsAvailable> inline constexpr Trait trait() { return IsTriviallyAvailable::value ? Trait::TriviallyAvailable : IsAvailable::value ? Trait::Available : Trait::Unavailable; } #ifdef MPARK_CPP14_CONSTEXPR template inline constexpr Trait common_trait(Traits... traits) { Trait result = Trait::TriviallyAvailable; for (Trait t : {traits...}) { if (static_cast(t) > static_cast(result)) { result = t; } } return result; } #else inline constexpr Trait common_trait_impl(Trait result) { return result; } template inline constexpr Trait common_trait_impl(Trait result, Trait t, Traits... ts) { return static_cast(t) > static_cast(result) ? common_trait_impl(t, ts...) : common_trait_impl(result, ts...); } template inline constexpr Trait common_trait(Traits... ts) { return common_trait_impl(Trait::TriviallyAvailable, ts...); } #endif template struct traits { static constexpr Trait copy_constructible_trait = common_trait(trait()...); static constexpr Trait move_constructible_trait = common_trait(trait()...); static constexpr Trait copy_assignable_trait = common_trait(copy_constructible_trait, trait()...); static constexpr Trait move_assignable_trait = common_trait(move_constructible_trait, trait()...); static constexpr Trait destructible_trait = common_trait(trait()...); }; namespace access { struct recursive_union { #ifdef MPARK_RETURN_TYPE_DEDUCTION template inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { return lib::forward(v).head_; } template inline static constexpr auto &&get_alt(V &&v, in_place_index_t) { return get_alt(lib::forward(v).tail_, in_place_index_t{}); } #else template struct get_alt_impl { template inline constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) }; template struct get_alt_impl<0, Dummy> { template inline constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN(lib::forward(v).head_) }; template inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t) AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) #endif }; struct base { template inline static constexpr AUTO_REFREF get_alt(V &&v) AUTO_REFREF_RETURN(recursive_union::get_alt( data(lib::forward(v)), in_place_index_t{})) }; struct variant { template inline static constexpr AUTO_REFREF get_alt(V &&v) AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) }; } // namespace access namespace visitation { struct base { private: template inline static constexpr const T &at(const T &elem) { return elem; } template inline static constexpr const lib::remove_all_extents_t &at( const lib::array &elems, std::size_t i, Is... is) { return at(elems[i], is...); } template inline static constexpr int visit_visitor_return_type_check() { static_assert(all(std::is_same::value...), "`mpark::visit` requires the visitor to have a single " "return type."); return 0; } template inline static constexpr lib::array< lib::common_type_t...>, sizeof...(Fs)> make_farray(Fs &&... fs) { using result = lib::array...>, sizeof...(Fs)>; return visit_visitor_return_type_check...>(), result{{lib::forward(fs)...}}; } template struct dispatcher { template struct impl { inline static constexpr DECLTYPE_AUTO dispatch(F f, Vs... vs) DECLTYPE_AUTO_RETURN(lib::invoke( static_cast(f), access::base::get_alt(static_cast(vs))...)) }; }; template inline static constexpr AUTO make_dispatch(lib::index_sequence) AUTO_RETURN(&dispatcher::template impl::dispatch) template inline static constexpr AUTO make_fdiagonal_impl() AUTO_RETURN(make_dispatch( lib::index_sequence::value...>{})) template inline static constexpr AUTO make_fdiagonal_impl( lib::index_sequence) AUTO_RETURN(make_farray(make_fdiagonal_impl()...)) template inline static constexpr /* auto * */ auto make_fdiagonal() -> decltype(make_fdiagonal_impl( lib::make_index_sequence::size()>{})) { static_assert( all((lib::decay_t::size() == lib::decay_t::size())...), "all of the variants must be the same size."); return make_fdiagonal_impl( lib::make_index_sequence::size()>{}); } #ifdef MPARK_RETURN_TYPE_DEDUCTION template inline static constexpr auto make_fmatrix_impl( lib::index_sequence is) { return make_dispatch(is); } template inline static constexpr auto make_fmatrix_impl( lib::index_sequence, lib::index_sequence, Ls... ls) { return make_farray(make_fmatrix_impl( lib::index_sequence{}, ls...)...); } template inline static constexpr auto make_fmatrix() { return make_fmatrix_impl( lib::index_sequence<>{}, lib::make_index_sequence::size()>{}...); } #else template struct make_fmatrix_impl { template struct impl; template struct impl> { inline constexpr AUTO operator()() const AUTO_RETURN( make_dispatch(lib::index_sequence{})) }; template struct impl, lib::index_sequence, Ls...> { inline constexpr AUTO operator()() const AUTO_RETURN(make_farray( impl, Ls...>{}()...)) }; }; template inline static constexpr AUTO make_fmatrix() AUTO_RETURN( typename make_fmatrix_impl::template impl< lib::index_sequence<>, lib::make_index_sequence::size()>...>{}()) #endif public: template inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( at(make_fdiagonal(vs)))...>(), index)(lib::forward(visitor), as_base(lib::forward(vs))...)) template inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( at(make_fmatrix(vs)))...>(), vs.index()...)(lib::forward(visitor), as_base(lib::forward(vs))...)) }; struct variant { private: template struct visit_exhaustive_visitor_check { static_assert( lib::is_invocable::value, "`mpark::visit` requires the visitor to be exhaustive."); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4100) #endif inline constexpr DECLTYPE_AUTO operator()(Visitor &&visitor, Values &&... values) const DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), lib::forward(values)...)) #ifdef _MSC_VER #pragma warning(pop) #endif }; template struct value_visitor { Visitor &&visitor_; template inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const DECLTYPE_AUTO_RETURN( visit_exhaustive_visitor_check< Visitor, decltype((lib::forward(alts).value))...>{}( lib::forward(visitor_), lib::forward(alts).value...)) }; template inline static constexpr AUTO make_value_visitor(Visitor &&visitor) AUTO_RETURN(value_visitor{lib::forward(visitor)}) public: template inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( base::visit_alt_at(index, lib::forward(visitor), lib::forward(vs).impl_...)) template inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN(base::visit_alt(lib::forward(visitor), lib::forward(vs).impl_...)) template inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( visit_alt_at(index, make_value_visitor(lib::forward(visitor)), lib::forward(vs)...)) template inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( visit_alt(make_value_visitor(lib::forward(visitor)), lib::forward(vs)...)) }; } // namespace visitation template struct alt { using value_type = T; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif template inline explicit constexpr alt(in_place_t, Args &&... args) : value(lib::forward(args)...) {} #ifdef _MSC_VER #pragma warning(pop) #endif T value; }; template union recursive_union; template union recursive_union {}; #define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ template \ union recursive_union { \ public: \ inline explicit constexpr recursive_union(valueless_t) noexcept \ : dummy_{} {} \ \ template \ inline explicit constexpr recursive_union(in_place_index_t<0>, \ Args &&... args) \ : head_(in_place_t{}, lib::forward(args)...) {} \ \ template \ inline explicit constexpr recursive_union(in_place_index_t, \ Args &&... args) \ : tail_(in_place_index_t{}, lib::forward(args)...) {} \ \ recursive_union(const recursive_union &) = default; \ recursive_union(recursive_union &&) = default; \ \ destructor \ \ recursive_union &operator=(const recursive_union &) = default; \ recursive_union &operator=(recursive_union &&) = default; \ \ private: \ char dummy_; \ alt head_; \ recursive_union tail_; \ \ friend struct access::recursive_union; \ } MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, ~recursive_union() = default;); MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, ~recursive_union() {}); MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, ~recursive_union() = delete;); #undef MPARK_VARIANT_RECURSIVE_UNION using index_t = unsigned int; template class base { public: inline explicit constexpr base(valueless_t tag) noexcept : data_(tag), index_(static_cast(-1)) {} template inline explicit constexpr base(in_place_index_t, Args &&... args) : data_(in_place_index_t{}, lib::forward(args)...), index_(I) {} inline constexpr bool valueless_by_exception() const noexcept { return index_ == static_cast(-1); } inline constexpr std::size_t index() const noexcept { return valueless_by_exception() ? variant_npos : index_; } protected: using data_t = recursive_union; friend inline constexpr base &as_base(base &b) { return b; } friend inline constexpr const base &as_base(const base &b) { return b; } friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } friend inline constexpr data_t &data(base &b) { return b.data_; } friend inline constexpr const data_t &data(const base &b) { return b.data_; } friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } inline static constexpr std::size_t size() { return sizeof...(Ts); } data_t data_; index_t index_; friend struct access::base; friend struct visitation::base; }; struct dtor { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4100) #endif template inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } #ifdef _MSC_VER #pragma warning(pop) #endif }; #if defined(_MSC_VER) && _MSC_VER < 1910 #define INHERITING_CTOR(type, base) \ template \ inline explicit constexpr type(Args &&... args) \ : base(lib::forward(args)...) {} #else #define INHERITING_CTOR(type, base) using base::base; #endif template class destructor; #define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ template \ class destructor, destructible_trait> \ : public base { \ using super = base; \ \ public: \ INHERITING_CTOR(destructor, super) \ using super::operator=; \ \ destructor(const destructor &) = default; \ destructor(destructor &&) = default; \ definition \ destructor &operator=(const destructor &) = default; \ destructor &operator=(destructor &&) = default; \ \ protected: \ destroy \ } MPARK_VARIANT_DESTRUCTOR( Trait::TriviallyAvailable, ~destructor() = default;, inline void destroy() noexcept { this->index_ = static_cast(-1); }); MPARK_VARIANT_DESTRUCTOR( Trait::Available, ~destructor() { destroy(); }, inline void destroy() noexcept { if (!this->valueless_by_exception()) { visitation::base::visit_alt(dtor{}, *this); } this->index_ = static_cast(-1); }); MPARK_VARIANT_DESTRUCTOR( Trait::Unavailable, ~destructor() = delete;, inline void destroy() noexcept = delete;); #undef MPARK_VARIANT_DESTRUCTOR template class constructor : public destructor { using super = destructor; public: INHERITING_CTOR(constructor, super) using super::operator=; protected: #ifndef MPARK_GENERIC_LAMBDAS struct ctor { template inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { constructor::construct_alt(lhs_alt, lib::forward(rhs_alt).value); } }; #endif template inline static T &construct_alt(alt &a, Args &&... args) { ::new (static_cast(lib::addressof(a))) alt(in_place_t{}, lib::forward(args)...); return a.value; } template inline static void generic_construct(constructor &lhs, Rhs &&rhs) { lhs.destroy(); if (!rhs.valueless_by_exception()) { visitation::base::visit_alt_at( rhs.index(), #ifdef MPARK_GENERIC_LAMBDAS [](auto &lhs_alt, auto &&rhs_alt) { constructor::construct_alt( lhs_alt, lib::forward(rhs_alt).value); } #else ctor{} #endif , lhs, lib::forward(rhs)); lhs.index_ = rhs.index_; } } }; template class move_constructor; #define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ template \ class move_constructor, move_constructible_trait> \ : public constructor> { \ using super = constructor>; \ \ public: \ INHERITING_CTOR(move_constructor, super) \ using super::operator=; \ \ move_constructor(const move_constructor &) = default; \ definition \ ~move_constructor() = default; \ move_constructor &operator=(const move_constructor &) = default; \ move_constructor &operator=(move_constructor &&) = default; \ } MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::TriviallyAvailable, move_constructor(move_constructor &&that) = default;); MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::Available, move_constructor(move_constructor &&that) noexcept( all(std::is_nothrow_move_constructible::value...)) : move_constructor(valueless_t{}) { this->generic_construct(*this, lib::move(that)); }); MPARK_VARIANT_MOVE_CONSTRUCTOR( Trait::Unavailable, move_constructor(move_constructor &&) = delete;); #undef MPARK_VARIANT_MOVE_CONSTRUCTOR template class copy_constructor; #define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ template \ class copy_constructor, copy_constructible_trait> \ : public move_constructor> { \ using super = move_constructor>; \ \ public: \ INHERITING_CTOR(copy_constructor, super) \ using super::operator=; \ \ definition \ copy_constructor(copy_constructor &&) = default; \ ~copy_constructor() = default; \ copy_constructor &operator=(const copy_constructor &) = default; \ copy_constructor &operator=(copy_constructor &&) = default; \ } MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::TriviallyAvailable, copy_constructor(const copy_constructor &that) = default;); MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::Available, copy_constructor(const copy_constructor &that) : copy_constructor(valueless_t{}) { this->generic_construct(*this, that); }); MPARK_VARIANT_COPY_CONSTRUCTOR( Trait::Unavailable, copy_constructor(const copy_constructor &) = delete;); #undef MPARK_VARIANT_COPY_CONSTRUCTOR template class assignment : public copy_constructor { using super = copy_constructor; public: INHERITING_CTOR(assignment, super) using super::operator=; template inline /* auto & */ auto emplace(Args &&... args) -> decltype(this->construct_alt(access::base::get_alt(*this), lib::forward(args)...)) { this->destroy(); auto &result = this->construct_alt(access::base::get_alt(*this), lib::forward(args)...); this->index_ = I; return result; } protected: #ifndef MPARK_GENERIC_LAMBDAS template struct assigner { template inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { self->assign_alt(this_alt, lib::forward(that_alt).value); } assignment *self; }; #endif template inline void assign_alt(alt &a, Arg &&arg) { if (this->index() == I) { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif a.value = lib::forward(arg); #ifdef _MSC_VER #pragma warning(pop) #endif } else { struct { void operator()(std::true_type) const { this_->emplace(lib::forward(arg_)); } void operator()(std::false_type) const { this_->emplace(T(lib::forward(arg_))); } assignment *this_; Arg &&arg_; } impl{this, lib::forward(arg)}; impl(lib::bool_constant< std::is_nothrow_constructible::value || !std::is_nothrow_move_constructible::value>{}); } } template inline void generic_assign(That &&that) { if (this->valueless_by_exception() && that.valueless_by_exception()) { // do nothing. } else if (that.valueless_by_exception()) { this->destroy(); } else { visitation::base::visit_alt_at( that.index(), #ifdef MPARK_GENERIC_LAMBDAS [this](auto &this_alt, auto &&that_alt) { this->assign_alt( this_alt, lib::forward(that_alt).value); } #else assigner{this} #endif , *this, lib::forward(that)); } } }; template class move_assignment; #define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ template \ class move_assignment, move_assignable_trait> \ : public assignment> { \ using super = assignment>; \ \ public: \ INHERITING_CTOR(move_assignment, super) \ using super::operator=; \ \ move_assignment(const move_assignment &) = default; \ move_assignment(move_assignment &&) = default; \ ~move_assignment() = default; \ move_assignment &operator=(const move_assignment &) = default; \ definition \ } MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::TriviallyAvailable, move_assignment &operator=(move_assignment &&that) = default;); MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::Available, move_assignment & operator=(move_assignment &&that) noexcept( all((std::is_nothrow_move_constructible::value && std::is_nothrow_move_assignable::value)...)) { this->generic_assign(lib::move(that)); return *this; }); MPARK_VARIANT_MOVE_ASSIGNMENT( Trait::Unavailable, move_assignment &operator=(move_assignment &&) = delete;); #undef MPARK_VARIANT_MOVE_ASSIGNMENT template class copy_assignment; #define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ template \ class copy_assignment, copy_assignable_trait> \ : public move_assignment> { \ using super = move_assignment>; \ \ public: \ INHERITING_CTOR(copy_assignment, super) \ using super::operator=; \ \ copy_assignment(const copy_assignment &) = default; \ copy_assignment(copy_assignment &&) = default; \ ~copy_assignment() = default; \ definition \ copy_assignment &operator=(copy_assignment &&) = default; \ } MPARK_VARIANT_COPY_ASSIGNMENT( Trait::TriviallyAvailable, copy_assignment &operator=(const copy_assignment &that) = default;); MPARK_VARIANT_COPY_ASSIGNMENT( Trait::Available, copy_assignment &operator=(const copy_assignment &that) { this->generic_assign(that); return *this; }); MPARK_VARIANT_COPY_ASSIGNMENT( Trait::Unavailable, copy_assignment &operator=(const copy_assignment &) = delete;); #undef MPARK_VARIANT_COPY_ASSIGNMENT template class impl : public copy_assignment> { using super = copy_assignment>; public: INHERITING_CTOR(impl, super) using super::operator=; template inline void assign(Arg &&arg) { this->assign_alt(access::base::get_alt(*this), lib::forward(arg)); } inline void swap(impl &that) { if (this->valueless_by_exception() && that.valueless_by_exception()) { // do nothing. } else if (this->index() == that.index()) { visitation::base::visit_alt_at(this->index(), #ifdef MPARK_GENERIC_LAMBDAS [](auto &this_alt, auto &that_alt) { using std::swap; swap(this_alt.value, that_alt.value); } #else swapper{} #endif , *this, that); } else { impl *lhs = this; impl *rhs = lib::addressof(that); if (lhs->move_nothrow() && !rhs->move_nothrow()) { std::swap(lhs, rhs); } impl tmp(lib::move(*rhs)); #ifdef MPARK_EXCEPTIONS // EXTENSION: When the move construction of `lhs` into `rhs` throws // and `tmp` is nothrow move constructible then we move `tmp` back // into `rhs` and provide the strong exception safety guarantee. try { this->generic_construct(*rhs, lib::move(*lhs)); } catch (...) { if (tmp.move_nothrow()) { this->generic_construct(*rhs, lib::move(tmp)); } throw; } #else this->generic_construct(*rhs, lib::move(*lhs)); #endif this->generic_construct(*lhs, lib::move(tmp)); } } private: #ifndef MPARK_GENERIC_LAMBDAS struct swapper { template inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { using std::swap; swap(this_alt.value, that_alt.value); } }; #endif inline constexpr bool move_nothrow() const { return this->valueless_by_exception() || lib::array{ {std::is_nothrow_move_constructible::value...} }[this->index()]; } }; template struct overload; template <> struct overload<> { void operator()() const {} }; template struct overload : overload { using overload::operator(); lib::identity operator()(T) const { return {}; } }; template using best_match_t = typename lib::invoke_result_t, T &&>::type; template struct is_in_place_index : std::false_type {}; template struct is_in_place_index> : std::true_type {}; template struct is_in_place_type : std::false_type {}; template struct is_in_place_type> : std::true_type {}; } // detail template class variant { static_assert(0 < sizeof...(Ts), "variant must consist of at least one alternative."); static_assert(lib::all::value...>::value, "variant can not have an array type as an alternative."); static_assert(lib::all::value...>::value, "variant can not have a reference type as an alternative."); static_assert(lib::all::value...>::value, "variant can not have a void type as an alternative."); public: template < typename Front = lib::type_pack_element_t<0, Ts...>, lib::enable_if_t::value, int> = 0> inline constexpr variant() noexcept( std::is_nothrow_default_constructible::value) : impl_(in_place_index_t<0>{}) {} variant(const variant &) = default; variant(variant &&) = default; template < typename Arg, typename Decayed = lib::decay_t, lib::enable_if_t::value, int> = 0, lib::enable_if_t::value, int> = 0, lib::enable_if_t::value, int> = 0, typename T = detail::best_match_t, std::size_t I = detail::find_index_sfinae::value, lib::enable_if_t::value, int> = 0> inline constexpr variant(Arg &&arg) noexcept( std::is_nothrow_constructible::value) : impl_(in_place_index_t{}, lib::forward(arg)) {} template < std::size_t I, typename... Args, typename T = lib::type_pack_element_t, lib::enable_if_t::value, int> = 0> inline explicit constexpr variant( in_place_index_t, Args &&... args) noexcept(std::is_nothrow_constructible::value) : impl_(in_place_index_t{}, lib::forward(args)...) {} template < std::size_t I, typename Up, typename... Args, typename T = lib::type_pack_element_t, lib::enable_if_t &, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_index_t, std::initializer_list il, Args &&... args) noexcept(std:: is_nothrow_constructible< T, std::initializer_list &, Args...>::value) : impl_(in_place_index_t{}, il, lib::forward(args)...) {} template < typename T, typename... Args, std::size_t I = detail::find_index_sfinae::value, lib::enable_if_t::value, int> = 0> inline explicit constexpr variant( in_place_type_t, Args &&... args) noexcept(std::is_nothrow_constructible::value) : impl_(in_place_index_t{}, lib::forward(args)...) {} template < typename T, typename Up, typename... Args, std::size_t I = detail::find_index_sfinae::value, lib::enable_if_t &, Args...>::value, int> = 0> inline explicit constexpr variant( in_place_type_t, std::initializer_list il, Args &&... args) noexcept(std:: is_nothrow_constructible< T, std::initializer_list &, Args...>::value) : impl_(in_place_index_t{}, il, lib::forward(args)...) {} ~variant() = default; variant &operator=(const variant &) = default; variant &operator=(variant &&) = default; template , variant>::value, int> = 0, typename T = detail::best_match_t, std::size_t I = detail::find_index_sfinae::value, lib::enable_if_t<(std::is_assignable::value && std::is_constructible::value), int> = 0> inline variant &operator=(Arg &&arg) noexcept( (std::is_nothrow_assignable::value && std::is_nothrow_constructible::value)) { impl_.template assign(lib::forward(arg)); return *this; } template < std::size_t I, typename... Args, typename T = lib::type_pack_element_t, lib::enable_if_t::value, int> = 0> inline T &emplace(Args &&... args) { return impl_.template emplace(lib::forward(args)...); } template < std::size_t I, typename Up, typename... Args, typename T = lib::type_pack_element_t, lib::enable_if_t &, Args...>::value, int> = 0> inline T &emplace(std::initializer_list il, Args &&... args) { return impl_.template emplace(il, lib::forward(args)...); } template < typename T, typename... Args, std::size_t I = detail::find_index_sfinae::value, lib::enable_if_t::value, int> = 0> inline T &emplace(Args &&... args) { return impl_.template emplace(lib::forward(args)...); } template < typename T, typename Up, typename... Args, std::size_t I = detail::find_index_sfinae::value, lib::enable_if_t &, Args...>::value, int> = 0> inline T &emplace(std::initializer_list il, Args &&... args) { return impl_.template emplace(il, lib::forward(args)...); } inline constexpr bool valueless_by_exception() const noexcept { return impl_.valueless_by_exception(); } inline constexpr std::size_t index() const noexcept { return impl_.index(); } template < bool Dummy = true, lib::enable_if_t::value && lib::is_swappable::value)...>::value, int> = 0> inline void swap(variant &that) noexcept( lib::all<(std::is_nothrow_move_constructible::value && lib::is_nothrow_swappable::value)...>::value) { impl_.swap(that.impl_); } private: detail::impl impl_; friend struct detail::access::variant; friend struct detail::visitation::variant; }; template inline constexpr bool holds_alternative(const variant &v) noexcept { return v.index() == I; } template inline constexpr bool holds_alternative(const variant &v) noexcept { return holds_alternative::value>(v); } namespace detail { template struct generic_get_impl { constexpr generic_get_impl(int) {} constexpr AUTO_REFREF operator()(V &&v) const AUTO_REFREF_RETURN( access::variant::get_alt(lib::forward(v)).value) }; template inline constexpr AUTO_REFREF generic_get(V &&v) AUTO_REFREF_RETURN(generic_get_impl( holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))( lib::forward(v))) } // namespace detail template inline constexpr variant_alternative_t> &get( variant &v) { return detail::generic_get(v); } template inline constexpr variant_alternative_t> &&get( variant &&v) { return detail::generic_get(lib::move(v)); } template inline constexpr const variant_alternative_t> &get( const variant &v) { return detail::generic_get(v); } template inline constexpr const variant_alternative_t> &&get( const variant &&v) { return detail::generic_get(lib::move(v)); } template inline constexpr T &get(variant &v) { return get::value>(v); } template inline constexpr T &&get(variant &&v) { return get::value>(lib::move(v)); } template inline constexpr const T &get(const variant &v) { return get::value>(v); } template inline constexpr const T &&get(const variant &&v) { return get::value>(lib::move(v)); } namespace detail { template inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept AUTO_RETURN(v && holds_alternative(*v) ? lib::addressof(access::variant::get_alt(*v).value) : nullptr) } // namespace detail template inline constexpr lib::add_pointer_t>> get_if(variant *v) noexcept { return detail::generic_get_if(v); } template inline constexpr lib::add_pointer_t< const variant_alternative_t>> get_if(const variant *v) noexcept { return detail::generic_get_if(v); } template inline constexpr lib::add_pointer_t get_if(variant *v) noexcept { return get_if::value>(v); } template inline constexpr lib::add_pointer_t get_if(const variant *v) noexcept { return get_if::value>(v); } template inline constexpr bool operator==(const variant &lhs, const variant &rhs) { using detail::visitation::variant; using lib::equal_to; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.index() != rhs.index()) return false; if (lhs.valueless_by_exception()) return true; return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); #else return lhs.index() == rhs.index() && (lhs.valueless_by_exception() || variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); #endif } template inline constexpr bool operator!=(const variant &lhs, const variant &rhs) { using detail::visitation::variant; using lib::not_equal_to; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.index() != rhs.index()) return true; if (lhs.valueless_by_exception()) return false; return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); #else return lhs.index() != rhs.index() || (!lhs.valueless_by_exception() && variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); #endif } template inline constexpr bool operator<(const variant &lhs, const variant &rhs) { using detail::visitation::variant; using lib::less; #ifdef MPARK_CPP14_CONSTEXPR if (rhs.valueless_by_exception()) return false; if (lhs.valueless_by_exception()) return true; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); #else return !rhs.valueless_by_exception() && (lhs.valueless_by_exception() || lhs.index() < rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); #endif } template inline constexpr bool operator>(const variant &lhs, const variant &rhs) { using detail::visitation::variant; using lib::greater; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.valueless_by_exception()) return false; if (rhs.valueless_by_exception()) return true; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); #else return !lhs.valueless_by_exception() && (rhs.valueless_by_exception() || lhs.index() > rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); #endif } template inline constexpr bool operator<=(const variant &lhs, const variant &rhs) { using detail::visitation::variant; using lib::less_equal; #ifdef MPARK_CPP14_CONSTEXPR if (lhs.valueless_by_exception()) return true; if (rhs.valueless_by_exception()) return false; if (lhs.index() < rhs.index()) return true; if (lhs.index() > rhs.index()) return false; return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); #else return lhs.valueless_by_exception() || (!rhs.valueless_by_exception() && (lhs.index() < rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); #endif } template inline constexpr bool operator>=(const variant &lhs, const variant &rhs) { using detail::visitation::variant; using lib::greater_equal; #ifdef MPARK_CPP14_CONSTEXPR if (rhs.valueless_by_exception()) return true; if (lhs.valueless_by_exception()) return false; if (lhs.index() > rhs.index()) return true; if (lhs.index() < rhs.index()) return false; return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); #else return rhs.valueless_by_exception() || (!lhs.valueless_by_exception() && (lhs.index() > rhs.index() || (lhs.index() == rhs.index() && variant::visit_value_at( lhs.index(), greater_equal{}, lhs, rhs)))); #endif } template inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( (detail::all(!vs.valueless_by_exception()...) ? (void)0 : throw_bad_variant_access()), detail::visitation::variant::visit_value(lib::forward(visitor), lib::forward(vs)...)) struct monostate {}; inline constexpr bool operator<(monostate, monostate) noexcept { return false; } inline constexpr bool operator>(monostate, monostate) noexcept { return false; } inline constexpr bool operator<=(monostate, monostate) noexcept { return true; } inline constexpr bool operator>=(monostate, monostate) noexcept { return true; } inline constexpr bool operator==(monostate, monostate) noexcept { return true; } inline constexpr bool operator!=(monostate, monostate) noexcept { return false; } template inline auto swap(variant &lhs, variant &rhs) noexcept(noexcept(lhs.swap(rhs))) -> decltype(lhs.swap(rhs)) { lhs.swap(rhs); } namespace detail { template using enabled_type = T; namespace hash { template constexpr bool meets_requirements() { return std::is_copy_constructible::value && std::is_move_constructible::value && lib::is_invocable_r::value; } template constexpr bool is_enabled() { using H = std::hash; return meets_requirements() && std::is_default_constructible::value && std::is_copy_assignable::value && std::is_move_assignable::value; } } // namespace hash } // namespace detail #undef AUTO #undef AUTO_RETURN #undef AUTO_REFREF #undef AUTO_REFREF_RETURN #undef DECLTYPE_AUTO #undef DECLTYPE_AUTO_RETURN } // namespace mpark namespace std { template struct hash, mpark::lib::enable_if_t>()...>::value>>> { using argument_type = mpark::variant; using result_type = std::size_t; inline result_type operator()(const argument_type &v) const { using mpark::detail::visitation::variant; std::size_t result = v.valueless_by_exception() ? 299792458 // Random value chosen by the universe upon creation : variant::visit_alt( #ifdef MPARK_GENERIC_LAMBDAS [](const auto &alt) { using alt_type = mpark::lib::decay_t; using value_type = mpark::lib::remove_const_t< typename alt_type::value_type>; return hash{}(alt.value); } #else hasher{} #endif , v); return hash_combine(result, hash{}(v.index())); } private: #ifndef MPARK_GENERIC_LAMBDAS struct hasher { template inline std::size_t operator()(const Alt &alt) const { using alt_type = mpark::lib::decay_t; using value_type = mpark::lib::remove_const_t; return hash{}(alt.value); } }; #endif static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); } }; template <> struct hash { using argument_type = mpark::monostate; using result_type = std::size_t; inline result_type operator()(const argument_type &) const noexcept { return 66740831; // return a fundamentally attractive random value. } }; } // namespace std #endif // MPARK_VARIANT_HPP