GCC Code Coverage Report


Directory: include/kumi/
File: include/kumi/algorithm/flatten.hpp
Date: 2026-10-14 16:33:56
Exec Total Coverage
Lines: 32 32 100.0%
Functions: 842 842 100.0%
Branches: 122 122 100.0%

Line Branch Exec Source
1 //======================================================================================================================
2 /*
3 KUMI - Compact Tuple Tools
4 Copyright : KUMI Project Contributors
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //======================================================================================================================
8 #pragma once
9
10 namespace kumi
11 {
12 namespace _
13 {
14 struct flatten_all_case_t
15 {
16 template<typename T, typename V, typename F, typename Self>
17 616 KUMI_HIDDEN_ABI constexpr auto operator()(T&&, V&& v, F f, Self s) const
18 {
19 using FV = kumi::result::field_value_of_t<V>;
20 if constexpr (kumi::concepts::record_type<FV> && kumi::concepts::record_type<T>)
21 148 return kumi::capture_field<kumi::identifier_of<V>()>(s(kumi::field_value_of(KUMI_FWD(v)), f));
22 74 else if constexpr (kumi::concepts::follows_same_semantic<T, V>) return s(KUMI_FWD(v), f);
23 else if constexpr (kumi::concepts::record_type<T> && kumi::concepts::field<V>)
24 702 return kumi::capture_field<kumi::identifier_of<V>()>(kumi::invoke(f, kumi::field_value_of(KUMI_FWD(v))));
25 234 else return kumi::invoke(f, KUMI_FWD(v));
26 }
27 };
28
29 KUMI_VARIABLE_ABI constexpr flatten_all_case_t flatten_all_case{};
30
31 struct flatten_case_t
32 {
33 988 template<typename T, typename V> KUMI_HIDDEN_ABI constexpr auto operator()(T&&, V&& v, auto J) const
34 {
35 using FV = kumi::result::field_value_of_t<V>;
36 if constexpr (kumi::concepts::record_type<FV> && kumi::concepts::record_type<T>)
37 {
38 226 constexpr auto new_name = kumi::label_of<V>() + kumi::label_of<kumi::element_t<J, FV>>();
39 return (
40 904 kumi::capture_field<name<new_name>{}>(kumi::field_value_of(get<J>(kumi::field_value_of(KUMI_FWD(v))))));
41 }
42 226 else if constexpr (kumi::concepts::follows_same_semantic<T, V>) return get<J>(KUMI_FWD(v));
43 536 else return KUMI_FWD(v);
44 }
45 };
46
47 KUMI_VARIABLE_ABI constexpr flatten_case_t flatten_case{};
48
49 template<typename T, typename V, std::size_t... J, std::size_t... I>
50 222 KUMI_HIDDEN_ABI constexpr auto flatten_intern_(
51 kumi::_::adl_tag_t, T&& t, V visitor, std::index_sequence<J...>, std::index_sequence<I...>)
52 {
53 8 if constexpr (sizeof...(I) == 0) return kumi::builder<T>::make();
54
16/16
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 21 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 21 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 18 times.
✓ Branch 11 taken 8 times.
✓ Branch 14 taken 8 times.
✓ Branch 17 taken 5 times.
✓ Branch 20 taken 4 times.
✓ Branch 21 taken 1 times.
✓ Branch 23 taken 4 times.
✓ Branch 24 taken 1 times.
✓ Branch 27 taken 3 times.
✓ Branch 30 taken 2 times.
✓ Branch 33 taken 2 times.
1178 else return kumi::builder<T>::make(visitor(KUMI_FWD(t), get<I>(KUMI_FWD(t)), kumi::index<J>)...);
55 }
56
57 template<typename T, typename V, std::size_t... I>
58 222 KUMI_HIDDEN_ABI constexpr auto flatten_(kumi::_::adl_tag_t, T&& t, V visitor, std::index_sequence<I...>)
59 {
60 using inner = kumi::function::cat_index_sequence<
61 std::make_index_sequence<kumi::function::size_or_v<kumi::stored_element_t<I, T>, 1>>...>;
62 using outer = kumi::function::cat_index_sequence<
63 kumi::function::fill_index_sequence<I, kumi::function::size_or_v<kumi::stored_element_t<I, T>, 1>>...>;
64
65 222 return flatten_intern_(kumi::_::adl_tag, KUMI_FWD(t), visitor, inner{}, outer{});
66 }
67
68 template<typename T, typename V, typename F, typename S, std::size_t... I>
69 196 KUMI_HIDDEN_ABI constexpr auto flatten_all_(
70 kumi::_::adl_tag_t, T&& t, V visitor, F f, S self, std::index_sequence<I...>)
71 {
72
7/7
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 19 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
✓ Branch 9 taken 2 times.
✓ Branch 11 taken 2 times.
812 return kumi::builder<T>::make(visitor(KUMI_FWD(t), get<I>(KUMI_FWD(t)), f, self)...);
73 }
74
75 template<typename E, std::size_t... I>
76 16 KUMI_HIDDEN_ABI constexpr auto compress_(kumi::_::adl_tag_t, E&& e, std::index_sequence<I...>)
77 {
78 using V = kumi::result::field_value_of_t<E>;
79 if constexpr (sizeof...(I) == 0 || kumi::concepts::empty_product_type<V>) return kumi::builder<V>::make();
80 else
81 {
82 16 constexpr auto outer = kumi::label_of<E>();
83 return kumi::builder<V>::make(
84 160 kumi::capture_field<kumi::name<outer + kumi::label_of<kumi::element_t<I, V>>()>{}>(
85 16 kumi::field_value_of(get<I>(kumi::field_value_of(KUMI_FWD(e)))))...);
86 }
87 }
88 }
89
90 struct compress_t
91 {
92 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
93 {
94 4 if constexpr (kumi::concepts::empty_product_type<T>) return KUMI_FWD(t);
95 else
96 {
97 using V = kumi::result::field_value_of_t<kumi::element_t<0, T>>;
98 if constexpr (kumi::concepts::sized_product_type<T, 1> && kumi::concepts::follows_same_semantic<T, V>)
99 {
100 if constexpr (kumi::concepts::record_type<T>)
101
6/6
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 16 taken 1 times.
13 return (*this)(compress_(kumi::_::adl_tag, get<0>(KUMI_FWD(t)), kumi::function::indexes_for<V>{}));
102 else return (*this)(get<0>(KUMI_FWD(t)));
103 }
104 24 else return KUMI_FWD(t);
105 }
106 }
107 };
108
109 struct flatten_t
110 {
111 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
112 {
113 4 if constexpr (kumi::concepts::empty_product_type<T>) return KUMI_FWD(t);
114
38/38
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 6 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
✓ Branch 16 taken 4 times.
✓ Branch 19 taken 6 times.
✓ Branch 22 taken 4 times.
✓ Branch 25 taken 4 times.
✓ Branch 28 taken 4 times.
✓ Branch 31 taken 2 times.
✓ Branch 34 taken 2 times.
✓ Branch 37 taken 2 times.
✓ Branch 40 taken 3 times.
✓ Branch 43 taken 2 times.
✓ Branch 46 taken 2 times.
✓ Branch 49 taken 2 times.
✓ Branch 52 taken 2 times.
✓ Branch 55 taken 2 times.
✓ Branch 58 taken 2 times.
✓ Branch 61 taken 2 times.
✓ Branch 64 taken 2 times.
✓ Branch 67 taken 3 times.
✓ Branch 70 taken 2 times.
✓ Branch 73 taken 2 times.
✓ Branch 76 taken 2 times.
✓ Branch 79 taken 2 times.
✓ Branch 82 taken 2 times.
✓ Branch 85 taken 2 times.
✓ Branch 88 taken 2 times.
✓ Branch 91 taken 2 times.
✓ Branch 94 taken 2 times.
✓ Branch 97 taken 2 times.
✓ Branch 100 taken 2 times.
✓ Branch 103 taken 2 times.
✓ Branch 106 taken 2 times.
✓ Branch 109 taken 2 times.
✓ Branch 112 taken 2 times.
112 else return flatten_(kumi::_::adl_tag, KUMI_FWD(t), kumi::_::flatten_case, kumi::function::indexes_for<T>{});
115 }
116 };
117
118 struct flatten_all_t : private kumi::flatten_t
119 {
120 template<kumi::concepts::product_type T, typename Func>
121 [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t, Func f) const
122 {
123 24 if constexpr (kumi::concepts::empty_product_type<T>) return KUMI_FWD(t);
124 else
125 {
126
55/55
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 3 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 2 times.
✓ Branch 17 taken 1 times.
✓ Branch 19 taken 4 times.
✓ Branch 21 taken 2 times.
✓ Branch 22 taken 2 times.
✓ Branch 23 taken 1 times.
✓ Branch 25 taken 3 times.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 3 times.
✓ Branch 31 taken 3 times.
✓ Branch 34 taken 2 times.
✓ Branch 35 taken 1 times.
✓ Branch 37 taken 2 times.
✓ Branch 40 taken 1 times.
✓ Branch 41 taken 1 times.
✓ Branch 43 taken 1 times.
✓ Branch 45 taken 2 times.
✓ Branch 46 taken 1 times.
✓ Branch 49 taken 2 times.
✓ Branch 52 taken 2 times.
✓ Branch 55 taken 2 times.
✓ Branch 58 taken 2 times.
✓ Branch 61 taken 2 times.
✓ Branch 64 taken 2 times.
✓ Branch 67 taken 2 times.
✓ Branch 68 taken 1 times.
✓ Branch 70 taken 1 times.
✓ Branch 72 taken 1 times.
✓ Branch 73 taken 1 times.
✓ Branch 76 taken 2 times.
✓ Branch 79 taken 1 times.
✓ Branch 80 taken 1 times.
✓ Branch 82 taken 1 times.
✓ Branch 83 taken 1 times.
✓ Branch 85 taken 1 times.
✓ Branch 86 taken 1 times.
✓ Branch 88 taken 1 times.
✓ Branch 89 taken 1 times.
✓ Branch 91 taken 1 times.
✓ Branch 92 taken 1 times.
✓ Branch 94 taken 1 times.
✓ Branch 95 taken 1 times.
✓ Branch 99 taken 1 times.
✓ Branch 103 taken 1 times.
✓ Branch 107 taken 1 times.
196 return this->flatten_t::operator()(flatten_all_(kumi::_::adl_tag, KUMI_FWD(t), kumi::_::flatten_all_case, f,
127 196 (*this), kumi::function::indexes_for<T>{}));
128 }
129 }
130
131 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
132 {
133 4 if constexpr (kumi::concepts::empty_product_type<T>) return KUMI_FWD(t);
134 20 else return (*this)(KUMI_FWD(t), kumi::function::identity);
135 }
136 };
137
138 struct as_flat_ptr_t : private kumi::flatten_all_t
139 {
140 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI auto operator()(T&& t) const noexcept
141 {
142 4 return this->flatten_all_t::operator()(KUMI_FWD(t), kumi::function::adressof);
143 }
144 };
145
146 //====================================================================================================================
147 /**
148 @ingroup kumi_generators
149
150 @var compress
151 @brief Callable object converting a product type of product type into a single product type recursively, or returns
152 the input.
153
154 This construction naturally arises from the definition of product types, a product type of the form T(T(x...)) is
155 strictly equivalent to T(x...) as long as the T is the same type.
156
157 On record types, the names of the outer record are concatenated to the inner ones ultimately constructing names
158 such as "outer.inner". If the input is a product type containing record types or vice versa only the inner types
159 matching the outer semantic will be compressed. Thus a record inside a tuple will not be compressed.
160
161 @qualifier nodiscard
162 @qualifier inline
163 @qualifier constexpr
164
165 @groupheader{Header file}
166 @code
167 #include <kumi/algorithm/flatten.hpp>
168 @endcode
169
170 @groupheader{Call Signature}
171
172 @code
173 template<product_type T>
174 constexpr auto compress(T && t) noexcept;
175 @endcode
176
177 @subgroupheader{Parameters}
178
179 - `t`: Product type to process
180
181 @subgroupheader{Return value}
182
183 - The resulting value of the application of `T0(...(Tn(values))) => T(values)`
184
185 @groupheader{Helper type}
186
187 @snippet include/kumi/algorithm/flatten.hpp compress_t
188
189 Computes the return type of a call to kumi::compress
190
191 @groupheader{Examples}
192
193 @tab_begin
194
195 @tab{Tuple}
196 @godbolt{doc/tuple/algo/compress.cpp}
197
198 @tab{Record}
199 @godbolt{doc/record/algo/compress.cpp}
200
201 @tab_end
202 **/
203 //====================================================================================================================
204 KUMI_VARIABLE_ABI constexpr compress_t compress{};
205
206 //====================================================================================================================
207 /**
208 @ingroup kumi_generators
209
210 @var flatten
211 @brief Callable object converting a product type of product types into a product type of all elements.
212
213 On record types, the names of the outer record are concatenated to the inner ones ultimately constructing names
214 such as "outer.inner". If the input is a product type containing record types or vice versa only the inner types
215 matching the outer semantic will be flattened. Thus a record inside a tuple will not be flattened.
216
217 @qualifier nodiscard
218 @qualifier inline
219 @qualifier constexpr
220
221 @groupheader{Header file}
222 @code
223 #include <kumi/algorithm/flatten.hpp>
224 @endcode
225
226 @groupheader{Call Signature}
227
228 @code
229 template<product_type T>
230 constexpr auto flatten(T && t) noexcept;
231 @endcode
232
233 @subgroupheader{Parameters}
234
235 - `t`: Product type to process
236
237 @subgroupheader{Return value}
238
239 - A product type composed of all elements of `t` flattened non-recursively
240
241 @groupheader{Helper type}
242
243 @snippet include/kumi/algorithm/flatten.hpp flatten_t
244
245 Computes the return type of a call to kumi::flatten
246
247 @groupheader{Examples}
248
249 @tab_begin
250
251 @tab{Tuple}
252 @godbolt{doc/tuple/algo/flatten.cpp}
253
254 @tab{Record}
255 @godbolt{doc/record/algo/flatten.cpp}
256
257 @tab_end
258 **/
259 //====================================================================================================================
260 KUMI_VARIABLE_ABI constexpr flatten_t flatten{};
261
262 //====================================================================================================================
263 /**
264 @ingroup kumi_generators
265
266 @var flatten_all
267 @brief Callable object converting recursively a product type of product types into a product type of all elements.
268
269 Recursively converts a product type of product types `t` into a product type of all elements of
270 said product types.
271
272 If the Callable object f is provided, non-product type elements are processed by `f` before
273 being inserted.
274
275 On record types, the names of the outer record are concatenated to the inner ones ultimately constructing names
276 such as "outer.inner". If the input is a product type containing record types or vice versa only the inner types
277 matching the outer semantic will be flattened. Thus a record inside a tuple will not be flattened.
278
279 @qualifier nodiscard
280 @qualifier inline
281 @qualifier constexpr
282
283 @groupheader{Header file}
284 @code
285 #include <kumi/algorithm/flatten.hpp>
286 @endcode
287
288 @groupheader{Call Signature}
289
290 @code
291 template<product_type T, typename Function>
292 constexpr auto flatten_all(T && t, Function && f) noexcept; // 1
293 @endcode
294
295 @code
296 template<product_type T>
297 constexpr auto flatten_all(T && t) noexcept; // 2
298 @endcode
299
300 @subgroupheader{Parameters}
301
302 - `t`: Product type to process
303 - `f`: Optional Callable object to apply when a sub-tuple is flattened
304
305 @subgroupheader{Return value}
306
307 - A product type composed of all elements of `t` flattened recursively
308
309 @groupheader{Helper type}
310
311 @snippet include/kumi/algorithm/flatten.hpp flatten_all_t
312
313 Computes the return type of a call to kumi::flatten_all
314
315 @groupheader{Examples}
316
317 @tab_begin
318
319 @tab{Tuple}
320 @godbolt{doc/tuple/algo/flatten_all.cpp}
321
322 @tab{Record}
323 @godbolt{doc/record/algo/flatten_all.cpp}
324
325 @tab_end
326 **/
327 //====================================================================================================================
328 KUMI_VARIABLE_ABI constexpr flatten_all_t flatten_all{};
329
330 //====================================================================================================================
331 /**
332 @ingroup kumi_generators
333
334 @var as_flat_ptr
335 @brief Callable object converting recursively a product type of product types into a flat product type of pointers
336 to each of its components.
337
338 On record types, the names of the outer record are concatenated to the inner ones ultimately constructing names
339 such as "outer.inner". If the input is a product type containing record types or vice versa only the inner types
340 matching the outer semantic will be flattened. Thus a record inside a tuple will not be flattened.
341
342 @qualifier nodiscard inline constexpr
343
344 @groupheader{Header file}
345 @code
346 #include <kumi/algorithm/flatten.hpp>
347 @endcode
348
349 @groupheader{Call Signature}
350
351 @code
352 template<product_type T>
353 constexpr auto as_flat_ptr(T && t) noexcept;
354 @endcode
355
356 @subgroupheader{Parameters}
357
358 - `t`: Product type to process
359
360 @subgroupheader{Return value}
361
362 - A flat product type composed of pointers to each element of `t`.
363
364 @groupheader{Helper type}
365
366 @snippet include/kumi/algorithm/flatten.hpp as_flat_ptr_t
367
368 Computes the return type of a call to kumi::as_flat_ptr
369
370 @groupheader{Examples}
371
372 @tab_begin
373
374 @tab{Tuple}
375 @godbolt{doc/tuple/algo/as_flat_ptr.cpp}
376
377 @tab{Record}
378 @godbolt{doc/record/algo/as_flat_ptr.cpp}
379
380 @tab_end
381 **/
382 //====================================================================================================================
383 KUMI_VARIABLE_ABI constexpr as_flat_ptr_t as_flat_ptr{};
384
385 namespace result
386 {
387 //! [compress_t]
388 template<kumi::concepts::product_type T> using compress_t = decltype(kumi::compress(std::declval<T>()));
389
390 template<kumi::concepts::product_type T> struct compress
391 {
392 using type = kumi::result::compress_t<T>;
393 };
394
395 //! [compress_t]
396
397 //! [flatten_t]
398 template<kumi::concepts::product_type T> using flatten_t = decltype(kumi::flatten(std::declval<T>()));
399
400 template<kumi::concepts::product_type T> struct flatten
401 {
402 using type = kumi::result::flatten_t<T>;
403 };
404
405 //! [flatten_t]
406
407 //! [flatten_all_t]
408 template<kumi::concepts::product_type T, typename... Func>
409 requires((sizeof...(Func) == 0) || (sizeof...(Func) == 1))
410 using flatten_all_t = decltype(kumi::flatten_all(std::declval<T>(), std::declval<Func>()...));
411
412 template<kumi::concepts::product_type T, typename... Func>
413 requires((sizeof...(Func) == 0) || (sizeof...(Func) == 1))
414 struct flatten_all
415 {
416 using type = kumi::result::flatten_all_t<T>;
417 };
418
419 //! [flatten_all_t]
420
421 //! [as_flat_ptr_t]
422 template<kumi::concepts::product_type T> using as_flat_ptr_t = decltype(kumi::as_flat_ptr(std::declval<T>()));
423
424 template<kumi::concepts::product_type T> struct as_flat_ptr
425 {
426 using type = kumi::result::as_flat_ptr_t<T>;
427 };
428
429 //! [as_flat_ptr_t]
430 }
431 }
432