source: mainline/uspace/lib/cpp/include/__bits/tuple/tuple.hpp@ 8fd0675f

Last change on this file since 8fd0675f was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2018 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_TUPLE
8#define LIBCPP_BITS_TUPLE
9
10#include <__bits/aux.hpp>
11#include <__bits/tuple/tuple_cat.hpp>
12#include <__bits/tuple/tuple_ops.hpp>
13#include <__bits/type_transformation.hpp>
14#include <functional>
15#include <type_traits>
16#include <utility>
17
18namespace std
19{
20 template<class... Ts>
21 class tuple;
22
23 /**
24 * 20.4.2.4, tuple creation functions:
25 */
26
27 namespace aux
28 {
29 struct ignore_t
30 {
31 template<class T>
32 const ignore_t& operator=(const T&) const
33 {
34 return *this;
35 }
36 };
37 }
38
39 inline constexpr aux::ignore_t ignore;
40
41 template<class... Ts> // TODO: test the reference_wrapper version once we got reference_wrapper
42 constexpr auto make_tuple(Ts&&... ts)
43 {
44 return tuple<aux::transform_tuple_types_t<Ts>...>(forward<Ts>(ts)...);
45 }
46
47 template<class... Ts>
48 constexpr tuple<Ts&&...> forward_as_tuple(Ts&&... ts) noexcept
49 {
50 return tuple<Ts&&...>(forward<Ts>(ts)...);
51 }
52
53 template<class... Ts>
54 constexpr tuple<Ts&...> tie(Ts&... ts) noexcept
55 {
56 return tuple<Ts&...>(ts...);
57 }
58
59 template<class... Tuples>
60 constexpr aux::tuple_cat_type_t<Tuples...> tuple_cat(Tuples&&... tpls)
61 { // TODO: currently does not work because of index mismatch
62 return aux::tuple_cat(
63 forward<Tuples>(tpls)...,
64 make_index_sequence<sizeof...(Tuples)>{},
65 aux::generate_indices_t<Tuples...>{}
66 );
67 }
68
69 /**
70 * 20.4.2.5, tuple helper classes:
71 */
72
73 template<class T>
74 class tuple_size; // undefined
75
76 template<class T>
77 class tuple_size<const T>
78 : public integral_constant<size_t, tuple_size<T>::value>
79 { /* DUMMY BODY */ };
80
81 template<class T>
82 class tuple_size<volatile T>
83 : public integral_constant<size_t, tuple_size<T>::value>
84 { /* DUMMY BODY */ };
85
86 template<class T>
87 class tuple_size<const volatile T>
88 : public integral_constant<size_t, tuple_size<T>::value>
89 { /* DUMMY BODY */ };
90
91 template<class... Ts>
92 class tuple_size<tuple<Ts...>>
93 : public integral_constant<size_t, sizeof...(Ts)>
94 { /* DUMMY BODY */ };
95
96 template<class T>
97 inline constexpr size_t tuple_size_v = tuple_size<T>::value;
98
99 template<size_t I, class T>
100 class tuple_element; // undefined
101
102 template<size_t I, class T>
103 class tuple_element<I, const T>
104 {
105 using type = add_const_t<typename tuple_element<I, T>::type>;
106 };
107
108 template<size_t I, class T>
109 class tuple_element<I, volatile T>
110 {
111 using type = add_volatile_t<typename tuple_element<I, T>::type>;
112 };
113
114 template<size_t I, class T>
115 class tuple_element<I, const volatile T>
116 {
117 using type = add_cv_t<typename tuple_element<I, T>::type>;
118 };
119
120 namespace aux
121 {
122 template<size_t I, class T, class... Ts>
123 struct type_at: type_at<I - 1, Ts...>
124 { /* DUMMY BODY */ };
125
126 template<class T, class... Ts>
127 struct type_at<0, T, Ts...>
128 {
129 using type = T;
130 };
131
132 template<size_t I, class... Ts>
133 using type_at_t = typename type_at<I, Ts...>::type;
134 }
135
136 template<size_t I, class... Ts>
137 class tuple_element<I, tuple<Ts...>>
138 {
139 public:
140 using type = aux::type_at_t<I, Ts...>;
141 };
142
143 template<size_t I, class T>
144 using tuple_element_t = typename tuple_element<I, T>::type;
145
146 namespace aux
147 {
148 template<size_t I, class T>
149 struct tuple_element_wrapper
150 {
151 constexpr tuple_element_wrapper() = default;
152
153 constexpr explicit tuple_element_wrapper(T&& val)
154 : value{forward<T>(val)}
155 { /* DUMMY BODY */ }
156
157 template<
158 class U,
159 class = enable_if_t<
160 is_convertible_v<U, T> && !is_same_v<U, T>,
161 void
162 >
163 >
164 constexpr explicit tuple_element_wrapper(U&& val)
165 : value(forward<U>(val))
166 { /* DUMMY BODY */ }
167
168 T value;
169 };
170
171 template<class, class...>
172 class tuple_impl; // undefined
173
174 template<size_t... Is, class... Ts>
175 class tuple_impl<index_sequence<Is...>, Ts...>: public tuple_element_wrapper<Is, Ts>...
176 {
177 public:
178 constexpr tuple_impl()
179 : tuple_element_wrapper<Is, Ts>{}...
180 { /* DUMMY BODY */ }
181
182 template<class... Us>
183 constexpr explicit tuple_impl(Us&&... us)
184 : tuple_element_wrapper<Is, Ts>(forward<Us>(us))...
185 { /* DUMMY BODY */ }
186
187 template<class... Us>
188 constexpr tuple_impl(const tuple<Us...>& tpl)
189 : tuple_impl{tpl, make_index_sequence<sizeof...(Us)>{}}
190 { /* DUMMY BODY */ }
191
192 template<class... Us>
193 constexpr tuple_impl(tuple<Us...>&& tpl)
194 : tuple_impl{move<tuple<Us...>>(tpl), make_index_sequence<sizeof...(Us)>{}}
195 { /* DUMMY BODY */ }
196
197 template<class... Us, size_t... Iss>
198 constexpr tuple_impl(const tuple<Us...>& tpl, index_sequence<Iss...>)
199 : tuple_impl{get<Iss>(tpl)...}
200 { /* DUMMY BODY */ }
201
202 template<class... Us, size_t... Iss>
203 constexpr tuple_impl(tuple<Us...>&& tpl, index_sequence<Iss...>)
204 : tuple_impl{get<Iss>(move(tpl))...}
205 { /* DUMMY BODY */ }
206 };
207
208 template<class T, class... Ts>
209 struct tuple_noexcept_swap
210 {
211 static constexpr bool value = noexcept(std::swap(declval<T&>(), declval<T&>()))
212 && tuple_noexcept_swap<Ts...>::value;
213 };
214
215 template<class T>
216 struct tuple_noexcept_swap<T>
217 {
218 static constexpr bool value = noexcept(std::swap(declval<T&>(), declval<T&>()));
219 };
220
221 template<class T, class... Ts>
222 struct tuple_noexcept_assignment
223 {
224 static constexpr bool value = is_nothrow_move_assignable<T>::value
225 && tuple_noexcept_assignment<Ts...>::value;
226 };
227
228 template<class T>
229 struct tuple_noexcept_assignment<T>
230 {
231 static constexpr bool value = is_nothrow_move_assignable<T>::value;
232 };
233 }
234
235 /**
236 * 20.4.2.6, element access:
237 */
238
239 template<size_t I, class... Ts>
240 constexpr tuple_element_t<I, tuple<Ts...>>& get(tuple<Ts...>& tpl) noexcept
241 {
242 aux::tuple_element_wrapper<I, tuple_element_t<I, tuple<Ts...>>>& wrapper = tpl;
243
244 return wrapper.value;
245 }
246
247 template<size_t I, class... Ts>
248 constexpr tuple_element_t<I, tuple<Ts...>>&& get(tuple<Ts...>&& tpl) noexcept
249 {
250 return forward<typename tuple_element<I, tuple<Ts...>>::type&&>(get<I>(tpl));
251 }
252
253 template<size_t I, class... Ts>
254 constexpr const tuple_element_t<I, tuple<Ts...>>& get(const tuple<Ts...>& tpl) noexcept
255 {
256 const aux::tuple_element_wrapper<I, tuple_element_t<I, tuple<Ts...>>>& wrapper = tpl;
257
258 return wrapper.value;
259 }
260
261 namespace aux
262 {
263 template<size_t I, class U, class T, class... Ts>
264 struct index_of_type: index_of_type<I + 1, U, Ts...>
265 { /* DUMMY BODY */ };
266
267 template<size_t I, class T, class... Ts>
268 struct index_of_type<I, T, T, Ts...>: std::integral_constant<std::size_t, I>
269 { /* DUMMY BODY */ };
270 }
271
272 template<class T, class... Ts>
273 constexpr T& get(tuple<Ts...>& tpl) noexcept
274 {
275 return get<aux::index_of_type<0, T, Ts...>::value>(tpl);
276 }
277
278 template<class T, class... Ts>
279 constexpr T&& get(tuple<Ts...>&& tpl) noexcept
280 {
281 return get<aux::index_of_type<0, T, Ts...>::value>(forward<tuple<Ts...>>(tpl));
282 }
283
284 template<class T, class... Ts>
285 constexpr const T& get(const tuple<Ts...>& tpl) noexcept
286 {
287 return get<aux::index_of_type<0, T, Ts...>::value>(tpl);
288 }
289
290 /**
291 * 20.4.2, class template tuple:
292 */
293
294 template<class... Ts>
295 class tuple: public aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>
296 {
297 using base_t = aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>;
298
299 public:
300
301 /**
302 * 20.4.2.1, tuple construction:
303 */
304
305 constexpr tuple()
306 : base_t{}
307 { /* DUMMY BODY */ }
308
309 constexpr explicit tuple(
310 const Ts&... ts, enable_if_t<sizeof...(Ts) != 0>* = nullptr)
311 : base_t(ts...)
312 { /* DUMMY BODY */ }
313
314 template<class... Us> // TODO: is_convertible == true for all Us to all Ts
315 constexpr explicit tuple(Us&&... us, enable_if_t<sizeof...(Us) == sizeof...(Ts)>* = nullptr)
316 : base_t(forward<Us>(us)...)
317 { /* DUMMY BODY */ }
318
319 tuple(const tuple&) = default;
320 tuple(tuple&&) = default;
321
322 template<class... Us>
323 constexpr tuple(const tuple<Us...>& tpl, enable_if_t<sizeof...(Us) == sizeof...(Ts)>* = nullptr)
324 : base_t(tpl)
325 { /* DUMMY BODY */ }
326
327 template<class... Us>
328 constexpr tuple(tuple<Us...>&& tpl, enable_if_t<sizeof...(Us) == sizeof...(Ts)>* = nullptr)
329 : base_t(move(tpl))
330 { /* DUMMY BODY */ }
331
332 // TODO: pair related construction and assignment needs convertibility, not size
333 template<class U1, class U2>
334 constexpr tuple(const pair<U1, U2>& p)
335 : base_t{}
336 {
337 get<0>(*this) = p.first;
338 get<1>(*this) = p.second;
339 }
340
341 template<class U1, class U2>
342 constexpr tuple(pair<U1, U2>&& p)
343 : base_t{}
344 {
345 get<0>(*this) = forward<U1>(p.first);
346 get<1>(*this) = forward<U2>(p.second);
347 }
348
349 // TODO: allocator-extended constructors
350
351 /**
352 * 20.4.2.2, tuple assignment:
353 */
354
355 tuple& operator=(const tuple& other)
356 {
357 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_copy(*this, other);
358
359 return *this;
360 }
361
362 tuple& operator=(tuple&& other) noexcept(aux::tuple_noexcept_assignment<Ts...>::value)
363 {
364 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_move(*this, move(other));
365
366 return *this;
367 }
368
369 template<class... Us>
370 tuple& operator=(const tuple<Us...>& other)
371 {
372 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_copy(*this, other);
373
374 return *this;
375 }
376
377 template<class... Us>
378 tuple& operator=(tuple<Us...>&& other)
379 {
380 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_move(*this, move(other));
381
382 return *this;
383 }
384
385 template<class U1, class U2>
386 tuple& operator=(const pair<U1, U2>& p)
387 {
388 get<0>(*this) = p.first;
389 get<1>(*this) = p.second;
390
391 return *this;
392 }
393
394 template<class U1, class U2>
395 tuple& operator=(pair<U1, U2>&& p)
396 {
397 get<0>(*this) = forward<U1>(p.first);
398 get<1>(*this) = forward<U2>(p.second);
399
400 return *this;
401 }
402
403 /**
404 * 20.4.2.3, tuple swap:
405 */
406
407 void swap(tuple& other) noexcept(aux::tuple_noexcept_swap<Ts...>::value)
408 {
409 aux::tuple_ops<0, sizeof...(Ts) - 1>::swap(*this, other);
410 }
411 };
412
413 template<>
414 class tuple<>
415 {
416 /**
417 * In some cases, e.g. for async() calls
418 * without argument to the functors, we need
419 * zero length tuples, which are provided by
420 * the following specialization.
421 * (Without it we get a resolution conflict between
422 * the default constructor and the Ts... constructor
423 * in the original tuple.)
424 */
425
426 tuple() = default;
427
428 void swap(tuple&) noexcept
429 { /* DUMMY BODY */ }
430 };
431
432 /**
433 * 20.4.2.7, relational operators:
434 */
435
436 template<class... Ts, class... Us>
437 constexpr bool operator==(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
438 {
439 if constexpr (sizeof...(Ts) == 0)
440 return true;
441 else
442 return aux::tuple_ops<0, sizeof...(Ts) - 1>::eq(lhs, rhs);
443 }
444
445 template<class... Ts, class... Us>
446 constexpr bool operator<(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
447 {
448 if constexpr (sizeof...(Ts) == 0)
449 return false;
450 else
451 return aux::tuple_ops<0, sizeof...(Ts) - 1>::lt(lhs, rhs);
452 }
453
454 template<class... Ts, class... Us>
455 constexpr bool operator!=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
456 {
457 return !(lhs == rhs);
458 }
459
460 template<class... Ts, class... Us>
461 constexpr bool operator>(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
462 {
463 return rhs < lhs;
464 }
465
466 template<class... Ts, class... Us>
467 constexpr bool operator<=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
468 {
469 return !(rhs < lhs);
470 }
471
472 template<class... Ts, class... Us>
473 constexpr bool operator>=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
474 {
475 return !(lhs < rhs);
476 }
477
478 /**
479 * 20.4.2.8, allocator-related traits:
480 */
481
482 template<class... Ts, class Alloc>
483 struct uses_allocator<tuple<Ts...>, Alloc>: true_type
484 { /* DUMMY BODY */ };
485
486 /**
487 * 20.4.2.9, specialized algorithms:
488 */
489
490 template<class... Ts>
491 void swap(tuple<Ts...>& lhs, tuple<Ts...>& rhs)
492 noexcept(noexcept(lhs.swap(rhs)))
493 {
494 lhs.swap(rhs);
495 }
496}
497
498#endif
Note: See TracBrowser for help on using the repository browser.