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