sandbox
Loading...
Searching...
No Matches
compressed_pair.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_CONTAINERS_COMPRESSED_PAIR_HPP_
3#define LIBSBX_CONTAINERS_COMPRESSED_PAIR_HPP_
4
5#include <type_traits>
6#include <utility>
7
8namespace sbx::containers {
9
10namespace detail {
11
12template<typename Type>
13struct is_ebco_eligible : std::bool_constant<std::is_empty_v<Type> && !std::is_final_v<Type>> { };
14
15template<typename Type>
16inline constexpr bool is_ebco_eligible_v = is_ebco_eligible<Type>::value;
17
18template<typename Type, std::size_t, typename = void>
20
21public:
22
23 using value_type = Type;
24 using reference = value_type&;
25 using const_reference = const value_type&;
26
27 template<typename Dummy = value_type, typename = std::enable_if_t<std::is_default_constructible_v<Dummy>>>
28 constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<value_type>) {}
29
30 template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
31 constexpr compressed_pair_element(Arg&& arg) noexcept(std::is_nothrow_constructible_v<value_type, Arg>)
32 : _value{std::forward<Arg>(arg)} { }
33
34 template<typename... Args, std::size_t... Index>
35 constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<value_type, Args...>)
36 : _value{std::forward<Args>(std::get<Index>(args))...} { }
37
38 [[nodiscard]] constexpr auto get() noexcept -> reference {
39 return _value;
40 }
41
42 [[nodiscard]] constexpr auto get() const noexcept -> const_reference {
43 return _value;
44 }
45
46private:
47
48 value_type _value{};
49
50}; // struct compressed_pair_element
51
52template<typename Type, std::size_t Tag>
53class compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>> : public Type {
54
55public:
56
57 using value_type = Type;
58 using reference = value_type&;
59 using const_reference = const value_type&;
60 using base_type = Type;
61
62 template<typename Dummy = value_type, typename = std::enable_if_t<std::is_default_constructible_v<Dummy>>>
63 constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>)
64 : base_type{} { }
65
66 template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
67 constexpr compressed_pair_element(Arg&& arg) noexcept(std::is_nothrow_constructible_v<base_type, Arg>)
68 : base_type{std::forward<Arg>(arg)} { }
69
70 template<typename... Args, std::size_t... Index>
71 constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<base_type, Args...>)
72 : base_type{std::forward<Args>(std::get<Index>(args))...} {}
73
74 [[nodiscard]] constexpr auto get() noexcept -> reference {
75 return *this;
76 }
77
78 [[nodiscard]] constexpr auto get() const noexcept -> const_reference {
79 return *this;
80 }
81
82}; // struct compressed_pair_element
83
84} // namespace detail
85
86template<typename First, typename Second>
88
91
92public:
93
94 using first_type = First;
95 using second_type = Second;
96
97 template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
98 constexpr compressed_pair() noexcept(std::is_nothrow_default_constructible_v<first_base> && std::is_nothrow_default_constructible_v<second_base>)
99 : first_base{},
100 second_base{} { }
101
102 constexpr compressed_pair(const compressed_pair &other) = default;
103
104 constexpr compressed_pair(compressed_pair &&other) noexcept = default;
105
106 template<typename Arg, typename Other>
107 constexpr compressed_pair(Arg&& arg, Other&& other) noexcept(std::is_nothrow_constructible_v<first_base, Arg> && std::is_nothrow_constructible_v<second_base, Other>)
108 : first_base{std::forward<Arg>(arg)},
109 second_base{std::forward<Other>(other)} { }
110
111 template<typename... Args, typename... Other>
112 constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other) noexcept(std::is_nothrow_constructible_v<first_base, Args...> && std::is_nothrow_constructible_v<second_base, Other...>)
113 : first_base{std::move(args), std::index_sequence_for<Args...>{}},
114 second_base{std::move(other), std::index_sequence_for<Other...>{}} { }
115
116 ~compressed_pair() = default;
117
118 constexpr compressed_pair &operator=(const compressed_pair &other) = default;
119
120 constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default;
121
122 [[nodiscard]] constexpr auto first() noexcept -> first_type& {
123 return static_cast<first_base&>(*this).get();
124 }
125
126 [[nodiscard]] constexpr auto first() const noexcept -> const first_type& {
127 return static_cast<const first_base&>(*this).get();
128 }
129
130 [[nodiscard]] constexpr auto second() noexcept -> second_type& {
131 return static_cast<second_base&>(*this).get();
132 }
133
134 [[nodiscard]] constexpr auto second() const noexcept -> const second_type& {
135 return static_cast<const second_base&>(*this).get();
136 }
137
138 constexpr void swap(compressed_pair &other) noexcept {
139 using std::swap;
140 swap(first(), other.first());
141 swap(second(), other.second());
142 }
143 template<std::size_t Index>
144 [[nodiscard]] constexpr auto get() noexcept -> decltype(auto) {
145 if constexpr (Index == 0u) {
146 return first();
147 } else {
148 static_assert(Index == 1u, "Index out of bounds");
149 return second();
150 }
151 }
152
154 template<std::size_t Index>
155 [[nodiscard]] constexpr auto get() const noexcept -> decltype(auto) {
156 if constexpr (Index == 0u) {
157 return first();
158 } else {
159 static_assert(Index == 1u, "Index out of bounds");
160 return second();
161 }
162 }
163
164}; // class compressed_pair
165
166template<typename Type, typename Other>
167compressed_pair(Type&&, Other&&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>;
168
169template<typename First, typename Second>
170constexpr auto swap(compressed_pair<First, Second>& lhs, compressed_pair<First, Second>& rhs) noexcept -> void {
171 lhs.swap(rhs);
172}
173
174} // namespace sbx::containers
175
176template<typename First, typename Second>
177struct std::tuple_size<sbx::containers::compressed_pair<First, Second>> : std::integral_constant<std::size_t, 2u> { };
178
179template<std::size_t Index, typename First, typename Second>
180struct std::tuple_element<Index, sbx::containers::compressed_pair<First, Second>> : std::conditional<Index == 0u, First, Second> {
181 static_assert(Index < 2u, "Index out of bounds");
182}; // struct std::tuple_element
183
184#endif // LIBSBX_CONTAINERS_COMPRESSED_PAIR_HPP_
Definition: compressed_pair.hpp:87
constexpr auto get() const noexcept -> decltype(auto)
Definition: compressed_pair.hpp:155
Definition: compressed_pair.hpp:19
Definition: compressed_pair.hpp:13