GCC Code Coverage Report


Directory: include/kumi/
File: include/kumi/algorithm/reduce.hpp
Date: 2026-10-14 16:33:56
Exec Total Coverage
Lines: 25 25 100.0%
Functions: 352 352 100.0%
Branches: 0 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 template<std::size_t L, std::size_t R, typename M, typename T>
15 866 KUMI_HIDDEN_ABI constexpr auto reduce_(kumi::_::adl_tag_t, M&& m, T&& t)
16 {
17 866 constexpr auto N = R - L;
18 500 if constexpr (N == 1) return get<L>(KUMI_FWD(t));
19 else
20 366 return kumi::invoke(KUMI_FWD(m), reduce_<L, L + (N / 2)>(kumi::_::adl_tag, KUMI_FWD(m), KUMI_FWD(t)),
21 732 reduce_<L + (N / 2), R>(kumi::_::adl_tag, KUMI_FWD(m), KUMI_FWD(t)));
22 }
23
24 template<std::size_t L, std::size_t R, typename M, typename T, typename F>
25 254 KUMI_HIDDEN_ABI constexpr auto map_reduce_(kumi::_::adl_tag_t, M&& m, T&& t, F f)
26 {
27 254 constexpr auto N = R - L;
28 292 if constexpr (N == 1) return kumi::invoke(f, get<L>(KUMI_FWD(t)));
29 else
30 108 return kumi::invoke(KUMI_FWD(m), map_reduce_<L, L + (N / 2)>(kumi::_::adl_tag, KUMI_FWD(m), KUMI_FWD(t), f),
31 216 map_reduce_<L + (N / 2), R>(kumi::_::adl_tag, KUMI_FWD(m), KUMI_FWD(t), f));
32 }
33 }
34
35 struct reduce_t
36 {
37 template<kumi::concepts::monoid M, kumi::concepts::product_type T>
38 [[nodiscard]] KUMI_ABI constexpr auto operator()(M&& m, T&& t) const
39 {
40 if constexpr (kumi::concepts::empty_product_type<T>) return m.identity;
41 32 else if constexpr (kumi::concepts::record_type<T>) return (*this)(KUMI_FWD(m), kumi::values_of(KUMI_FWD(t)));
42 else if constexpr (kumi::concepts::sized_product_type<T, 1>) return get<0>(KUMI_FWD(t));
43 67 else return reduce_<0, kumi::size_v<T>>(kumi::_::adl_tag, KUMI_FWD(m), KUMI_FWD(t));
44 }
45
46 template<kumi::concepts::monoid M, kumi::concepts::product_type T, typename Value>
47 [[nodiscard]] KUMI_ABI constexpr auto operator()(M&& m, T&& t, Value init) const
48 {
49 if constexpr (kumi::concepts::empty_product_type<T>) return init;
50 40 else return KUMI_FWD(m)(init, (*this)(KUMI_FWD(m), KUMI_FWD(t)));
51 }
52 };
53
54 struct map_reduce_t
55 {
56 template<kumi::concepts::product_type T, kumi::concepts::monoid M, typename Function>
57 [[nodiscard]] KUMI_ABI constexpr auto operator()(Function f, M&& m, T&& t) const
58 {
59 if constexpr (kumi::concepts::empty_product_type<T>) return m.identity;
60 2 else if constexpr (kumi::concepts::record_type<T>) return (*this)(f, KUMI_FWD(m), kumi::values_of(KUMI_FWD(t)));
61 else if constexpr (kumi::concepts::sized_product_type<T, 1>) return kumi::invoke(f, get<0>(KUMI_FWD(t)));
62 19 else return map_reduce_<0, kumi::size_v<T>>(kumi::_::adl_tag, KUMI_FWD(m), KUMI_FWD(t), f);
63 }
64
65 template<kumi::concepts::monoid M, kumi::concepts::product_type T, typename Function, typename Value>
66 [[nodiscard]] KUMI_ABI constexpr auto operator()(Function f, M&& m, T&& t, Value init) const
67 {
68 if constexpr (kumi::concepts::empty_product_type<T>) return kumi::invoke(f, init);
69 else return KUMI_FWD(m)(kumi::invoke(f, init), (*this)(f, KUMI_FWD(m), KUMI_FWD(t)));
70 }
71 };
72
73 struct sum_t : private kumi::reduce_t
74 {
75 template<kumi::concepts::product_type T, typename Value>
76 [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t, Value init) const
77 {
78 2 return this->reduce_t::operator()(kumi::function::plus, KUMI_FWD(t), init);
79 }
80
81 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
82 {
83 2 return this->reduce_t::operator()(kumi::function::plus, KUMI_FWD(t));
84 }
85 };
86
87 struct prod_t : private kumi::reduce_t
88 {
89 template<kumi::concepts::product_type T, typename Value>
90 [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t, Value init) const
91 {
92 2 return this->reduce_t::operator()(kumi::function::multiplies, KUMI_FWD(t), init);
93 }
94
95 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
96 {
97 2 return this->reduce_t::operator()(kumi::function::multiplies, KUMI_FWD(t));
98 }
99 };
100
101 struct bit_and_t : private kumi::reduce_t
102 {
103 template<kumi::concepts::product_type T, typename Value>
104 [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t, Value init) const
105 {
106 2 return this->reduce_t::operator()(kumi::function::bit_and, KUMI_FWD(t), init);
107 }
108
109 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
110 {
111 2 return this->reduce_t::operator()(kumi::function::bit_and, KUMI_FWD(t));
112 }
113 };
114
115 struct bit_or_t : private kumi::reduce_t
116 {
117 template<kumi::concepts::product_type T, typename Value>
118 [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t, Value init) const
119 {
120 2 return this->reduce_t::operator()(kumi::function::bit_or, KUMI_FWD(t), init);
121 }
122
123 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
124 {
125 2 return this->reduce_t::operator()(kumi::function::bit_or, KUMI_FWD(t));
126 }
127 };
128
129 struct bit_xor_t : private kumi::reduce_t
130 {
131 template<kumi::concepts::product_type T, typename Value>
132 [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t, Value init) const
133 {
134 2 return this->reduce_t::operator()(kumi::function::bit_xor, KUMI_FWD(t), init);
135 }
136
137 template<kumi::concepts::product_type T> [[nodiscard]] KUMI_ABI constexpr auto operator()(T&& t) const
138 {
139 2 return this->reduce_t::operator()(kumi::function::bit_xor, KUMI_FWD(t));
140 }
141 };
142
143 //====================================================================================================================
144 /**
145 @ingroup kumi_reductions
146
147 @var reduce
148 @brief Callable object performing a tree-like reduction of all elements of a product type.
149
150 On record types, this function operates on the underlying values, not on the fields themselves.
151
152 @note For associative operations, this produces the same result as a left or right fold,
153 but has a different intermediate evaluation order.
154
155 @qualifier nodiscard inline constexpr
156
157 @groupheader{Header file}
158 @code
159 #include <kumi/algorithm/reduce.hpp>
160 @endcode
161
162 @groupheader{Call Signature}
163
164 @code
165 template<monoid M, product_type T>
166 constexpr auto reduce(M && m, T && t);
167 @endcode
168
169 @code
170 template<monoid M, product_type T, typename V>
171 constexpr auto reduce(M && m, T && t, V init);
172 @endcode
173
174 @subgroupheader{Parameters}
175
176 - `m`: Monoid callable function to apply
177 - `t`: Product Type to reduce
178 - `init`: Optional initial value of the reduction.
179
180 @subgroupheader{Return value}
181
182 * The result of reducing the elements of `t` by `m`, recursively combining elements in a tree structure.
183
184 @groupheader{Helper type}
185
186 @code
187 namespace kumi::result
188 {
189 template<monoid M, product_type T> struct reduce;
190
191 template<monoid M, product_type T>
192 using reduce_t = typename reduce<M,T>::type;
193
194 template<monoid M, product_type T, typename Value> struct reduce;
195
196 template<monoid M, product_type T, typename Value>
197 using reduce_t = typename reduce<M,T,Value>::type;
198 }
199 @endcode
200
201 Computes the return type of a call to kumi::reduce
202
203 @groupheader{Examples}
204
205 @tab_begin
206
207 @tab{Tuple}
208 @godbolt{doc/tuple/algo/reduce.cpp}
209
210 @tab{Record}
211 @godbolt{doc/record/algo/reduce.cpp}
212
213 @tab_end
214 **/
215 //====================================================================================================================
216 KUMI_VARIABLE_ABI constexpr reduce_t reduce{};
217
218 //====================================================================================================================
219 /**
220 @ingroup kumi_reductions
221
222 @var map_reduce
223 @brief Callable object performing a tree-like reduction of all elements of a product type. The given map
224 function is applied before executing the reduction to each element of the input.
225
226
227 On record types, this function operates on the underlying values, not on the fields themselves.
228
229 @note For associative operations, this produces the same result as a left or right fold preceded by map,
230 but has a different intermediate evaluation order.
231
232 @qualifier nodiscard inline constexpr
233
234 @groupheader{Header file}
235 @code
236 #include <kumi/algorithm/reduce.hpp>
237 @endcode
238
239 @groupheader{Call Signature}
240
241 @code
242 template<typename Function, monoid M, product_type T>
243 constexpr auto map_reduce(Function f, M && m, T && t);
244 @endcode
245
246 @code
247 template<typename Function, monoid M, product_type T, typename V>
248 constexpr auto map_reduce(Function f, M && m, T && t, V init);
249 @endcode
250
251 @subgroupheader{Parameters}
252
253 - `f`: Mapping function to apply
254 - `m`: Monoid callable function to apply
255 - `t`: Product Type to reduce
256 - `init`: Optional initial value of the reduction.
257
258 @subgroupheader{Return value}
259
260 * The result of reducing the elements of `t` by `m` after being processed by `f`,
261 recursively combining elements in a tree structure.
262
263 @groupheader{Helper type}
264
265 @code
266 namespace kumi::result
267 {
268 template<monoid M, product_type T> struct map_reduce;
269
270 template<monoid M, product_type T>
271 using map_reduce_t = typename map_reduce<M,T>::type;
272
273 template<monoid M, product_type T, typename Value> struct map_reduce;
274
275 template<monoid M, product_type T, typename Value>
276 using map_reduce_t = typename map_reduce<M,T,Value>::type;
277 }
278 @endcode
279
280 Computes the return type of a call to kumi::map_reduce
281
282 @groupheader{Examples}
283
284 @tab_begin
285
286 @tab{Tuple}
287 @godbolt{doc/tuple/algo/map_reduce.cpp}
288
289 @tab{Record}
290 @godbolt{doc/record/algo/map_reduce.cpp}
291
292 @tab_end
293 **/
294 //====================================================================================================================
295 KUMI_VARIABLE_ABI constexpr map_reduce_t map_reduce{};
296
297 //====================================================================================================================
298 /**
299 @ingroup kumi_reductions
300
301 @var sum
302 @brief Callable object computing the sum of all elements.
303
304 On record types, this function operates on the underlying values, not on the fields themselves.
305
306 @note For associative operations, this produces the same result as a left or right fold,
307 but has a different intermediate evaluation order.
308
309 @qualifier nodiscard inline constexpr
310
311 @groupheader{Header file}
312 @code
313 #include <kumi/algorithm/reduce.hpp>
314 @endcode
315
316 @groupheader{Call Signature}
317
318 @code
319 template<product_type T>
320 constexpr auto sum(T && t);
321 @endcode
322
323 @code
324 template<product_type T, typename V>
325 constexpr auto sum(T && t, V init);
326 @endcode
327
328 @subgroupheader{Parameters}
329
330 - `t`: Product Type to operate on
331 - `init`: Optional initial value of the reduction.
332
333 @subgroupheader{Return value}
334
335 * The result of the computation of `get<0>(t) + ... + get<N-1>(t) + init`
336
337 @groupheader{Helper type}
338
339 @code
340 namespace kumi::result
341 {
342 template<product_type T, typename Value> struct sum;
343
344 template<product_type T, typename Value>
345 using sum_t = typename sum<T,Value>::type;
346 }
347 @endcode
348
349 Computes the return type of a call to kumi::sum
350
351 @groupheader{Examples}
352
353 @tab_begin
354
355 @tab{Tuple}
356 @godbolt{doc/tuple/algo/sum.cpp}
357
358 @tab{Record}
359 @godbolt{doc/record/algo/sum.cpp}
360
361 @tab_end
362 **/
363 //====================================================================================================================
364 KUMI_VARIABLE_ABI constexpr sum_t sum{};
365
366 //====================================================================================================================
367 /**
368 @ingroup kumi_reductions
369
370 @var prod
371 @brief Callable object computing the product of all elements.
372
373 On record types, this function operates on the underlying values, not on the fields themselves.
374
375 @note For associative operations, this produces the same result as a left or right fold,
376 but has a different intermediate evaluation order.
377
378 @qualifier nodiscard inline constexpr
379
380 @groupheader{Header file}
381 @code
382 #include <kumi/algorithm/reduce.hpp>
383 @endcode
384
385 @groupheader{Call Signature}
386
387 @code
388 template<product_type T>
389 constexpr auto prod(T && t);
390 @endcode
391
392 @code
393 template<product_type T, typename V>
394 constexpr auto prod(T && t, V init);
395 @endcode
396
397 @subgroupheader{Parameters}
398
399 - `t`: Product Type to operate on
400 - `init`: Optional initial value of the reduction.
401
402 @subgroupheader{Return value}
403
404 * The result of the computation of `get<0>(t) * ... * get<N-1>(t) * init`
405
406 @groupheader{Helper type}
407
408 @code
409 namespace kumi::result
410 {
411 template<product_type T, typename Value> struct prod;
412
413 template<product_type T, typename Value>
414 using prod_t = typename prod<T,Value>::type;
415 }
416 @endcode
417
418 Computes the return type of a call to kumi::prod
419
420 @groupheader{Examples}
421
422 @tab_begin
423
424 @tab{Tuple}
425 @godbolt{doc/tuple/algo/prod.cpp}
426
427 @tab{Record}
428 @godbolt{doc/record/algo/prod.cpp}
429
430 @tab_end
431 **/
432 //====================================================================================================================
433 KUMI_VARIABLE_ABI constexpr prod_t prod{};
434
435 //====================================================================================================================
436 /**
437 @ingroup kumi_reductions
438
439 @var bit_and
440 @brief Callable object computing the bitwise AND of all elements.
441
442 On record types, this function operates on the underlying values, not on the fields themselves.
443
444 @note For associative operations, this produces the same result as a left or right fold,
445 but has a different intermediate evaluation order.
446
447 @qualifier nodiscard inline constexpr
448
449 @groupheader{Header file}
450 @code
451 #include <kumi/algorithm/reduce.hpp>
452 @endcode
453
454 @groupheader{Call Signature}
455
456 @code
457 template<product_type T>
458 constexpr auto bit_and(T && t);
459 @endcode
460
461 @code
462 template<product_type T, typename V>
463 constexpr auto bit_and(T && t, V init);
464 @endcode
465
466 @subgroupheader{Parameters}
467
468 - `t`: Product Type to operate on
469 - `init`: Optional initial value of the reduction.
470
471 @subgroupheader{Return value}
472
473 * The result of the computation of `get<0>(t) & ... & get<N-1>(t) & init`
474
475 @groupheader{Helper type}
476
477 @code
478 namespace kumi::result
479 {
480 template<product_type T, typename Value> struct bit_and;
481
482 template<product_type T, typename Value>
483 using bit_and_t = typename bit_and<T,Value>::type;
484 }
485 @endcode
486
487 Computes the return type of a call to kumi::bit_and
488
489 @groupheader{Examples}
490
491 @tab_begin
492
493 @tab{Tuple}
494 @godbolt{doc/tuple/algo/bit_and.cpp}
495
496 @tab{Record}
497 @godbolt{doc/record/algo/bit_and.cpp}
498
499 @tab_end
500 **/
501 //====================================================================================================================
502 KUMI_VARIABLE_ABI constexpr bit_and_t bit_and{};
503
504 //====================================================================================================================
505 /**
506 @ingroup kumi_reductions
507
508 @var bit_or
509 @brief Callable object computing the bitwise OR of all elements.
510
511 On record types, this function operates on the underlying values, not on the fields themselves.
512
513 @note For associative operations, this produces the same result as a left or right fold,
514 but has a different intermediate evaluation order.
515
516 @qualifier nodiscard inline constexpr
517
518 @groupheader{Header file}
519 @code
520 #include <kumi/algorithm/reduce.hpp>
521 @endcode
522
523 @groupheader{Call Signature}
524
525 @code
526 template<product_type T>
527 constexpr auto bit_or(T && t);
528 @endcode
529
530 @code
531 template<product_type T, typename V>
532 constexpr auto bit_or(T && t, V init);
533 @endcode
534
535 @subgroupheader{Parameters}
536
537 - `t`: Product Type to operate on
538 - `init`: Optional initial value of the reduction.
539
540 @subgroupheader{Return value}
541
542 * The result of the computation of `get<0>(t) | ... | get<N-1>(t) | init`
543
544 @groupheader{Helper type}
545
546 @code
547 namespace kumi::result
548 {
549 template<product_type T, typename Value> struct bit_or;
550
551 template<product_type T, typename Value>
552 using bit_or_t = typename bit_or<T,Value>::type;
553 }
554 @endcode
555
556 Computes the return type of a call to kumi::bit_or
557
558 @groupheader{Examples}
559
560 @tab_begin
561
562 @tab{Tuple}
563 @godbolt{doc/tuple/algo/bit_or.cpp}
564
565 @tab{Record}
566 @godbolt{doc/record/algo/bit_or.cpp}
567
568 @tab_end
569 **/
570 //====================================================================================================================
571 KUMI_VARIABLE_ABI constexpr bit_or_t bit_or{};
572
573 //====================================================================================================================
574 /**
575 @ingroup kumi_reductions
576
577 @var bit_xor
578 @brief Callable object computing the bitwise XOR of all elements.
579
580 On record types, this function operates on the underlying values, not on the fields themselves.
581
582 @note For associative operations, this produces the same result as a left or right fold,
583 but has a different intermediate evaluation order.
584
585 @qualifier nodiscard inline constexpr
586
587 @groupheader{Header file}
588 @code
589 #include <kumi/algorithm/reduce.hpp>
590 @endcode
591
592 @groupheader{Call Signature}
593
594 @code
595 template<product_type T>
596 constexpr auto bit_xor(T && t);
597 @endcode
598
599 @code
600 template<product_type T, typename V>
601 constexpr auto bit_xor(T && t, V init);
602 @endcode
603
604 @subgroupheader{Parameters}
605
606 - `t`: Product Type to operate on
607 - `init`: Optional initial value of the reduction.
608
609 @subgroupheader{Return value}
610
611 * The result of the computation of `get<0>(t) ^ ... ^ get<N-1>(t) ^ init`
612
613 @groupheader{Helper type}
614
615 @code
616 namespace kumi::result
617 {
618 template<product_type T, typename Value> struct bit_xor;
619
620 template<product_type T, typename Value>
621 using bit_xor_t = typename bit_xor<T,Value>::type;
622 }
623 @endcode
624
625 Computes the return type of a call to kumi::bit_xor
626
627 @groupheader{Examples}
628
629 @tab_begin
630
631 @tab{Tuple}
632 @godbolt{doc/tuple/algo/bit_xor.cpp}
633
634 @tab{Record}
635 @godbolt{doc/record/algo/bit_xor.cpp}
636
637 @tab_end
638 **/
639 //====================================================================================================================
640 KUMI_VARIABLE_ABI constexpr bit_xor_t bit_xor{};
641
642 namespace result
643 {
644 //! [reduce_t]
645 template<kumi::concepts::monoid M, kumi::concepts::product_type T, typename... Value>
646 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
647 using reduce_t = decltype(kumi::reduce(std::declval<M>(), std::declval<T>(), std::declval<Value>()...));
648
649 template<kumi::concepts::monoid M, kumi::concepts::product_type T, typename... Value>
650 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
651 struct reduce
652 {
653 using type = kumi::result::reduce_t<M, T, Value...>;
654 };
655
656 //! [reduce_t]
657
658 //! [map_reduce_t]
659 template<typename F, kumi::concepts::monoid M, kumi::concepts::product_type T, typename... Value>
660 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
661 using map_reduce_t =
662 decltype(kumi::map_reduce(std::declval<F>(), std::declval<M>(), std::declval<T>(), std::declval<Value>()...));
663
664 template<typename F, kumi::concepts::monoid M, kumi::concepts::product_type T, typename... Value>
665 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
666 struct map_reduce
667 {
668 using type = kumi::result::map_reduce_t<F, M, T, Value...>;
669 };
670
671 //! [map_reduce_t]
672
673 //! [sum_t]
674 template<kumi::concepts::product_type T, typename... Value>
675 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
676 using sum_t = decltype(kumi::sum(std::declval<T>(), std::declval<Value>()...));
677
678 template<kumi::concepts::product_type T, typename... Value>
679 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
680 struct sum
681 {
682 using type = kumi::result::sum_t<T, Value...>;
683 };
684
685 //! [sum_t]
686
687 //! [prod_t]
688 template<kumi::concepts::product_type T, typename... Value>
689 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
690 using prod_t = decltype(kumi::prod(std::declval<T>(), std::declval<Value>()...));
691
692 template<kumi::concepts::product_type T, typename... Value>
693 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
694 struct prod
695 {
696 using type = kumi::result::prod_t<T, Value...>;
697 };
698
699 //! [prod_t]
700
701 //! [bit_and_t]
702 template<kumi::concepts::product_type T, typename... Value>
703 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
704 using bit_and_t = decltype(kumi::bit_and(std::declval<T>(), std::declval<Value>()...));
705
706 template<kumi::concepts::product_type T, typename... Value>
707 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
708 struct bit_and
709 {
710 using type = kumi::result::bit_and_t<T, Value...>;
711 };
712
713 //! [bit_and_t]
714
715 //! [bit_or_t]
716 template<kumi::concepts::product_type T, typename... Value>
717 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
718 using bit_or_t = decltype(kumi::bit_or(std::declval<T>(), std::declval<Value>()...));
719
720 template<kumi::concepts::product_type T, typename... Value>
721 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
722 struct bit_or
723 {
724 using type = kumi::result::bit_or_t<T, Value...>;
725 };
726
727 //! [bit_or_t]
728
729 //! [bit_xor_t]
730 template<kumi::concepts::product_type T, typename... Value>
731 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
732 using bit_xor_t = decltype(kumi::bit_xor(std::declval<T>(), std::declval<Value>()...));
733
734 template<kumi::concepts::product_type T, typename... Value>
735 requires((sizeof...(Value) == 0) || (sizeof...(Value) == 1))
736 struct bit_xor
737 {
738 using type = kumi::result::bit_xor_t<T, Value...>;
739 };
740
741 //! [bit_xor_t]
742 }
743 }
744