Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
tuple_cat.hpp
Go to the documentation of this file.
1/// Copyright 2026, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_TUPLE_TUPLE_CAT_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_TUPLE_TUPLE_CAT_HPP_
7
8// IWYU pragma: private, include "arene/base/tuple.hpp"
9// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
10
11// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
12#include "arene/base/compiler_support/cpp14_inline.hpp"
13#include "arene/base/constraints/constraints.hpp"
14#include "arene/base/integer_sequences.hpp"
15#include "arene/base/stdlib_choice/cstddef.hpp"
16#include "arene/base/stdlib_choice/declval.hpp"
17#include "arene/base/stdlib_choice/enable_if.hpp"
18#include "arene/base/stdlib_choice/forward.hpp"
19#include "arene/base/stdlib_choice/forward_as_tuple.hpp"
20#include "arene/base/stdlib_choice/integer_sequence.hpp"
21#include "arene/base/stdlib_choice/remove_cv.hpp"
22#include "arene/base/stdlib_choice/remove_reference.hpp"
23#include "arene/base/stdlib_choice/tuple.hpp"
24#include "arene/base/stdlib_choice/tuple_size.hpp"
25#include "arene/base/tuple/detail/as_type_list.hpp"
26#include "arene/base/tuple/detail/get.hpp"
27#include "arene/base/type_list/concat.hpp"
28#include "arene/base/type_manipulation/repeat_type.hpp"
29#include "arene/base/type_traits/all_of.hpp"
30#include "arene/base/type_traits/is_tuple_like.hpp"
31#include "arene/base/type_traits/remove_cvref.hpp"
32// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
33
34namespace arene {
35namespace base {
36
37namespace tuple_cat_detail {
38
39/// @brief helper binding tuple_index positions to their corresponding tuple sizes
40/// @tparam Is pack of tuple_index values (one per input tuple)
41/// @tparam Sizes... sizes of the input tuples, in positional correspondence with @c Is
42template <class Is, std::size_t... Sizes>
43class tuple_index_seq_impl;
44
45/// @brief tuple_index_seq_impl specialization that concatenates one run per input tuple
46/// @tparam Is pack of tuple_index values (one per input tuple)
47/// @tparam Sizes... sizes of the input tuples, in positional correspondence with @c Is
48///
49/// @note Prepending an empty @c std::index_sequence<> seed makes the empty-pack case
50/// well-formed, as @c integer_sequence_cat rejects an empty pack.
51template <std::size_t... Is, std::size_t... Sizes>
52class tuple_index_seq_impl<std::index_sequence<Is...>, Sizes...> {
53 public:
54 /// @brief The resulting integer sequence
55 using type = integer_sequence_cat<std::index_sequence<>, make_index_sequence_repeat_n<Is, Sizes>...>;
56};
57
58/// @brief Generate the @c tuple_index sequence, used as the first index into the @c bundle
59/// @tparam Sizes... sizes of the input tuples, in order
60///
61/// For each input tuple at position @c k in the bundle (with size @c Sizes[k]), emit the
62/// value @c k repeated @c Sizes[k] times; the resulting runs are concatenated into a single
63/// flat sequence whose length equals the total number of output elements.
64template <std::size_t... Sizes>
65using tuple_index_seq_t = typename tuple_index_seq_impl<std::make_index_sequence<sizeof...(Sizes)>, Sizes...>::type;
66
67/// @brief helper producing the flat element_index sequence
68/// @tparam Sizes... sizes of the input tuples, in order
69///
70/// @note Prepending an empty @c std::index_sequence<> seed makes the empty-pack case
71/// well-formed, as @c integer_sequence_cat rejects an empty pack.
72template <std::size_t... Sizes>
73class element_index_seq_impl {
74 public:
75 /// @brief The resulting integer sequence
76 using type = integer_sequence_cat<std::index_sequence<>, std::make_index_sequence<Sizes>...>;
77};
78
79/// @brief Generate the @c element_index sequence, used as the second index into the @c bundle
80/// @tparam Sizes... sizes of the input tuples, in order
81///
82/// For each input tuple at position @c k in the bundle (with size @c Sizes[k]), emit the sequence <c>[0, 1, ...,
83/// Sizes[k] - 1]</c>; the resulting runs are concatenated into a single flat sequence whose length equals the total
84/// number of output elements.
85template <std::size_t... Sizes>
86using element_index_seq_t = typename element_index_seq_impl<Sizes...>::type;
87
88/// @brief result of concatenating the element types of tuple-likes @c Ts...
89/// @tparam Ts... tuple-like types
90template <class... Ts>
91using tuple_cat_result_t = type_lists::concat_t<std::tuple<>, tuple_detail::as_type_list_t<Ts>...>;
92
93/// @brief function object implementing tuple concatenation
94///
95/// Rather than a recursive approach, this implementation builds the resulting tuple in a single pack expansion.
96///
97/// Start by creating a single tuple-of-tuples (the @c bundle) from the list of input tuples. This bundle can be treated
98/// as a jagged 2D array (an array where each row can have different length), which can be indexed into with two
99/// coordinates. By generating a list of coordinates which covers each item in the bundle, each element in the bundle
100/// can be fetched and used to build the resulting tuple in a single expansion.
101///
102/// Two parallel <c>std::index_sequence</c>s can be used to represent the 2d coordinates. Both sequences must be of
103/// equal length @c K (where @c K is the total number of output elements). The first @c std::index_sequence holds the
104/// @c tuple_index - the first index into the @c bundle. The second @c std::index_sequence holds the @c element_index -
105/// the index into the particular tuple at @c tuple_index of the bundle.
106///
107/// The @c tuple_index @c std::index_sequence is generated by repeating the tuple's position in the bundle a number of
108/// times equal to that tuple's size. The @c element_index sequence is generated by concatenating the result of @c
109/// std::index_sequence_for for each tuple in the bundle.
110///
111/// For example, for <c>tuple_cat(tuple<A,B>, tuple<C>, tuple<D,E,F>)</c>:
112///
113/// @code
114/// output index k : 0 1 2 3 4 5
115/// tuple_index[k] : 0, 0, 1, 2, 2, 2
116/// element_index[k] : 0, 1, 0, 0, 1, 2
117/// @endcode
118///
119/// Once both index sequences are created, they can be simultaneously expanded to generate the final tuple. To continue
120/// the example:
121/// @code
122/// (0,0) -> A
123/// (0,1) -> B
124/// (1,0) -> C
125/// (2,0) -> D
126/// (2,1) -> E
127/// (2,2) -> F
128/// @endcode
129///
130/// Credit for this algorithm goes to Stephen T. Lavavej in the implementation of @c std::tuple_cat for MSVC.
131/// This particular implementation is inspired by Eric Niebler's implemetation
132/// @see https://ericniebler.com/2014/11/13/tiny-metaprogramming-library/
133// parasoft-begin-suppress AUTOSAR-M2_10_1-a "Similar names permitted by M2-10-1 Permit #1"
134class tuple_cat_fn {
135 private:
136 /// @brief concatenation implementation over a bundle of forwarded tuples
137 /// @tparam Result @c std::tuple type carrying the final element types
138 /// @tparam Bundle @c std::tuple holding forwarded input tuples
139 /// @tparam TupleIndices value pack: for each output position, which input tuple to read from
140 /// @tparam ElementIndices value pack: for each output position, which slot within that tuple
141 /// @param bundle bundle of tuples
142 /// @return concatenated @c std::tuple
143 // parasoft-begin-suppress CERT_C-EXP37-a "False positive: The rule does not mention naming all parameters"
144 // parasoft-begin-suppress AUTOSAR-A0_1_4-a "False positive: The parameter bundles is used"
145 template <class Result, class Bundle, std::size_t... TupleIndices, std::size_t... ElementIndices>
146 static constexpr auto
147 impl(Bundle&& bundle, std::index_sequence<TupleIndices...>, std::index_sequence<ElementIndices...>) noexcept(
148 noexcept(Result{tuple_detail::get<ElementIndices>(tuple_detail::get<TupleIndices>(std::declval<Bundle>()))...})
149 ) -> Result {
150 return Result{tuple_detail::get<ElementIndices>(tuple_detail::get<TupleIndices>(std::forward<Bundle>(bundle)))...};
151 }
152 // parasoft-end-suppress AUTOSAR-A0_1_4-a
153 // parasoft-end-suppress CERT_C-EXP37-a
154
155 public:
156 /// @brief concatenate zero or more tuple-ish inputs
157 /// @tparam Ts tuple-ish input types
158 /// @param args tuple-ish arguments
159 /// @return @c std::tuple formed by concatenating the elements of each input in order;
160 /// an empty @c std::tuple<> when called with no arguments
161 ///
162 /// @note Constraints: <br>
163 /// * Every input must satisfy @c arene::base::is_tuple_like_v
164 ///
165 /// @note A type implements the tuple protocol if it
166 /// * provides a specialization of @c std::tuple_size
167 /// * provides a specialization of @c std::tuple_element
168 /// * provides a function to get an element by index @c I, which is specified
169 /// as:
170 /// ** <c> std::forward<Tuple>(tuple).get<I>() </c> if valid
171 /// ** otherwise, <c> get<I>(std::forward<Tuple>(tuple)) </c> if valid,
172 /// where @c get is looked up by ADL only
173 /// Note that the tuple-like concept defines types that satisfy the tuple
174 /// protocol but are restricted to a list of types defined in the @c std
175 /// namespace (@c std::array, @c std::pair, @c std::tuple in C++14). The term
176 /// tuple-ish is used to define types that satisfy the tuple protocol without
177 /// the restriction that the type is define in the @c std namespace -- which
178 /// includes user-defined types.
179 template <
180 class... Ts,
181 constraints<std::enable_if_t<all_of_v<is_tuple_like_v<Ts>...>>> = nullptr,
182 class Result = tuple_cat_result_t<remove_cvref_t<Ts>...>,
183 class TupleIndices = tuple_index_seq_t<std::tuple_size<remove_cvref_t<Ts>>::value...>,
184 class ElementIndices = element_index_seq_t<std::tuple_size<remove_cvref_t<Ts>>::value...>>
185 constexpr auto operator()(Ts&&... args) const
186 noexcept(noexcept(impl<Result>(std::declval<std::tuple<Ts&&...>>(), TupleIndices{}, ElementIndices{})))
187 -> Result {
188 return impl<Result>(std::forward_as_tuple(std::forward<Ts>(args)...), TupleIndices{}, ElementIndices{});
189 }
190};
191// parasoft-end-suppress AUTOSAR-M2_10_1-a
192
193} // namespace tuple_cat_detail
194
195/// @def arene::base::tuple_cat
196/// @copydoc arene::base::tuple_cat_detail::tuple_cat_fn::operator()
197// parasoft-begin-suppress AUTOSAR-M7_3_3-a "An unnamed namespace is used to create a per-TU reference to a global
198// object used in multiple TUs."
199// parasoft-begin-suppress CERT_CPP-DCL59-a "An unnamed namespace is used to create a per-TU reference to a global
200// object used in multiple TUs."
201ARENE_CPP14_INLINE_VARIABLE(tuple_cat_detail::tuple_cat_fn, tuple_cat);
202// parasoft-end-suppress AUTOSAR-M7_3_3-a
203// parasoft-end-suppress CERT_CPP-DCL59-a
204
205} // namespace base
206} // namespace arene
207
208#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_TUPLE_TUPLE_CAT_HPP_
Definition array_exceptions_disabled.cpp:11
ARENE_CPP14_INLINE_VARIABLE(tuple_cat_detail::tuple_cat_fn, tuple_cat)
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10