Header file range/v3/detail/variant.hpp

#include <meta/meta.hpp>

#include <range/v3/range_fwd.hpp>

#include <range/v3/utility/concepts.hpp>

#include <range/v3/utility/iterator_concepts.hpp>

#include <range/v3/utility/iterator_traits.hpp>

#include <range/v3/utility/functional.hpp>

#define RANGES_EMPLACED_INDEX_T(I) _emplaced_index_t_<I>

namespace ranges
{
    inline namespace v3
    {
        template <std::size_t I>
        struct emplaced_index_t
        : meta::size_t<I>
        {};
        
        template <std::size_t I>
        emplaced_index_t<I> emplaced_index();
        
        template <std::size_t I>
        using _emplaced_index_t_ = emplaced_index_t<I>(&)();
        
        template <std::size_t N, typename ... Ts, typename ... Args>
        void emplace(variant<Ts...>& var, Args&&... args);
        
        struct bad_variant_access
        : std::logic_error
        {
            explicit bad_variant_access(std::string const& what_arg);
            
            explicit bad_variant_access(char const* what_arg);
        };
        
        template <typename T, std::size_t Index>
        struct indexed_element
        : reference_wrapper<T>
        {
            using reference_wrapper<T>::reference_wrapper;
        };
        
        template <typename T, std::size_t Index>
        struct indexed_element<T&, Index>
        : reference_wrapper<T>
        {
            using reference_wrapper<T>::reference_wrapper;
        };
        
        template <typename T, std::size_t Index>
        struct indexed_element<T&&, Index>
        : reference_wrapper<T, true>
        {
            using reference_wrapper<T, true>::reference_wrapper;
        };
        
        template <std::size_t Index>
        struct indexed_element<void, Index>
        {
            void get() const;
        };
        
        namespace detail
        {
            template <typename I, typename S, typename O, int _concept_requires_120 = 42, typename std::enable_if<(_concept_requires_120==43)||(!SizedSentinel<S, I>()), int>::type=0>
            O uninitialized_copy(I first, S last, O out);
            
            template <typename I, typename S, typename O, int _concept_requires_129 = 42, typename std::enable_if<(_concept_requires_129==43)||(SizedSentinel<S, I>()), int>::type=0>
            O uninitialized_copy(I first, S last, O out);
            
            template <typename I, typename O>
            O uninitialized_copy(I first, I last, O out);
            
            template <typename T, typename Index>
            struct indexed_datum
            {
                template <int _concept_requires_147 = 42, typename std::enable_if<(_concept_requires_147==43)||(DefaultConstructible<T>()), int>::type=0>
                constexpr indexed_datum();
                
                template <typename ... Ts, int _concept_requires_152 = 42, typename std::enable_if<(_concept_requires_152==43)||(Constructible<T, Ts&&>()), int>::type ... = 0>
                constexpr indexed_datum(Ts&&... ts);
                
                constexpr indexed_element<T, Index::value> ref();
                
                constexpr indexed_element<T const, Index::value> ref() const;
                
                constexpr T& get() noexcept;
                
                constexpr T const& get() const noexcept;
            };
            
            template <typename T, typename Index>
            struct indexed_datum<T&, Index>
            : reference_wrapper<T>
            {
                indexed_datum() = delete;
                
                using reference_wrapper<T>::reference_wrapper;
                
                constexpr indexed_element<T&, Index::value> ref() const;
            };
            
            template <typename T, typename Index>
            struct indexed_datum<T&&, Index>
            : reference_wrapper<T, true>
            {
                indexed_datum() = delete;
                
                using reference_wrapper<T, true>::reference_wrapper;
                
                constexpr indexed_element<T&&, Index::value> ref() const;
            };
            
            template <typename Index>
            struct indexed_datum<void, Index>
            {
                void get() const;
                
                constexpr indexed_element<void, Index::value> ref() const;
            };
            
            using variant_nil = indexed_datum<void, meta::npos>;
            
            template <typename Ts, bool Trivial = meta::apply<meta::quote<meta::and_>, meta::transform<Ts, meta::quote<std::is_trivially_destructible>>>::type::value>
            struct variant_data_
            {
                using type = indexed_datum<void, meta::npos>;
            };
            
            template <typename T, typename ... Ts>
            struct variant_data_<meta::list<T, Ts...>, true>
            {
                struct type
                {
                    using head_t = T;
                    
                    using tail_t = meta::_t<variant_data_<meta::list<Ts...>>>;
                    
                    union 
                    {
                        head_t head;
                        
                        tail_t tail;
                    };
                    
                    type();
                    
                    template <typename ... Args>
                    constexpr type(meta::size_t<0>, Args&&... args);
                    
                    template <std::size_t N, typename ... Args>
                    constexpr type(meta::size_t<N>, Args&&... args);
                };
            };
            
            template <typename T, typename ... Ts>
            struct variant_data_<meta::list<T, Ts...>, false>
            {
                struct type
                {
                    using head_t = T;
                    
                    using tail_t = meta::_t<variant_data_<meta::list<Ts...>>>;
                    
                    union 
                    {
                        head_t head;
                        
                        tail_t tail;
                    };
                    
                    type();
                    
                    ~type();
                    
                    template <typename ... Args>
                    constexpr type(meta::size_t<0>, Args&&... args);
                    
                    template <std::size_t N, typename ... Args>
                    constexpr type(meta::size_t<N>, Args&&... args);
                };
            };
            
            template <typename ... Ts>
            using variant_data = meta::_t<variant_data_<meta::transform<meta::list<Ts...>, meta::as_list<meta::make_index_sequence<sizeof...(Ts)>>, meta::quote<indexed_datum>>>>;
            
            std::size_t variant_move_copy_(std::size_t, variant_nil, variant_nil);
            
            template <typename Data0, typename Data1>
            std::size_t variant_move_copy_(std::size_t n, Data0& self, Data1&& that);
            
            constexpr bool variant_equal_(std::size_t, variant_nil, variant_nil);
            
            template <typename Data0, typename Data1>
            constexpr bool variant_equal_(std::size_t n, Data0 const& self, Data1 const& that);
            
            template <typename Fun, typename Proj = indexed_element_fn>
            constexpr int variant_visit_(std::size_t, variant_nil, Fun, Proj = {});
            
            template <typename Data, typename Fun, typename Proj = indexed_element_fn>
            constexpr int variant_visit_(std::size_t n, Data& self, Fun fun, Proj proj = {});
            
            struct get_datum_fn
            {
                template <typename T>
                decltype(t.get()) operator()(T&& t) const;
            };
            
            struct indexed_element_fn
            {
                template <typename T>
                decltype(t.ref()) operator()(T&& t) const;
            };
            
            struct empty_variant_tag{};
            
            struct variant_core_access
            {
                template <typename ... Ts>
                static constexpr variant_data<Ts...>& data(variant<Ts...>& var);
                
                template <typename ... Ts>
                static constexpr variant_data<Ts...>const& data(variant<Ts...>const& var);
                
                template <typename ... Ts>
                static constexpr variant_data<Ts...>&& data(variant<Ts...>&& var);
                
                template <typename ... Ts>
                static variant<Ts...> make_empty(meta::id<variant<Ts...>>);
            };
            
            struct delete_fn
            {
                template <typename T>
                void operator()(T const& t) const;
            };
            
            template <std::size_t N, typename ... Ts>
            struct construct_fn
            {
                std::tuple<Ts...> args_;
                
                template <typename U, std::size_t ... Is>
                void construct_(U& u, meta::index_sequence<Is...>);
                
                construct_fn(Ts&&... ts);
                
                template <typename U, std::size_t M>
                meta::if_c<N!=M> operator()(indexed_datum<U, meta::size_t<M>>&);
                
                template <typename U>
                meta::if_<std::is_object<U>> operator()(indexed_datum<U, meta::size_t<N>>& u);
                
                template <typename U>
                meta::if_<meta::not_<std::is_object<U>>> operator()(indexed_datum<U, meta::size_t<N>>& u);
            };
            
            template <typename T, std::size_t N>
            struct get_fn
            {
                T** t_;
                
                template <typename U, std::size_t M>
                meta::if_c<M!=N> operator()(indexed_element<U, M>) const;
                
                template <typename U>
                void operator()(indexed_element<U, N> t) const;
                
                void operator()(indexed_element<void, N>) const;
            };
            
            template <typename Variant, std::size_t N>
            struct emplace_fn
            {
                Variant* var_;
                
                template <typename ... Ts>
                void operator()(Ts&&... ts) const;
            };
            
            template <typename Fun, typename Variant>
            struct variant_visitor
            {
                Fun fun_;
                
                Variant* var_;
                
                template <typename U, std::size_t N>
                void operator()(indexed_element<U, N> u);
            };
            
            template <typename Variant, typename Fun>
            variant_visitor<Fun, Variant> make_variant_visitor(Variant& var, Fun fun);
            
            template <typename ... To, typename ... From>
            struct unique_visitor<variant<To...>, variant<From...>>
            {
                variant<To...>* var_;
                
                template <typename T, std::size_t N>
                void operator()(indexed_element<T, N> t) const;
            };
            
            template <typename T>
            T& variant_deref_(T* t);
            
            void variant_deref_(void const volatile*);
            
            template <typename Variant, bool Trivial = std::is_trivially_destructible<meta::apply<meta::quote<variant_data>, meta::as_list<Variant>>>::value>
            struct variant_base
            {
                ~variant_base();
            };
            
            template <typename ... Ts>
            struct variant_base<variant<Ts...>, true>{};
        }
        
        template <typename ... Ts>
        struct variant;
        
        template <typename ... Ts, typename ... Us, int _concept_requires_652 = 42, typename std::enable_if<(_concept_requires_652==43)||(meta::and_c<(bool)EqualityComparable<Ts, Us>()>::value), int>::type ... = 0>
        bool operator==(variant<Ts...>const& lhs, variant<Us...>const& rhs);
        
        template <typename ... Ts, typename ... Us, int _concept_requires_664 = 42, typename std::enable_if<(_concept_requires_664==43)||(meta::and_c<(bool)EqualityComparable<Ts, Us>()>::value), int>::type ... = 0>
        bool operator!=(variant<Ts...>const& lhs, variant<Us...>const& rhs);
        
        template <std::size_t N, typename ... Ts>
        meta::_t<std::add_lvalue_reference<meta::at_c<meta::list<Ts...>, N>>> get(variant<Ts...>& var);
        
        template <std::size_t N, typename ... Ts>
        meta::_t<std::add_lvalue_reference<meta::at_c<meta::list<Ts...>, N>const>> get(variant<Ts...>const& var);
        
        template <std::size_t N, typename ... Ts>
        meta::_t<std::add_rvalue_reference<meta::at_c<meta::list<Ts...>, N>>> get(variant<Ts...>&& var);
        
        template <typename Var>
        struct variant_unique;
        
        template <typename ... Ts>
        struct variant_unique<variant<Ts...>>
        {
            using type = meta::apply<meta::quote<variant>, meta::unique<meta::list<Ts...>>>;
        };
        
        template <typename Var>
        using variant_unique_t = meta::_t<variant_unique<Var>>;
        
        template <typename ... Ts>
        variant_unique_t<variant<Ts...>> unique_variant(variant<Ts...>const& var);
    }
}

