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

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

cpp: added pair::pair(piecewise_construct_t, …), but had to temporarily remove templated tuple constructor which needs is_convertible etc on variadic types

  • Property mode set to 100644
File size: 13.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 <internal/aux.hpp>
33#include <internal/tuple_cat.hpp>
34#include <internal/tuple_ops.hpp>
35#include <internal/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 {
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 constexpr explicit tuple_impl(Ts&&... ts)
205 : tuple_element_wrapper<Is, Ts>(forward<Ts>(ts))...
206 { /* DUMMY BODY */ }
207
208 // TODO: enable only if Us is convertible to Ts and they are not same
209 /* template<class... Us> */
210 /* constexpr explicit tuple_impl(Us&&... us) */
211 /* : tuple_element_wrapper<Is, Ts>(forward<Us>(us))... */
212 /* { /1* DUMMY BODY *1/ } */
213 };
214
215 template<class T, class... Ts>
216 struct tuple_noexcept_swap
217 {
218 static constexpr bool value = noexcept(std::swap(declval<T&>(), declval<T&>()))
219 && tuple_noexcept_swap<Ts...>::value;
220 };
221
222 template<class T>
223 struct tuple_noexcept_swap<T>
224 {
225 static constexpr bool value = noexcept(std::swap(declval<T&>(), declval<T&>()));
226 };
227
228 template<class T, class... Ts>
229 struct tuple_noexcept_assignment
230 {
231 static constexpr bool value = is_nothrow_move_assignable<T>::value
232 && tuple_noexcept_assignment<Ts...>::value;
233 };
234
235 template<class T>
236 struct tuple_noexcept_assignment<T>
237 {
238 static constexpr bool value = is_nothrow_move_assignable<T>::value;
239 };
240 }
241
242 /**
243 * 20.4.2.6, element access:
244 */
245
246 template<size_t I, class... Ts>
247 constexpr tuple_element_t<I, tuple<Ts...>>& get(tuple<Ts...>& tpl) noexcept
248 {
249 aux::tuple_element_wrapper<I, tuple_element_t<I, tuple<Ts...>>>& wrapper = tpl;
250
251 return wrapper.value;
252 }
253
254 template<size_t I, class... Ts>
255 constexpr tuple_element_t<I, tuple<Ts...>>&& get(tuple<Ts...>&& tpl) noexcept
256 {
257 return forward<typename tuple_element<I, tuple<Ts...>>::type&&>(get<I>(tpl));
258 }
259
260 template<size_t I, class... Ts>
261 constexpr const tuple_element_t<I, tuple<Ts...>>& get(const tuple<Ts...>& tpl) noexcept
262 {
263 const aux::tuple_element_wrapper<I, tuple_element_t<I, tuple<Ts...>>>& wrapper = tpl;
264
265 return wrapper.value;
266 }
267
268 namespace aux
269 {
270 template<size_t I, class U, class T, class... Ts>
271 struct index_of_type: index_of_type<I + 1, U, Ts...>
272 { /* DUMMY BODY */ };
273
274 template<size_t I, class T, class... Ts>
275 struct index_of_type<I, T, T, Ts...>: std::integral_constant<std::size_t, I>
276 { /* DUMMY BODY */ };
277 }
278
279 template<class T, class... Ts>
280 constexpr T& get(tuple<Ts...>& tpl) noexcept
281 {
282 return get<aux::index_of_type<0, T, Ts...>::value>(tpl);
283 }
284
285 template<class T, class... Ts>
286 constexpr T&& get(tuple<Ts...>&& tpl) noexcept
287 {
288 return get<aux::index_of_type<0, T, Ts...>::value>(forward<tuple<Ts...>>(tpl));
289 }
290
291 template<class T, class... Ts>
292 constexpr const T& get(const tuple<Ts...>& tpl) noexcept
293 {
294 return get<aux::index_of_type<0, T, Ts...>::value>(tpl);
295 }
296
297 /**
298 * 20.4.2, class template tuple:
299 */
300
301 template<class... Ts>
302 class tuple: public aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>
303 {
304 using base_t = aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>;
305
306 public:
307
308 /**
309 * 20.4.2.1, tuple construction:
310 */
311
312 constexpr tuple()
313 : base_t{}
314 { /* DUMMY BODY */ }
315
316 constexpr explicit tuple(const Ts&... ts)
317 : base_t(ts...)
318 { /* DUMMY BODY */ }
319
320 template<class... Us>
321 constexpr explicit tuple(Us&&... us)
322 : base_t(forward<Us>(us)...)
323 { /* DUMMY BODY */ }
324
325 tuple(const tuple&) = default;
326 tuple(tuple&&) = default;
327
328 template<class... Us>
329 constexpr tuple(const tuple<Us...>& tpl)
330 : base_t(tpl)
331 { /* DUMMY BODY */ }
332
333 template<class... Us>
334 constexpr tuple(tuple<Us...>&& tpl)
335 : base_t(forward<tuple<Us>>(tpl)...)
336 { /* DUMMY BODY */ }
337
338 // TODO: pair related construction and assignment needs convertibility, not size
339 template<class U1, class U2>
340 constexpr tuple(const pair<U1, U2>& p)
341 : base_t{}
342 {
343 get<0>(*this) = p.first;
344 get<1>(*this) = p.second;
345 }
346
347 template<class U1, class U2>
348 constexpr tuple(pair<U1, U2>&& p)
349 : base_t{}
350 {
351 get<0>(*this) = forward<U1>(p.first);
352 get<1>(*this) = forward<U2>(p.second);
353 }
354
355 // TODO: allocator-extended constructors
356
357 /**
358 * 20.4.2.2, tuple assignment:
359 */
360
361 tuple& operator=(const tuple& other)
362 {
363 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, other);
364
365 return *this;
366 }
367
368 tuple& operator=(tuple&& other) noexcept(aux::tuple_noexcept_assignment<Ts...>::value)
369 {
370 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, forward<tuple>(other));
371
372 return *this;
373 }
374
375 template<class... Us>
376 tuple& operator=(const tuple<Us...>& other)
377 {
378 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, other);
379
380 return *this;
381 }
382
383 template<class... Us>
384 tuple& operator=(tuple<Us...>&& other)
385 {
386 aux::tuple_ops<0, sizeof...(Ts) - 1>::assign(*this, forward<Us>(other)...);
387
388 return *this;
389 }
390
391 template<class U1, class U2>
392 tuple& operator=(const pair<U1, U2>& p)
393 {
394 get<0>(*this) = p.first;
395 get<1>(*this) = p.second;
396 }
397
398 template<class U1, class U2>
399 tuple& operator=(pair<U1, U2>&& p)
400 {
401 get<0>(*this) = forward<U1>(p.first);
402 get<1>(*this) = forward<U2>(p.second);
403 }
404
405 /**
406 * 20.4.2.3, tuple swap:
407 */
408
409 void swap(tuple& other) noexcept(aux::tuple_noexcept_swap<Ts...>::value)
410 {
411 aux::tuple_ops<0, sizeof...(Ts) - 1>::swap(*this, other);
412 }
413 };
414
415 /**
416 * 20.4.2.7, relational operators:
417 */
418
419 template<class... Ts, class... Us>
420 constexpr bool operator==(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
421 {
422 if constexpr (sizeof...(Ts) == 0)
423 return true;
424 else
425 return aux::tuple_ops<0, sizeof...(Ts) - 1>::eq(lhs, rhs);
426 }
427
428 template<class... Ts, class... Us>
429 constexpr bool operator<(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
430 {
431 if constexpr (sizeof...(Ts) == 0)
432 return false;
433 else
434 return aux::tuple_ops<0, sizeof...(Ts) - 1>::lt(lhs, rhs);
435 }
436
437 template<class... Ts, class... Us>
438 constexpr bool operator!=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
439 {
440 return !(lhs == rhs);
441 }
442
443 template<class... Ts, class... Us>
444 constexpr bool operator>(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
445 {
446 return rhs < lhs;
447 }
448
449 template<class... Ts, class... Us>
450 constexpr bool operator<=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
451 {
452 return !(rhs < lhs);
453 }
454
455 template<class... Ts, class... Us>
456 constexpr bool operator>=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
457 {
458 return !(lhs < rhs);
459 }
460
461 /**
462 * 20.4.2.8, allocator-related traits:
463 */
464
465 template<class...>
466 struct uses_allocator;
467
468 template<class... Ts, class Alloc>
469 struct uses_allocator<tuple<Ts...>, Alloc>: true_type
470 { /* DUMMY BODY */ };
471
472 /**
473 * 20.4.2.9, specialized algorithms:
474 */
475
476 template<class... Ts>
477 void swap(tuple<Ts...>& lhs, tuple<Ts...>& rhs)
478 noexcept(noexcept(lhs.swap(rhs)))
479 {
480 lhs.swap(rhs);
481 }
482}
483
484#endif
Note: See TracBrowser for help on using the repository browser.