Skip to content

Commit 32b6e19

Browse files
committed
Simplify visit implementation.
1 parent f1b340d commit 32b6e19

File tree

1 file changed

+50
-82
lines changed

1 file changed

+50
-82
lines changed

source/tv/visit.cpp

Lines changed: 50 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -70,54 +70,44 @@ constexpr auto is_cartesian_product_callable<Function, types<Args...>, types<Typ
7070
is_cartesian_product_callable<Function, types<Args..., Types>, Rest...>
7171
);
7272

73-
// The primary template just rotates the parameters
74-
template<std::size_t index, template<typename> typename GetTypes, typename Arg, typename... Args>
75-
constexpr auto is_variants_then_visit_function = is_variants_then_visit_function<
76-
index - 1U,
77-
GetTypes,
78-
Args...,
79-
Arg
80-
>;
81-
// The specialization forwards to the implementation that does the real work
82-
template<template<typename> typename GetTypes, typename Function, typename... Variants>
83-
constexpr auto is_variants_then_visit_function<
84-
0U,
85-
GetTypes,
86-
Function,
87-
Variants...
88-
> = is_cartesian_product_callable<
89-
Function,
90-
types<>,
91-
GetTypes<Variants>...
92-
>;
93-
94-
95-
template<std::size_t... indexes>
96-
constexpr decltype(auto) visit_implementation(
73+
template<template<typename> typename GetTypes, typename Function, typename... Variants, std::size_t... indexes>
74+
consteval auto is_variants_then_visit_function(std::index_sequence<indexes...>) -> bool {
75+
return is_cartesian_product_callable<
76+
Function,
77+
types<>,
78+
GetTypes<Variants...[indexes]>...
79+
>;
80+
}
81+
82+
template<bool use_index, std::size_t, std::size_t... indexes>
83+
constexpr auto visit_implementation(
9784
auto && function,
9885
std::index_sequence<indexes...>,
9986
bounded::constant_t<0>,
10087
auto && ... variants
101-
) requires(sizeof...(indexes) == sizeof...(variants)) {
102-
return OPERATORS_FORWARD(function)(
103-
indexed_value<
104-
decltype(OPERATORS_FORWARD(variants)[bounded::constant<indexes>]),
105-
indexes
106-
>(OPERATORS_FORWARD(variants)[bounded::constant<indexes>])...
107-
);
88+
) -> decltype(auto) requires(sizeof...(indexes) == sizeof...(variants)) {
89+
if constexpr (use_index) {
90+
return OPERATORS_FORWARD(function)(
91+
indexed_value<
92+
decltype(OPERATORS_FORWARD(variants)[bounded::constant<indexes>]),
93+
indexes
94+
>(OPERATORS_FORWARD(variants)[bounded::constant<indexes>])...
95+
);
96+
} else {
97+
return OPERATORS_FORWARD(function)(
98+
OPERATORS_FORWARD(variants)[bounded::constant<indexes>]...
99+
);
100+
}
108101
}
109102

110-
// This function accepts the pack of all variants twice. It passes over them
111-
// once to get all the indexes, then again to pull out the values.
112-
template<std::size_t... indexes>
113-
constexpr decltype(auto) visit_implementation(
103+
template<bool use_index, std::size_t variant_index, std::size_t... indexes>
104+
constexpr auto visit_implementation(
114105
auto && function,
115106
std::index_sequence<indexes...> initial_indexes,
116107
auto offset,
117-
auto const & variant,
118108
auto && ... variants
119-
) requires(sizeof...(indexes) < sizeof...(variants)) {
120-
auto const search_index = variant.index().integer();
109+
) -> decltype(auto) requires(sizeof...(indexes) < sizeof...(variants)) {
110+
auto const search_index = variants...[variant_index].index().integer();
121111
auto const this_search = search_index - offset;
122112

123113
// Cannot use a lambda because there is no return type that would be valid
@@ -127,7 +117,7 @@ constexpr decltype(auto) visit_implementation(
127117
if constexpr (numeric_traits::max_value<decltype(this_search)> < (index)) { \
128118
std::unreachable(); \
129119
} else { \
130-
return ::tv::visit_implementation( \
120+
return ::tv::visit_implementation<use_index, variant_index + 1>( \
131121
OPERATORS_FORWARD(function), \
132122
std::index_sequence<indexes..., static_cast<std::size_t>(offset + (index))>{}, \
133123
0_bi, \
@@ -159,11 +149,10 @@ constexpr decltype(auto) visit_implementation(
159149
if constexpr (numeric_traits::max_value<decltype(this_search)> < max_index) {
160150
std::unreachable();
161151
} else {
162-
return ::tv::visit_implementation(
152+
return ::tv::visit_implementation<use_index, variant_index>(
163153
OPERATORS_FORWARD(function),
164154
initial_indexes,
165155
offset + max_index,
166-
variant,
167156
OPERATORS_FORWARD(variants)...
168157
);
169158
}
@@ -172,65 +161,44 @@ constexpr decltype(auto) visit_implementation(
172161
#undef VISIT_IMPL
173162
}
174163

175-
template<typename, auto>
176-
concept any_with_value = true;
177-
178164
// Often, we want to write a function that accepts a variadic number of
179165
// arguments and a function. We would like to accept the function parameter
180166
// last, since that gives the best syntax when passing a lambda. However, you
181167
// cannot put something after a variadic pack, therefore the function is part of
182168
// the pack. rotate_transform allows us to write an interface that accepts stuff
183169
// and a function to operate on the stuff, but allows us to decide whether to
184170
// pass values or indexed values to the user's function.
185-
template<std::size_t... indexes>
186-
constexpr auto rotate_transform_impl(std::index_sequence<indexes...>) {
187-
return [](
188-
auto const transform,
189-
any_with_value<indexes> auto && ... variants,
190-
auto && function
191-
) -> decltype(auto) {
192-
return ::tv::visit_implementation(
193-
transform(OPERATORS_FORWARD(function)),
194-
std::index_sequence<>{},
195-
0_bi,
196-
variants...,
197-
OPERATORS_FORWARD(variants)...
198-
);
199-
};
200-
}
201-
202-
constexpr auto rotate_transform(auto const transform, auto && ... args) -> decltype(auto) {
203-
auto impl = ::tv::rotate_transform_impl(std::make_index_sequence<sizeof...(args) - 1>());
204-
return impl(transform, OPERATORS_FORWARD(args)...);
171+
template<bool use_index, std::size_t... indexes>
172+
constexpr auto rotate_transform(auto && function, std::index_sequence<indexes...>, auto && ... args) -> decltype(auto) {
173+
return ::tv::visit_implementation<use_index, 0>(
174+
OPERATORS_FORWARD(function),
175+
std::index_sequence<>(),
176+
0_bi,
177+
OPERATORS_FORWARD(args...[indexes])...
178+
);
205179
}
206180

207-
struct identity {
208-
static constexpr auto operator()(auto && function) -> auto && {
209-
return function;
210-
}
211-
};
212-
213181
// Accepts any number of variants (including 0) followed by one function
214182
export constexpr auto visit_with_index = []<typename... Args>(Args && ... args) static -> decltype(auto)
215-
requires is_variants_then_visit_function<sizeof...(Args) - 1U, indexed_variant_types, Args...>
183+
requires(is_variants_then_visit_function<indexed_variant_types, Args...[sizeof...(args) - 1], Args...>(std::make_index_sequence<sizeof...(Args) - 1>()))
216184
{
217-
return ::tv::rotate_transform(identity(), OPERATORS_FORWARD(args)...);
218-
};
219-
220-
struct remove_index {
221-
static constexpr auto operator()(auto && function) {
222-
return [&](auto && ... args) -> decltype(auto) {
223-
return OPERATORS_FORWARD(function)(OPERATORS_FORWARD(args).value()...);
224-
};
225-
}
185+
return ::tv::rotate_transform<true>(
186+
OPERATORS_FORWARD(args...[sizeof...(args) - 1]),
187+
std::make_index_sequence<sizeof...(args) - 1>(),
188+
OPERATORS_FORWARD(args)...
189+
);
226190
};
227191

228192
// Accepts any number of variants (including 0) followed by one function with
229193
// arity equal to the number of variants
230194
export constexpr auto visit = []<typename... Args>(Args && ... args) static -> decltype(auto)
231-
requires is_variants_then_visit_function<sizeof...(Args) - 1U, variant_types, Args...>
195+
requires(is_variants_then_visit_function<variant_types, Args...[sizeof...(args) - 1], Args...>(std::make_index_sequence<sizeof...(Args) - 1>()))
232196
{
233-
return ::tv::rotate_transform(remove_index(), OPERATORS_FORWARD(args)...);
197+
return ::tv::rotate_transform<false>(
198+
OPERATORS_FORWARD(args...[sizeof...(args) - 1]),
199+
std::make_index_sequence<sizeof...(args) - 1>(),
200+
OPERATORS_FORWARD(args)...
201+
);
234202
};
235203

236204
} // namespace tv

0 commit comments

Comments
 (0)