namespace std{}

Class template ranges::v3::variant<Ts...>

template <typename ... Ts>
struct variant
{
    template <int _concept_requires_551 = 42, typename std::enable_if<(_concept_requires_551==43)||(DefaultConstructible<datum_t<0>>()), int>::type=0>
    constexpr variant();
    
    template <std::size_t N, typename ... Args, int _concept_requires_556 = 42, typename std::enable_if<(_concept_requires_556==43)||(Constructible<datum_t<N>, Args&&>()), int>::type ... = 0>
    constexpr variant(_emplaced_index_t_<N>, Args&&... args);
    
    template <std::size_t N, typename T, int _concept_requires_562 = 42, typename std::enable_if<(_concept_requires_562==43)||(Constructible<datum_t<N>, std::initializer_list<T>>()), int>::type=0>
    constexpr variant(_emplaced_index_t_<N>, std::initializer_list<T> il);
    
    template <std::size_t N, int _concept_requires_568 = 42, typename std::enable_if<(_concept_requires_568==43)||(Constructible<datum_t<N>, meta::nil_>()), int>::type=0>
    constexpr variant(_emplaced_index_t_<N>, meta::nil_);
    
    variant(variant&& that);
    
    variant(variant const& that);
    
    variant& operator=(variant&& that);
    
