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

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

cpp: resolved conflict between tuple constructors when sizeof…(Ts) == 0

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