Skip to content

Commit 02c3330

Browse files
authored
feat(bb): iterative constexpr_for (#8502)
Replaces the custom made solution. Needed for stack not to blow up in a few places.
1 parent 5a76ec6 commit 02c3330

File tree

2 files changed

+22
-41
lines changed

2 files changed

+22
-41
lines changed

barretenberg/cpp/src/barretenberg/common/constexpr_utils.hpp

+20-31
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@
55
#include <utility>
66

77
namespace bb {
8+
namespace detail {
9+
10+
/**
11+
* @brief Create an index sequence from Min to Max (not included) with an increment of Inc
12+
*/
13+
template <size_t Min, size_t Max, size_t Inc> constexpr auto make_index_range()
14+
{
15+
static_assert(Max >= Min);
16+
static_assert(Inc >= 1);
17+
return []<size_t... Is>(std::index_sequence<Is...>) {
18+
return std::index_sequence<Min + (Is * Inc)...>{};
19+
}(std::make_index_sequence<(Max - Min - 1) / Inc + 1>{});
20+
}
21+
22+
} // namespace detail
823

924
/**
1025
* @brief Implements a loop using a compile-time iterator. Requires c++20.
@@ -55,37 +70,11 @@ namespace bb {
5570
*/
5671
template <size_t Start, size_t End, size_t Inc, class F> constexpr void constexpr_for(F&& f)
5772
{
58-
// Call function `f<Start>()` iff Start < End
59-
if constexpr (Start < End) {
60-
// F must be a template lambda with a single **typed** template parameter that represents the iterator
61-
// (e.g. [&]<size_t i>(){ ... } is good)
62-
// (and [&]<typename i>(){ ... } won't compile!)
63-
64-
/**
65-
* Explaining f.template operator()<Start>()
66-
*
67-
* The following line must explicitly tell the compiler that <Start> is a template parameter by using the
68-
* `template` keyword.
69-
* (if we wrote f<Start>(), the compiler could legitimately interpret `<` as a less than symbol)
70-
*
71-
* The fragment `f.template` tells the compiler that we're calling a *templated* member of `f`.
72-
* The "member" being called is the function operator, `operator()`, which must be explicitly provided
73-
* (for any function X, `X(args)` is an alias for `X.operator()(args)`)
74-
* The compiler has no alias `X.template <tparam>(args)` for `X.template operator()<tparam>(args)` so we must
75-
* write it explicitly here
76-
*
77-
* To summarize what the next line tells the compiler...
78-
* 1. I want to call a member of `f` that expects one or more template parameters
79-
* 2. The member of `f` that I want to call is the function operator
80-
* 3. The template parameter is `Start`
81-
* 4. The function operator itself contains no arguments
82-
*/
83-
f.template operator()<Start>();
84-
85-
// Once we have executed `f`, we recursively call the `constexpr_for` function, increasing the value of `Start`
86-
// by `Inc`
87-
constexpr_for<Start + Inc, End, Inc>(f);
88-
}
73+
// F must be a template lambda with a single **typed** template parameter that represents the iterator
74+
// (e.g. [&]<size_t i>(){ ... } is good)
75+
// (and [&]<typename i>(){ ... } won't compile!)
76+
constexpr auto indices = detail::make_index_range<Start, End, Inc>();
77+
[&]<size_t... Is>(std::index_sequence<Is...>) { (f.template operator()<Is>(), ...); }(indices);
8978
}
9079

9180
}; // namespace bb

barretenberg/cpp/src/barretenberg/relations/utils.hpp

+2-10
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,6 @@ template <typename Flavor> class RelationUtils {
140140
}
141141
}
142142

143-
// This is an simpler, iterative version of constexpr_for.
144-
// Replace it with constexpr_for once that one is iterative.
145-
template <size_t N, typename F> static constexpr void iterative_constexpr_for(F&& f)
146-
{
147-
auto seq = std::make_index_sequence<N>{};
148-
[&]<size_t... I>(std::index_sequence<I...>) { (f.template operator()<I>(), ...); }(seq);
149-
}
150-
151143
/**
152144
* @brief Calculate the contribution of each relation to the expected value of the full Honk relation.
153145
*
@@ -164,7 +156,7 @@ template <typename Flavor> class RelationUtils {
164156
const Parameters& relation_parameters,
165157
const FF& partial_evaluation_result)
166158
{
167-
iterative_constexpr_for<NUM_RELATIONS>([&]<size_t rel_index>() {
159+
constexpr_for<0, NUM_RELATIONS, 1>([&]<size_t rel_index>() {
168160
// FIXME: You wan't /*consider_skipping=*/false here, but tests need to be fixed.
169161
accumulate_single_relation<Parameters, rel_index, /*consider_skipping=*/true>(
170162
evaluations, relation_evaluations, relation_parameters, partial_evaluation_result);
@@ -187,7 +179,7 @@ template <typename Flavor> class RelationUtils {
187179
const Parameters& relation_parameters,
188180
const FF& partial_evaluation_result)
189181
{
190-
iterative_constexpr_for<NUM_RELATIONS>([&]<size_t rel_index>() {
182+
constexpr_for<0, NUM_RELATIONS, 1>([&]<size_t rel_index>() {
191183
accumulate_single_relation<Parameters, rel_index>(
192184
evaluations, relation_evaluations, relation_parameters, partial_evaluation_result);
193185
});

0 commit comments

Comments
 (0)