Skip to content

Commit 3bbd78a

Browse files
committed
select optimization: avoid backtracking on mutually exclusive branches
When we match against characters that belong to no other select branch we can avoid backtracking by a significant amount. Note: HeadOptions could be a fairly large sequence, we could use calculate_first() to evaluate the initial condition and backtrack by at worst one character*
1 parent 9a37e55 commit 3bbd78a

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

include/ctre/evaluation.hpp

+16-3
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,24 @@ constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, c
136136
// matching select in patterns
137137
template <typename R, typename Iterator, typename EndIterator, typename HeadOptions, typename... TailOptions, typename... Tail>
138138
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, const flags & f, R captures, ctll::list<select<HeadOptions, TailOptions...>, Tail...>) noexcept {
139-
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>())) {
140-
return r;
139+
#ifndef CTRE_DISABLE_GREEDY_OPT
140+
if constexpr (sizeof...(TailOptions) > 0 && !collides(calculate_first(sequence<HeadOptions, Tail...>{}), calculate_first(sequence<select<TailOptions...>, Tail...>{}))) {
141+
auto r = evaluate(begin, current, end, f, captures, ctll::list<decltype(transform_into_set(calculate_first(sequence<HeadOptions, Tail...>{}))), end_cycle_mark>{});
142+
if (r) {
143+
return evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>{});
144+
} else {
145+
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
146+
}
141147
} else {
142-
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
148+
#endif
149+
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>())) {
150+
return r;
151+
} else {
152+
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
153+
}
154+
#ifndef CTRE_DISABLE_GREEDY_OPT
143155
}
156+
#endif
144157
}
145158

146159
template <typename R, typename Iterator, typename EndIterator, typename... Tail>

include/ctre/first.hpp

+21
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,21 @@ template <typename CB> constexpr void negative_helper(ctre::negative_set<>, CB &
368368
}
369369
}
370370

371+
template <typename... Content>
372+
constexpr auto transform_into_set(ctll::list<Content...>) {
373+
return ctre::set<decltype(transform_into_set(Content{}))...>{};
374+
}
375+
376+
template <typename T>
377+
constexpr auto transform_into_set(T) {
378+
return T{};
379+
}
380+
381+
template<>
382+
constexpr auto transform_into_set(can_be_anything) {
383+
return ctre::char_range<std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max()>{};
384+
}
385+
371386
// simple fixed set
372387
// TODO: this needs some optimizations
373388
template <size_t Capacity> class point_set {
@@ -469,6 +484,9 @@ template <size_t Capacity> class point_set {
469484
constexpr bool check(can_be_anything) {
470485
return used > 0;
471486
}
487+
constexpr bool check(empty) {
488+
return used == 0;
489+
}
472490
template <typename... Content> constexpr bool check(ctre::negative_set<Content...> nset) {
473491
bool collision = false;
474492
negative_helper(nset, [&](int64_t low, int64_t high){
@@ -497,6 +515,9 @@ template <size_t Capacity> class point_set {
497515
constexpr void populate(can_be_anything) {
498516
insert(std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max());
499517
}
518+
constexpr void populate(empty) {
519+
//do nothing
520+
}
500521
template <typename... Content> constexpr void populate(ctre::negative_set<Content...> nset) {
501522
negative_helper(nset, [&](int64_t low, int64_t high){
502523
this->insert(low, high);

0 commit comments

Comments
 (0)