#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP #include "../stl/concepts.hpp" #include "../stl/cstddef.hpp" #include "../stl/tuple.hpp" #include "../stl/type_traits.hpp" #include "../stl/utility.hpp" #include "fwd.hpp" #include "type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif