Skip to content

Commit 9231456

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, here we use calculate_first() to evaluate the initial condition for a mutually exclusive branch*
1 parent 9a37e55 commit 9231456

File tree

3 files changed

+48
-6
lines changed

3 files changed

+48
-6
lines changed

include/ctre/atoms_characters.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@ template <auto V> struct character {
2424
};
2525

2626
template <typename... Content> struct negative_set {
27-
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value) noexcept {
27+
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char([[maybe_unused]] CharT value) noexcept {
2828
return !(Content::match_char(value) || ... || false);
2929
}
3030
};
3131

3232
template <typename... Content> struct set {
33-
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value) noexcept {
33+
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char([[maybe_unused]] CharT value) noexcept {
3434
return (Content::match_char(value) || ... || false);
3535
}
3636
};
3737

3838
template <auto... Cs> struct enumeration : set<character<Cs>...> { };
3939

4040
template <typename... Content> struct negate {
41-
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value) noexcept {
41+
template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char([[maybe_unused]] CharT value) noexcept {
4242
return !(Content::match_char(value) || ... || false);
4343
}
4444
};

include/ctre/evaluation.hpp

+24-3
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,32 @@ 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+
using set_type = decltype(transform_into_set(calculate_first(sequence<HeadOptions, Tail...>{})));
142+
if constexpr (::std::is_same_v<set<>, set_type>) {
143+
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>())) {
144+
return r;
145+
} else {
146+
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
147+
}
148+
} else {
149+
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<set_type, end_cycle_mark>{})) {
150+
return evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>{});
151+
} else {
152+
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
153+
}
154+
}
141155
} else {
142-
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
156+
#endif
157+
if (auto r = evaluate(begin, current, end, f, captures, ctll::list<HeadOptions, Tail...>())) {
158+
return r;
159+
} else {
160+
return evaluate(begin, current, end, f, captures, ctll::list<select<TailOptions...>, Tail...>());
161+
}
162+
#ifndef CTRE_DISABLE_GREEDY_OPT
143163
}
164+
#endif
144165
}
145166

146167
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)