[patch v3 2/4][libstdc++]: Templatize regex executor traversal mode [PR126274]

Jonathan Wakely jwakely@redhat.com
Fri Sep 18 12:09:52 GMT 2026


On Thu, 20 Aug 2026 at 18:13 +0100, Tamar Christina wrote:
>In GCC 16 the commit r16-7193-g158ad5f96954da5fa24d5c2a91ae92417fb62e20
>caused a big regression in performance of regex in libstdc++.
>
>This and other patches were tested using the CPP version of the benchmarks
>at https://github.com/mariomka/regex-benchmark/
>
>The benchmark uses regex_token_iterator over the input text with these patterns:
>
>- email: [\w.+-]+@[\w.-]+\.[\w.-]+
>- URI: [\w]+:\/\/[^\/\s?#]+[^\s?#]+(?:\?[^\s#]*)?(?:#[^\s]*)?
>- IPv4: (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9])
>
>Where it tests various types of regexpr. "email" has no backtracking so it's the
>simplest NFA possible which we should be able to handle quickly.
>
>"uri" has optional matches and some non capturing groups and "ipv4" adds some
>alternative matching to the equation.
>
>The input string is a 6.52 mb test file "input-text.txt"
>
>The regressions of each type of regexpr compared to GCC 15 are:
>
>  email: 118.9%
>  URI: 124.8%
>  IPv4: 139.8%
>
>So most matches became > 2x slower.
>
>This patch series addresses the regressions and gets the new code to be
>ultimately faster than the GCC 15 implementation.
>
>Currently the _Executor class implements both a DFS and a BFS traveral mode
>for the regex matching.  It has a parameter _M_search_mode which it uses
>inside the _Executor functions to separate out the implementations.
>
>However this parameter is rather opague to IPA and so for each implementation
>the other branch is always dead but they haven't been folded away.
>
>This increases the number of dynamic instructions and branches being executed
>and the branches seem to be often mispredicted.
>
>The patch fixes it by moving _Search_mode out of the class and making it a
>template parameter instead so we can at compile time fold away the two
>implementations.  This removes all the extra compare and branches from the
>hot functions.
>
>These changes improve the benchmarks compared with previous patch in series
>
> at -O2:
>
>  email: +11.1%
>  URI: +10.3%
>  IPv4 +7.3%
>
> at -O3:
>
>  email: +8.6%,
>  URI: +7.9%
>  IPv4: +3.6%
>
>Bootstrapped Regtested on aarch64-none-linux-gnu,
>arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
>-m32, -m64 and no issues.
>
>Ok for master?

OK for trunk

Also OK for gcc-16 if/when this series is backported.


