EnTT  3.10.0
compressed_pair.hpp
1 #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP
2 #define ENTT_CORE_COMPRESSED_PAIR_HPP
3 
4 #include <cstddef>
5 #include <tuple>
6 #include <type_traits>
7 #include <utility>
8 #include "../config/config.h"
9 #include "type_traits.hpp"
10 
11 namespace entt {
12 
18 namespace internal {
19 
20 template<typename Type, std::size_t, typename = void>
21 struct compressed_pair_element {
22  using reference = Type &;
23  using const_reference = const Type &;
24 
25  template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<Type>>>
26  compressed_pair_element()
27  : value{} {}
28 
29  template<typename Args, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Args>>, compressed_pair_element>>>
30  compressed_pair_element(Args &&args)
31  : value{std::forward<Args>(args)} {}
32 
33  template<typename... Args, std::size_t... Index>
34  compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>)
35  : value{std::forward<Args>(std::get<Index>(args))...} {}
36 
37  [[nodiscard]] reference get() ENTT_NOEXCEPT {
38  return value;
39  }
40 
41  [[nodiscard]] const_reference get() const ENTT_NOEXCEPT {
42  return value;
43  }
44 
45 private:
46  Type value;
47 };
48 
49 template<typename Type, std::size_t Tag>
50 struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>>: Type {
51  using reference = Type &;
52  using const_reference = const Type &;
53  using base_type = Type;
54 
55  template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<base_type>>>
56  compressed_pair_element()
57  : base_type{} {}
58 
59  template<typename Args, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Args>>, compressed_pair_element>>>
60  compressed_pair_element(Args &&args)
61  : base_type{std::forward<Args>(args)} {}
62 
63  template<typename... Args, std::size_t... Index>
64  compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>)
65  : base_type{std::forward<Args>(std::get<Index>(args))...} {}
66 
67  [[nodiscard]] reference get() ENTT_NOEXCEPT {
68  return *this;
69  }
70 
71  [[nodiscard]] const_reference get() const ENTT_NOEXCEPT {
72  return *this;
73  }
74 };
75 
76 } // namespace internal
77 
92 template<typename First, typename Second>
93 class compressed_pair final
94  : internal::compressed_pair_element<First, 0u>,
95  internal::compressed_pair_element<Second, 1u> {
96  using first_base = internal::compressed_pair_element<First, 0u>;
97  using second_base = internal::compressed_pair_element<Second, 1u>;
98 
99 public:
101  using first_type = First;
103  using second_type = Second;
104 
113  template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
114  constexpr compressed_pair()
115  : first_base{},
116  second_base{} {}
117 
122  constexpr compressed_pair(const compressed_pair &other) = default;
123 
128  constexpr compressed_pair(compressed_pair &&other) = default;
129 
137  template<typename Arg, typename Other>
138  constexpr compressed_pair(Arg &&arg, Other &&other)
139  : first_base{std::forward<Arg>(arg)},
140  second_base{std::forward<Other>(other)} {}
141 
149  template<typename... Args, typename... Other>
150  constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other)
151  : first_base{std::move(args), std::index_sequence_for<Args...>{}},
152  second_base{std::move(other), std::index_sequence_for<Other...>{}} {}
153 
159  constexpr compressed_pair &operator=(const compressed_pair &other) = default;
160 
166  constexpr compressed_pair &operator=(compressed_pair &&other) = default;
167 
172  [[nodiscard]] first_type &first() ENTT_NOEXCEPT {
173  return static_cast<first_base &>(*this).get();
174  }
175 
177  [[nodiscard]] const first_type &first() const ENTT_NOEXCEPT {
178  return static_cast<const first_base &>(*this).get();
179  }
180 
185  [[nodiscard]] second_type &second() ENTT_NOEXCEPT {
186  return static_cast<second_base &>(*this).get();
187  }
188 
190  [[nodiscard]] const second_type &second() const ENTT_NOEXCEPT {
191  return static_cast<const second_base &>(*this).get();
192  }
193 
198  void swap(compressed_pair &other) {
199  using std::swap;
200  swap(first(), other.first());
201  swap(second(), other.second());
202  }
203 
210  template<std::size_t Index>
211  decltype(auto) get() ENTT_NOEXCEPT {
212  if constexpr(Index == 0u) {
213  return first();
214  } else {
215  static_assert(Index == 1u, "Index out of bounds");
216  return second();
217  }
218  }
219 
221  template<std::size_t Index>
222  decltype(auto) get() const ENTT_NOEXCEPT {
223  if constexpr(Index == 0u) {
224  return first();
225  } else {
226  static_assert(Index == 1u, "Index out of bounds");
227  return second();
228  }
229  }
230 };
231 
237 template<typename Type, typename Other>
238 compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>;
239 
247 template<typename First, typename Second>
249  lhs.swap(rhs);
250 }
251 
252 } // namespace entt
253 
254 // disable structured binding support for clang 6, it messes when specializing tuple_size
255 #if !defined __clang_major__ || __clang_major__ > 6
256 namespace std {
257 
263 template<typename First, typename Second>
264 struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {};
265 
272 template<size_t Index, typename First, typename Second>
273 struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
274  static_assert(Index < 2u, "Index out of bounds");
275 };
276 
277 } // namespace std
278 #endif
279 
280 #endif
A compressed pair.
void swap(compressed_pair &other)
Swaps two compressed pair objects.
constexpr compressed_pair(const compressed_pair &other)=default
Copy constructor.
const second_type & second() const
Returns the second element that a pair stores.
First first_type
The type of the first element that the pair stores.
constexpr compressed_pair(Arg &&arg, Other &&other)
Constructs a pair from its values.
constexpr compressed_pair & operator=(const compressed_pair &other)=default
Copy assignment operator.
second_type & second()
Returns the second element that a pair stores.
first_type & first()
Returns the first element that a pair stores.
constexpr compressed_pair(compressed_pair &&other)=default
Move constructor.
const first_type & first() const
Returns the first element that a pair stores.
constexpr compressed_pair()
Default constructor, conditionally enabled.
constexpr compressed_pair & operator=(compressed_pair &&other)=default
Move assignment operator.
Second second_type
The type of the second element that the pair stores.
constexpr compressed_pair(std::piecewise_construct_t, std::tuple< Args... > args, std::tuple< Other... > other)
Constructs a pair by forwarding the arguments to its parts.
EnTT default namespace.
Definition: dense_map.hpp:22
constexpr get_t< Type... > get
Variable template for lists of observed components.
Definition: utility.hpp:34
void swap(compressed_pair< First, Second > &lhs, compressed_pair< First, Second > &rhs)
Swaps two compressed pair objects.