GCC Code Coverage Report


Directory: include/kumi/
File: include/kumi/product_types/tuple.hpp
Date: 2026-10-14 16:33:56
Exec Total Coverage
Lines: 62 62 100.0%
Functions: 215 304 70.7%
Branches: 2 2 100.0%

Line Branch Exec Source
1 //======================================================================================================================
2 //! @file
3 /*
4 KUMI - Compact Tuple Tools
5 Copyright : KUMI Project Contributors
6 SPDX-License-Identifier: BSL-1.0
7 */
8 //======================================================================================================================
9 #pragma once
10
11 #include <kumi/product_types/shared.hpp>
12
13 namespace kumi
14 {
15 //====================================================================================================================
16 /**
17 @class tuple
18 @ingroup kumi_tuple_related
19 @brief Fixed-size collection of heterogeneous values.
20
21 kumi::tuple provides an aggregate based implementation of a tuple. It provides algorithms and
22 functions designed to facilitate tuple's handling and transformations.
23
24 kumi::tuple is also compatible with standard tuple operations and structured bindings.
25
26 @tparam Ts Sequence of types stored inside kumi::tuple.
27
28 @see @ref kumi_product_type
29
30 ## Example:
31 @include doc/tuple/api/introduction.cpp
32 **/
33 //====================================================================================================================
34 template<typename... Ts> struct tuple
35 {
36 using binder_t = kumi::_::make_binder_t<std::index_sequence_for<Ts...>, Ts...>;
37
38 static constexpr bool is_homogeneous = binder_t::is_homogeneous;
39
40 binder_t impl;
41
42 //==================================================================================================================
43 /**
44 @name Accessors
45 @{
46 **/
47 //==================================================================================================================
48
49 //==================================================================================================================
50 /**
51 @brief Extracts the Ith element from a kumi::tuple
52
53 @note Does not participate in overload resolution if `I` is not in [0, sizeof...(Ts)).
54 @param i Compile-time index of the element to access
55 @return A reference to the selected element of current tuple.
56
57 ## Example:
58 @include doc/tuple/api/subscript.cpp
59 **/
60 //==================================================================================================================
61 template<std::size_t I>
62 KUMI_ABI constexpr decltype(auto) operator[]([[maybe_unused]] kumi::index_t<I> i) & noexcept
63 requires(I < sizeof...(Ts))
64 {
65 2269 return impl(std::integral_constant<std::size_t, I>{});
66 }
67
68 /// @overload
69 template<std::size_t I>
70 KUMI_ABI constexpr decltype(auto) operator[](kumi::index_t<I>) && noexcept
71 requires(I < sizeof...(Ts))
72 {
73 1877 return static_cast<binder_t&&>(impl)(std::integral_constant<std::size_t, I>{});
74 }
75
76 /// @overload
77 template<std::size_t I>
78 KUMI_ABI constexpr decltype(auto) operator[](kumi::index_t<I>) const&& noexcept
79 requires(I < sizeof...(Ts))
80 {
81 25 return static_cast<binder_t const&&>(impl)(std::integral_constant<std::size_t, I>{});
82 }
83
84 /// @overload
85 template<std::size_t I>
86 KUMI_ABI constexpr decltype(auto) operator[](kumi::index_t<I>) const& noexcept
87 requires(I < sizeof...(Ts))
88 {
89 420427 return impl(std::integral_constant<std::size_t, I>{});
90 }
91
92 //==================================================================================================================
93 /**
94 @brief Extracts the element with type T from a kumi::tuple
95
96 @note Does not participate in overload resolution if `T` is not present in the tuple or if
97 the tuple contains duplicate types
98
99 @param type The type to access in the tuple
100 @return A reference to the selected element of the current tuple.
101
102 ## Example:
103 @include doc/tuple/api/typed_subscript.cpp
104 **/
105 //==================================================================================================================
106 template<typename T>
107 KUMI_ABI constexpr decltype(auto) operator[]([[maybe_unused]] kumi::as<T> type) & noexcept
108 requires(kumi::concepts::uniquely_typed<Ts...> && kumi::concepts::contains_type<T, Ts...>)
109 {
110 20 return impl(std::type_identity<T>{});
111 }
112
113 /// @overload
114 template<typename T>
115 KUMI_ABI constexpr decltype(auto) operator[](kumi::as<T>) && noexcept
116 requires(kumi::concepts::uniquely_typed<Ts...> && kumi::concepts::contains_type<T, Ts...>)
117 {
118 return static_cast<binder_t&&>(impl)(std::type_identity<T>{});
119 }
120
121 /// @overload
122 template<typename T>
123 KUMI_ABI constexpr decltype(auto) operator[](kumi::as<T>) const&& noexcept
124 requires(kumi::concepts::uniquely_typed<Ts...> && kumi::concepts::contains_type<T, Ts...>)
125 {
126 return static_cast<binder_t const&&>(impl)(std::type_identity<T>{});
127 }
128
129 /// @overload
130 template<typename T>
131 KUMI_ABI constexpr decltype(auto) operator[](kumi::as<T>) const& noexcept
132 requires(kumi::concepts::uniquely_typed<Ts...> && kumi::concepts::contains_type<T, Ts...>)
133 {
134 13 return impl(std::type_identity<T>{});
135 }
136
137 //==================================================================================================================
138 /**
139 @brief Extracts the element of the field labeled L from a kumi::tuple
140
141 @note Does not participate in overload resolution if the label is not present in the tuple
142
143 @param s label of the field to access
144 @return A reference to the element of the selected field of current tuple.
145
146 ## Example:
147 @include doc/tuple/api/labeled_subscript.cpp
148 **/
149 //==================================================================================================================
150 template<kumi::str L>
151 KUMI_ABI constexpr decltype(auto) operator[]([[maybe_unused]] kumi::label_t<L> s) & noexcept
152 requires(kumi::concepts::contains_label<kumi::label_t<L>, Ts...>)
153 {
154 8 return impl(std::integral_constant<kumi::str<L.size()>, L>{});
155 }
156
157 /// @overload
158 template<kumi::str L>
159 KUMI_ABI constexpr decltype(auto) operator[](kumi::label_t<L>) && noexcept
160 requires(kumi::concepts::contains_label<kumi::label_t<L>, Ts...>)
161 {
162 return static_cast<binder_t&&>(impl)(std::integral_constant<kumi::str<L.size()>, L>{});
163 }
164
165 /// @overload
166 template<kumi::str L>
167 KUMI_ABI constexpr decltype(auto) operator[](kumi::label_t<L>) const&& noexcept
168 requires(kumi::concepts::contains_label<kumi::label_t<L>, Ts...>)
169 {
170 return static_cast<binder_t const&&>(impl)(std::integral_constant<kumi::str<L.size()>, L>{});
171 }
172
173 /// @overload
174 template<kumi::str L>
175 KUMI_ABI constexpr decltype(auto) operator[](kumi::label_t<L>) const& noexcept
176 requires(kumi::concepts::contains_label<kumi::label_t<L>, Ts...>)
177 {
178 return impl(std::integral_constant<kumi::str<L.size()>, L>{});
179 }
180
181 //==================================================================================================================
182 /**
183 @brief Extracts the element whose identifier matches Id from a kumi::tuple
184
185 @note Does not participate in overload resolution if no field whose identifier matches Id is present in
186 the tuple or if the tuple contains duplicate identifiers.
187 @tparam Id Identifier of the element to access
188 @return A reference to the selected element of current tuple.
189
190 ## Example:
191 @include doc/tuple/api/named_subscript.cpp
192 **/
193 //==================================================================================================================
194 template<kumi::concepts::identifier Id>
195 KUMI_ABI constexpr decltype(auto) operator[](Id const&) & noexcept
196 requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::contains_identifier<Id, Ts...>)
197 {
198 40 return impl(kumi::_::tag_of_t<Id>{});
199 }
200
201 /// @overload
202 template<kumi::concepts::identifier Id>
203 KUMI_ABI constexpr decltype(auto) operator[](Id const&) && noexcept
204 requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::contains_identifier<Id, Ts...>)
205 {
206 2 return static_cast<binder_t&&>(impl)(kumi::_::tag_of_t<Id>{});
207 }
208
209 /// @overload
210 template<kumi::concepts::identifier Id>
211 KUMI_ABI constexpr decltype(auto) operator[](Id const&) const&& noexcept
212 requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::contains_identifier<Id, Ts...>)
213 {
214 return static_cast<binder_t const&&>(impl)(kumi::_::tag_of_t<Id>{});
215 }
216
217 /// @overload
218 template<kumi::concepts::identifier Id>
219 KUMI_ABI constexpr decltype(auto) operator[](Id const&) const& noexcept
220 requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::contains_identifier<Id, Ts...>)
221 {
222 19 return impl(kumi::_::tag_of_t<Id>{});
223 }
224
225 //==================================================================================================================
226 //! @}
227 //==================================================================================================================
228
229 //==================================================================================================================
230 /**
231 @name Properties
232 @{
233 **/
234 //==================================================================================================================
235
236 /// @return Returns the number of elements in a kumi::tuple
237 22 [[nodiscard]] KUMI_ABI static constexpr auto size() noexcept { return sizeof...(Ts); }
238
239 /// @return Returns `true` if a kumi::tuple contains 0 elements
240 [[nodiscard]] KUMI_ABI static constexpr bool empty() noexcept { return sizeof...(Ts) == 0; }
241
242 /// Returns the identifiers associated to the elements of a kumi::tuple
243 [[nodiscard]] KUMI_ABI static constexpr auto identifiers() noexcept
244 {
245 return kumi::tuple{kumi::identifier_of<Ts>()...};
246 }
247
248 /// Returns the labels associated to the elements of a kumi::tuple
249 [[nodiscard]] KUMI_ABI static constexpr auto labels() noexcept { return kumi::tuple{kumi::label_of<Ts>()...}; }
250
251 //==================================================================================================================
252 //! @}
253 //==================================================================================================================
254
255 //==================================================================================================================
256 /**
257 @name Conversions
258 @{
259 **/
260 //==================================================================================================================
261
262 //==================================================================================================================
263 /**
264 @brief Enables static casting a tuple<Ts...> to a tuple<Us...>, the conversion is explicit
265 if the casting requires internal explicit conversions.
266 @tparam Us Types composing the destination tuple
267
268 @note This function does not participate in overload resolution if the target tuple cannot be constructed
269 from the values of the source, if their size does not match or if they are the same type.
270 The conversion is explicit if the conversion of some member to the target needs to be explicit.
271
272 @qualifier explicit
273
274 This permits the conversion from a tuple<T>& to a tuple<T&> which makes it suitable
275 for some zip-like cases such as building a structure of arrays iterator.
276
277 ## Example :
278 @include doc/tuple/api/cast.cpp
279 @include doc/tuple/api/soa.cpp
280 **/
281 //==================================================================================================================
282 // nvcc with a clang host rejects [[nodiscard]] on a conversion operator once optimizing.
283 template<typename... Us>
284 KUMI_ABI
285 #ifndef KUMI_DOXYGEN_INVOKED
286 explicit(!kumi::_::piecewise_convertible<tuple<Ts const&...>, tuple<Us...>>)
287 #endif
288 constexpr operator tuple<Us...>() const
289 requires(sizeof...(Us) == sizeof...(Ts)) && (!std::same_as<tuple<Ts...>, tuple<Us...>>)
290 #ifndef KUMI_DOXYGEN_INVOKED
291 && (kumi::_::piecewise_constructible<tuple<Ts const&...>, tuple<Us...>>)
292 #endif
293 {
294 2 return kumi::_::static_cast_<tuple<Us...>>(*this, std::make_index_sequence<sizeof...(Ts)>{});
295 }
296
297 /// @overload
298 template<typename... Us>
299 KUMI_ABI
300 #ifndef KUMI_DOXYGEN_INVOKED
301 explicit(!kumi::_::piecewise_convertible<tuple<Ts&...>, tuple<Us...>>)
302 #endif
303 constexpr operator tuple<Us...>()
304 requires(sizeof...(Us) == sizeof...(Ts)) && (!std::same_as<tuple<Ts...>, tuple<Us...>>)
305 #ifndef KUMI_DOXYGEN_INVOKED
306 && (kumi::_::piecewise_constructible<tuple<Ts&...>, tuple<Us...>>)
307 #endif
308 {
309 4 return kumi::_::static_cast_<tuple<Us...>>(*this, std::make_index_sequence<sizeof...(Ts)>{});
310 }
311
312 //==================================================================================================================
313 //! @}
314 //==================================================================================================================
315
316 //==================================================================================================================
317 /**
318 @brief Replaces the contents of the tuple with the contents of another tuple.
319 @param other kumi::tuple to copy or move from
320 @return `*this`
321
322 @note This function does not participate in overload resolution if the members from the source tuple cannot
323 be converted to the members of the current tuple.
324 **/
325 //==================================================================================================================
326 template<typename... Us>
327 KUMI_ABI constexpr tuple& operator=(tuple<Us...> const& other)
328 #ifndef KUMI_DOXYGEN_INVOKED
329 requires(kumi::_::piecewise_convertible<tuple, tuple<Us...>>)
330 #endif
331 {
332 kumi::_::assign(*this, other, std::make_index_sequence<sizeof...(Ts)>{});
333 return *this;
334 }
335
336 /// @overload
337 template<typename... Us>
338 KUMI_ABI constexpr tuple& operator=(tuple<Us...>&& other)
339 #ifndef KUMI_DOXYGEN_INVOKED
340 requires(kumi::_::piecewise_convertible<tuple, tuple<Us...>>)
341 #endif
342 {
343
1/1
✓ Branch 1 taken 1 times.
2 kumi::_::assign(*this, other, std::make_index_sequence<sizeof...(Ts)>{});
344 2 return *this;
345 }
346 };
347
348 //====================================================================================================================
349 /**
350 @name Comparison operators
351 @related kumi::tuple
352 @{
353 **/
354 //====================================================================================================================
355
356 /// @brief Compares a tuple with another for equality
357 template<typename... Ts, typename... Us>
358 KUMI_ABI constexpr auto operator==(tuple<Ts...> const& self, tuple<Us...> const& other) noexcept
359 #ifndef KUMI_DOXYGEN_INVOKED
360 requires(sizeof...(Ts) > 0) && (kumi::_::piecewise_comparable<tuple<Ts...>, tuple<Us...>>)
361 #endif
362 {
363 32767 return kumi::_::compare(self, other, std::make_index_sequence<sizeof...(Ts)>{});
364 }
365
366 /// @brief Compares a tuple with another for inequality
367 template<typename... Ts, typename... Us>
368 KUMI_ABI constexpr auto operator!=(tuple<Ts...> const& self, tuple<Us...> const& other) noexcept
369 #ifndef KUMI_DOXYGEN_INVOKED
370 requires(sizeof...(Ts) > 0) && (kumi::_::piecewise_comparable<tuple<Ts...>, tuple<Us...>>)
371 #endif
372 {
373 return !(self == other);
374 }
375
376 /// @brief Compares tuples for the lexicographical less-than relation
377 /// @note This function does not participate in overload resolution if the tuples are not lexicographically ordered
378 template<typename... Ts, typename... Us>
379 KUMI_ABI constexpr auto operator<(tuple<Ts...> const& lhs, tuple<Us...> const& rhs) noexcept
380 requires(sizeof...(Ts) > 0 && sizeof...(Ts) == sizeof...(Us))
381 #ifndef KUMI_DOXYGEN_INVOKED
382 && (kumi::_::piecewise_ordered<tuple<Ts...>, tuple<Us...>>)
383 #endif
384 {
385 // lexicographical order is defined as
386 // (v0 < w0) || ... andnot(wi < vi, vi+1 < wi+1) ... || andnot(wn-1 < vn-1, vn < wn);
387 24369 return kumi::_::lexicographic_compare(lhs, rhs, std::make_index_sequence<sizeof...(Ts)>{});
388 }
389
390 /// @brief Compares tuples for the lexicographical less-than-or-equal relation
391 template<typename... Ts, typename... Us>
392 KUMI_ABI constexpr auto operator<=(tuple<Ts...> const& lhs, tuple<Us...> const& rhs) noexcept
393 requires requires { rhs < lhs; }
394 {
395 8122 return !(rhs < lhs);
396 }
397
398 /// @brief Compares tuples for the lexicographical greater-than relation
399 template<typename... Ts, typename... Us>
400 KUMI_ABI constexpr auto operator>(tuple<Ts...> const& lhs, tuple<Us...> const& rhs) noexcept
401 requires requires { rhs < lhs; }
402 {
403 8120 return rhs < lhs;
404 }
405
406 /// @brief Compares tuples for the lexicographical greater-than-or-equal relation
407 template<typename... Ts, typename... Us>
408 KUMI_ABI constexpr auto operator>=(tuple<Ts...> const& lhs, tuple<Us...> const& rhs) noexcept
409 requires requires { lhs < rhs; }
410 {
411 8120 return !(lhs < rhs);
412 }
413
414 //==================================================================================================================
415 //! @}
416 //==================================================================================================================
417
418 //==================================================================================================================
419 /**
420 @related kumi::tuple
421 @brief Inserts a kumi::tuple in an output stream
422 **/
423 //==================================================================================================================
424 template<typename CharT, typename Traits, typename... Ts>
425 requires(sizeof...(Ts) > 0)
426 371 std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, tuple<Ts...> const& t) noexcept
427 {
428 371 return kumi::_::print(os, t, '(', ',', ')', std::make_index_sequence<sizeof...(Ts) - 1>{});
429 }
430
431 template<> struct tuple<>
432 {
433 static constexpr bool is_homogeneous = false;
434
435 6 [[nodiscard]] KUMI_ABI static constexpr auto size() noexcept { return std::size_t{0}; }
436
437 [[nodiscard]] KUMI_ABI static constexpr auto empty() noexcept { return true; }
438
439 [[nodiscard]] KUMI_ABI static constexpr auto names() noexcept { return kumi::tuple{}; }
440
441 51 KUMI_ABI friend constexpr auto operator<=>(tuple<>, tuple<>) noexcept = default;
442
443 template<typename T>
444 [[nodiscard]] KUMI_ABI constexpr operator T() const noexcept
445 requires(kumi::concepts::unit_type<T>)
446 {
447 return {};
448 }
449
450 template<typename T>
451 [[nodiscard]] KUMI_ABI constexpr operator T() noexcept
452 requires(kumi::concepts::unit_type<T>)
453 {
454 return {};
455 }
456
457 template<typename CharT, typename Traits>
458 2 friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, tuple<>) noexcept
459 {
460 2 return os << "()";
461 }
462 };
463
464 //====================================================================================================================
465 /**
466 @name Tuple deduction guides
467 @{
468 **/
469 //====================================================================================================================
470
471 //====================================================================================================================
472 /**
473 @related kumi::tuple
474 @brief kumi::tuple deduction guide
475 @tparam Ts Type lists to build the tuple with.
476 **/
477 //====================================================================================================================
478 template<typename... Ts> tuple(Ts&&...) -> tuple<std::unwrap_ref_decay_t<Ts>...>;
479
480 //====================================================================================================================
481 //! @}
482 //====================================================================================================================
483
484 //====================================================================================================================
485 /**
486 @name Tuple construction
487 @{
488 **/
489 //====================================================================================================================
490
491 struct tie_t
492 {
493 template<typename... Ts> [[nodiscard]] KUMI_ABI constexpr kumi::tuple<Ts&...> operator()(Ts&... ts) const
494 {
495 14 return {ts...};
496 }
497 };
498
499 //====================================================================================================================
500 /**
501 @ingroup kumi_tuple_related
502
503 @var tie
504 @brief Creates a kumi::tuple of lvalue references to its arguments.
505
506 @qualifier inline
507 @qualifier constexpr
508 @qualifier nodiscard
509
510 @groupheader{Header file}
511 @code
512 #include <kumi/product_types/tuple.hpp>
513 @endcode
514
515 @groupheader{Call Signature}
516
517 @code
518 template<typename... Ts>
519 constexpr auto tie(Ts&... ts);
520 @endcode
521
522 @subgroupheader{Parameters}
523
524 - `ts`: Zero or more lvalue arguments to construct the tuple from.
525
526 @subgroupheader{Return value}
527
528 - A kumi::tuple object containing lvalue references.
529
530 @groupheader{Example}
531
532 @godbolt{doc/tuple/api/tie.cpp}
533
534 **/
535 //====================================================================================================================
536 KUMI_VARIABLE_ABI constexpr tie_t tie{};
537
538 struct forward_as_tuple_t
539 {
540 template<typename... Ts> [[nodiscard]] KUMI_ABI constexpr auto operator()(Ts&&... ts) const -> kumi::tuple<Ts&&...>
541 {
542 63 return {KUMI_FWD(ts)...};
543 }
544 };
545
546 //====================================================================================================================
547 /**
548 @ingroup kumi_tuple_related
549
550 @var forward_as_tuple
551 @brief Creates a kumi::tuple of forwarding references to its arguments.
552
553 Constructs a tuple of references to the arguments in ts suitable for forwarding as an
554 argument to a function. The tuple has rvalue reference data members when rvalues are used as
555 arguments, and otherwise has lvalue reference data members.
556
557 @note If the arguments are temporaries, `forward_as_tuple` does not extend their lifetime;
558 they have to be used before the end of the full expression.
559
560 @qualifier inline
561 @qualifier constexpr
562 @qualifier nodiscard
563
564 @groupheader{Header file}
565 @code
566 #include <kumi/product_types/tuple.hpp>
567 @endcode
568
569 @groupheader{Call Signature}
570
571 @code
572 template<typename... Ts>
573 constexpr auto forward_as_tuple(Ts&&... ts);
574 @endcode
575
576 @subgroupheader{Parameters}
577
578 - `ts`: Zero or more arguments to construct the tuple from.
579
580 @subgroupheader{Return value}
581
582 - A kumi::tuple constructed as `kumi::tuple<Ts&&...>(std::forward<Ts>(ts)...)`
583
584 @groupheader{Example}
585
586 @godbolt{doc/tuple/api/forward_as_tuple.cpp}
587
588 **/
589 //====================================================================================================================
590 KUMI_VARIABLE_ABI constexpr forward_as_tuple_t forward_as_tuple{};
591
592 struct make_tuple_t
593 {
594 template<typename... Ts>
595 [[nodiscard]] KUMI_ABI constexpr auto operator()(Ts&&... ts) const -> kumi::tuple<std::unwrap_ref_decay_t<Ts>...>
596 {
597 314 return {KUMI_FWD(ts)...};
598 3 }
599 };
600
601 //====================================================================================================================
602 /**
603 @ingroup kumi_tuple_related
604
605 @var make_tuple
606 @brief Creates a tuple object, deducing the target type from the types of arguments.
607
608 @qualifier inline
609 @qualifier constexpr
610 @qualifier nodiscard
611
612 @groupheader{Header file}
613 @code
614 #include <kumi/product_types/tuple.hpp>
615 @endcode
616
617 @groupheader{Call Signature}
618
619 @code
620 template<typename... Ts>
621 constexpr auto make_tuple(Ts&&... ts);
622 @endcode
623
624 @subgroupheader{Parameters}
625
626 - `ts`: Zero or more arguments to construct the tuple from.
627
628 @subgroupheader{Return value}
629
630 - A kumi::tuple constructed from the arguments or their inner references when an argument
631 is an instance of `std::reference_wrapper`.
632
633 @groupheader{Example}
634
635 @godbolt{doc/tuple/api/make_tuple.cpp}
636
637 **/
638 //====================================================================================================================
639 KUMI_VARIABLE_ABI constexpr make_tuple_t make_tuple{};
640
641 namespace _
642 {
643 template<kumi::concepts::product_type T, std::size_t... I>
644 18 KUMI_HIDDEN_ABI constexpr auto to_ref_(kumi::_::adl_tag_t, T&& t, std::index_sequence<I...>)
645 -> kumi::tuple<kumi::member_t<I, T>&&...>
646 {
647 65 return {get<I>(KUMI_FWD(t))...};
648 }
649 }
650
651 struct to_ref_t
652 {
653 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
654 {
655 24 return to_ref_(kumi::_::adl_tag, KUMI_FWD(t), std::make_index_sequence<kumi::size_v<T>>{});
656 }
657 };
658
659 //====================================================================================================================
660 /**
661 @ingroup kumi_transforms
662
663 @var to_ref
664 @brief Callable object creating a kumi::concepts::product_type of references given a reference to a
665 kumi::concepts::product_type.
666
667 If the input type matches the kumi::concepts::record_type protocol, return a kumi::record, returns a kumi::tuple
668 otherwise.
669
670 @qualifier inline
671 @qualifier constexpr
672 @qualifier noexcept
673 @qualifier nodiscard
674
675 @groupheader{Header file}
676 @code
677 #include <kumi/tuple.hpp>
678 @endcode
679
680 @groupheader{Call Signature}
681
682 @code
683 template<product_type T>
684 constexpr decltype(auto) to_ref(T && t) noexcept;
685 @endcode
686
687 @subgroupheader{Parameters}
688
689 - `t`: Product Type whose elements are to be referenced.
690
691 @subgroupheader{Return value}
692
693 - A kumi::concepts::product_type with each element being a reference to the corresponding element in the input.
694
695 @groupheader{Examples}
696
697 @godbolt{doc/tuple/api/to_ref.cpp}
698 **/
699 //====================================================================================================================
700 KUMI_VARIABLE_ABI constexpr to_ref_t to_ref{};
701
702 //====================================================================================================================
703 //! @}
704 //====================================================================================================================
705
706 //====================================================================================================================
707 /**
708 @name Tuple conversions
709 @{
710 **/
711 //====================================================================================================================
712
713 template<typename Type> struct from_tuple_t
714 {
715 private:
716 3 template<typename T, std::size_t... I> KUMI_HIDDEN_ABI constexpr Type impl(T&& t, std::index_sequence<I...>) const
717 {
718 5 return {get<I>(KUMI_FWD(t))...};
719 3 }
720
721 public:
722 template<typename... Ts>
723 [[nodiscard]] KUMI_ABI constexpr Type operator()(tuple<Ts...> const& t) const
724 requires(!kumi::concepts::product_type<Type> && kumi::_::implicit_constructible<Type, Ts...>)
725 {
726
1/1
✓ Branch 1 taken 1 times.
3 return impl(t, std::make_index_sequence<sizeof...(Ts)>{});
727 }
728 };
729
730 //====================================================================================================================
731 /**
732 @ingroup kumi_tuple_related
733
734 @var from_tuple
735 @brief Converts a kumi::tuple to an instance of an arbitrary type
736
737 Constructs an instance of `Type` by passing elements of `t` to the appropriate constructor.
738
739 @qualifier inline
740 @qualifier constexpr
741 @qualifier nodiscard
742
743 @groupheader{Header file}
744 @code
745 #include <kumi/product_types/tuple.hpp>
746 @endcode
747
748 @groupheader{Call Signature}
749
750 @code
751 template<typename Type, product_type T>
752 constexpr auto from_tuple(T&& t);
753 @endcode
754
755 @subgroupheader{Parameters}
756
757 - `Type` : Type to generate
758 - `t`: kumi::tuple to convert.
759
760 @subgroupheader{Return value}
761
762 - An instance of `Type` constructed from each element of `t` in order.
763
764 @groupheader{Example}
765
766 @godbolt{doc/tuple/api/from_tuple.cpp}
767
768 **/
769 //====================================================================================================================
770 template<typename Type> KUMI_VARIABLE_ABI constexpr from_tuple_t<Type> from_tuple{};
771
772 struct to_tuple_t
773 {
774 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
775 {
776 if constexpr (kumi::concepts::empty_product_type<T>) return kumi::tuple{};
777 else
778 16 return [&]<std::size_t... I>(std::index_sequence<I...>) {
779 6 return kumi::tuple{get<I>(KUMI_FWD(t))...};
780 12 }(std::make_index_sequence<kumi::size_v<T>>{});
781 }
782
783 /// @overload
784 template<kumi::concepts::static_container S>
785 [[nodiscard]] KUMI_ABI constexpr auto operator()(S&& s) const
786 requires(!kumi::concepts::product_type<S>)
787 {
788 4 constexpr std::size_t N = kumi::container_size_v<S>;
789 if constexpr (N == 0) return kumi::tuple{};
790 else
791 10 return [&]<std::size_t... I>(std::index_sequence<I...>) {
792 4 return kumi::tuple{KUMI_FWD(s)[I]...};
793 8 }(std::make_index_sequence<N>{});
794 }
795 };
796
797 //====================================================================================================================
798 /**
799 @ingroup kumi_tuple_related
800
801 @var to_tuple
802 @brief Converts a kumi::concepts::product_type to an instance of kumi::tuple
803
804 Constructs an instance of kumi::tuple from the elements of the kumi::concepts::product_type parameters
805
806 @note An overload is provided for kumi::concepts::static_container.
807
808 @qualifier inline
809 @qualifier constexpr
810 @qualifier nodiscard
811
812 @groupheader{Header file}
813 @code
814 #include <kumi/product_types/tuple.hpp>
815 @endcode
816
817 @groupheader{Call Signature}
818
819 @code
820 template<product_type T>
821 constexpr auto to_tuple(T&& t);
822 @endcode
823
824 @subgroupheader{Parameters}
825
826 - `t`: kumi::concepts::product_type to convert
827
828 @subgroupheader{Return value}
829
830 - An instance of kumi::tuple constructed from each element of `t` in order.
831
832 @groupheader{Example}
833
834 @godbolt{doc/tuple/api/to_tuple.cpp}
835
836 **/
837 //====================================================================================================================
838 KUMI_VARIABLE_ABI constexpr to_tuple_t to_tuple{};
839
840 namespace _
841 {
842 template<typename T, typename IndexSequence, template<typename...> class Meta = std::type_identity> struct as_tuple;
843
844 template<typename T, std::size_t... I> struct as_tuple<T, std::index_sequence<I...>>
845 {
846 using type = kumi::tuple<kumi::element_t<I, T>...>;
847 };
848
849 template<typename T, std::size_t... I, template<typename...> class Meta>
850 struct as_tuple<T, std::index_sequence<I...>, Meta>
851 {
852 using type = tuple<typename Meta<kumi::element_t<I, T>>::type...>;
853 };
854 }
855
856 //====================================================================================================================
857 /**
858 @ingroup kumi_tuple_related
859 @brief Generate a kumi::tuple type from a type
860
861 If `T` is a @ref kumi::concepts::product_type, returns the kumi::tuple type containing the same element
862 as `T`. Otherwise, it returns `kumi::tuple<T>`.
863
864 A template meta-function can be optionally passed to be applied to each of those types when
865 types are computed.
866
867 @tparam T Type to transform
868 @tparam Meta Unary template meta-function to apply to each type.
869 Defaults to `std::type_identity`
870
871 ## Helper type
872 @code
873 namespace kumi
874 {
875 template<typename T, template<typename...> class Meta = std::type_identity>
876 using as_tuple_t = typename as_tuple<T, Meta>::type;
877 }
878 @endcode
879
880 ## Example:
881 @include doc/tuple/api/as_tuple.cpp
882 **/
883 //====================================================================================================================
884 template<typename T, template<typename...> class Meta = std::type_identity> struct as_tuple;
885
886 template<typename T, template<typename...> class Meta>
887 requires(kumi::concepts::product_type<T>)
888 struct as_tuple<T, Meta> : kumi::_::as_tuple<T, std::make_index_sequence<kumi::size_v<T>>, Meta>
889 {
890 };
891
892 template<typename T, template<typename...> class Meta>
893 requires(!kumi::concepts::product_type<T>)
894 struct as_tuple<T, Meta>
895 {
896 using type = kumi::tuple<typename Meta<T>::type>;
897 };
898
899 template<typename T, template<typename...> class Meta = std::type_identity>
900 using as_tuple_t = typename kumi::as_tuple<T, Meta>::type;
901
902 //====================================================================================================================
903 //! @}
904 //====================================================================================================================
905
906 //====================================================================================================================
907 //! @name Tuple properties
908 //! @{
909 //====================================================================================================================
910
911 struct members_of_t
912 {
913 private:
914 template<typename T, std::size_t... I>
915 4 KUMI_HIDDEN_ABI constexpr auto impl(as<T>, std::index_sequence<I...>) const noexcept
916 {
917 if constexpr (sizeof...(I) == 0) return kumi::tuple{};
918 4 else return kumi::tuple{kumi::identifier_of<kumi::element_t<I, T>>()...};
919 }
920
921 public:
922 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(as<T> type) const noexcept
923 {
924 2 return impl(type, std::make_index_sequence<kumi::size_v<T>>{});
925 }
926 };
927
928 //====================================================================================================================
929 /**
930 @ingroup kumi_utility
931
932 @var members_of
933 @brief Extracts the names of the fields of a kumi::product_type.
934
935 @note If some fields are unnamed, the associated name is kumi::unit.
936
937 @qualifier inline
938 @qualifier constexpr
939 @qualifier nodiscard
940
941 @groupheader{Header file}
942 @code
943 #include <kumi/product_types/tuple.hpp>
944 @endcode
945
946 @groupheader{Call Signature}
947
948 @code
949 template<product_type T>
950 constexpr auto members_of(kumi::as<T> type);
951 @endcode
952
953 @subgroupheader{Parameters}
954 - `type`: the type of the kumi::concepts::product_type from which to extract names.
955
956 @subgroupheader{Return value}
957
958 - A tuple of the names of a kumi::product_type.
959
960 @groupheader{Example}
961
962 @godbolt{doc/infra/members_of.cpp}
963
964 **/
965 //====================================================================================================================
966 KUMI_VARIABLE_ABI constexpr members_of_t members_of{};
967
968 struct values_of_t
969 {
970 template<typename T, std::size_t... I>
971 365 KUMI_HIDDEN_ABI constexpr auto impl(T&& t, std::index_sequence<I...>) const noexcept
972 {
973 4 if constexpr (sizeof...(I) == 0) return kumi::tuple{};
974 else
975 return kumi::tuple<kumi::result::field_value_of_t<kumi::member_t<I, T>>...>{
976 2578 kumi::field_value_of(get<I>(KUMI_FWD(t)))...};
977 }
978
979 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const noexcept
980 {
981 195 return impl(KUMI_FWD(t), std::make_index_sequence<kumi::size_v<T>>{});
982 }
983 };
984
985 //====================================================================================================================
986 /**
987 @ingroup kumi_utility
988
989 @var values_of
990 @brief Extracts the values of the fields of a kumi::product_type.
991
992 @qualifier inline
993 @qualifier constexpr
994 @qualifier noexcept
995 @qualifier nodiscard
996
997 @groupheader{Header file}
998 @code
999 #include <kumi/product_types/tuple.hpp>
1000 @endcode
1001
1002 @groupheader{Call Signature}
1003
1004 @code
1005 template<product_type T>
1006 constexpr auto values_of(T && t) noexcept;
1007 @endcode
1008
1009 @subgroupheader{Parameters}
1010 - `t`: the product_type from which to extract values.
1011
1012 @subgroupheader{Return value}
1013
1014 - A tuple of references to the values of a kumi::product_type.
1015
1016 @groupheader{Example}
1017
1018 @godbolt{doc/infra/values_of.cpp}
1019
1020 **/
1021 //====================================================================================================================
1022 KUMI_VARIABLE_ABI constexpr values_of_t values_of{};
1023
1024 namespace result
1025 {
1026 template<kumi::concepts::product_type T> using members_of_t = decltype(kumi::members_of(as<T>{}));
1027
1028 template<kumi::concepts::product_type T> struct members_of
1029 {
1030 using type = kumi::result::members_of_t<T>;
1031 };
1032
1033 template<kumi::concepts::product_type T> using values_of_t = decltype(kumi::values_of(std::declval<T>()));
1034
1035 template<kumi::concepts::product_type T> struct values_of
1036 {
1037 using type = kumi::result::values_of_t<T>;
1038 };
1039 }
1040
1041 //====================================================================================================================
1042 //! @}
1043 //====================================================================================================================
1044
1045 //====================================================================================================================
1046 /**
1047 @name Tuple Accessors
1048 @{
1049 **/
1050 //====================================================================================================================
1051
1052 //====================================================================================================================
1053 /**
1054 @related tuple
1055 @brief Extracts the Ith element from a kumi::tuple
1056
1057 @note Does not participate in overload resolution if `I` is not in [0, sizeof...(Ts)).
1058 @tparam I Compile-time index of the element to access
1059 @param t Tuple to index
1060 @return A reference to the selected element of t.
1061
1062 @qualifier nodiscard
1063 @qualifier inline
1064 @qualifier constexpr
1065 @qualifier noexcept
1066
1067 ## Example:
1068 @include doc/tuple/api/get.cpp
1069 **/
1070 //====================================================================================================================
1071 template<std::size_t I, typename... Ts>
1072 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...>& t) noexcept
1073 requires(I < sizeof...(Ts))
1074 {
1075 2203 return t[kumi::index<I>];
1076 }
1077
1078 /// @related tuple
1079 /// @overload
1080 template<std::size_t I, typename... Ts>
1081 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...>&& arg) noexcept
1082 requires(I < sizeof...(Ts))
1083 {
1084 1873 return static_cast<tuple<Ts...>&&>(arg)[kumi::index<I>];
1085 }
1086
1087 /// @related tuple
1088 /// @overload
1089 template<std::size_t I, typename... Ts>
1090 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...> const& arg) noexcept
1091 requires(I < sizeof...(Ts))
1092 {
1093 420402 return arg[kumi::index<I>];
1094 }
1095
1096 /// @related tuple
1097 /// @overload
1098 template<std::size_t I, typename... Ts>
1099 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...> const&& arg) noexcept
1100 requires(I < sizeof...(Ts))
1101 {
1102 25 return static_cast<tuple<Ts...> const&&>(arg)[kumi::index<I>];
1103 }
1104
1105 //====================================================================================================================
1106 /**
1107 @related tuple
1108 @brief Extracts the field labeled L from a kumi::tuple if it exists
1109
1110 @note Does not participate in overload resolution if the names are not unique
1111 @tparam L Non type template parameter label of the element to access
1112 @param t Tuple to index
1113 @return A reference to the selected element of t.
1114
1115 @qualifier nodiscard
1116 @qualifier inline
1117 @qualifier constexpr
1118 @qualifier noexcept
1119
1120 ## Example:
1121 @include doc/tuple/api/labeled_get.cpp
1122 **/
1123 //====================================================================================================================
1124 template<kumi::str L, typename... Ts>
1125 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...>& t) noexcept
1126 requires(kumi::concepts::uniquely_named<Ts...> && kumi::_::contains_label<L, Ts...>())
1127 {
1128 4 return t[kumi::label<L>];
1129 }
1130
1131 /// @related tuple
1132 /// @overload
1133 template<kumi::str L, typename... Ts>
1134 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...>&& t) noexcept
1135 requires(kumi::concepts::uniquely_named<Ts...> && kumi::_::contains_label<L, Ts...>())
1136 {
1137 return static_cast<tuple<Ts...>&&>(t)[kumi::label<L>];
1138 }
1139
1140 /// @related tuple
1141 /// @overload
1142 template<kumi::str L, typename... Ts>
1143 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...> const& t) noexcept
1144 requires(kumi::concepts::uniquely_named<Ts...> && kumi::_::contains_label<L, Ts...>())
1145 {
1146 return t[kumi::label<L>];
1147 }
1148
1149 /// @related tuple
1150 /// @overload
1151 template<kumi::str L, typename... Ts>
1152 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...> const&& t) noexcept
1153 requires(kumi::concepts::uniquely_named<Ts...> && kumi::_::contains_label<L, Ts...>())
1154 {
1155 return static_cast<tuple<Ts...> const&&>(t)[kumi::label<L>];
1156 }
1157
1158 //====================================================================================================================
1159 /**
1160 @related tuple
1161 @brief Extracts the field identified by Id from a kumi::tuple if it exists
1162
1163 @note Does not participate in overload resolution if the names are not unique
1164 @tparam Id Non type template parameter identifier of the element to access
1165 @param t Tuple to index
1166 @return A reference to the selected element of t.
1167
1168 @qualifier nodiscard
1169 @qualifier inline
1170 @qualifier constexpr
1171 @qualifier noexcept
1172
1173 ## Example:
1174 @include doc/tuple/api/named_get.cpp
1175 **/
1176 //====================================================================================================================
1177 template<kumi::concepts::identifier auto Id, typename... Ts>
1178 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...>& t) noexcept
1179 requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::contains_identifier<decltype(Id), Ts...>)
1180 {
1181 5 return t[Id];
1182 }
1183
1184 /// @related tuple
1185 /// @overload
1186 template<kumi::concepts::identifier auto Id, typename... Ts>
1187 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...>&& t) noexcept
1188 requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::contains_identifier<decltype(Id), Ts...>)
1189 {
1190 1 return static_cast<tuple<Ts...>&&>(t)[Id];
1191 }
1192
1193 /// @related tuple
1194 /// @overload
1195 template<kumi::concepts::identifier auto Id, typename... Ts>
1196 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...> const& t) noexcept
1197 requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::contains_identifier<decltype(Id), Ts...>)
1198 {
1199 19 return t[Id];
1200 }
1201
1202 /// @related tuple
1203 /// @overload
1204 template<kumi::concepts::identifier auto Id, typename... Ts>
1205 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...> const&& t) noexcept
1206 requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::contains_identifier<decltype(Id), Ts...>)
1207 {
1208 return static_cast<tuple<Ts...> const&&>(t)[Id];
1209 }
1210
1211 //====================================================================================================================
1212 /**
1213 @related tuple
1214 @brief Extracts the field whose type is T from a kumi::tuple if it exists
1215
1216 @note Does not participate in overload resolution if the types are not unique
1217 @tparam T Type of the element to access
1218 @param t Tuple to index
1219 @return A reference to the selected element of t.
1220
1221 @qualifier nodiscard inline constexpr noexcept
1222
1223 ## Example:
1224 @include doc/tuple/api/typed_get.cpp
1225 **/
1226 //====================================================================================================================
1227 template<typename T, typename... Ts>
1228 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...>& t) noexcept
1229 requires(kumi::concepts::uniquely_typed<Ts...> && kumi::concepts::contains_type<T, Ts...>)
1230 {
1231 29 return t[kumi::as<T>{}];
1232 }
1233
1234 /// @related tuple
1235 /// @overload
1236 template<typename T, typename... Ts>
1237 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...>&& t) noexcept
1238 requires(kumi::concepts::uniquely_typed<Ts...> && kumi::concepts::contains_type<T, Ts...>)
1239 {
1240 return static_cast<tuple<Ts...>&&>(t)[kumi::as<T>{}];
1241 }
1242
1243 /// @related tuple
1244 /// @overload
1245 template<typename T, typename... Ts>
1246 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...> const& t) noexcept
1247 requires(kumi::concepts::uniquely_typed<Ts...> && kumi::concepts::contains_type<T, Ts...>)
1248 {
1249 26 return t[kumi::as<T>{}];
1250 }
1251
1252 /// @related tuple
1253 /// @overload
1254 template<typename T, typename... Ts>
1255 [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(tuple<Ts...> const&& t) noexcept
1256 requires(kumi::concepts::uniquely_typed<Ts...> && kumi::concepts::contains_type<T, Ts...>)
1257 {
1258 return static_cast<tuple<Ts...> const&&>(t)[kumi::as<T>{}];
1259 }
1260
1261 //====================================================================================================================
1262 //! @}
1263 //====================================================================================================================
1264
1265 #ifndef KUMI_DOXYGEN_INVOKED
1266 /// Improves diagnostic for out of bounds index
1267 template<std::size_t I, typename T>
1268 requires(kumi::is_kumi_tuple_v<std::remove_cvref_t<T>> && (I >= kumi::size_v<T>))
1269 constexpr auto get(T&& r) = delete;
1270
1271 /// Improves diagnostic for non present label
1272 template<str S, typename T>
1273 requires(kumi::is_kumi_tuple_v<std::remove_cvref_t<T>> && !kumi::_::contains_identifier<S, T>())
1274 constexpr auto get(T&& t) = delete;
1275
1276 /// Improves diagnostic for non present identifier
1277 template<kumi::concepts::identifier auto S, typename T>
1278 requires(kumi::is_kumi_tuple_v<std::remove_cvref_t<T>> && !kumi::concepts::contains_identifier<decltype(S), T>)
1279 constexpr auto get(T&& t) = delete;
1280
1281 /// Improves diagnostic for non present type
1282 template<typename U, typename T>
1283 requires(kumi::is_kumi_tuple_v<std::remove_cvref_t<T>> && !kumi::concepts::contains_type<U, T>)
1284 constexpr auto get(T&& t) = delete;
1285 #endif
1286
1287 // Builder protocol
1288 template<kumi::concepts::product_type T> struct builder<T>
1289 {
1290 using type = T;
1291
1292 template<typename... Us> using to = kumi::tuple<Us...>;
1293
1294 template<typename... Args> [[nodiscard]] KUMI_ABI static constexpr auto make(Args&&... args)
1295 {
1296 189 return kumi::make_tuple(KUMI_FWD(args)...);
1297 }
1298
1299 template<typename... Args> [[nodiscard]] KUMI_ABI static constexpr auto build(Args&&... args)
1300 {
1301 return kumi::tuple{KUMI_FWD(args)...};
1302 }
1303 };
1304
1305 // As we are lacking a proper mechanism to find the least restrictive subtype, we fallback to a specializable trait
1306 template<kumi::concepts::product_type... Ts> struct common_product_type<Ts...>
1307 {
1308 using type = kumi::tuple<>;
1309 };
1310 }
1311