Skip to content

Commit 8060195

Browse files
committed
patch: optimize selects by extracting exclusive branches
1 parent 95afdd8 commit 8060195

File tree

3 files changed

+115
-3
lines changed

3 files changed

+115
-3
lines changed

include/ctll/list.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ template <typename T> struct item_matcher {
6161
static constexpr auto check(...) { return std::false_type{}; }
6262
static constexpr auto select(T) { return not_selected{}; }
6363
template <typename Y> static constexpr auto select(Y) { return wrapper<Y>{}; }
64+
static constexpr auto pick(std::true_type) { return wrapper<Y>{}; };
65+
static constexpr auto pick(std::false_type) { return not_selected{}; };
6466
};
6567

6668
template <typename T, typename... Ts> constexpr bool exists_in(T, list<Ts...>) noexcept {

include/ctre/atoms.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct any { };
2020
// actual AST of regexp
2121
template <auto... Str> struct string { };
2222
template <typename... Opts> struct select { };
23+
template <typename... Opts> struct non_exclusive_select { };
2324
template <typename... Content> struct sequence { };
2425
struct empty { };
2526

include/ctre/evaluation.hpp

+112-3
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,106 @@ constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, c
135135
return evaluate(begin, result.position, last, consumed_something(f, sizeof...(String) > 0), captures, ctll::list<Tail...>());
136136
}
137137

138+
template <typename T, typename... Ts> constexpr auto collides_with(T, ctll::list<Ts...>) noexcept {
139+
return decltype((ctll::list<>{} + ... + ctll::item_matcher<Ts>::pick(
140+
typename std::conditional<collides(calculate_first(sequence<T>{}), calculate_first(sequence<Ts>{})), std::true_type, std::false_type>::type{}
141+
))){};
142+
}
143+
template <typename T, typename... Ts> constexpr auto collides_with_negated(T, ctll::list<Ts...>) noexcept {
144+
return decltype((ctll::list<>{} + ... + ctll::item_matcher<Ts>::pick(
145+
typename std::conditional<collides(ctre::negative_set<decltype(calculate_first(sequence<T>{}))>{}, calculate_first(sequence<Ts>{})), std::true_type, std::false_type>::type{}
146+
))){};
147+
}
148+
149+
template <typename T, typename... Ts> constexpr auto mutually_exclusive_with(T, ctll::list<Ts...>) noexcept {
150+
return decltype((ctll::list<>{} + ... + ctll::item_matcher<Ts>::pick(
151+
typename std::conditional<!collides(calculate_first(sequence<T>{}), calculate_first(sequence<Ts>{})), std::true_type, std::false_type>::type{}
152+
))){};
153+
}
154+
155+
namespace detail {
156+
template <typename... Content>
157+
constexpr auto transform_into_set(ctll::list<Content...>) {
158+
return ctre::set<decltype(Content{})...>{};
159+
//return ctre::set<decltype(transform_into_set(Content{}))... > {};
160+
}
161+
162+
template <typename T>
163+
constexpr auto transform_into_set(T) {
164+
return T{};
165+
}
166+
167+
template<>
168+
constexpr auto transform_into_set(can_be_anything) {
169+
return ctre::char_range<std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max()>{};
170+
}
171+
172+
template <typename... Content>
173+
constexpr auto transform_into_select(ctll::list<Content...>) {
174+
return ctre::select<decltype(Content{})...>{};
175+
}
176+
}
177+
138178
// matching select in patterns
139179
template <typename R, typename Iterator, typename EndIterator, typename HeadOptions, typename... TailOptions, typename... Tail>
140180
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<select<HeadOptions, TailOptions...>, Tail...>) noexcept {
141-
if (auto r = evaluate(begin, current, last, f, captures, ctll::list<HeadOptions, Tail...>())) {
142-
return r;
181+
constexpr auto collision_list = collides_with(sequence<HeadOptions, Tail...>, ctll::list<
182+
sequence<TailOptions, Tail...>, ...
183+
>{});
184+
if constexpr (ctll::empty(collision_list)) {
185+
// we're mutually exclusive from everything else
186+
using set_type = decltype(detail::transform_into_set(calculate_first(sequence<HeadOptions, Tail...>{})));
187+
if constexpr (::std::is_same_v<set<>, set_type>) {
188+
//fail handle as normal
189+
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>())) {
190+
return r;
191+
} else {
192+
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
193+
}
194+
} else {
195+
//ok optimize into exclusive select
196+
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<set_type, end_cycle_mark>{})) {
197+
return evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>{});
198+
} else {
199+
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
200+
}
201+
}
202+
203+
return evaluate(begin, current, last, f, captures, ctll::list<HeadOptions, Tail...>());
204+
} else if constexpr (ctll::size(collision_list) == sizeof...(TailOptions)) {
205+
//continue as normal...we collided with everything
206+
if (auto r = evaluate(begin, current, last, f, captures, ctll::list<HeadOptions, Tail...>())) {
207+
return r;
208+
} else {
209+
return evaluate(begin, current, last, f, captures, ctll::list<select<TailOptions...>, Tail...>());
210+
}
143211
} else {
144-
return evaluate(begin, current, last, f, captures, ctll::list<select<TailOptions...>, Tail...>());
212+
//we collided with some things, but not others, bifricate on the first character we see
213+
//may be less computationally expensive to do a set subtraction from the complete list with the collision list, because we're evaluating collisions again
214+
constexpr auto negated_collision_list = collides_with_negated(sequence<HeadOptions, Tail...>, ctll::list<
215+
sequence<TailOptions, Tail...>, ...
216+
>{});
217+
218+
using set_type = decltype(detail::transform_into_set(calculate_first(sequence<HeadOptions, Tail...>{})));
219+
if constexpr (::std::is_same_v<set<>, set_type>) {
220+
//fail fallback to normal
221+
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>())) {
222+
return r;
223+
} else {
224+
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
225+
}
226+
} else {
227+
//ok optimize into a split
228+
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<set_type, end_cycle_mark>{})) {
229+
if (auto r2 = evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>{})) {
230+
return r2;
231+
} else {
232+
return evaluate(begin, current, end, f, captures, detail::transform_into_select(collision_list));
233+
}
234+
} else {
235+
return evaluate(begin, current, end, f, captures, detail::transform_into_select(negated_collision_list));
236+
}
237+
}
145238
}
146239
}
147240

@@ -151,6 +244,22 @@ constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterat
151244
return not_matched;
152245
}
153246

247+
// non exclusive select (assume collisions)
248+
template <typename R, typename Iterator, typename EndIterator, typename HeadOptions, typename... TailOptions, typename... Tail>
249+
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<non_exclusive_select<HeadOptions, TailOptions...>, Tail...>) noexcept {
250+
if (auto r = evaluate(begin, current, last, f, captures, ctll::list<HeadOptions, Tail...>())) {
251+
return r;
252+
} else {
253+
return evaluate(begin, current, last, f, captures, ctll::list<non_exclusive_select<TailOptions...>, Tail...>());
254+
}
255+
}
256+
257+
template <typename R, typename Iterator, typename EndIterator, typename... Tail>
258+
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterator, flags, R, ctll::list<non_exclusive_select<>, Tail...>) noexcept {
259+
// no previous option was matched => REJECT
260+
return not_matched;
261+
}
262+
154263
// matching sequence in patterns
155264
template <typename R, typename Iterator, typename EndIterator, typename HeadContent, typename... TailContent, typename... Tail>
156265
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<sequence<HeadContent, TailContent...>, Tail...>) noexcept {

0 commit comments

Comments
 (0)