source: mainline/uspace/lib/cpp/include/impl/tuple.hpp@ 3d6f7f3

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

cpp: reorganized tuple header, added a WIP version of tuple_cat (mismatched indices at the moment)

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