#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP #include #include #include #include #include "../config/config.h" #include "type_traits.hpp" namespace entt { /** * @cond TURN_OFF_DOXYGEN * Internal details not to be documented. */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; template>> compressed_pair_element() : value{} {} template>, compressed_pair_element>>> compressed_pair_element(Args &&args) : value{std::forward(args)} {} template compressed_pair_element(std::tuple args, std::index_sequence) : value{std::forward(std::get(args))...} {} [[nodiscard]] reference get() ENTT_NOEXCEPT { return value; } [[nodiscard]] const_reference get() const ENTT_NOEXCEPT { return value; } private: Type value; }; template struct compressed_pair_element>>: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; template>> compressed_pair_element() : base_type{} {} template>, compressed_pair_element>>> compressed_pair_element(Args &&args) : base_type{std::forward(args)} {} template compressed_pair_element(std::tuple args, std::index_sequence) : base_type{std::forward(std::get(args))...} {} [[nodiscard]] reference get() ENTT_NOEXCEPT { return *this; } [[nodiscard]] const_reference get() const ENTT_NOEXCEPT { return *this; } }; } // namespace internal /** * Internal details not to be documented. * @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. * * @tparam Dummy Dummy template parameter used for internal purposes. */ template && std::is_default_constructible_v>> constexpr compressed_pair() : 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) = 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) : first_base{std::forward(arg)}, second_base{std::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(std::piecewise_construct_t, std::tuple args, std::tuple other) : first_base{std::move(args), std::index_sequence_for{}}, second_base{std::move(other), std::index_sequence_for{}} {} /** * @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) = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] first_type &first() ENTT_NOEXCEPT { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] const first_type &first() const ENTT_NOEXCEPT { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] second_type &second() ENTT_NOEXCEPT { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] const second_type &second() const ENTT_NOEXCEPT { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ void swap(compressed_pair &other) { using std::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 decltype(auto) get() ENTT_NOEXCEPT { if constexpr(Index == 0u) { return first(); } else { static_assert(Index == 1u, "Index out of bounds"); return second(); } } /*! @copydoc get */ template decltype(auto) get() const ENTT_NOEXCEPT { if constexpr(Index == 0u) { return first(); } else { static_assert(Index == 1u, "Index out of bounds"); 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, std::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 inline void swap(compressed_pair &lhs, compressed_pair &rhs) { lhs.swap(rhs); } } // namespace entt // disable structured binding support for clang 6, it messes when specializing tuple_size #if !defined __clang_major__ || __clang_major__ > 6 namespace std { /** * @brief `std::tuple_size` specialization for `compressed_pair`s. * @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 struct tuple_size>: integral_constant {}; /** * @brief `std::tuple_element` specialization for `compressed_pair`s. * @tparam Index The index of the type to return. * @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 struct tuple_element>: conditional { static_assert(Index < 2u, "Index out of bounds"); }; } // namespace std #endif #endif