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

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

cpp: split too big files into smaller (loosely related) sub files

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