From eeb4e13a381ca2b4ba74ff11cb5c925e092bde96 Mon Sep 17 00:00:00 2001 From: Andersama Date: Sat, 17 Jul 2021 21:21:06 -0700 Subject: [PATCH] patch: optimize selects by extracting exclusive branches --- include/ctll/list.hpp | 2 + include/ctre/atoms.hpp | 1 + include/ctre/evaluation.hpp | 125 +++++++++++++++++++++++++++++++++++- 3 files changed, 125 insertions(+), 3 deletions(-) diff --git a/include/ctll/list.hpp b/include/ctll/list.hpp index ae1fd0c3..dae346e2 100644 --- a/include/ctll/list.hpp +++ b/include/ctll/list.hpp @@ -61,6 +61,8 @@ template struct item_matcher { static constexpr auto check(...) { return std::false_type{}; } static constexpr auto select(T) { return not_selected{}; } template static constexpr auto select(Y) { return wrapper{}; } + static constexpr auto pick(std::true_type) { return wrapper{}; }; + static constexpr auto pick(std::false_type) { return not_selected{}; }; }; template constexpr bool exists_in(T, list) noexcept { diff --git a/include/ctre/atoms.hpp b/include/ctre/atoms.hpp index 94a105bf..36f8b5fd 100644 --- a/include/ctre/atoms.hpp +++ b/include/ctre/atoms.hpp @@ -20,6 +20,7 @@ struct any { }; // actual AST of regexp template struct string { }; template struct select { }; +template struct non_exclusive_select { }; template struct sequence { }; struct empty { }; diff --git a/include/ctre/evaluation.hpp b/include/ctre/evaluation.hpp index 8191be00..c6ba5be0 100644 --- a/include/ctre/evaluation.hpp +++ b/include/ctre/evaluation.hpp @@ -135,13 +135,116 @@ constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, c return evaluate(begin, result.position, last, consumed_something(f, sizeof...(String) > 0), captures, ctll::list()); } +template constexpr auto collides_with(T, ctll::list) noexcept { + return decltype((ctll::list<>{} + ... + ctll::item_matcher::pick( + typename std::conditional{}), calculate_first(sequence{})), std::true_type, std::false_type>::type{} + ))){}; +} + +template constexpr auto collides_with_negated(T, ctll::list) noexcept { + return decltype((ctll::list<>{} + ... + ctll::item_matcher::pick( + typename std::conditional{}))>{}, calculate_first(sequence{})), std::true_type, std::false_type>::type{} + ))){}; +} + +template constexpr auto mutually_exclusive_with(T, ctll::list) noexcept { + return decltype((ctll::list<>{} + ... + ctll::item_matcher::pick( + typename std::conditional{}), calculate_first(sequence{})), std::true_type, std::false_type>::type{} + ))){}; +} + +namespace detail { + template + constexpr auto transform_into_set(ctll::list) { + return ctre::set{}; + //return ctre::set {}; + } + + template + constexpr auto transform_into_set(T) { + return T{}; + } + + template<> + constexpr auto transform_into_set(can_be_anything) { + return ctre::char_range::min(), std::numeric_limits::max()>{}; + } + + template + constexpr auto transform_into_select(ctll::list) { + return ctre::select{}; + } +} + // matching select in patterns template constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list, Tail...>) noexcept { - if (auto r = evaluate(begin, current, last, f, captures, ctll::list())) { - return r; + if constexpr (sizeof...(TailOptions) > 1) { + constexpr auto collision_list = collides_with(sequence{}, ctll::list< + decltype(sequence{})... + >{}); + + if constexpr (ctll::empty(collision_list)) { + using set_type = decltype(detail::transform_into_set(calculate_first(sequence{}))); + if constexpr (::std::is_same_v, set_type>) { + //fail handle as normal + if (auto r = evaluate(begin, current, last, f, captures, ctll::list())) { + return r; + } else { + return evaluate(begin, current, last, f, captures, ctll::list, Tail...>()); + } + } else { + //ok optimize into exclusive select + if (auto r = evaluate(begin, current, last, f, captures, ctll::list{})) { + return evaluate(begin, current, last, f, captures, ctll::list{}); + } else { + return evaluate(begin, current, last, f, captures, ctll::list, Tail...>()); + } + } + + return evaluate(begin, current, last, f, captures, ctll::list()); + } else if constexpr (ctll::size(collision_list) == sizeof...(TailOptions)) { + //continue as normal...we collided with everything + if (auto r = evaluate(begin, current, last, f, captures, ctll::list())) { + return r; + } else { + return evaluate(begin, current, last, f, captures, ctll::list, Tail...>()); + } + } else { + //we collided with some things, but not others, bifricate on the first character we see + //may be less computationally expensive to do a set subtraction from the complete list with the collision list, because we're evaluating collisions again + constexpr auto negated_collision_list = collides_with_negated(sequence{}, ctll::list< + decltype(sequence{})... + >{}); + + using set_type = decltype(detail::transform_into_set(calculate_first(sequence{}))); + if constexpr (::std::is_same_v, set_type>) { + //fail + if (auto r = evaluate(begin, current, last, f, captures, ctll::list())) { + return r; + } else { + return evaluate(begin, current, last, f, captures, ctll::list, Tail...>()); + } + } else { + //ok optimize into a split + if (auto r = evaluate(begin, current, last, f, captures, ctll::list{})) { + if (auto r2 = evaluate(begin, current, last, f, captures, ctll::list{})) { + return r2; + } else { + return evaluate(begin, current, last, f, captures, detail::transform_into_select(collision_list)); + } + } else { + return evaluate(begin, current, last, f, captures, detail::transform_into_select(negated_collision_list)); + } + } + } } else { - return evaluate(begin, current, last, f, captures, ctll::list, Tail...>()); + //simple case, too few branches to pick handle as normal + if (auto r = evaluate(begin, current, last, f, captures, ctll::list())) { + return r; + } else { + return evaluate(begin, current, last, f, captures, ctll::list, Tail...>()); + } } } @@ -151,6 +254,22 @@ constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterat return not_matched; } +// non exclusive select (assume collisions) +template +constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list, Tail...>) noexcept { + if (auto r = evaluate(begin, current, last, f, captures, ctll::list())) { + return r; + } else { + return evaluate(begin, current, last, f, captures, ctll::list, Tail...>()); + } +} + +template +constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterator, flags, R, ctll::list, Tail...>) noexcept { + // no previous option was matched => REJECT + return not_matched; +} + // matching sequence in patterns template constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list, Tail...>) noexcept {