🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
9.3 KiB

  1. #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP
  2. #define ENTT_CORE_COMPRESSED_PAIR_HPP
  3. #include <cstddef>
  4. #include <tuple>
  5. #include <type_traits>
  6. #include <utility>
  7. #include "../config/config.h"
  8. #include "type_traits.hpp"
  9. namespace entt {
  10. /**
  11. * @cond TURN_OFF_DOXYGEN
  12. * Internal details not to be documented.
  13. */
  14. namespace internal {
  15. template<typename Type, std::size_t, typename = void>
  16. struct compressed_pair_element {
  17. using reference = Type &;
  18. using const_reference = const Type &;
  19. template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<Type>>>
  20. compressed_pair_element()
  21. : value{} {}
  22. template<typename Args, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Args>>, compressed_pair_element>>>
  23. compressed_pair_element(Args &&args)
  24. : value{std::forward<Args>(args)} {}
  25. template<typename... Args, std::size_t... Index>
  26. compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>)
  27. : value{std::forward<Args>(std::get<Index>(args))...} {}
  28. [[nodiscard]] reference get() ENTT_NOEXCEPT {
  29. return value;
  30. }
  31. [[nodiscard]] const_reference get() const ENTT_NOEXCEPT {
  32. return value;
  33. }
  34. private:
  35. Type value;
  36. };
  37. template<typename Type, std::size_t Tag>
  38. struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>>: Type {
  39. using reference = Type &;
  40. using const_reference = const Type &;
  41. using base_type = Type;
  42. template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<base_type>>>
  43. compressed_pair_element()
  44. : base_type{} {}
  45. template<typename Args, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Args>>, compressed_pair_element>>>
  46. compressed_pair_element(Args &&args)
  47. : base_type{std::forward<Args>(args)} {}
  48. template<typename... Args, std::size_t... Index>
  49. compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>)
  50. : base_type{std::forward<Args>(std::get<Index>(args))...} {}
  51. [[nodiscard]] reference get() ENTT_NOEXCEPT {
  52. return *this;
  53. }
  54. [[nodiscard]] const_reference get() const ENTT_NOEXCEPT {
  55. return *this;
  56. }
  57. };
  58. } // namespace internal
  59. /**
  60. * Internal details not to be documented.
  61. * @endcond
  62. */
  63. /**
  64. * @brief A compressed pair.
  65. *
  66. * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to
  67. * reduce its final size to a minimum.
  68. *
  69. * @tparam First The type of the first element that the pair stores.
  70. * @tparam Second The type of the second element that the pair stores.
  71. */
  72. template<typename First, typename Second>
  73. class compressed_pair final
  74. : internal::compressed_pair_element<First, 0u>,
  75. internal::compressed_pair_element<Second, 1u> {
  76. using first_base = internal::compressed_pair_element<First, 0u>;
  77. using second_base = internal::compressed_pair_element<Second, 1u>;
  78. public:
  79. /*! @brief The type of the first element that the pair stores. */
  80. using first_type = First;
  81. /*! @brief The type of the second element that the pair stores. */
  82. using second_type = Second;
  83. /**
  84. * @brief Default constructor, conditionally enabled.
  85. *
  86. * This constructor is only available when the types that the pair stores
  87. * are both at least default constructible.
  88. *
  89. * @tparam Dummy Dummy template parameter used for internal purposes.
  90. */
  91. template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
  92. constexpr compressed_pair()
  93. : first_base{},
  94. second_base{} {}
  95. /**
  96. * @brief Copy constructor.
  97. * @param other The instance to copy from.
  98. */
  99. constexpr compressed_pair(const compressed_pair &other) = default;
  100. /**
  101. * @brief Move constructor.
  102. * @param other The instance to move from.
  103. */
  104. constexpr compressed_pair(compressed_pair &&other) = default;
  105. /**
  106. * @brief Constructs a pair from its values.
  107. * @tparam Arg Type of value to use to initialize the first element.
  108. * @tparam Other Type of value to use to initialize the second element.
  109. * @param arg Value to use to initialize the first element.
  110. * @param other Value to use to initialize the second element.
  111. */
  112. template<typename Arg, typename Other>
  113. constexpr compressed_pair(Arg &&arg, Other &&other)
  114. : first_base{std::forward<Arg>(arg)},
  115. second_base{std::forward<Other>(other)} {}
  116. /**
  117. * @brief Constructs a pair by forwarding the arguments to its parts.
  118. * @tparam Args Types of arguments to use to initialize the first element.
  119. * @tparam Other Types of arguments to use to initialize the second element.
  120. * @param args Arguments to use to initialize the first element.
  121. * @param other Arguments to use to initialize the second element.
  122. */
  123. template<typename... Args, typename... Other>
  124. constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other)
  125. : first_base{std::move(args), std::index_sequence_for<Args...>{}},
  126. second_base{std::move(other), std::index_sequence_for<Other...>{}} {}
  127. /**
  128. * @brief Copy assignment operator.
  129. * @param other The instance to copy from.
  130. * @return This compressed pair object.
  131. */
  132. constexpr compressed_pair &operator=(const compressed_pair &other) = default;
  133. /**
  134. * @brief Move assignment operator.
  135. * @param other The instance to move from.
  136. * @return This compressed pair object.
  137. */
  138. constexpr compressed_pair &operator=(compressed_pair &&other) = default;
  139. /**
  140. * @brief Returns the first element that a pair stores.
  141. * @return The first element that a pair stores.
  142. */
  143. [[nodiscard]] first_type &first() ENTT_NOEXCEPT {
  144. return static_cast<first_base &>(*this).get();
  145. }
  146. /*! @copydoc first */
  147. [[nodiscard]] const first_type &first() const ENTT_NOEXCEPT {
  148. return static_cast<const first_base &>(*this).get();
  149. }
  150. /**
  151. * @brief Returns the second element that a pair stores.
  152. * @return The second element that a pair stores.
  153. */
  154. [[nodiscard]] second_type &second() ENTT_NOEXCEPT {
  155. return static_cast<second_base &>(*this).get();
  156. }
  157. /*! @copydoc second */
  158. [[nodiscard]] const second_type &second() const ENTT_NOEXCEPT {
  159. return static_cast<const second_base &>(*this).get();
  160. }
  161. /**
  162. * @brief Swaps two compressed pair objects.
  163. * @param other The compressed pair to swap with.
  164. */
  165. void swap(compressed_pair &other) {
  166. using std::swap;
  167. swap(first(), other.first());
  168. swap(second(), other.second());
  169. }
  170. /**
  171. * @brief Extracts an element from the compressed pair.
  172. * @tparam Index An integer value that is either 0 or 1.
  173. * @return Returns a reference to the first element if `Index` is 0 and a
  174. * reference to the second element if `Index` is 1.
  175. */
  176. template<std::size_t Index>
  177. decltype(auto) get() ENTT_NOEXCEPT {
  178. if constexpr(Index == 0u) {
  179. return first();
  180. } else {
  181. static_assert(Index == 1u, "Index out of bounds");
  182. return second();
  183. }
  184. }
  185. /*! @copydoc get */
  186. template<std::size_t Index>
  187. decltype(auto) get() const ENTT_NOEXCEPT {
  188. if constexpr(Index == 0u) {
  189. return first();
  190. } else {
  191. static_assert(Index == 1u, "Index out of bounds");
  192. return second();
  193. }
  194. }
  195. };
  196. /**
  197. * @brief Deduction guide.
  198. * @tparam Type Type of value to use to initialize the first element.
  199. * @tparam Other Type of value to use to initialize the second element.
  200. */
  201. template<typename Type, typename Other>
  202. compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>;
  203. /**
  204. * @brief Swaps two compressed pair objects.
  205. * @tparam First The type of the first element that the pairs store.
  206. * @tparam Second The type of the second element that the pairs store.
  207. * @param lhs A valid compressed pair object.
  208. * @param rhs A valid compressed pair object.
  209. */
  210. template<typename First, typename Second>
  211. inline void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Second> &rhs) {
  212. lhs.swap(rhs);
  213. }
  214. } // namespace entt
  215. // disable structured binding support for clang 6, it messes when specializing tuple_size
  216. #if !defined __clang_major__ || __clang_major__ > 6
  217. namespace std {
  218. /**
  219. * @brief `std::tuple_size` specialization for `compressed_pair`s.
  220. * @tparam First The type of the first element that the pair stores.
  221. * @tparam Second The type of the second element that the pair stores.
  222. */
  223. template<typename First, typename Second>
  224. struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {};
  225. /**
  226. * @brief `std::tuple_element` specialization for `compressed_pair`s.
  227. * @tparam Index The index of the type to return.
  228. * @tparam First The type of the first element that the pair stores.
  229. * @tparam Second The type of the second element that the pair stores.
  230. */
  231. template<size_t Index, typename First, typename Second>
  232. struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
  233. static_assert(Index < 2u, "Index out of bounds");
  234. };
  235. } // namespace std
  236. #endif
  237. #endif