bool __dfs_mode>
class _Executor
{
- using __search_mode = integral_constant<bool, __dfs_mode>;
- using __dfs = true_type;
- using __bfs = false_type;
-
+ enum class _Search_mode : unsigned char { _BFS = 0, _DFS = 1 };
enum class _Match_mode : unsigned char { _Exact, _Prefix };
public:
_BiIter __end,
_ResultsVec& __results,
const _RegexT& __re,
- _FlagT __flags)
+ _FlagT __flags,
+ bool __use_dfs)
: _M_cur_results(__results.get_allocator()),
_M_begin(__begin),
_M_end(__end),
_M_nfa(*__re._M_automaton),
_M_results(__results),
_M_rep_count(_M_nfa.size()),
- _M_states(_M_nfa._M_start(), _M_nfa.size()),
- _M_flags(__flags)
+ _M_start(_M_nfa._M_start()),
+ _M_visited_states(nullptr),
+ _M_flags(__flags),
+ _M_search_mode(__use_dfs ? _Search_mode::_DFS : _Search_mode::_BFS)
{
using namespace regex_constants;
if (__flags & match_prev_avail) // ignore not_bol and not_bow
_M_flags &= ~(match_not_bol | match_not_bow);
+ if (_M_search_mode == _Search_mode::_BFS)
+ _M_visited_states = new bool[_M_nfa.size()];
}
+ ~_Executor()
+ { delete[] _M_visited_states; }
+
// Set matched when string exactly matches the pattern.
bool
_M_match()
bool
_M_main(_Match_mode __match_mode)
- { return _M_main_dispatch(__match_mode, __search_mode{}); }
+ {
+ if (_M_search_mode == _Search_mode::_DFS)
+ return _M_main_dfs(__match_mode);
+ else
+ return _M_main_bfs(__match_mode);
+ }
bool
- _M_main_dispatch(_Match_mode __match_mode, __dfs);
+ _M_main_dfs(_Match_mode __match_mode);
bool
- _M_main_dispatch(_Match_mode __match_mode, __bfs);
+ _M_main_bfs(_Match_mode __match_mode);
bool
_M_is_word(_CharT __ch) const
return (_M_re._M_automaton->_M_options() & __m) == __m;
}
- // Holds additional information used in BFS-mode.
- template<typename _SearchMode, typename _ResultsVec>
- struct _State_info;
-
- template<typename _ResultsVec>
- struct _State_info<__bfs, _ResultsVec>
- {
- explicit
- _State_info(_StateIdT __start, size_t __n)
- : _M_visited_states(new bool[__n]()), _M_start(__start)
- { }
-
- ~_State_info() { delete[] _M_visited_states; }
-
- _State_info(const _State_info&) = delete;
- _State_info& operator=(const _State_info&) = delete;
-
- bool _M_visited(_StateIdT __i)
+ bool
+ _M_visited(_StateIdT __i)
+ {
+ if (_M_visited_states)
{
if (_M_visited_states[__i])
return true;
_M_visited_states[__i] = true;
- return false;
}
+ return false;
+ }
- void _M_queue(_StateIdT __i, const _ResultsVec& __res)
- { _M_match_queue.emplace_back(__i, __res); }
-
- // Dummy implementations for BFS mode.
- _BiIter* _M_get_sol_pos() { return nullptr; }
-
- // Saves states that need to be considered for the next character.
- _GLIBCXX_STD_C::vector<pair<_StateIdT, _ResultsVec>> _M_match_queue;
- // Indicates which states are already visited.
- bool* _M_visited_states;
- // To record current solution.
- _StateIdT _M_start;
- };
-
- template<typename _ResultsVec>
- struct _State_info<__dfs, _ResultsVec>
- {
- explicit
- _State_info(_StateIdT __start, size_t) : _M_start(__start)
- { }
-
- // Dummy implementations for DFS mode.
- bool _M_visited(_StateIdT) const { return false; }
- void _M_queue(_StateIdT, const _ResultsVec&) { }
-
- _BiIter* _M_get_sol_pos() { return &_M_sol_pos; }
-
- // To record current solution.
- _StateIdT _M_start;
- _BiIter _M_sol_pos;
- };
+ _BiIter* _M_get_sol_pos() { return &_M_sol_pos; }
public:
_GLIBCXX_STD_C::vector<_ExecutorFrame<_BiIter>> _M_frames;
const _NFAT& _M_nfa;
_ResultsVec& _M_results;
_GLIBCXX_STD_C::vector<pair<_BiIter, int>> _M_rep_count;
- _State_info<__search_mode, _ResultsVec> _M_states;
+ // To record current solution.
+ _StateIdT _M_start;
+ _BiIter _M_sol_pos;
+ // (BFS only) Saves states that need to be considered for the next character.
+ _GLIBCXX_STD_C::vector<pair<_StateIdT, _ResultsVec>> _M_match_queue;
+ // (BFS only) Indicates which states are already visited.
+ bool* _M_visited_states;
_FlagT _M_flags;
+ const _Search_mode _M_search_mode;
// Do we have a solution so far?
bool _M_has_sol;
};
};
// The _M_main function operates in different modes, DFS mode or BFS mode,
- // indicated by template parameter __dfs_mode, and dispatches to one of the
- // _M_main_dispatch overloads.
+ // indicated by _M_search_mode, and dispatches to either _M_main_dfs or
+ // _M_main_bfs.
//
// ------------------------------------------------------------
//
template<typename _BiIter, typename _Alloc, typename _TraitsT,
bool __dfs_mode>
bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
- _M_main_dispatch(_Match_mode __match_mode, __dfs)
+ _M_main_dfs(_Match_mode __match_mode)
{
_M_has_sol = false;
- *_M_states._M_get_sol_pos() = _BiIter();
+ *_M_get_sol_pos() = _BiIter();
_M_cur_results = _M_results;
- _M_dfs(__match_mode, _M_states._M_start);
+ _M_dfs(__match_mode, _M_start);
return _M_has_sol;
}
// It first computes epsilon closure (states that can be achieved without
// consuming characters) for every state that's still matching,
// using the same DFS algorithm, but doesn't re-enter states (using
- // _M_states._M_visited to check), nor follow _S_opcode_match.
+ // _M_visited to check), nor follow _S_opcode_match.
//
- // Then apply DFS using every _S_opcode_match (in _M_states._M_match_queue)
+ // Then apply DFS using every _S_opcode_match (in _M_match_queue)
// as the start state.
//
// It significantly reduces potential duplicate states, so has a better
template<typename _BiIter, typename _Alloc, typename _TraitsT,
bool __dfs_mode>
bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
- _M_main_dispatch(_Match_mode __match_mode, __bfs)
+ _M_main_bfs(_Match_mode __match_mode)
{
- _M_states._M_queue(_M_states._M_start, _M_results);
+ _M_match_queue.emplace_back(_M_start, _M_results);
bool __ret = false;
while (1)
{
_M_has_sol = false;
- if (_M_states._M_match_queue.empty())
+ if (_M_match_queue.empty())
break;
- std::fill_n(_M_states._M_visited_states, _M_nfa.size(), false);
- auto __old_queue = std::move(_M_states._M_match_queue);
+ std::fill_n(_M_visited_states, _M_nfa.size(), false);
+ auto __old_queue = std::move(_M_match_queue);
auto __alloc = _M_cur_results.get_allocator();
for (auto& __task : __old_queue)
{
}
if (__match_mode == _Match_mode::_Exact)
__ret = _M_has_sol;
- _M_states._M_match_queue.clear();
+ _M_match_queue.clear();
return __ret;
}
// We may want to make this faster by not copying,
// but let's not be clever prematurely.
_ResultsVec __what(_M_cur_results);
- _Executor __sub(_M_current, _M_end, __what, _M_re, _M_flags);
- __sub._M_states._M_start = __next;
+ _Executor __sub(_M_current, _M_end, __what, _M_re, _M_flags,
+ bool(_M_search_mode));
+ __sub._M_start = __next;
if (__sub._M_search_from_first())
{
for (size_t __i = 0; __i < __what.size(); __i++)
// Greedy.
if (!__state._M_neg)
{
- if constexpr (__dfs_mode)
+ if (_M_search_mode == _Search_mode::_DFS)
// If it's DFS executor and already accepted, we're done.
_M_frames.emplace_back(_S_fopcode_fallback_next, __state._M_next,
_M_current);
}
else // Non-greedy mode
{
- if constexpr (__dfs_mode)
+ if (_M_search_mode == _Search_mode::_DFS)
{
// vice-versa.
_M_frames.emplace_back(_S_fopcode_fallback_rep_once_more, __i,
const auto& __state = _M_nfa[__i];
if (_M_current == _M_end)
return;
- if constexpr (__dfs_mode)
+ if (_M_search_mode == _Search_mode::_DFS)
{
if (__state._M_matches(*_M_current))
{
}
else
if (__state._M_matches(*_M_current))
- _M_states._M_queue(__state._M_next, _M_cur_results);
+ _M_match_queue.emplace_back(__state._M_next, _M_cur_results);
}
template<typename _BiIter, typename _TraitsT>
void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
_M_handle_backref(_Match_mode __match_mode, _StateIdT __i)
{
- static_assert(__dfs_mode, "this should never be instantiated");
+ __glibcxx_assert(_M_search_mode == _Search_mode::_DFS);
const auto& __state = _M_nfa[__i];
auto& __submatch = _M_cur_results[__state._M_backref_index];
void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
_M_handle_accept(_Match_mode __match_mode, _StateIdT)
{
- if constexpr (__dfs_mode)
+ if (_M_search_mode == _Search_mode::_DFS)
{
__glibcxx_assert(!_M_has_sol);
if (__match_mode == _Match_mode::_Exact)
_M_results = _M_cur_results;
else // POSIX
{
- __glibcxx_assert(_M_states._M_get_sol_pos());
+ __glibcxx_assert(_M_get_sol_pos());
// Here's POSIX's logic: match the longest one. However
// we never know which one (lhs or rhs of "|") is longer
// unless we try both of them and compare the results.
// position of the last successful match. It's better
// to be larger, because POSIX regex is always greedy.
// TODO: This could be slow.
- if (*_M_states._M_get_sol_pos() == _BiIter()
- || std::distance(_M_begin,
- *_M_states._M_get_sol_pos())
+ if (*_M_get_sol_pos() == _BiIter()
+ || std::distance(_M_begin, *_M_get_sol_pos())
< std::distance(_M_begin, _M_current))
{
- *_M_states._M_get_sol_pos() = _M_current;
+ *_M_get_sol_pos() = _M_current;
_M_results = _M_cur_results;
}
}
inline void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
_M_node(_Match_mode __match_mode, _StateIdT __i)
{
- if (_M_states._M_visited(__i))
+ if (_M_visited(__i))
return;
switch (_M_nfa[__i]._M_opcode())
case _S_opcode_match:
_M_handle_match(__match_mode, __i); break;
case _S_opcode_backref:
- if constexpr (__dfs_mode)
+ if (_M_search_mode == _Search_mode::_DFS)
_M_handle_backref(__match_mode, __i);
else
__builtin_unreachable();
}
template<typename _BiIter, typename _Alloc, typename _TraitsT,
- bool __dfs_mode>
- void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
+ bool __dummy>
+ void _Executor<_BiIter, _Alloc, _TraitsT, __dummy>::
_M_dfs(_Match_mode __match_mode, _StateIdT __start)
{
+ const bool __dfs_mode = (_M_search_mode == _Search_mode::_DFS);
_M_frames.emplace_back(_S_fopcode_next, __start);
while (!_M_frames.empty())
case _S_fopcode_fallback_next:
if (_M_has_sol)
break;
- if constexpr (__dfs_mode)
+ if (__dfs_mode)
_M_current = __frame._M_pos;
[[__fallthrough__]];
case _S_fopcode_next:
case _S_fopcode_fallback_rep_once_more:
if (_M_has_sol)
break;
- if constexpr (__dfs_mode)
+ if (__dfs_mode)
_M_current = __frame._M_pos;
[[__fallthrough__]];
case _S_fopcode_rep_once_more:
case _S_fopcode_posix_alternative:
_M_frames.emplace_back(_S_fopcode_merge_sol, 0, _M_has_sol);
_M_frames.emplace_back(_S_fopcode_next, __frame._M_state_id);
- if constexpr (__dfs_mode)
+ if (__dfs_mode)
_M_current = __frame._M_pos;
_M_has_sol = false;
break;