Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
transform_reduce.hpp
Go to the documentation of this file.
1// parasoft-begin-suppress AUTOSAR-A2_8_1-a-2 "False positive: also defines arene::base::transform_reduce"
2
3// Copyright 2026, Toyota Motor Corporation
4//
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
7#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_ALGORITHM_TRANSFORM_REDUCE_HPP_
8#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_ALGORITHM_TRANSFORM_REDUCE_HPP_
9
10// IWYU pragma: private, include "arene/base/algorithm.hpp"
11// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
12
13// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
14
15// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
16#include "arene/base/algorithm/detail/generalized_transform_reduce.hpp"
17#include "arene/base/algorithm/detail/traits.hpp"
18#include "arene/base/compiler_support/cpp14_inline.hpp"
19#include "arene/base/constraints/constraints.hpp"
20#include "arene/base/optional/optional.hpp"
21#include "arene/base/stdlib_choice/enable_if.hpp"
22#include "arene/base/stdlib_choice/forward.hpp"
23#include "arene/base/stdlib_choice/is_constructible.hpp"
24#include "arene/base/stdlib_choice/is_destructible.hpp"
25#include "arene/base/stdlib_choice/is_move_assignable.hpp"
26#include "arene/base/stdlib_choice/is_move_constructible.hpp"
27#include "arene/base/stdlib_choice/move.hpp"
28#include "arene/base/stdlib_choice/multiplies.hpp"
29#include "arene/base/stdlib_choice/plus.hpp"
30#include "arene/base/type_traits/is_invocable.hpp"
31#include "arene/base/type_traits/iterator_category_traits.hpp"
32// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
33
34// IWYU pragma: no_include "arene/base/stdlib_choice/iterator_traits.hpp"
35
36// parasoft-begin-suppress AUTOSAR-M2_10_1-a-2 "Similar names permitted by M2-10-1 Permit #1"
37
38namespace arene {
39namespace base {
40namespace algorithm_detail {
41namespace transform_reduce_detail {
42
43/// @brief function object implementing 'transform_reduce'
44class transform_reduce_fn {
45 /// @brief obtains the return type of invoking the first argument on a pack of dereferenced instances of the remaining
46 /// arguments
47 /// @tparam Invocable invocable type
48 /// @tparam Iterator iterator argument types
49 ///
50 template <class Invocable, class... Iterator>
51 using iter_result_t = invoke_result_t<Invocable, iter_reference_t<Iterator>...>;
52
53 /// @brief policy for handling the accumulator
54 /// @tparam Value accumulator value type
55 ///
56 /// Primary template for types that are *not* move assignable. Uses an
57 /// @c optional to allow use of @c transform_reduce for types that are move
58 /// constructible but not move assignable.
59 ///
60 template <class Value, bool = std::is_move_assignable<Value>::value>
61 class reduce_value_policy {
62 public:
63 /// @brief value type to use in the underlying implementation function
64 using value_type = optional<Value>;
65
66 /// @brief generalized assignment
67 /// @tparam Result result type
68 /// @param acc reference to the accumulator
69 /// @param result value to assign
70 ///
71 /// Update @c acc with @c result. This is intended to provide functionality
72 /// similar to ranges exposition-only utility movable-box.
73 ///
74 template <class Result>
75 static auto assign(value_type& acc, Result&& result) noexcept(
76 std::is_nothrow_destructible<value_type>::value && //
77 std::is_nothrow_constructible<Value, Result&&>::value
78 ) -> void {
79 acc.emplace(std::forward<Result>(result));
80 }
81 /// @brief generalized access
82 /// @param acc lvalue reference to the accumulator
83 /// @return <c> move(acc) </c>
84 ///
85 static auto access(value_type& acc) noexcept -> Value&& { return *std::move(acc); }
86 /// @brief generalized access
87 /// @param acc rvalue reference to the accumulator
88 /// @return <c> move(acc) </c>
89 ///
90 static auto access(value_type&& acc) noexcept -> Value&& { return *std::move(acc); }
91 };
92
93 /// @brief policy for handling the accumulator
94 /// @tparam Value accumulator value type
95 ///
96 /// Specialization for types that *are* move assignable.
97 ///
98 template <class Value>
99 class reduce_value_policy<Value, true> //
100 : public generalized_transform_reduce::default_reduce_value_policy<Value> {};
101
102 public:
103 /// @brief applies an invocable, then reduces out of order
104 /// @tparam InputIt1 type of the iterator for the first range
105 /// @tparam InputIt2 type of the iterator for the second range
106 /// @tparam Value type of the reduced value
107 /// @tparam Reduce type of the reduction operation
108 /// @tparam Transform type of the transform operation
109 /// @param first1 iterator to the beginning of the first range
110 /// @param last1 iterator to one past the end of the first range
111 /// @param first2 iterator to the beginning of the second range
112 /// @param init initial value to start with
113 /// @param reduce binary function object used to reduce transformed elements
114 /// to a single value
115 /// @param transform binary function object applied to each pair of elements
116 /// of the input ranges
117 ///
118 /// @return The generalized sum of @c init and @c values over @c reduce, where
119 /// @c values are the values transformed by @c transform, each value is
120 /// transformed from a pair of elements from the two input ranges.
121 ///
122 /// @pre <c> [first2, first2 + distance(first1, last1)) </c> is a valid range
123 /// @pre @c reduce does not invalidate subranges, nor modify elements in the
124 /// ranges <c> [first1, last1) </c> and
125 /// <c> [first2, first2 + distance(first1, last1))) </c>
126 /// @pre @c transform does not invalidate subranges, nor modify elements in the
127 /// ranges <c> [first1, last1) </c> and
128 /// <c> [first2, first2 + distance(first1, last1)) </c>
129 ///
130 /// @note Constraints <br>
131 /// * @c InputIt1 must satisfy the input iterator requirements
132 /// * @c InputIt2 must satisfy the input iterator requirements
133 /// * @c Value is move constructible
134 /// * <c> reduce(init, init) </c> is convertible to @c Value
135 /// * <c> reduce(init, transform(*first1, *first2)) </c>
136 /// is convertible to @c Value
137 /// * <c> reduce(transform(*first1, *first2), init) </c>
138 /// is convertible to @c Value
139 /// * <c> reduce(transform(*first1, *first2), transform(*first1, *first2)) </c>
140 /// is convertible to @c Value
141 ///
142 /// @note Complexity <br>
143 /// O(N) applications of @c reduce and @c transform, where
144 /// <c> N = distance(first1, last1) </c>.
145 ///
146 /// @note Unlike @c inner_product, the order in which elements are transformed
147 /// and reduced is unspecified.
148 ///
149 /// @note The result is non-deterministic if @c reduce is not associative or
150 /// not commutative (e.g. floating-point addition).
151 ///
152 template <
153 class InputIt1,
154 class InputIt2,
155 class Value,
156 class Reduce,
157 class Transform,
158 constraints<
159 std::enable_if_t<is_input_iterator_v<InputIt1>>,
160 std::enable_if_t<is_input_iterator_v<InputIt2>>,
161 std::enable_if_t<std::is_move_constructible<Value>::value>,
162 std::enable_if_t<is_invocable_r_v< //
163 Value,
164 Reduce&,
165 Value&,
166 Value&>>,
167 std::enable_if_t<is_invocable_r_v< //
168 Value,
169 Reduce&,
170 Value&,
171 iter_result_t<Transform&, InputIt1, InputIt2>>>,
172 std::enable_if_t<is_invocable_r_v< //
173 Value,
174 Reduce&,
175 iter_result_t<Transform&, InputIt1, InputIt2>,
176 Value&>>,
177 std::enable_if_t<is_invocable_r_v< //
178 Value,
179 Reduce&,
180 iter_result_t<Transform&, InputIt1, InputIt2>,
181 iter_result_t<Transform&, InputIt1, InputIt2>>>> = nullptr>
182 constexpr auto operator()(
183 InputIt1 first1,
184 InputIt1 last1,
185 InputIt2 first2,
186 Value init,
187 Reduce reduce,
188 // parasoft-begin-suppress AUTOSAR-A2_10_1-a "It does not matter if 'transform' hides an identifier at global or namespace scope"
189 Transform transform
190 // parasoft-end-suppress AUTOSAR-A2_10_1-a
191 ) const noexcept( //
192 std::is_nothrow_constructible<
193 typename reduce_value_policy<Value>::value_type,
194 Value&&
195 >::value &&
196 std::is_nothrow_move_constructible<Value>::value &&
197 is_nothrow_invocable_v<
198 generalized_transform_reduce,
199 reduce_value_policy<Value>,
200 InputIt1&,
201 InputIt1&,
202 InputIt2&,
203 typename reduce_value_policy<Value>::value_type,
204 Reduce&,
205 Transform&>
206 )
207 -> Value
208 {
209 using value_policy = reduce_value_policy<Value>;
210
211 return value_policy::access( //
212 generalized_transform_reduce{}( //
213 value_policy{},
214 first1,
215 last1,
216 first2,
217 typename value_policy::value_type{std::move(init)},
218 reduce,
219 transform
220 )
221 );
222 }
223
224 /// @brief applies an invocable, then reduces out of order
225 /// @tparam InputIt1 type of the iterator for the first range
226 /// @tparam InputIt2 type of the iterator for the second range
227 /// @tparam Value type of the reduced value
228 /// @param first1 iterator to the beginning of the first range
229 /// @param last1 iterator to one past the end of the first range
230 /// @param first2 iterator to the beginning of the second range
231 /// @param init initial value to start with
232 ///
233 /// @return The generalized sum of @c init and @c values over @c operator+, where
234 /// @c values are the values transformed by @c operator*, each value is
235 /// transformed from a pair of elements from the two input ranges.
236 ///
237 /// @pre <c> [first2, first2 + distance(first1, last1)) </c> is a valid range
238 /// @pre binary @c operator+ does not invalidate subranges, nor modify
239 /// elements in the ranges <c> [first1, last1) </c> and
240 /// <c> [first2, first2 + distance(first1, last1))) </c>
241 /// @pre binary @c operator* does not invalidate subranges, nor modify
242 /// elements in the ranges <c> [first1, last1) </c> and
243 /// <c> [first2, first2 + distance(first1, last1)) </c>
244 ///
245 /// @note Constraints <br>
246 /// * @c InputIt1 must satisfy the input iterator requirements
247 /// * @c InputIt2 must satisfy the input iterator requirements
248 /// * @c Value is move constructible
249 /// * <c> init + init </c> is convertible to @c Value
250 /// * <c> init + (*first1 * *first2) </c>
251 /// is convertible to @c Value
252 /// * <c> (*first1 * *first2) + init </c>
253 /// is convertible to @c Value
254 /// * <c> (*first1 * *first2) + (*first1 * *first2)) </c>
255 /// is convertible to @c Value
256 ///
257 /// @note Complexity <br>
258 /// O(N) applications of @c operator+ and @c operator*, where
259 /// <c> N = distance(first1, last1) </c>.
260 ///
261 /// @note Unlike @c inner_product, the order in which elements are transformed
262 /// and reduced is unspecified.
263 ///
264 /// @note The result is non-deterministic if @c operator+ is not associative or
265 /// not commutative (e.g. floating-point addition).
266 ///
267 template <
268 class InputIt1,
269 class InputIt2,
270 class Value,
271 constraints<
272 std::enable_if_t<is_input_iterator_v<InputIt1>>,
273 std::enable_if_t<is_input_iterator_v<InputIt2>>,
274 std::enable_if_t<std::is_move_constructible<Value>::value>,
275 std::enable_if_t<is_invocable_r_v< //
276 Value,
277 std::plus<>&,
278 Value&,
279 Value&>>,
280 std::enable_if_t<is_invocable_r_v< //
281 Value,
282 std::plus<>&,
283 Value&,
284 iter_result_t<std::multiplies<>&, InputIt1, InputIt2>>>,
285 std::enable_if_t<is_invocable_r_v< //
286 Value,
287 std::plus<>&,
288 iter_result_t<std::multiplies<>&, InputIt1, InputIt2>,
289 Value&>>,
290 std::enable_if_t<is_invocable_r_v< //
291 Value,
292 std::plus<>&,
293 iter_result_t<std::multiplies<>&, InputIt1, InputIt2>,
294 iter_result_t<std::multiplies<>&, InputIt1, InputIt2>>>> = nullptr>
295 constexpr auto operator()(
296 InputIt1 first1,
297 InputIt1 last1,
298 InputIt2 first2,
299 Value init
300 ) const noexcept( //
301 is_nothrow_invocable_v<
302 transform_reduce_fn,
303 InputIt1&&,
304 InputIt1&&,
305 InputIt2&&,
306 Value&&,
307 std::plus<>&&,
308 std::multiplies<>&&>
309 )
310 -> Value
311 {
312 return (*this)(
313 std::move(first1),
314 std::move(last1),
315 std::move(first2),
316 std::move(init),
317 std::plus<>{},
318 std::multiplies<>{}
319 );
320 }
321};
322} // namespace transform_reduce_detail
323} // namespace algorithm_detail
324
325/// @def arene::base::transform_reduce
326/// @brief applies an invocable, then reduces out of order
327/// @copydoc arene::base::algorithm_detail::transform_reduce_detail::transform_reduce_fn::operator()
328// parasoft-begin-suppress AUTOSAR-M7_3_3-a "An unnamed namespace is used to create a per-TU reference to a global
329// object used in multiple TUs."
330// parasoft-begin-suppress CERT_CPP-DCL59-a "An unnamed namespace is used to create a per-TU reference to a global
331// object used in multiple TUs."
332ARENE_CPP14_INLINE_VARIABLE(algorithm_detail::transform_reduce_detail::transform_reduce_fn, transform_reduce);
333// parasoft-end-suppress AUTOSAR-M7_3_3-a
334// parasoft-end-suppress CERT_CPP-DCL59-a
335
336} // namespace base
337} // namespace arene
338
339#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_ALGORITHM_TRANSFORM_REDUCE_HPP_
Definition array_exceptions_disabled.cpp:11
ARENE_CPP14_INLINE_VARIABLE(algorithm_detail::transform_reduce_detail::transform_reduce_fn, transform_reduce)
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10