tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
pair.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2020 Tobias Hienzsch
3
4#ifndef TETL_UTILITY_PAIR_HPP
5#define TETL_UTILITY_PAIR_HPP
6
7#include <etl/_tuple/is_tuple_like.hpp>
8#include <etl/_tuple/tuple_element.hpp>
9#include <etl/_tuple/tuple_size.hpp>
10#include <etl/_type_traits/common_reference.hpp>
11#include <etl/_type_traits/decay.hpp>
12#include <etl/_type_traits/integral_constant.hpp>
13#include <etl/_type_traits/is_assignable.hpp>
14#include <etl/_type_traits/is_constructible.hpp>
15#include <etl/_type_traits/is_convertible.hpp>
16#include <etl/_type_traits/is_copy_constructible.hpp>
17#include <etl/_type_traits/is_default_constructible.hpp>
18#include <etl/_type_traits/is_implicit_default_constructible.hpp>
19#include <etl/_type_traits/is_move_assignable.hpp>
20#include <etl/_type_traits/is_nothrow_swappable.hpp>
21#include <etl/_utility/forward.hpp>
22#include <etl/_utility/move.hpp>
23#include <etl/_utility/swap.hpp>
24
25namespace etl {
26
27/// \brief etl::pair is a class template that provides a way to store two
28/// heterogeneous objects as a single unit. A pair is a specific case of a
29/// etl::tuple with two elements. If neither T1 nor T2 is a possibly
30/// cv-qualified class type with non-trivial destructor, or array thereof, the
31/// destructor of pair is trivial.
32///
33/// https://en.cppreference.com/w/cpp/utility/pair
34///
35/// \ingroup utility
36template <typename T1, typename T2>
37struct pair {
38 using first_type = T1;
39 using second_type = T2;
40
41 /// \brief Default constructor. Value-initializes both elements.
42 explicit(
43 not is_implicit_default_constructible_v<T1> || not is_implicit_default_constructible_v<T2>
44 ) constexpr pair()
45 requires(is_default_constructible_v<T1> and is_default_constructible_v<T2>)
46 : first{}
47 , second{}
48 {
49 }
50
51 /// \brief Initializes first with x and second with y.
52 explicit(
53 not is_convertible_v<T1 const&, T1> or not is_convertible_v<T2 const&, T2>
54 ) constexpr pair(T1 const& t1, T2 const& t2)
55 requires(is_copy_constructible_v<T1> and is_copy_constructible_v<T2>)
56 : first(t1)
58 {
59 }
60
61 /// \brief Initializes first with forward<U1>(x) and second with forward<U2>(y).
62 template <typename U1 = T1, typename U2 = T2>
63 requires(is_constructible_v<T1, U1 &&> and is_constructible_v<T2, U2 &&>)
64 explicit(not is_convertible_v<U1&&, T1> || not is_convertible_v<U2&&, T2>) constexpr pair(U1&& x, U2&& y)
65 : first(etl::forward<U1>(x))
66 , second(etl::forward<U2>(y))
67 {
68 }
69
70 /// \brief Initializes first with p.first and second with p.second.
71 template <typename U1, typename U2>
72 requires(is_constructible_v<T1, U1 const&> and is_constructible_v<T2, U2 const&>)
73 explicit(not is_convertible_v<U1 const&, T1> or not is_convertible_v<U2 const&, T2>) constexpr pair(
74 pair<U1, U2> const& p
75 )
76 : first(p.first)
77 , second(p.second)
78 {
79 }
80
81 /// \brief Initializes first with forward<U1>(p.first) and second with forward<U2>(p.second).
82 template <typename U1, typename U2>
83 requires(is_constructible_v<T1, U1 &&> and is_constructible_v<T2, U2 &&>)
84 explicit(not is_convertible_v<U1&&, T1> || not is_convertible_v<U2&&, T2>) constexpr pair(pair<U1, U2>&& p)
85 : first(etl::forward<U1>(p.first))
86 , second(etl::forward<U2>(p.second))
87 {
88 }
89
90 /// \brief Copy constructor is defaulted, and is constexpr if copying of
91 /// both elements satisfies the requirements on constexpr functions.
92 constexpr pair(pair const& p) = default;
93
94 /// \brief Move constructor is defaulted, and is constexpr if moving of both
95 /// elements satisfies the requirements on constexpr functions.
96 constexpr pair(pair&& p) noexcept = default;
97
98 /// \brief Defaulted destructor.
99 ~pair() noexcept = default;
100
101 constexpr auto operator=(pair const& p) -> pair& = default;
102
103 template <typename U1, typename U2>
104 constexpr auto operator=(pair<U1, U2> const& p) -> pair&
105 requires((is_assignable_v<first_type&, U1 const&> and is_assignable_v<second_type&, U2 const&>))
106 {
107 first = p.first;
108 second = p.second;
109 return *this;
110 }
111
112 constexpr auto operator=(pair&& p) noexcept -> pair&
113 requires(is_move_assignable_v<first_type> and is_move_assignable_v<second_type>)
114 {
115 first = etl::move(p.first);
116 second = etl::move(p.second);
117 return *this;
118 }
119
120 template <typename U1, typename U2>
121 requires(is_assignable_v<first_type&, U1> and is_assignable_v<second_type&, U2>)
122 constexpr auto operator=(pair<U1, U2>&& p) -> pair&
123 {
124 first = etl::move(p.first);
125 second = etl::move(p.second);
126 return *this;
127 }
128
129 constexpr auto
131 {
132 using etl::swap;
133 swap(first, other.first);
134 swap(second, other.second);
135 }
136
139
140}; // namespace etl
141
142// One deduction guide is provided for pair to account for the edge
143// cases missed by the implicit deduction guides. In particular, non-copyable
144// arguments and array to pointer conversion.
145template <typename T1, typename T2>
146pair(T1, T2) -> pair<T1, T2>;
147
148template <typename T, typename U>
149inline constexpr auto is_tuple_like<etl::pair<T, U>> = true;
150
151/// \brief Swaps the contents of x and y. Equivalent to x.swap(y).
152template <typename T1, typename T2>
153constexpr auto swap(pair<T1, T2>& lhs, pair<T1, T2>& rhs) noexcept(noexcept(lhs.swap(rhs))) -> void
154{
155 lhs.swap(rhs);
156}
157
158/// \brief Creates a etl::pair object, deducing the target type from the types
159/// of arguments.
160///
161/// \details The deduced types V1 and V2 are etl::decay<T1>::type and
162/// etl::decay<T2>::type (the usual type transformations applied to arguments of
163/// functions passed by value).
164///
165/// https://en.cppreference.com/w/cpp/utility/pair/make_pair
166template <typename T1, typename T2>
167[[nodiscard]] constexpr auto make_pair(T1&& t, T2&& u) -> pair<decay_t<T1>, decay_t<T2>>
168{
169 return {etl::forward<T1>(t), etl::forward<T2>(u)};
170}
171
172/// \brief Tests if both elements of lhs and rhs are equal, that is, compares
173/// lhs.first with rhs.first and lhs.second with rhs.second.
174template <typename T1, typename T2>
175constexpr auto operator==(pair<T1, T2> const& lhs, pair<T1, T2> const& rhs) -> bool
176{
177 return (lhs.first == rhs.first) and (lhs.second == rhs.second);
178}
179
180/// \brief Compares lhs and rhs lexicographically by operator<, that is,
181/// compares the first elements and only if they are equivalent, compares the
182/// second elements.
183template <typename T1, typename T2>
184constexpr auto operator<(pair<T1, T2> const& lhs, pair<T1, T2> const& rhs) -> bool
185{
186 if (lhs.first < rhs.first) {
187 return true;
188 }
189 if (rhs.first < lhs.first) {
190 return false;
191 }
192 if (lhs.second < rhs.second) {
193 return true;
194 }
195 return false;
196}
197
198/// \brief Compares lhs and rhs lexicographically by operator<, that is,
199/// compares the first elements and only if they are equivalent, compares the
200/// second elements.
201template <typename T1, typename T2>
202constexpr auto operator<=(pair<T1, T2> const& lhs, pair<T1, T2> const& rhs) -> bool
203{
204 return !(rhs < lhs);
205}
206
207/// \brief Compares lhs and rhs lexicographically by operator<, that is,
208/// compares the first elements and only if they are equivalent, compares the
209/// second elements.
210template <typename T1, typename T2>
211constexpr auto operator>(pair<T1, T2> const& lhs, pair<T1, T2> const& rhs) -> bool
212{
213 return rhs < lhs;
214}
215
216/// \brief Compares lhs and rhs lexicographically by operator<, that is,
217/// compares the first elements and only if they are equivalent, compares the
218/// second elements.
219template <typename T1, typename T2>
220constexpr auto operator>=(pair<T1, T2> const& lhs, pair<T1, T2> const& rhs) -> bool
221{
222 return !(lhs < rhs);
223}
224
225/// \brief The partial specialization of tuple_size for pairs provides a
226/// compile-time way to obtain the number of elements in a pair, which is always
227/// 2, using tuple-like syntax.
228template <typename T1, typename T2>
229struct tuple_size<pair<T1, T2>> : integral_constant<size_t, 2> { };
230
231/// \brief The partial specializations of tuple_element for pairs provide
232/// compile-time access to the types of the pair's elements, using tuple-like
233/// syntax. The program is ill-formed if I >= 2.
234template <size_t I, typename T1, typename T2>
235struct tuple_element<I, pair<T1, T2>> {
236 static_assert(I < 2, "pair index out of range");
237 using type = conditional_t<I == 0, T1, T2>;
238};
239
240/// \brief Extracts an element from the pair using tuple-like interface.
241///
242/// \details The index-based overloads (1-4) fail to compile if the index I is
243/// neither 0 nor 1. See Alisdar Meredith talk "Recreational C++" 35:00 to
244/// 46:00. https://youtu.be/ovxNM865WaU
245template <size_t I, typename T1, typename T2>
246constexpr auto get(pair<T1, T2>& p) noexcept -> tuple_element_t<I, pair<T1, T2>>&
247{
248 if constexpr (I == 0) {
249 return p.first;
250 } else {
251 return p.second;
252 }
253}
254
255/// \brief Extracts an element from the pair using tuple-like interface.
256///
257/// \details The index-based overloads (1-4) fail to compile if the index I is
258/// neither 0 nor 1. See Alisdar Meredith talk "Recreational C++" 35:00 to
259/// 46:00. https://youtu.be/ovxNM865WaU
260template <size_t I, typename T1, typename T2>
261[[nodiscard]] constexpr auto get(pair<T1, T2> const& p) noexcept -> tuple_element_t<I, pair<T1, T2>> const&
262{
263 if constexpr (I == 0) {
264 return p.first;
265 } else {
266 return p.second;
267 }
268}
269
270/// \brief Extracts an element from the pair using tuple-like interface.
271///
272/// \details The index-based overloads (1-4) fail to compile if the index I is
273/// neither 0 nor 1. See Alisdar Meredith talk "Recreational C++" 35:00 to
274/// 46:00. https://youtu.be/ovxNM865WaU
275template <size_t I, typename T1, typename T2>
276[[nodiscard]] constexpr auto get(pair<T1, T2>&& p) noexcept -> tuple_element_t<I, pair<T1, T2>>&&
277{
278 if constexpr (I == 0) {
279 return etl::move(p.first);
280 } else {
281 return etl::move(p.second);
282 }
283}
284
285/// \brief Extracts an element from the pair using tuple-like interface.
286///
287/// \details The index-based overloads (1-4) fail to compile if the index I is
288/// neither 0 nor 1. See Alisdar Meredith talk "Recreational C++" 35:00 to
289/// 46:00. https://youtu.be/ovxNM865WaU
290template <size_t I, typename T1, typename T2>
291[[nodiscard]] constexpr auto get(pair<T1, T2> const&& p) noexcept -> tuple_element_t<I, pair<T1, T2>> const&&
292{
293 if constexpr (I == 0) {
294 return etl::move(p.first);
295 } else {
296 return etl::move(p.second);
297 }
298}
299
300template <
301 typename T1,
302 typename T2,
303 typename U1,
304 typename U2,
305 template <typename> typename TQual,
306 template <typename> typename UQual
307>
308 requires requires {
309 typename pair<common_reference_t<TQual<T1>, UQual<U1>>, common_reference_t<TQual<T2>, UQual<U2>>>;
310 }
311struct basic_common_reference<pair<T1, T2>, pair<U1, U2>, TQual, UQual> {
312 using type = pair<common_reference_t<TQual<T1>, UQual<U1>>, common_reference_t<TQual<T2>, UQual<U2>>>;
313};
314
315} // namespace etl
316
317#endif // TETL_UTILITY_PAIR_HPP
Definition adjacent_find.hpp:9
pair(T1, T2) -> pair< T1, T2 >
constexpr auto operator<(pair< T1, T2 > const &lhs, pair< T1, T2 > const &rhs) -> bool
Compares lhs and rhs lexicographically by operator<, that is, compares the first elements and only if...
Definition pair.hpp:184
constexpr auto get(pair< T1, T2 > const &p) noexcept -> tuple_element_t< I, pair< T1, T2 > > const &
Extracts an element from the pair using tuple-like interface.
Definition pair.hpp:261
constexpr auto operator==(pair< T1, T2 > const &lhs, pair< T1, T2 > const &rhs) -> bool
Tests if both elements of lhs and rhs are equal, that is, compares lhs.first with rhs....
Definition pair.hpp:175
constexpr auto operator<=(pair< T1, T2 > const &lhs, pair< T1, T2 > const &rhs) -> bool
Compares lhs and rhs lexicographically by operator<, that is, compares the first elements and only if...
Definition pair.hpp:202
constexpr auto swap(pair< T1, T2 > &lhs, pair< T1, T2 > &rhs) noexcept(noexcept(lhs.swap(rhs))) -> void
Swaps the contents of x and y. Equivalent to x.swap(y).
Definition pair.hpp:153
constexpr auto get(pair< T1, T2 > const &&p) noexcept -> tuple_element_t< I, pair< T1, T2 > > const &&
Extracts an element from the pair using tuple-like interface.
Definition pair.hpp:291
constexpr auto operator>=(pair< T1, T2 > const &lhs, pair< T1, T2 > const &rhs) -> bool
Compares lhs and rhs lexicographically by operator<, that is, compares the first elements and only if...
Definition pair.hpp:220
constexpr auto make_pair(T1 &&t, T2 &&u) -> pair< decay_t< T1 >, decay_t< T2 > >
Creates a etl::pair object, deducing the target type from the types of arguments.
Definition pair.hpp:167
constexpr auto get(pair< T1, T2 > &p) noexcept -> tuple_element_t< I, pair< T1, T2 > > &
Extracts an element from the pair using tuple-like interface.
Definition pair.hpp:246
constexpr auto operator>(pair< T1, T2 > const &lhs, pair< T1, T2 > const &rhs) -> bool
Compares lhs and rhs lexicographically by operator<, that is, compares the first elements and only if...
Definition pair.hpp:211
constexpr auto get(pair< T1, T2 > &&p) noexcept -> tuple_element_t< I, pair< T1, T2 > > &&
Extracts an element from the pair using tuple-like interface.
Definition pair.hpp:276
The class template basic_common_reference is a customization point that allows users to influence the...
Definition basic_common_reference.hpp:13
Definition integral_constant.hpp:10
etl::pair is a class template that provides a way to store two heterogeneous objects as a single unit...
Definition pair.hpp:37
U2 && y
Definition pair.hpp:66
explicit(not is_convertible_v< U1 &&, T1 >||not is_convertible_v< U2 &&, T2 >) const expr pair(pair< U1
Initializes first with forward<U1>(p.first) and second with forward<U2>(p.second).
T2 const & t2
Definition pair.hpp:57
U2 const & p
Definition pair.hpp:77
TETL_NO_UNIQUE_ADDRESS T2 second
Definition pair.hpp:138
U2 && p
Definition pair.hpp:86
TETL_NO_UNIQUE_ADDRESS T1 first
Definition pair.hpp:137
constexpr auto operator=(pair< U1, U2 > const &p) -> pair &requires((is_assignable_v< first_type &, U1 const & > and is_assignable_v< second_type &, U2 const & >))
Definition pair.hpp:104
explicit(not is_convertible_v< U1 const &, T1 > or not is_convertible_v< U2 const &, T2 >) const expr pair(pair< U1
Initializes first with p.first and second with p.second.
explicit(not is_convertible_v< U1 &&, T1 >||not is_convertible_v< U2 &&, T2 >) const expr pair(U1 &&x
Initializes first with forward<U1>(x) and second with forward<U2>(y).
constexpr auto operator=(pair const &p) -> pair &=default
constexpr auto operator=(pair &&p) noexcept -> pair &requires(is_move_assignable_v< first_type > and is_move_assignable_v< second_type >)
Definition pair.hpp:112
constexpr auto swap(pair &other) noexcept(is_nothrow_swappable_v< first_type > and is_nothrow_swappable_v< second_type >) -> void
Definition pair.hpp:130
explicit(not is_convertible_v< T1 const &, T1 > or not is_convertible_v< T2 const &, T2 >) const expr pair(T1 const &t1
Initializes first with x and second with y.
constexpr auto operator=(pair< U1, U2 > &&p) -> pair &
Definition pair.hpp:122
constexpr pair(pair const &p)=default
Copy constructor is defaulted, and is constexpr if copying of both elements satisfies the requirement...
~pair() noexcept=default
Defaulted destructor.
constexpr pair(pair &&p) noexcept=default
Move constructor is defaulted, and is constexpr if moving of both elements satisfies the requirements...