source: mainline/uspace/lib/cpp/include/impl/tuple.hpp@ 55cd829

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 55cd829 was 55cd829, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: added tuple relational operators, changed tuple_ops to be ascending and removed enable_ifs on pair related constructors and assignment operators that weren't supposed to be there

  • Property mode set to 100644
File size: 15.1 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_TUPLE
30#define LIBCPP_TUPLE
31
32#include <internal/aux.hpp>
33#include <functional>
34#include <type_traits>
35#include <utility>
36
37namespace std
38{
39 template<class... Ts>
40 class tuple;
41
42 /**
43 * 20.4.2.4, tuple creation functions:
44 */
45
46 namespace aux
47 {
48 struct ignore_t
49 {
50 template<class T>
51 const ignore_t& operator=(const T&) const
52 {
53 return *this;
54 }
55 };
56 }
57
58 inline constexpr aux::ignore_t ignore;
59
60 namespace aux
61 {
62 template<class T>
63 struct remove_reference_wrapper: type_is<T>
64 { /* DUMMY BODY */ };
65
66 template<class T>
67 struct remove_reference_wrapper<reference_wrapper<T>>: type_is<T&>
68 { /* DUMMY BODY */ };
69
70 template<class T>
71 using remove_reference_wrapper_t = typename remove_reference_wrapper<T>::type;
72
73 template<class T>
74 using transform_tuple_types_t = remove_reference_wrapper_t<decay_t<T>>;
75 }
76
77 template<class... Ts> // TODO: test the reference_wrapper version once we got reference_wrapper
78 constexpr auto make_tuple(Ts&&... ts)
79 {
80 return tuple<aux::transform_tuple_types_t<Ts>...>(forward<Ts>(ts)...);
81 }
82
83 template<class... Ts>
84 constexpr tuple<Ts&&...> forward_as_tuple(Ts&&... ts) noexcept
85 {
86 return tuple<Ts&&...>(forward<Ts>(ts)...);
87 }
88
89 template<class... Ts>
90 constexpr tuple<Ts&...> tie(Ts&... ts) noexcept
91 {
92 return tuple<Ts&...>(ts...);
93 }
94
95 template<class... Tuples> // TODO: dafuq is ctypes?
96 constexpr tuple<Tuples...> tuple_cat(Tuples&&... tpls);
97
98 /**
99 * 20.4.2.5, tuple helper classes:
100 */
101
102 template<class T>
103 class tuple_size; // undefined
104
105 template<class T>
106 class tuple_size<const T>
107 : public integral_constant<size_t, tuple_size<T>::value>
108 { /* DUMMY BODY */ };
109
110 template<class T>
111 class tuple_size<volatile T>
112 : public integral_constant<size_t, tuple_size<T>::value>
113 { /* DUMMY BODY */ };
114
115 template<class T>
116 class tuple_size<const volatile T>
117 : public integral_constant<size_t, tuple_size<T>::value>
118 { /* DUMMY BODY */ };
119
120 template<class... Ts>
121 class tuple_size<tuple<Ts...>>
122 : public integral_constant<size_t, sizeof...(Ts)>
123 { /* DUMMY BODY */ };
124
125 template<class T>
126 inline constexpr size_t tuple_size_v = tuple_size<T>::value;
127
128 template<size_t I, class T>
129 class tuple_element; // undefined
130
131 template<size_t I, class T>
132 class tuple_element<I, const T>
133 {
134 using type = add_const_t<typename tuple_element<I, T>::type>;
135 };
136
137 template<size_t I, class T>
138 class tuple_element<I, volatile T>
139 {
140 using type = add_volatile_t<typename tuple_element<I, T>::type>;
141 };
142
143 template<size_t I, class T>
144 class tuple_element<I, const volatile T>
145 {
146 using type = add_cv_t<typename tuple_element<I, T>::type>;
147 };
148
149 namespace aux
150 {
151 template<size_t I, class T, class... Ts>
152 struct type_at: type_at<I - 1, Ts...>
153 { /* DUMMY BODY */ };
154
155 template<class T, class... Ts>
156 struct type_at<0, T, Ts...>
157 {
158 using type = T;
159 };
160
161 template<size_t I, class... Ts>
162 using type_at_t = typename type_at<I, Ts...>::type;
163 }
164
165 template<size_t I, class... Ts>
166 class tuple_element<I, tuple<Ts...>>
167 {
168 public:
169 using type = aux::type_at_t<I, Ts...>;
170 };
171
172 template<size_t I, class T>
173 using tuple_element_t = typename tuple_element<I, T>::type;
174
175 namespace aux
176 {
177 template<size_t I, class T>
178 struct tuple_element_wrapper
179 {
180 constexpr tuple_element_wrapper() = default;
181
182 constexpr explicit tuple_element_wrapper(T val)
183 : value{val}
184 { /* DUMMY BODY */ }
185
186 T value;
187 };
188
189 template<class, class...>
190 class tuple_impl; // undefined
191
192 template<size_t... Is, class... Ts>
193 class tuple_impl<index_sequence<Is...>, Ts...>: public tuple_element_wrapper<Is, Ts>...
194 {
195 public:
196 constexpr tuple_impl()
197 : tuple_element_wrapper<Is, Ts>{}...
198 { /* DUMMY BODY */ }
199
200 constexpr explicit tuple_impl(const Ts&... ts)
201 : tuple_element_wrapper<Is, Ts>(ts)...
202 { /* DUMMY BODY */ }
203 };
204
205 template<class T, class... Ts>
206 struct tuple_noexcept_swap
207 {
208 static constexpr bool value = noexcept(std::swap(declval<T&>(), declval<T&>()))
209 && tuple_noexcept_swap<Ts...>::value;
210 };
211
212 template<class T>
213 struct tuple_noexcept_swap<T>
214 {
215 static constexpr bool value = noexcept(std::swap(declval<T&>(), declval<T&>()));
216 };
217
218 template<class T, class... Ts>
219 struct tuple_noexcept_assignment
220 {
221 static constexpr bool value = is_nothrow_move_assignable<T>::value
222 && tuple_noexcept_assignment<Ts...>::value;
223 };
224
225 template<class T>
226 struct tuple_noexcept_assignment<T>
227 {
228 static constexpr bool value = is_nothrow_move_assignable<T>::value;
229 };
230 }
231
232 /**
233 * 20.4.2.6, element access:
234 */
235
236 template<size_t I, class... Ts>
237 constexpr tuple_element_t<I, tuple<Ts...>>& get(tuple<Ts...>& tpl) noexcept
238 {
239 aux::tuple_element_wrapper<I, tuple_element_t<I, tuple<Ts...>>>& wrapper = tpl;
240
241 return wrapper.value;
242 }
243
244 template<size_t I, class... Ts>
245 constexpr tuple_element_t<I, tuple<Ts...>>&& get(tuple<Ts...>&& tpl) noexcept
246 {
247 return forward<typename tuple_element<I, tuple<Ts...>>::type&&>(get<I>(tpl));
248 }
249
250 template<size_t I, class... Ts>
251 constexpr const tuple_element_t<I, tuple<Ts...>>& get(const tuple<Ts...>& tpl) noexcept
252 {
253 const aux::tuple_element_wrapper<I, tuple_element_t<I, tuple<Ts...>>>& wrapper = tpl;
254
255 return wrapper.value;
256 }
257
258
259 namespace aux
260 {
261 template<size_t I, class U, class T, class... Ts>
262 struct index_of_type: index_of_type<I + 1, U, Ts...>
263 { /* DUMMY BODY */ };
264
265 template<size_t I, class T, class... Ts>
266 struct index_of_type<I, T, T, Ts...>: std::integral_constant<std::size_t, I>
267 { /* DUMMY BODY */ };
268 }
269
270 template<class T, class... Ts>
271 constexpr T& get(tuple<Ts...>& tpl) noexcept
272 {
273 return get<aux::index_of_type<0, T, Ts...>::value>(tpl);
274 }
275
276 template<class T, class... Ts>
277 constexpr T&& get(tuple<Ts...>&& tpl) noexcept
278 {
279 return get<aux::index_of_type<0, T, Ts...>::value>(forward<tuple<Ts...>>(tpl));
280 }
281
282 template<class T, class... Ts>
283 constexpr const T& get(const tuple<Ts...>& tpl) noexcept
284 {
285 return get<aux::index_of_type<0, T, Ts...>::value>(tpl);
286 }
287
288 namespace aux
289 {
290 template<size_t I, size_t N>
291 struct tuple_ops
292 {
293 template<class T, class U>
294 static void assign(T&& lhs, U&& rhs)
295 {
296 get<I>(forward<T>(lhs)) = get<I>(forward<U>(rhs));
297
298 tuple_ops<I + 1, N>::assign(forward<T>(lhs), forward<U>(rhs));
299 }
300
301 template<class T, class U>
302 static void swap(T& lhs, U& rhs)
303 {
304 std::swap(get<I>(lhs), get<I>(rhs));
305
306 tuple_ops<I + 1, N>::swap(lhs, rhs);
307 }
308
309 template<class T, class U>
310 static bool eq(const T& lhs, const U& rhs)
311 {
312 return (get<I>(lhs) == get<I>(rhs)) && tuple_ops<I + 1, N>::eq(lhs, rhs);
313 }
314
315 template<class T, class U>
316 static bool lt(const T& lhs, const U& rhs)
317 {
318 return (get<I>(lhs) < get<I>(rhs)) ||
319 (!(get<I>(rhs) < get<I>(lhs)) && tuple_ops<I + 1, N>::lt(lhs, rhs));
320 }
321 };
322
323 template<size_t N>
324 struct tuple_ops<N, N>
325 {
326 template<class T, class U>
327 static void assign(T&& lhs, U&& rhs)
328 {
329 get<N>(forward<T>(lhs)) = get<N>(forward<U>(rhs));
330 }
331
332 template<class T, class U>
333 static void swap(T& lhs, U& rhs)
334 {
335 std::swap(get<N>(lhs), get<N>(rhs));
336 }
337
338 template<class T, class U>
339 static bool eq(const T& lhs, const U& rhs)
340 {
341 return get<N>(lhs) == get<N>(rhs);
342 }
343
344 template<class T, class U>
345 static bool lt(const T& lhs, const U& rhs)
346 {
347 return get<N>(lhs) < get<N>(rhs);
348 }
349 };
350 }
351
352 /**
353 * 20.4.2, class template tuple:
354 */
355
356
357 template<class... Ts>
358 class tuple: public aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>
359 {
360 using base_t = aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>;
361
362 public:
363
364 /**
365 * 20.4.2.1, tuple construction:
366 */
367
368 constexpr tuple()
369 : base_t{}
370 { /* DUMMY BODY */ }
371
372 constexpr explicit tuple(const Ts&... ts)
373 : base_t(ts...)
374 { /* DUMMY BODY */ }
375
376 template<class... Us>
377 constexpr explicit tuple(Us&&... us)
378 : base_t(forward<Us>(us)...)
379 { /* DUMMY BODY */ }
380
381 tuple(const tuple&) = default;
382 tuple(tuple&&) = default;
383
384 /* template<class... Us> */
385 /* constexpr tuple(const tuple<Us...>& tpl) */
386 /* : base_t(tpl) */
387 //{ /* DUMMY BODY */ }
388
389 /* template<class... Us> */
390 /* constexpr tuple(tuple<Us...>& tpl) */
391 /* : base_t(forward<tuple<Us>>(tpl)...) */
392 //{ /* DUMMY BODY */ }
393
394 // TODO: pair related construction and assignment needs convertibility, not size
395 template<class U1, class U2>
396 constexpr tuple(const pair<U1, U2>& p)
397 : base_t{}
398 {
399 get<0>(*this) = p.first;
400 get<1>(*this) = p.second;
401 }
402
403 template<class U1, class U2>
404 constexpr tuple(pair<U1, U2>&& p)
405 : base_t{}
406 {
407 get<0>(*this) = forward<U1>(p.first);
408 get<1>(*this) = forward<U2>(p.second);
409 }
410
411 // TODO: allocator-extended constructors
412
413 /**
414 * 20.4.2.2, tuple assignment:
415 */
416
417 tuple& operator=(const tuple& other)
418 {
419 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, other);
420
421 return *this;
422 }
423
424 tuple& operator=(tuple&& other) noexcept(aux::tuple_noexcept_assignment<Ts...>::value)
425 {
426 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, forward<tuple>(other));
427
428 return *this;
429 }
430
431 template<class... Us>
432 tuple& operator=(const tuple<Us...>& other)
433 {
434 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, other);
435
436 return *this;
437 }
438
439 template<class... Us>
440 tuple& operator=(tuple<Us...>&& other)
441 {
442 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, forward<Us>(other)...);
443
444 return *this;
445 }
446
447 template<class U1, class U2>
448 tuple& operator=(const pair<U1, U2>& p)
449 {
450 get<0>(*this) = p.first;
451 get<1>(*this) = p.second;
452 }
453
454 template<class U1, class U2>
455 tuple& operator=(pair<U1, U2>&& p)
456 {
457 get<0>(*this) = forward<U1>(p.first);
458 get<1>(*this) = forward<U2>(p.second);
459 }
460
461 /**
462 * 20.4.2.3, tuple swap:
463 */
464
465 void swap(tuple& other) noexcept(aux::tuple_noexcept_swap<Ts...>::value)
466 {
467 aux::tuple_ops<0, sizeof...(Ts) - 1>::swap(*this, other);
468 }
469 };
470
471 /**
472 * 20.4.2.7, relational operators:
473 */
474
475 template<class... Ts, class... Us>
476 constexpr bool operator==(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
477 {
478 if constexpr (sizeof...(Ts) == 0)
479 return true;
480 else
481 return aux::tuple_ops<0, sizeof...(Ts) - 1>::eq(lhs, rhs);
482 }
483
484 template<class... Ts, class... Us>
485 constexpr bool operator<(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
486 {
487 if constexpr (sizeof...(Ts) == 0)
488 return false;
489 else
490 return aux::tuple_ops<0, sizeof...(Ts) - 1>::lt(lhs, rhs);
491 }
492
493 template<class... Ts, class... Us>
494 constexpr bool operator!=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
495 {
496 return !(lhs == rhs);
497 }
498
499 template<class... Ts, class... Us>
500 constexpr bool operator>(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
501 {
502 return rhs < lhs;
503 }
504
505 template<class... Ts, class... Us>
506 constexpr bool operator<=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
507 {
508 return !(rhs < lhs);
509 }
510
511 template<class... Ts, class... Us>
512 constexpr bool operator>=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
513 {
514 return !(lhs < rhs);
515 }
516
517 /**
518 * 20.4.2.8, allocator-related traits:
519 */
520
521 template<class...>
522 struct uses_allocator;
523
524 template<class... Ts, class Alloc>
525 struct uses_allocator<tuple<Ts...>, Alloc>: true_type
526 { /* DUMMY BODY */ };
527
528 /**
529 * 20.4.2.9, specialized algorithms:
530 */
531
532 template<class... Ts>
533 void swap(tuple<Ts...>& lhs, tuple<Ts...>& rhs)
534 noexcept(noexcept(lhs.swap(rhs)))
535 {
536 lhs.swap(rhs);
537 }
538}
539
540#endif
Note: See TracBrowser for help on using the repository browser.