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

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

cpp: fixed and operators in noexcept metafunctions

  • Property mode set to 100644
File size: 14.2 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>
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>::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>::swap(lhs, rhs);
307 }
308
309 // TODO: for rel ops we will need this to be ascending, not descending
310 template<class T, class U>
311 static bool eq(const T& lhs, const T& rhs)
312 {
313 return (get<I>(lhs) == get<I>(rhs)) && tuple_ops<I - 1>::eq(lhs, rhs);
314 }
315 };
316
317 template<>
318 struct tuple_ops<0>
319 {
320 template<class T, class U>
321 static void assign(T&& lhs, U&& rhs)
322 {
323 get<0>(forward<T>(lhs)) = get<0>(forward<U>(rhs));
324 }
325
326 template<class T, class U>
327 static void swap(T& lhs, U& rhs)
328 {
329 std::swap(get<0>(lhs), get<0>(rhs));
330 }
331 };
332 }
333
334 /**
335 * 20.4.2, class template tuple:
336 */
337
338
339 template<class... Ts>
340 class tuple: public aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>
341 {
342 using base_t = aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>;
343
344 public:
345
346 /**
347 * 20.4.2.1, tuple construction:
348 */
349
350 constexpr tuple()
351 : base_t{}
352 { /* DUMMY BODY */ }
353
354 constexpr explicit tuple(const Ts&... ts)
355 : base_t(ts...)
356 { /* DUMMY BODY */ }
357
358 template<class... Us>
359 constexpr explicit tuple(Us&&... us)
360 : base_t(forward<Us>(us)...)
361 { /* DUMMY BODY */ }
362
363 tuple(const tuple&) = default;
364 tuple(tuple&&) = default;
365
366 /* template<class... Us> */
367 /* constexpr tuple(const tuple<Us...>& tpl) */
368 /* : base_t(tpl) */
369 //{ /* DUMMY BODY */ }
370
371 /* template<class... Us> */
372 /* constexpr tuple(tuple<Us...>& tpl) */
373 /* : base_t(forward<tuple<Us>>(tpl)...) */
374 //{ /* DUMMY BODY */ }
375
376 template<class U1, class U2, class = enable_if_t<sizeof...(Ts) == 2, void>>
377 constexpr tuple(const pair<U1, U2>& p)
378 : base_t{}
379 {
380 get<0>(*this) = p.first;
381 get<1>(*this) = p.second;
382 }
383
384 template<class U1, class U2, class = enable_if_t<sizeof...(Ts) == 2, void>>
385 constexpr tuple(pair<U1, U2>&& p)
386 : base_t{}
387 {
388 get<0>(*this) = forward<U1>(p.first);
389 get<1>(*this) = forward<U2>(p.second);
390 }
391
392 // TODO: allocator-extended constructors
393
394 /**
395 * 20.4.2.2, tuple assignment:
396 */
397
398 tuple& operator=(const tuple& other)
399 {
400 aux::tuple_ops<sizeof...(Ts) - 1>::assign(*this, other);
401
402 return *this;
403 }
404
405 tuple& operator=(tuple&& other) noexcept(aux::tuple_noexcept_assignment<Ts...>::value)
406 {
407 aux::tuple_ops<sizeof...(Ts) - 1>::assign(*this, forward<tuple>(other));
408
409 return *this;
410 }
411
412 template<class... Us>
413 tuple& operator=(const tuple<Us...>& other)
414 {
415 aux::tuple_ops<sizeof...(Ts) - 1>::assign(*this, other);
416
417 return *this;
418 }
419
420 template<class... Us>
421 tuple& operator=(tuple<Us...>&& other)
422 {
423 aux::tuple_ops<sizeof...(Ts) - 1>::assign(*this, forward<Us>(other)...);
424
425 return *this;
426 }
427
428 template<class U1, class U2, class = enable_if_t<sizeof...(Ts) == 2, void>>
429 tuple& operator=(const pair<U1, U2>& p)
430 {
431 get<0>(*this) = p.first;
432 get<1>(*this) = p.second;
433 }
434
435 template<class U1, class U2, class = enable_if_t<sizeof...(Ts) == 2, void>>
436 tuple& operator=(pair<U1, U2>&& p)
437 {
438 get<0>(*this) = forward<U1>(p.first);
439 get<1>(*this) = forward<U2>(p.second);
440 }
441
442 /**
443 * 20.4.2.3, tuple swap:
444 */
445
446 void swap(tuple& other) noexcept(aux::tuple_noexcept_swap<Ts...>::value)
447 {
448 aux::tuple_ops<sizeof...(Ts) - 1>::swap(*this, other);
449 }
450 };
451
452 /**
453 * 20.4.2.7, relational operators:
454 */
455
456 template<class... Ts, class... Us>
457 constexpr bool operator==(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
458
459 template<class... Ts, class... Us>
460 constexpr bool operator<(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
461
462 template<class... Ts, class... Us>
463 constexpr bool operator!=(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
464
465 template<class... Ts, class... Us>
466 constexpr bool operator>(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
467
468 template<class... Ts, class... Us>
469 constexpr bool operator<=(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
470
471 template<class... Ts, class... Us>
472 constexpr bool operator>=(const tuple<Ts...>& lhs, const tuple<Us...> rhs);
473
474 /**
475 * 20.4.2.8, allocator-related traits:
476 */
477
478 template<class...>
479 struct uses_allocator;
480
481 template<class... Ts, class Alloc>
482 struct uses_allocator<tuple<Ts...>, Alloc>: true_type
483 { /* DUMMY BODY */ };
484
485 /**
486 * 20.4.2.9, specialized algorithms:
487 */
488
489 template<class... Ts>
490 void swap(tuple<Ts...>& lhs, tuple<Ts...>& rhs)
491 noexcept(noexcept(lhs.swap(rhs)))
492 {
493 lhs.swap(rhs);
494 }
495}
496
497#endif
Note: See TracBrowser for help on using the repository browser.