>Thanks,
>Tamar
>
>libstdc++-v3/ChangeLog:
>
>	PR libstdc++/126274
>	* include/bits/regex_executor.h (_Search_mode): Move to top level.
>	(_M_handle_repeat, _M_handle_match, _M_handle_accept, _M_node, _M_dfs):
>	Add template parameter.
>	(_M_visited): Add inline keyword.
>	* include/bits/regex_executor.tcc (_M_handle_repeat, _M_handle_match,
>	_M_handle_accept, _M_node, _M_dfs): Use template parameter.
>
>---
>diff --git a/libstdc++-v3/include/bits/regex_executor.h b/libstdc++-v3/include/bits/regex_executor.h
>index c2d1d5f0bfeee279fbd1fb138c58f45f9cdbe60e..2a9c87af59489f5202554d1052ec8355b7c5646b 100644
>--- a/libstdc++-v3/include/bits/regex_executor.h
>+++ b/libstdc++-v3/include/bits/regex_executor.h
>@@ -51,10 +51,11 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>    * The %_Executor class has two modes: DFS mode and BFS mode, controlled
>    * by the function parameter %__search_mode.
>    */
>+  enum class _Search_mode : unsigned char { _Bfs = 0, _Dfs = 1 };
>+
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>     class _Executor
>     {
>-      enum class _Search_mode : unsigned char { _BFS = 0, _DFS = 1 };
>       enum class _Match_mode : unsigned char { _Exact, _Prefix };
>
>     public:
>@@ -82,12 +83,12 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	_M_start(_M_nfa._M_start()),
> 	_M_visited_states(nullptr),
> 	_M_flags(__flags),
>-	_M_search_mode(__use_dfs ? _Search_mode::_DFS : _Search_mode::_BFS)
>+	_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)
>+	if (_M_search_mode == _Search_mode::_Bfs)
> 	  _M_visited_states = new bool[_M_nfa.size()];
>       }
>
>@@ -117,13 +118,16 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       _StateIdT
>       _M_rep_once_more(_Match_mode __match_mode, _StateIdT);
>
>+      template<_Search_mode __search_mode>
>       _StateIdT
>       _M_handle_repeat(_Match_mode, _StateIdT);
>
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_handle_subexpr_begin(_Match_mode, _StateIdT);
>
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_handle_subexpr_end(_Match_mode, _StateIdT);
>
>       _StateIdT
>@@ -138,28 +142,32 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       _StateIdT
>       _M_handle_subexpr_lookahead(_Match_mode, _StateIdT);
>
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_handle_match(_Match_mode, _StateIdT);
>
>       _StateIdT
>       _M_handle_backref(_Match_mode, _StateIdT);
>
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_handle_accept(_Match_mode, _StateIdT);
>
>       _StateIdT
>       _M_handle_alternative(_Match_mode, _StateIdT);
>
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_node(_Match_mode, _StateIdT);
>
>-      void
>+      template<_Search_mode __search_mode>
>+	void
>       _M_dfs(_Match_mode __match_mode, _StateIdT __start);
>
>       bool
>       _M_main(_Match_mode __match_mode)
>       {
>-	if (_M_search_mode == _Search_mode::_DFS)
>+	if (_M_search_mode == _Search_mode::_Dfs)
> 	  return _M_main_dfs(__match_mode);
> 	else
> 	  return _M_main_bfs(__match_mode);
>diff --git a/libstdc++-v3/include/bits/regex_executor.tcc b/libstdc++-v3/include/bits/regex_executor.tcc
>index 87d5ac68685c22bbedcf9e67f96b50b61392a701..6e4c2a238cf8e393c8ae561edb88f94bf35331c0 100644
>--- a/libstdc++-v3/include/bits/regex_executor.tcc
>+++ b/libstdc++-v3/include/bits/regex_executor.tcc
>@@ -166,7 +166,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       _M_has_sol = false;
>       *_M_get_sol_pos() = _BiIter();
>       _M_cur_results = _M_results;
>-      _M_dfs(__match_mode, _M_start);
>+      _M_dfs<_Search_mode::_Dfs>(__match_mode, _M_start);
>       return _M_has_sol;
>     }
>
>@@ -209,7 +209,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	  for (auto& __task : __old_queue)
> 	    {
> 	      _M_cur_results = _ResultsVec(std::move(__task.second), __alloc);
>-	      _M_dfs(__match_mode, __task.first);
>+	      _M_dfs<_Search_mode::_Bfs>(__match_mode, __task.first);
> 	    }
> 	  if (__match_mode == _Match_mode::_Prefix)
> 	    __ret |= _M_has_sol;
>@@ -289,6 +289,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>   // mean the same thing, and we need to choose the correct order under
>   // given greedy mode.
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -299,7 +300,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       // Greedy.
>       if (!__state._M_neg)
> 	{
>-	  if (_M_search_mode == _Search_mode::_DFS)
>+	  if constexpr (__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);
>@@ -309,7 +310,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	}
>       else // Non-greedy mode
> 	{
>-	  if (_M_search_mode == _Search_mode::_DFS)
>+	  if constexpr (__search_mode == _Search_mode::_Dfs)
> 	    {
> 	      // vice-versa.
> 	      _M_frames.emplace_back(_S_fopcode_fallback_rep_once_more, __i,
>@@ -335,6 +336,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
>
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -345,7 +347,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       auto& __res = _M_cur_results[__state._M_subexpr];
>       if (_M_nfa._M_has_backref
> 	  || __state._M_subexpr != 0
>-	  || _M_search_mode != _Search_mode::_DFS)
>+	  || __search_mode != _Search_mode::_Dfs)
> 	_M_frames.emplace_back(_S_fopcode_restore_cur_results,
> 			       static_cast<_StateIdT>(__state._M_subexpr),
> 			       __res.first);
>@@ -354,6 +356,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
>
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -364,7 +367,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       auto& __res = _M_cur_results[__state._M_subexpr];
>       if (_M_nfa._M_has_backref
> 	  || __state._M_subexpr != 0
>-	  || _M_search_mode != _Search_mode::_DFS)
>+	  || __search_mode != _Search_mode::_Dfs)
> 	{
> 	  _M_frames.emplace_back(_S_fopcode_restore_cur_results,
> 				 static_cast<_StateIdT>(__state._M_subexpr),
>@@ -421,6 +424,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
>
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -430,7 +434,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       const auto& __state = _M_nfa[__i];
>       if (_M_current == _M_end)
> 	return _S_invalid_state_id;
>-      if (_M_search_mode == _Search_mode::_DFS)
>+      if constexpr (__search_mode == _Search_mode::_Dfs)
> 	{
> 	  if (__state._M_matches(*_M_current))
> 	    {
>@@ -501,7 +505,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     _StateIdT _Executor<_BiIter, _Alloc, _TraitsT>::
>     _M_handle_backref(_Match_mode, _StateIdT __i)
>     {
>-      __glibcxx_assert(_M_search_mode == _Search_mode::_DFS);
>+      __glibcxx_assert(_M_search_mode == _Search_mode::_Dfs);
>
>       const auto& __state = _M_nfa[__i];
>       auto& __submatch = _M_cur_results[__state._M_backref_index];
>@@ -525,13 +529,14 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
>
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>     inline _StateIdT _Executor<_BiIter, _Alloc, _TraitsT>::
>     _M_handle_accept(_Match_mode __match_mode, _StateIdT)
>     {
>-      if (_M_search_mode == _Search_mode::_DFS)
>+      if constexpr (__search_mode == _Search_mode::_Dfs)
> 	{
> 	  __glibcxx_assert(!_M_has_sol);
> 	  if (__match_mode == _Match_mode::_Exact)
>@@ -607,6 +612,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
>
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -615,7 +621,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     {
>       // DFS has no _M_visited implementation as such don't even have the branch
>       // or the check in the call graph.
>-      if (_M_search_mode == _Search_mode::_BFS)
>+      if constexpr (__search_mode == _Search_mode::_Bfs)
> 	if (_M_visited(__i))
> 	  return _S_invalid_state_id;
>
>@@ -623,12 +629,12 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       switch (_M_nfa[__i]._M_opcode())
> 	{
> 	case _S_opcode_repeat:
>-	  __next = _M_handle_repeat(__match_mode, __i); break;
>+	  __next = _M_handle_repeat<__search_mode>(__match_mode, __i); break;
> 	case _S_opcode_subexpr_begin:
>-	  __next = _M_handle_subexpr_begin(__match_mode, __i);
>+	  __next = _M_handle_subexpr_begin<__search_mode>(__match_mode, __i);
> 	  break;
> 	case _S_opcode_subexpr_end:
>-	  __next = _M_handle_subexpr_end(__match_mode, __i);
>+	  __next = _M_handle_subexpr_end<__search_mode>(__match_mode, __i);
> 	  break;
> 	case _S_opcode_line_begin_assertion:
> 	  __next = _M_handle_line_begin_assertion(__match_mode, __i); break;
>@@ -639,15 +645,15 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	case _S_opcode_subexpr_lookahead:
> 	  __next = _M_handle_subexpr_lookahead(__match_mode, __i); break;
> 	case _S_opcode_match:
>-	  __next = _M_handle_match(__match_mode, __i); break;
>+	  __next = _M_handle_match<__search_mode>(__match_mode, __i); break;
> 	case _S_opcode_backref:
>-	  if (_M_search_mode == _Search_mode::_DFS)
>+	  if constexpr (__search_mode == _Search_mode::_Dfs)
> 	    __next = _M_handle_backref(__match_mode, __i);
> 	  else
> 	    __builtin_unreachable();
> 	  break;
> 	case _S_opcode_accept:
>-	  __next = _M_handle_accept(__match_mode, __i); break;
>+	  __next = _M_handle_accept<__search_mode>(__match_mode, __i); break;
> 	case _S_opcode_alternative:
> 	  __next = _M_handle_alternative(__match_mode, __i); break;
> 	default:
>@@ -657,6 +663,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
>
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
>     void _Executor<_BiIter, _Alloc, _TraitsT>::
>     _M_dfs(_Match_mode __match_mode, _StateIdT __start)
>     {
>@@ -668,7 +675,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	  // loop until we fail.  This avoids the needless state save and
> 	  // restore through memory.
> 	  while (__next != _S_invalid_state_id)
>-	    __next = _M_node(__match_mode, __next);
>+	    __next = _M_node<__search_mode>(__match_mode, __next);
>
> 	  if (_M_frames.empty())
> 	    break;
>@@ -681,7 +688,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	    case _S_fopcode_fallback_next:
> 	      if (_M_has_sol)
> 		break;
>-	      if (_M_search_mode == _Search_mode::_DFS)
>+	      if constexpr (__search_mode == _Search_mode::_Dfs)
> 		_M_current = __frame._M_pos;
> 	      [[__fallthrough__]];
> 	    case _S_fopcode_next:
>@@ -691,7 +698,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	    case _S_fopcode_fallback_rep_once_more:
> 	      if (_M_has_sol)
> 		break;
>-	      if (_M_search_mode == _Search_mode::_DFS)
>+	      if constexpr (__search_mode == _Search_mode::_Dfs)
> 		_M_current = __frame._M_pos;
> 	      [[__fallthrough__]];
> 	    case _S_fopcode_rep_once_more:
>@@ -701,7 +708,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	    case _S_fopcode_posix_alternative:
> 	      _M_frames.emplace_back(_S_fopcode_merge_sol, 0, _M_has_sol);
> 	      __next = __frame._M_state_id;
>-	      if (_M_search_mode == _Search_mode::_DFS)
>+	      if constexpr (__search_mode == _Search_mode::_Dfs)
> 		_M_current = __frame._M_pos;
> 	      _M_has_sol = false;
> 	      break;
>
>
>-- 

>diff --git a/libstdc++-v3/include/bits/regex_executor.h b/libstdc++-v3/include/bits/regex_executor.h
>index c2d1d5f0bfeee279fbd1fb138c58f45f9cdbe60e..2a9c87af59489f5202554d1052ec8355b7c5646b 100644
>--- a/libstdc++-v3/include/bits/regex_executor.h
>+++ b/libstdc++-v3/include/bits/regex_executor.h
>@@ -51,10 +51,11 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>    * The %_Executor class has two modes: DFS mode and BFS mode, controlled
>    * by the function parameter %__search_mode.
>    */
>+  enum class _Search_mode : unsigned char { _Bfs = 0, _Dfs = 1 };
>+
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>     class _Executor
>     {
>-      enum class _Search_mode : unsigned char { _BFS = 0, _DFS = 1 };
>       enum class _Match_mode : unsigned char { _Exact, _Prefix };
> 
>     public:
>@@ -82,12 +83,12 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	_M_start(_M_nfa._M_start()),
> 	_M_visited_states(nullptr),
> 	_M_flags(__flags),
>-	_M_search_mode(__use_dfs ? _Search_mode::_DFS : _Search_mode::_BFS)
>+	_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)
>+	if (_M_search_mode == _Search_mode::_Bfs)
> 	  _M_visited_states = new bool[_M_nfa.size()];
>       }
> 
>@@ -117,13 +118,16 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       _StateIdT
>       _M_rep_once_more(_Match_mode __match_mode, _StateIdT);
> 
>+      template<_Search_mode __search_mode>
>       _StateIdT
>       _M_handle_repeat(_Match_mode, _StateIdT);
> 
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_handle_subexpr_begin(_Match_mode, _StateIdT);
> 
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_handle_subexpr_end(_Match_mode, _StateIdT);
> 
>       _StateIdT
>@@ -138,28 +142,32 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       _StateIdT
>       _M_handle_subexpr_lookahead(_Match_mode, _StateIdT);
> 
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_handle_match(_Match_mode, _StateIdT);
> 
>       _StateIdT
>       _M_handle_backref(_Match_mode, _StateIdT);
> 
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_handle_accept(_Match_mode, _StateIdT);
> 
>       _StateIdT
>       _M_handle_alternative(_Match_mode, _StateIdT);
> 
>-      _StateIdT
>+      template<_Search_mode __search_mode>
>+	_StateIdT
>       _M_node(_Match_mode, _StateIdT);
> 
>-      void
>+      template<_Search_mode __search_mode>
>+	void
>       _M_dfs(_Match_mode __match_mode, _StateIdT __start);
> 
>       bool
>       _M_main(_Match_mode __match_mode)
>       {
>-	if (_M_search_mode == _Search_mode::_DFS)
>+	if (_M_search_mode == _Search_mode::_Dfs)
> 	  return _M_main_dfs(__match_mode);
> 	else
> 	  return _M_main_bfs(__match_mode);
>diff --git a/libstdc++-v3/include/bits/regex_executor.tcc b/libstdc++-v3/include/bits/regex_executor.tcc
>index 87d5ac68685c22bbedcf9e67f96b50b61392a701..6e4c2a238cf8e393c8ae561edb88f94bf35331c0 100644
>--- a/libstdc++-v3/include/bits/regex_executor.tcc
>+++ b/libstdc++-v3/include/bits/regex_executor.tcc
>@@ -166,7 +166,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       _M_has_sol = false;
>       *_M_get_sol_pos() = _BiIter();
>       _M_cur_results = _M_results;
>-      _M_dfs(__match_mode, _M_start);
>+      _M_dfs<_Search_mode::_Dfs>(__match_mode, _M_start);
>       return _M_has_sol;
>     }
> 
>@@ -209,7 +209,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	  for (auto& __task : __old_queue)
> 	    {
> 	      _M_cur_results = _ResultsVec(std::move(__task.second), __alloc);
>-	      _M_dfs(__match_mode, __task.first);
>+	      _M_dfs<_Search_mode::_Bfs>(__match_mode, __task.first);
> 	    }
> 	  if (__match_mode == _Match_mode::_Prefix)
> 	    __ret |= _M_has_sol;
>@@ -289,6 +289,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>   // mean the same thing, and we need to choose the correct order under
>   // given greedy mode.
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -299,7 +300,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       // Greedy.
>       if (!__state._M_neg)
> 	{
>-	  if (_M_search_mode == _Search_mode::_DFS)
>+	  if constexpr (__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);
>@@ -309,7 +310,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	}
>       else // Non-greedy mode
> 	{
>-	  if (_M_search_mode == _Search_mode::_DFS)
>+	  if constexpr (__search_mode == _Search_mode::_Dfs)
> 	    {
> 	      // vice-versa.
> 	      _M_frames.emplace_back(_S_fopcode_fallback_rep_once_more, __i,
>@@ -335,6 +336,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
> 
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -345,7 +347,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       auto& __res = _M_cur_results[__state._M_subexpr];
>       if (_M_nfa._M_has_backref
> 	  || __state._M_subexpr != 0
>-	  || _M_search_mode != _Search_mode::_DFS)
>+	  || __search_mode != _Search_mode::_Dfs)
> 	_M_frames.emplace_back(_S_fopcode_restore_cur_results,
> 			       static_cast<_StateIdT>(__state._M_subexpr),
> 			       __res.first);
>@@ -354,6 +356,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
> 
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -364,7 +367,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       auto& __res = _M_cur_results[__state._M_subexpr];
>       if (_M_nfa._M_has_backref
> 	  || __state._M_subexpr != 0
>-	  || _M_search_mode != _Search_mode::_DFS)
>+	  || __search_mode != _Search_mode::_Dfs)
> 	{
> 	  _M_frames.emplace_back(_S_fopcode_restore_cur_results,
> 				 static_cast<_StateIdT>(__state._M_subexpr),
>@@ -421,6 +424,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
> 
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -430,7 +434,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       const auto& __state = _M_nfa[__i];
>       if (_M_current == _M_end)
> 	return _S_invalid_state_id;
>-      if (_M_search_mode == _Search_mode::_DFS)
>+      if constexpr (__search_mode == _Search_mode::_Dfs)
> 	{
> 	  if (__state._M_matches(*_M_current))
> 	    {
>@@ -501,7 +505,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     _StateIdT _Executor<_BiIter, _Alloc, _TraitsT>::
>     _M_handle_backref(_Match_mode, _StateIdT __i)
>     {
>-      __glibcxx_assert(_M_search_mode == _Search_mode::_DFS);
>+      __glibcxx_assert(_M_search_mode == _Search_mode::_Dfs);
> 
>       const auto& __state = _M_nfa[__i];
>       auto& __submatch = _M_cur_results[__state._M_backref_index];
>@@ -525,13 +529,14 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
> 
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>     inline _StateIdT _Executor<_BiIter, _Alloc, _TraitsT>::
>     _M_handle_accept(_Match_mode __match_mode, _StateIdT)
>     {
>-      if (_M_search_mode == _Search_mode::_DFS)
>+      if constexpr (__search_mode == _Search_mode::_Dfs)
> 	{
> 	  __glibcxx_assert(!_M_has_sol);
> 	  if (__match_mode == _Match_mode::_Exact)
>@@ -607,6 +612,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
> 
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
> #ifdef __OPTIMIZE__
>     [[__gnu__::__always_inline__]]
> #endif
>@@ -615,7 +621,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     {
>       // DFS has no _M_visited implementation as such don't even have the branch
>       // or the check in the call graph.
>-      if (_M_search_mode == _Search_mode::_BFS)
>+      if constexpr (__search_mode == _Search_mode::_Bfs)
> 	if (_M_visited(__i))
> 	  return _S_invalid_state_id;
> 
>@@ -623,12 +629,12 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>       switch (_M_nfa[__i]._M_opcode())
> 	{
> 	case _S_opcode_repeat:
>-	  __next = _M_handle_repeat(__match_mode, __i); break;
>+	  __next = _M_handle_repeat<__search_mode>(__match_mode, __i); break;
> 	case _S_opcode_subexpr_begin:
>-	  __next = _M_handle_subexpr_begin(__match_mode, __i);
>+	  __next = _M_handle_subexpr_begin<__search_mode>(__match_mode, __i);
> 	  break;
> 	case _S_opcode_subexpr_end:
>-	  __next = _M_handle_subexpr_end(__match_mode, __i);
>+	  __next = _M_handle_subexpr_end<__search_mode>(__match_mode, __i);
> 	  break;
> 	case _S_opcode_line_begin_assertion:
> 	  __next = _M_handle_line_begin_assertion(__match_mode, __i); break;
>@@ -639,15 +645,15 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	case _S_opcode_subexpr_lookahead:
> 	  __next = _M_handle_subexpr_lookahead(__match_mode, __i); break;
> 	case _S_opcode_match:
>-	  __next = _M_handle_match(__match_mode, __i); break;
>+	  __next = _M_handle_match<__search_mode>(__match_mode, __i); break;
> 	case _S_opcode_backref:
>-	  if (_M_search_mode == _Search_mode::_DFS)
>+	  if constexpr (__search_mode == _Search_mode::_Dfs)
> 	    __next = _M_handle_backref(__match_mode, __i);
> 	  else
> 	    __builtin_unreachable();
> 	  break;
> 	case _S_opcode_accept:
>-	  __next = _M_handle_accept(__match_mode, __i); break;
>+	  __next = _M_handle_accept<__search_mode>(__match_mode, __i); break;
> 	case _S_opcode_alternative:
> 	  __next = _M_handle_alternative(__match_mode, __i); break;
> 	default:
>@@ -657,6 +663,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>     }
> 
>   template<typename _BiIter, typename _Alloc, typename _TraitsT>
>+  template<_Search_mode __search_mode>
>     void _Executor<_BiIter, _Alloc, _TraitsT>::
>     _M_dfs(_Match_mode __match_mode, _StateIdT __start)
>     {
>@@ -668,7 +675,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	  // loop until we fail.  This avoids the needless state save and
> 	  // restore through memory.
> 	  while (__next != _S_invalid_state_id)
>-	    __next = _M_node(__match_mode, __next);
>+	    __next = _M_node<__search_mode>(__match_mode, __next);
> 
> 	  if (_M_frames.empty())
> 	    break;
>@@ -681,7 +688,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	    case _S_fopcode_fallback_next:
> 	      if (_M_has_sol)
> 		break;
>-	      if (_M_search_mode == _Search_mode::_DFS)
>+	      if constexpr (__search_mode == _Search_mode::_Dfs)
> 		_M_current = __frame._M_pos;
> 	      [[__fallthrough__]];
> 	    case _S_fopcode_next:
>@@ -691,7 +698,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	    case _S_fopcode_fallback_rep_once_more:
> 	      if (_M_has_sol)
> 		break;
>-	      if (_M_search_mode == _Search_mode::_DFS)
>+	      if constexpr (__search_mode == _Search_mode::_Dfs)
> 		_M_current = __frame._M_pos;
> 	      [[__fallthrough__]];
> 	    case _S_fopcode_rep_once_more:
>@@ -701,7 +708,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> 	    case _S_fopcode_posix_alternative:
> 	      _M_frames.emplace_back(_S_fopcode_merge_sol, 0, _M_has_sol);
> 	      __next = __frame._M_state_id;
>-	      if (_M_search_mode == _Search_mode::_DFS)
>+	      if constexpr (__search_mode == _Search_mode::_Dfs)
> 		_M_current = __frame._M_pos;
> 	      _M_has_sol = false;
> 	      break;
>



More information about the Libstdc++ mailing list