    variant& operator=(variant const& that);
    
    static constexpr std::size_t size();
    
    template <std::size_t N, typename ... Args, int _concept_requires_599 = 42, typename std::enable_if<(_concept_requires_599==43)||(Constructible<datum_t<N>, Args&&>()), int>::type ... = 0>
    void emplace(Args&&... args);
    
    constexpr bool valid() const;
    
    constexpr std::size_t index() const;
    
    template <typename Fun>
    variant<alt_result_t<composed<Fun, unbox_fn>, Ts>...> visit(Fun fun);
    
    template <typename Fun>
    variant<alt_result_t<composed<Fun, unbox_fn>, add_const_t<Ts>>...> visit(Fun fun) const;
    
    template <typename Fun>
    variant<alt_result_t<Fun, Ts>...> visit_i(Fun fun);
    
    template <typename Fun>
    variant<alt_result_t<Fun, add_const_t<Ts>>...> visit_i(Fun fun) const;
};

@{


Function template ranges::v3::get<N, Ts...>

template <std::size_t N, typename ... Ts>
meta::_t<std::add_lvalue_reference<meta::at_c<meta::list<Ts...>, N>>> get(variant<Ts...>& var);

/////////////////////////////////////////////////////////////////////////////////////////


Class template ranges::v3::variant_unique<Var>

template <typename Var>
struct variant_unique{};

/////////////////////////////////////////////////////////////////////////////////////////


Function template ranges::v3::unique_variant<Ts...>

template <typename ... Ts>
variant_unique_t<variant<Ts...>> unique_variant(variant<Ts...>const& var);

/////////////////////////////////////////////////////////////////////////////////////////