<commit_before>// Copyright (C) 2016-2018 <NAME> <<EMAIL>>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#ifndef TYPE_SAFE_VARIANT_HPP_INCLUDED
#define TYPE_SAFE_VARIANT_HPP_INCLUDED

#include <type_safe/detail/variant_impl.hpp>
#include <type_safe/optional_ref.hpp>

namespace type_safe
{
    /// Convenience alias for [ts::union_type]().
    /// \module variant
    template <typename T>
    using variant_type = union_type<T>;

    /// Convenience alias for [ts::union_types]().
    /// \module variant
    template <typename... Ts>
    using variant_types = union_types<Ts...>;

    /// Tag type to mark a [ts::basic_variant]() without a value.
    /// \module variant
    struct nullvar_t
    {
        constexpr nullvar_t() {}
    };

    /// Tag object of type [ts::nullvar_t]().
    /// \module variant
    constexpr nullvar_t nullvar;

    /// An improved `union` storing at most one of the given types at a time (or possibly none).
    ///
    /// It is an improved version of [std::variant]().
    /// A big problem with variant is implementing the operation that changes the type.
    /// It has to destroy the old value and then create the new one.
    /// But how to handle an exception when creating the new type?
    /// There are multiple ways of handling this, so it is outsourced in a policy.
    /// The variant policy is a class that must have the following members:
    /// * `allow_empty` - either [std::true_type]() or [std::false_type]().
    /// If it is "true", the variant can be put in the empty state explicitly.
    /// * `void change_value(variant_type<T>, tagged_union<Types...>&, Args&&... args)` - changes the value and type.
    /// It will be called when the variant already contains an object of a different type.
    /// It must destroy the old type and create a new one with the given type and arguments.
    /// \module variant
    template <class VariantPolicy, typename HeadT, typename... TailT>
    class basic_variant : detail::variant_copy<HeadT, TailT...>,
                          detail::variant_move<HeadT, TailT...>
    {
        using union_t = tagged_union<HeadT, TailT...>;
        using traits  = detail::traits<HeadT, TailT...>;

    public:
        using types   = typename union_t::types;
        using type_id = typename union_t::type_id;

        using allow_empty = typename VariantPolicy::allow_empty;

        static constexpr type_id invalid_type = union_t::invalid_type;

        //=== constructors/destructors/assignment/swap ===//
        /// \effects Initializes the variant to the empty state.
        /// \notes This constructor only participates in overload resolution,
        /// if the policy allows an empty variant.
        /// \group default
        /// \param Dummy
        /// \exclude
        /// \param 1
        /// \exclude
        template <typename Dummy = void, typename = typename std::enable_if<
                                             VariantPolicy::allow_empty::value, Dummy>::type>
        basic_variant() noexcept
        {
        }

        /// \group default
        /// \param Dummy
        /// \exclude
        /// \param 1
        /// \exclude
        template <typename Dummy = void, typename = typename std::enable_if<
                                             VariantPolicy::allow_empty::value, Dummy>::type>
        basic_variant(nullvar_t) noexcept : basic_variant()
        {
        }

        /// Copy (1)/move (2) constructs a variant.
        /// \effects If the other variant is not empty, it will call [ts::copy](standardese://ts::copy_union/) (1)
        /// or [ts::move](standardese://ts::move_union/) (2).
        /// \throws Anything thrown by the copy (1)/move (2) constructor.
        /// \notes This constructor only participates in overload resolution,
        /// if all types are copy (1)/move (2) constructible./
        /// \notes The move constructor only moves the stored value,
        /// and does not make the other variant empty.
        /// \group copy_move_ctor
        basic_variant(const basic_variant&) = default;

        /// \group copy_move_ctor
        basic_variant(basic_variant&&)
            TYPE_SAFE_NOEXCEPT_DEFAULT(traits::nothrow_move_constructible::value) = default;

        /// Initializes it containing a new object of the given type.
        /// \effects Creates it by calling `T`s constructor with the perfectly forwarded arguments.
        /// \throws Anything thrown by `T`s constructor.
        /// \notes This constructor does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and constructible from the arguments.
        /// \param 2
        /// \exclude
        template <typename T, typename... Args,
                  typename = detail::enable_variant_type<union_t, T, Args&&...>>
        explicit basic_variant(variant_type<T> type, Args&&... args)
        {
            storage_.get_union().emplace(type, std::forward<Args>(args)...);
        }

        /// Initializes it with a copy of the given object.
        /// \effects Same as the type + argument constructor called with the decayed type of the argument
        /// and the object perfectly forwarded.
        /// \throws Anything thrown by `T`s copy/move constructor.
        /// \notes This constructor does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and copy/move constructible.
        /// \param 1
        /// \exclude
        template <typename T, typename = detail::enable_variant_type<union_t, T, T&&>>
        basic_variant(T&& obj)
        : basic_variant(variant_type<typename std::decay<T>::type>{}, std::forward<T>(obj))
        {
        }

        /// Initializes it from a [ts::tagged_union]().
        /// \effects Copies the currently stored type of the union
        /// into the variant by calling the copy (1)/move (2) constructor of the stored type.
        /// \throws Anything thrown by the selected copy (1)/move (2) constructor.
        /// \requires If the variant policy does not allow the empty state,
        /// the union must not be empty.
        /// \group ctor_union
        explicit basic_variant(const tagged_union<HeadT, TailT...>& u)
        {
            DEBUG_ASSERT(allow_empty::value || u.has_value(), detail::precondition_error_handler{});
            copy(storage_.get_union(), u);
        }

        /// \group ctor_union
        explicit basic_variant(tagged_union<HeadT, TailT...>&& u)
        {
            DEBUG_ASSERT(allow_empty::value || u.has_value(), detail::precondition_error_handler{});
            move(storage_.get_union(), std::move(u));
        }

        /// \effects Destroys the currently stored value,
        /// if there is any.
        ~basic_variant() noexcept = default;

        /// Copy (1)/move (2) assigns a variant.
        /// \effects If the other variant is empty,
        /// makes this one empty as well.
        /// Otherwise let the other variant contains an object of type `T`.
        /// If this variant contains the same type and there is a copy (1)/move (2) assignment operator available,
        /// assigns the object to this object.
        /// Else forwards to the variant policy's `change_value()` function.
        /// \throws Anything thrown by either the copy (1)/move (2) assignment operator
        /// or copy (1)/move (2) constructor.
        /// If the assignment operator throws, the variant will contain the partially assigned object.
        /// If the constructor throws, the state depends on the variant policy.
        /// \notes This function does not participate in overload resolution,
        /// unless all types are copy (1)/move (2) constructible.
        /// \group copy_move_assign
        basic_variant& operator=(const basic_variant&) = default;
        /// \group copy_move_assign
        basic_variant& operator                                                =(basic_variant&&)
            TYPE_SAFE_NOEXCEPT_DEFAULT(traits::nothrow_move_assignable::value) = default;

        /// Alias for [*reset()]().
        /// \param Dummy
        /// \exclude
        /// \param 1
        /// \exclude
        template <typename Dummy = void, typename = typename std::enable_if<
                                             VariantPolicy::allow_empty::value, Dummy>::type>
        basic_variant& operator=(nullvar_t) noexcept
        {
            reset();
            return *this;
        }

        /// Same as the single argument `emplace()`.
        /// \effects Changes the value to a copy of `obj`.
        /// \throws Anything thrown by `T`s copy/move constructor.
        /// \notes This function does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and copy/move constructible.
        /// \param 1
        /// \exclude
        template <typename T, typename = detail::enable_variant_type<union_t, T, T&&>>
        basic_variant& operator=(T&& obj)
        {
            emplace(variant_type<typename std::decay<T>::type>{}, std::forward<T>(obj));
            return *this;
        }

        /// Swaps two variants.
        /// \effects There are four cases:
        /// * Both variants are empty. Then the function has no effect.
        /// * Both variants contain the same type, `T`. Then it calls swap on the stored type.
        /// * Both variants contain a type, but different types.
        /// Then it swaps the variant by move constructing the objects from one type to the other,
        /// using the variant policy.
        /// * Only one variant contains an object. Then it moves the value to the empty variant,
        /// and destroys it in the non-empty variant.
        ///
        /// \effects In either case, it will only call the swap() function or the move constructor.
        /// \throws Anything thrown by the swap function,
        /// in which case both variants contain the partially swapped values,
        /// or the mvoe constructor, in which case the exact behavior depends on the variant policy.
        friend void swap(basic_variant& a,
                         basic_variant& b) noexcept(traits::nothrow_swappable::value)
        {
            auto& a_union = a.storage_.get_union();
            auto& b_union = b.storage_.get_union();

            if (a_union.has_value() && b_union.has_value())
                detail::swap_union<VariantPolicy, union_t>::swap(a_union, b_union);
            else if (a_union.has_value() && !b_union.has_value())
            {
                b = std::move(a);
                a.reset();
            }
            else if (!a_union.has_value() && b_union.has_value())
            {
                a = std::move(b);
                b.reset();
            }
        }

        //=== modifiers ===//
        /// \effects Destroys the stored value in the variant, if any.
        /// \notes This function only participate in overload resolution,
        /// if the variant policy allows the empty state.
        /// \param Dummy
        /// \exclude
        /// \param 1
        /// \exclude
        template <typename Dummy = void, typename = typename std::enable_if<
                                             VariantPolicy::allow_empty::value, Dummy>::type>
        void reset() noexcept
        {
            destroy(storage_.get_union());
        }

        /// Changes the value to a new object of the given type.
        /// \effects If the variant contains an object of the same type,
        /// assigns the argument to it.
        /// Otherwise behaves as the other emplace version.
        /// \throws Anything thrown by the chosen assignment operator
        /// or the other `emplace()`.
        /// If the assignment operator throws,
        /// the variant contains a partially assigned object.
        /// Otherwise it depends on the variant policy.
        /// \notes This function does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and assignable from the argument
        /// without creating an additional temporary.
        /// \param 2
        /// \exclude
        /// \param 3
        /// \exclude
        template <
            typename T, typename Arg,
            typename = typename std::enable_if<detail::is_direct_assignable<T, Arg&&>::value>::type,
            typename = detail::enable_variant_type<union_t, T, Arg&&>>
        void emplace(variant_type<T> type, Arg&& arg)
        {
            if (storage_.get_union().type() == typename union_t::type_id(type))
                storage_.get_union().value(type) = std::forward<Arg>(arg);
            else
                emplace_impl(type, std::forward<Arg>(arg));
        }

        /// Changes the value to a new object of given type.
        /// \effects If variant is empty, creates the object directly in place
        /// by perfectly forwarding the arguments.
        /// Otherwise it forwards to the variant policy's `change_value()` function.
        /// \throws Anything thrown by `T`s constructor or possibly move constructor.
        /// If the variant was empty before, it is still empty afterwards.
        /// Otherwise the state depends on the policy.
        /// \notes This function does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and constructible from the arguments.
        /// \param 2
        /// \exclude
        template <typename T, typename... Args,
                  typename = detail::enable_variant_type<union_t, T, Args&&...>>
        void emplace(variant_type<T> type, Args&&... args)
        {
            emplace_impl(type, std::forward<Args>(args)...);
        }

    private:
        template <typename T, typename... Args>
        void emplace_impl(variant_type<T> type, Args&&... args)
        {
            if (storage_.get_union().has_value())
                VariantPolicy::change_value(type, storage_.get_union(),
                                            std::forward<Args>(args)...);
            else
                storage_.get_union().emplace(type, std::forward<Args>(args)...);
        }

    public:
        //=== observers ===//
        /// \returns The type id representing the type of the value currently stored in the variant.
        /// \notes If it does not have a value stored, returns [*invalid_type]().
        type_id type() const noexcept
        {
            return storage_.get_union().type();
        }

        /// \returns `true` if the variant currently contains a value,
        /// `false` otherwise.
        /// \notes Depending on the variant policy,
        /// it can be guaranteed to return `true` all the time.
        /// \group has_value
        bool has_value() const noexcept
        {
            return storage_.get_union().has_value();
        }

        /// \group has_value
        explicit operator bool() const noexcept
        {
            return has_value();
        }

        /// \group has_value
        bool has_value(variant_type<nullvar_t>) const noexcept
        {
            return !has_value();
        }

        /// \returns `true` if the variant currently stores an object of type `T`,
        /// `false` otherwise.
        /// \notes `T` must not necessarily be a type that can be stored in the variant.
        template <typename T>
        bool has_value(variant_type<T> type) const noexcept
        {
            return this->type() == type_id(type);
        }

        /// \returns A copy of [ts::nullvar]().
        /// \requires The variant must be empty.
        nullvar_t value(variant_type<nullvar_t>) const noexcept
        {
            DEBUG_ASSERT(!has_value(), detail::precondition_error_handler{});
            return nullvar;
        }

        /// \returns A (`const`) lvalue (1, 2)/rvalue (3, 4) reference to the stored object of the given type.
        /// \requires The variant must currently store an object of the given type,
        /// i.e. `has_value(type)` must return `true`.
        /// \group value
        /// \param 1
        /// \exclude
        template <typename T,
                  typename = typename std::enable_if<type_id::template is_valid<T>()>::type>
        T& value(variant_type<T> type) TYPE_SAFE_LVALUE_REF noexcept
        {
            return storage_.get_union().value(type);
        }

        /// \group value
        /// \param 1
        /// \exclude
        template <typename T,
                  typename = typename std::enable_if<type_id::template is_valid<T>()>::type>
        const T& value(variant_type<T> type) const TYPE_SAFE_LVALUE_REF noexcept
        {
            return storage_.get_union().value(type);
        }

#if TYPE_SAFE_USE_REF_QUALIFIERS
        /// \group value
        /// \param 1
        /// \exclude
        template <typename T,
                  typename = typename std::enable_if<type_id::template is_valid<T>()>::type>
            T&& value(variant_type<T> type) && noexcept
        {
            return std::move(storage_.get_union()).value(type);
        }

        /// \group value
        /// \param 1
        /// \exclude
        template <typename T,
                  typename = typename std::enable_if<type_id::template is_valid<T>()>::type>
        const T&& value(variant_type<T> type) const && noexcept
        {
            return std::move(storage_.get_union()).value(type);
        }
#endif

        /// \returns A [ts::optional_ref]() to [ts::nullvar]().
        /// If the variant is not empty, returns a null reference.
        optional_ref<const nullvar_t> optional_value(variant_type<nullvar_t>) const noexcept
        {
            return has_value() ? nullptr : type_safe::opt_ref(&nullvar);
        }

        /// \returns A (`const`) [ts::optional_ref]() (1, 2)/[ts::optional_xvalue_ref]() to the stored value of given type.
        /// If it stores a different type, returns a null reference.
        /// \group optional_value
        template <typename T>
        optional_ref<T> optional_value(variant_type<T> type) TYPE_SAFE_LVALUE_REF noexcept
        {
            return has_value(type) ? type_safe::opt_ref(&storage_.get_union().value(type)) :
                                     nullptr;
        }

        /// \group optional_value
        template <typename T>
        optional_ref<const T> optional_value(variant_type<T> type) const TYPE_SAFE_LVALUE_REF
            noexcept
        {
            return has_value(type) ? type_safe::opt_ref(&storage_.get_union().value(type)) :
                                     nullptr;
        }

#if TYPE_SAFE_USE_REF_QUALIFIERS
        /// \group optional_value
        template <typename T>
            optional_xvalue_ref<T> optional_value(variant_type<T> type) && noexcept
        {
            return has_value(type) ? type_safe::opt_xref(&storage_.get_union().value(type)) :
                                     nullptr;
        }

        /// \group optional_value
        template <typename T>
        optional_xvalue_ref<const T> optional_value(variant_type<T> type) const && noexcept
        {
            return has_value(type) ? type_safe::opt_xref(&storage_.get_union().value(type)) :
                                     nullptr;
        }
#endif

        /// \returns If the variant currently stores an object of type `T`,
        /// returns a copy of that by copy (1)/move (2) constructing.
        /// Otherwise returns `other` converted to `T`.<commit_msg>Try workaround issue in is_valid<commit_after>// Copyright (C) 2016-2018 <NAME> <<EMAIL>>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#ifndef TYPE_SAFE_VARIANT_HPP_INCLUDED
#define TYPE_SAFE_VARIANT_HPP_INCLUDED

#include <type_safe/detail/variant_impl.hpp>
#include <type_safe/optional_ref.hpp>

namespace type_safe
{
    /// Convenience alias for [ts::union_type]().
    /// \module variant
    template <typename T>
    using variant_type = union_type<T>;

    /// Convenience alias for [ts::union_types]().
    /// \module variant
    template <typename... Ts>
    using variant_types = union_types<Ts...>;

    /// Tag type to mark a [ts::basic_variant]() without a value.
    /// \module variant
    struct nullvar_t
    {
        constexpr nullvar_t() {}
    };

    /// Tag object of type [ts::nullvar_t]().
    /// \module variant
    constexpr nullvar_t nullvar;

    /// An improved `union` storing at most one of the given types at a time (or possibly none).
    ///
    /// It is an improved version of [std::variant]().
    /// A big problem with variant is implementing the operation that changes the type.
    /// It has to destroy the old value and then create the new one.
    /// But how to handle an exception when creating the new type?
    /// There are multiple ways of handling this, so it is outsourced in a policy.
    /// The variant policy is a class that must have the following members:
    /// * `allow_empty` - either [std::true_type]() or [std::false_type]().
    /// If it is "true", the variant can be put in the empty state explicitly.
    /// * `void change_value(variant_type<T>, tagged_union<Types...>&, Args&&... args)` - changes the value and type.
    /// It will be called when the variant already contains an object of a different type.
    /// It must destroy the old type and create a new one with the given type and arguments.
    /// \module variant
    template <class VariantPolicy, typename HeadT, typename... TailT>
    class basic_variant : detail::variant_copy<HeadT, TailT...>,
                          detail::variant_move<HeadT, TailT...>
    {
        using union_t = tagged_union<HeadT, TailT...>;
        using traits  = detail::traits<HeadT, TailT...>;

    public:
        using types   = typename union_t::types;
        using type_id = typename union_t::type_id;

        using allow_empty = typename VariantPolicy::allow_empty;

        static constexpr type_id invalid_type = union_t::invalid_type;

        //=== constructors/destructors/assignment/swap ===//
        /// \effects Initializes the variant to the empty state.
        /// \notes This constructor only participates in overload resolution,
        /// if the policy allows an empty variant.
        /// \group default
        /// \param Dummy
        /// \exclude
        /// \param 1
        /// \exclude
        template <typename Dummy = void, typename = typename std::enable_if<
                                             VariantPolicy::allow_empty::value, Dummy>::type>
        basic_variant() noexcept
        {
        }

        /// \group default
        /// \param Dummy
        /// \exclude
        /// \param 1
        /// \exclude
        template <typename Dummy = void, typename = typename std::enable_if<
                                             VariantPolicy::allow_empty::value, Dummy>::type>
        basic_variant(nullvar_t) noexcept : basic_variant()
        {
        }

        /// Copy (1)/move (2) constructs a variant.
        /// \effects If the other variant is not empty, it will call [ts::copy](standardese://ts::copy_union/) (1)
        /// or [ts::move](standardese://ts::move_union/) (2).
        /// \throws Anything thrown by the copy (1)/move (2) constructor.
        /// \notes This constructor only participates in overload resolution,
        /// if all types are copy (1)/move (2) constructible./
        /// \notes The move constructor only moves the stored value,
        /// and does not make the other variant empty.
        /// \group copy_move_ctor
        basic_variant(const basic_variant&) = default;

        /// \group copy_move_ctor
        basic_variant(basic_variant&&)
            TYPE_SAFE_NOEXCEPT_DEFAULT(traits::nothrow_move_constructible::value) = default;

        /// Initializes it containing a new object of the given type.
        /// \effects Creates it by calling `T`s constructor with the perfectly forwarded arguments.
        /// \throws Anything thrown by `T`s constructor.
        /// \notes This constructor does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and constructible from the arguments.
        /// \param 2
        /// \exclude
        template <typename T, typename... Args,
                  typename = detail::enable_variant_type<union_t, T, Args&&...>>
        explicit basic_variant(variant_type<T> type, Args&&... args)
        {
            storage_.get_union().emplace(type, std::forward<Args>(args)...);
        }

        /// Initializes it with a copy of the given object.
        /// \effects Same as the type + argument constructor called with the decayed type of the argument
        /// and the object perfectly forwarded.
        /// \throws Anything thrown by `T`s copy/move constructor.
        /// \notes This constructor does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and copy/move constructible.
        /// \param 1
        /// \exclude
        template <typename T, typename = detail::enable_variant_type<union_t, T, T&&>>
        basic_variant(T&& obj)
        : basic_variant(variant_type<typename std::decay<T>::type>{}, std::forward<T>(obj))
        {
        }

        /// Initializes it from a [ts::tagged_union]().
        /// \effects Copies the currently stored type of the union
        /// into the variant by calling the copy (1)/move (2) constructor of the stored type.
        /// \throws Anything thrown by the selected copy (1)/move (2) constructor.
        /// \requires If the variant policy does not allow the empty state,
        /// the union must not be empty.
        /// \group ctor_union
        explicit basic_variant(const tagged_union<HeadT, TailT...>& u)
        {
            DEBUG_ASSERT(allow_empty::value || u.has_value(), detail::precondition_error_handler{});
            copy(storage_.get_union(), u);
        }

        /// \group ctor_union
        explicit basic_variant(tagged_union<HeadT, TailT...>&& u)
        {
            DEBUG_ASSERT(allow_empty::value || u.has_value(), detail::precondition_error_handler{});
            move(storage_.get_union(), std::move(u));
        }

        /// \effects Destroys the currently stored value,
        /// if there is any.
        ~basic_variant() noexcept = default;

        /// Copy (1)/move (2) assigns a variant.
        /// \effects If the other variant is empty,
        /// makes this one empty as well.
        /// Otherwise let the other variant contains an object of type `T`.
        /// If this variant contains the same type and there is a copy (1)/move (2) assignment operator available,
        /// assigns the object to this object.
        /// Else forwards to the variant policy's `change_value()` function.
        /// \throws Anything thrown by either the copy (1)/move (2) assignment operator
        /// or copy (1)/move (2) constructor.
        /// If the assignment operator throws, the variant will contain the partially assigned object.
        /// If the constructor throws, the state depends on the variant policy.
        /// \notes This function does not participate in overload resolution,
        /// unless all types are copy (1)/move (2) constructible.
        /// \group copy_move_assign
        basic_variant& operator=(const basic_variant&) = default;
        /// \group copy_move_assign
        basic_variant& operator                                                =(basic_variant&&)
            TYPE_SAFE_NOEXCEPT_DEFAULT(traits::nothrow_move_assignable::value) = default;

        /// Alias for [*reset()]().
        /// \param Dummy
        /// \exclude
        /// \param 1
        /// \exclude
        template <typename Dummy = void, typename = typename std::enable_if<
                                             VariantPolicy::allow_empty::value, Dummy>::type>
        basic_variant& operator=(nullvar_t) noexcept
        {
            reset();
            return *this;
        }

        /// Same as the single argument `emplace()`.
        /// \effects Changes the value to a copy of `obj`.
        /// \throws Anything thrown by `T`s copy/move constructor.
        /// \notes This function does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and copy/move constructible.
        /// \param 1
        /// \exclude
        template <typename T, typename = detail::enable_variant_type<union_t, T, T&&>>
        basic_variant& operator=(T&& obj)
        {
            emplace(variant_type<typename std::decay<T>::type>{}, std::forward<T>(obj));
            return *this;
        }

        /// Swaps two variants.
        /// \effects There are four cases:
        /// * Both variants are empty. Then the function has no effect.
        /// * Both variants contain the same type, `T`. Then it calls swap on the stored type.
        /// * Both variants contain a type, but different types.
        /// Then it swaps the variant by move constructing the objects from one type to the other,
        /// using the variant policy.
        /// * Only one variant contains an object. Then it moves the value to the empty variant,
        /// and destroys it in the non-empty variant.
        ///
        /// \effects In either case, it will only call the swap() function or the move constructor.
        /// \throws Anything thrown by the swap function,
        /// in which case both variants contain the partially swapped values,
        /// or the mvoe constructor, in which case the exact behavior depends on the variant policy.
        friend void swap(basic_variant& a,
                         basic_variant& b) noexcept(traits::nothrow_swappable::value)
        {
            auto& a_union = a.storage_.get_union();
            auto& b_union = b.storage_.get_union();

            if (a_union.has_value() && b_union.has_value())
                detail::swap_union<VariantPolicy, union_t>::swap(a_union, b_union);
            else if (a_union.has_value() && !b_union.has_value())
            {
                b = std::move(a);
                a.reset();
            }
            else if (!a_union.has_value() && b_union.has_value())
            {
                a = std::move(b);
                b.reset();
            }
        }

        //=== modifiers ===//
        /// \effects Destroys the stored value in the variant, if any.
        /// \notes This function only participate in overload resolution,
        /// if the variant policy allows the empty state.
        /// \param Dummy
        /// \exclude
        /// \param 1
        /// \exclude
        template <typename Dummy = void, typename = typename std::enable_if<
                                             VariantPolicy::allow_empty::value, Dummy>::type>
        void reset() noexcept
        {
            destroy(storage_.get_union());
        }

        /// Changes the value to a new object of the given type.
        /// \effects If the variant contains an object of the same type,
        /// assigns the argument to it.
        /// Otherwise behaves as the other emplace version.
        /// \throws Anything thrown by the chosen assignment operator
        /// or the other `emplace()`.
        /// If the assignment operator throws,
        /// the variant contains a partially assigned object.
        /// Otherwise it depends on the variant policy.
        /// \notes This function does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and assignable from the argument
        /// without creating an additional temporary.
        /// \param 2
        /// \exclude
        /// \param 3
        /// \exclude
        template <
            typename T, typename Arg,
            typename = typename std::enable_if<detail::is_direct_assignable<T, Arg&&>::value>::type,
            typename = detail::enable_variant_type<union_t, T, Arg&&>>
        void emplace(variant_type<T> type, Arg&& arg)
        {
            if (storage_.get_union().type() == typename union_t::type_id(type))
                storage_.get_union().value(type) = std::forward<Arg>(arg);
            else
                emplace_impl(type, std::forward<Arg>(arg));
        }

        /// Changes the value to a new object of given type.
        /// \effects If variant is empty, creates the object directly in place
        /// by perfectly forwarding the arguments.
        /// Otherwise it forwards to the variant policy's `change_value()` function.
        /// \throws Anything thrown by `T`s constructor or possibly move constructor.
        /// If the variant was empty before, it is still empty afterwards.
        /// Otherwise the state depends on the policy.
        /// \notes This function does not participate in overload resolution,
        /// unless `T` is a valid type for the variant and constructible from the arguments.
        /// \param 2
        /// \exclude
        template <typename T, typename... Args,
                  typename = detail::enable_variant_type<union_t, T, Args&&...>>
        void emplace(variant_type<T> type, Args&&... args)
        {
            emplace_impl(type, std::forward<Args>(args)...);
        }

    private:
        template <typename T, typename... Args>
        void emplace_impl(variant_type<T> type, Args&&... args)
        {
            if (storage_.get_union().has_value())
                VariantPolicy::change_value(type, storage_.get_union(),
                                            std::forward<Args>(args)...);
            else
                storage_.get_union().emplace(type, std::forward<Args>(args)...);
        }

        template <typename T>
        using enable_valid = typename std::enable_if<(type_id::template is_valid<T>)()>::type;

    public:
        //=== observers ===//
        /// \returns The type id representing the type of the value currently stored in the variant.
        /// \notes If it does not have a value stored, returns [*invalid_type]().
        type_id type() const noexcept
        {
            return storage_.get_union().type();
        }

        /// \returns `true` if the variant currently contains a value,
        /// `false` otherwise.
        /// \notes Depending on the variant policy,
        /// it can be guaranteed to return `true` all the time.
        /// \group has_value
        bool has_value() const noexcept
        {
            return storage_.get_union().has_value();
        }

        /// \group has_value
        explicit operator bool() const noexcept
        {
            return has_value();
        }

        /// \group has_value
        bool has_value(variant_type<nullvar_t>) const noexcept
        {
            return !has_value();
        }

        /// \returns `true` if the variant currently stores an object of type `T`,
        /// `false` otherwise.
        /// \notes `T` must not necessarily be a type that can be stored in the variant.
        template <typename T>
        bool has_value(variant_type<T> type) const noexcept
        {
            return this->type() == type_id(type);
        }

        /// \returns A copy of [ts::nullvar]().
        /// \requires The variant must be empty.
        nullvar_t value(variant_type<nullvar_t>) const noexcept
        {
            DEBUG_ASSERT(!has_value(), detail::precondition_error_handler{});
            return nullvar;
        }

        /// \returns A (`const`) lvalue (1, 2)/rvalue (3, 4) reference to the stored object of the given type.
        /// \requires The variant must currently store an object of the given type,
        /// i.e. `has_value(type)` must return `true`.
        /// \group value
        /// \param 1
        /// \exclude
        template <typename T, typename = enable_valid<T>>
        T& value(variant_type<T> type) TYPE_SAFE_LVALUE_REF noexcept
        {
            return storage_.get_union().value(type);
        }

        /// \group value
        /// \param 1
        /// \exclude
        template <typename T, typename = enable_valid<T>>
        const T& value(variant_type<T> type) const TYPE_SAFE_LVALUE_REF noexcept
        {
            return storage_.get_union().value(type);
        }

#if TYPE_SAFE_USE_REF_QUALIFIERS
        /// \group value
        /// \param 1
        /// \exclude
        template <typename T, typename = enable_valid<T>>
            T&& value(variant_type<T> type) && noexcept
        {
            return std::move(storage_.get_union()).value(type);
        }

        /// \group value
        /// \param 1
        /// \exclude
        template <typename T, typename = enable_valid<T>>
        const T&& value(variant_type<T> type) const&& noexcept
        {
            return std::move(storage_.get_union()).value(type);
        }
#endif

        /// \returns A [ts::optional_ref]() to [ts::nullvar]().
        /// If the variant is not empty, returns a null reference.
        optional_ref<const nullvar_t> optional_value(variant_type<nullvar_t>) const noexcept
        {
            return has_value() ? nullptr : type_safe::opt_ref(&nullvar);
        }

        /// \returns A (`const`) [ts::optional_ref]() (1, 2)/[ts::optional_xvalue_ref]() to the stored value of given type.
        /// If it stores a different type, returns a null reference.
        /// \group optional_value
        template <typename T>
        optional_ref<T> optional_value(variant_type<T> type) TYPE_SAFE_LVALUE_REF noexcept
        {
            return has_value(type) ? type_safe::opt_ref(&storage_.get_union().value(type)) :
                                     nullptr;
        }

        /// \group optional_value
        template <typename T>
        optional_ref<const T> optional_value(variant_type<T> type) const TYPE_SAFE_LVALUE_REF
            noexcept
        {
            return has_value(type) ? type_safe::opt_ref(&storage_.get_union().value(type)) :
                                     nullptr;
        }

#if TYPE_SAFE_USE_REF_QUALIFIERS
        /// \group optional_value
        template <typename T>
            optional_xvalue_ref<T> optional_value(variant_type<T> type) && noexcept
        {
            return has_value(type) ? type_safe::opt_xref(&storage_.get_union().value(type)) :
                                     nullptr;
        }

        /// \group optional_value
        template <typename T>
        optional_xvalue_ref<const T> optional_value(variant_type<T> type) const&& noexcept
        {
            return has_value(type) ? type_safe::opt_xref(&storage_.get_union().value(type)) :
                                     nullptr;
        }
#endif

        /// \returns If the variant currently stores an object of type `T`,
        /// returns a copy of that by copy (1)/move (2) constructing.
        /// Otherwise returns `other` converted to `T`.
{'fraction_non_alphanumeric': 0.1134039209624649, 'fraction_numerical': 0.002679238477986449, 'mean_word_length': 1.9088047958036718, 'pattern_counts': {'":': 0, '<': 182, '<?xml version=': 0, '>': 184, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4985174', 'n_tokens_mistral': 10363, 'n_tokens_neox': 9975, 'n_words': 3431}