LCOV - code coverage report
Current view: top level - usr/include/c++/9/bits - regex_executor.tcc (source / functions) Hit Total Coverage
Test: ROSE Lines: 44 201 21.9 %
Date: 2022-12-08 13:48:47 Functions: 5 32 15.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // class template regex -*- C++ -*-
       2             : 
       3             : // Copyright (C) 2013-2019 Free Software Foundation, Inc.
       4             : //
       5             : // This file is part of the GNU ISO C++ Library.  This library is free
       6             : // software; you can redistribute it and/or modify it under the
       7             : // terms of the GNU General Public License as published by the
       8             : // Free Software Foundation; either version 3, or (at your option)
       9             : // any later version.
      10             : 
      11             : // This library is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : 
      16             : // Under Section 7 of GPL version 3, you are granted additional
      17             : // permissions described in the GCC Runtime Library Exception, version
      18             : // 3.1, as published by the Free Software Foundation.
      19             : 
      20             : // You should have received a copy of the GNU General Public License and
      21             : // a copy of the GCC Runtime Library Exception along with this program;
      22             : // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23             : // <http://www.gnu.org/licenses/>.
      24             : 
      25             : /**
      26             :  *  @file bits/regex_executor.tcc
      27             :  *  This is an internal header file, included by other library headers.
      28             :  *  Do not attempt to use it directly. @headername{regex}
      29             :  */
      30             : 
      31             : namespace std _GLIBCXX_VISIBILITY(default)
      32             : {
      33             : _GLIBCXX_BEGIN_NAMESPACE_VERSION
      34             : 
      35             : namespace __detail
      36             : {
      37             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
      38             :            bool __dfs_mode>
      39             :     bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
      40             :     _M_search()
      41             :     {
      42             :       if (_M_search_from_first())
      43             :         return true;
      44             :       if (_M_flags & regex_constants::match_continuous)
      45             :         return false;
      46             :       _M_flags |= regex_constants::match_prev_avail;
      47             :       while (_M_begin != _M_end)
      48             :         {
      49             :           ++_M_begin;
      50             :           if (_M_search_from_first())
      51             :             return true;
      52             :         }
      53             :       return false;
      54             :     }
      55             : 
      56             :   // The _M_main function operates in different modes, DFS mode or BFS mode,
      57             :   // indicated by template parameter __dfs_mode, and dispatches to one of the
      58             :   // _M_main_dispatch overloads.
      59             :   //
      60             :   // ------------------------------------------------------------
      61             :   //
      62             :   // DFS mode:
      63             :   //
      64             :   // It applies a Depth-First-Search (aka backtracking) on given NFA and input
      65             :   // string.
      66             :   // At the very beginning the executor stands in the start state, then it
      67             :   // tries every possible state transition in current state recursively. Some
      68             :   // state transitions consume input string, say, a single-char-matcher or a
      69             :   // back-reference matcher; some don't, like assertion or other anchor nodes.
      70             :   // When the input is exhausted and/or the current state is an accepting
      71             :   // state, the whole executor returns true.
      72             :   //
      73             :   // TODO: This approach is exponentially slow for certain input.
      74             :   //       Try to compile the NFA to a DFA.
      75             :   //
      76             :   // Time complexity: \Omega(match_length), O(2^(_M_nfa.size()))
      77             :   // Space complexity: \theta(match_results.size() + match_length)
      78             :   //
      79             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
      80             :            bool __dfs_mode>
      81             :     bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
      82             :     _M_main_dispatch(_Match_mode __match_mode, __dfs)
      83             :     {
      84             :       _M_has_sol = false;
      85             :       *_M_states._M_get_sol_pos() = _BiIter();
      86             :       _M_cur_results = _M_results;
      87             :       _M_dfs(__match_mode, _M_states._M_start);
      88             :       return _M_has_sol;
      89             :     }
      90             : 
      91             :   // ------------------------------------------------------------
      92             :   //
      93             :   // BFS mode:
      94             :   //
      95             :   // Russ Cox's article (http://swtch.com/~rsc/regexp/regexp1.html)
      96             :   // explained this algorithm clearly.
      97             :   //
      98             :   // It first computes epsilon closure (states that can be achieved without
      99             :   // consuming characters) for every state that's still matching,
     100             :   // using the same DFS algorithm, but doesn't re-enter states (using
     101             :   // _M_states._M_visited to check), nor follow _S_opcode_match.
     102             :   //
     103             :   // Then apply DFS using every _S_opcode_match (in _M_states._M_match_queue)
     104             :   // as the start state.
     105             :   //
     106             :   // It significantly reduces potential duplicate states, so has a better
     107             :   // upper bound; but it requires more overhead.
     108             :   //
     109             :   // Time complexity: \Omega(match_length * match_results.size())
     110             :   //                  O(match_length * _M_nfa.size() * match_results.size())
     111             :   // Space complexity: \Omega(_M_nfa.size() + match_results.size())
     112             :   //                   O(_M_nfa.size() * match_results.size())
     113             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     114             :            bool __dfs_mode>
     115           0 :     bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     116             :     _M_main_dispatch(_Match_mode __match_mode, __bfs)
     117             :     {
     118           0 :       _M_states._M_queue(_M_states._M_start, _M_results);
     119           0 :       bool __ret = false;
     120             :       while (1)
     121             :         {
     122           0 :           _M_has_sol = false;
     123           0 :           if (_M_states._M_match_queue.empty())
     124             :             break;
     125           0 :           std::fill_n(_M_states._M_visited_states.get(), _M_nfa.size(), false);
     126           0 :           auto __old_queue = std::move(_M_states._M_match_queue);
     127           0 :           for (auto& __task : __old_queue)
     128             :             {
     129           0 :               _M_cur_results = std::move(__task.second);
     130           0 :               _M_dfs(__match_mode, __task.first);
     131             :             }
     132           0 :           if (__match_mode == _Match_mode::_Prefix)
     133           0 :             __ret |= _M_has_sol;
     134           0 :           if (_M_current == _M_end)
     135             :             break;
     136           0 :           ++_M_current;
     137             :         }
     138           0 :       if (__match_mode == _Match_mode::_Exact)
     139           0 :         __ret = _M_has_sol;
     140           0 :       _M_states._M_match_queue.clear();
     141           0 :       return __ret;
     142             :     }
     143             : 
     144             :   // Return whether now match the given sub-NFA.
     145             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     146             :            bool __dfs_mode>
     147           0 :     bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     148             :     _M_lookahead(_StateIdT __next)
     149             :     {
     150             :       // Backreferences may refer to captured content.
     151             :       // We may want to make this faster by not copying,
     152             :       // but let's not be clever prematurely.
     153           0 :       _ResultsVec __what(_M_cur_results);
     154           0 :       _Executor __sub(_M_current, _M_end, __what, _M_re, _M_flags);
     155           0 :       __sub._M_states._M_start = __next;
     156           0 :       if (__sub._M_search_from_first())
     157             :         {
     158           0 :           for (size_t __i = 0; __i < __what.size(); __i++)
     159           0 :             if (__what[__i].matched)
     160           0 :               _M_cur_results[__i] = __what[__i];
     161             :           return true;
     162             :         }
     163             :       return false;
     164             :     }
     165             : 
     166             :   // __rep_count records how many times (__rep_count.second)
     167             :   // this node is visited under certain input iterator
     168             :   // (__rep_count.first). This prevent the executor from entering
     169             :   // infinite loop by refusing to continue when it's already been
     170             :   // visited more than twice. It's `twice` instead of `once` because
     171             :   // we need to spare one more time for potential group capture.
     172             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     173             :            bool __dfs_mode>
     174           0 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     175             :     _M_rep_once_more(_Match_mode __match_mode, _StateIdT __i)
     176             :     {
     177           0 :       const auto& __state = _M_nfa[__i];
     178           0 :       auto& __rep_count = _M_rep_count[__i];
     179           0 :       if (__rep_count.second == 0 || __rep_count.first != _M_current)
     180             :         {
     181           0 :           auto __back = __rep_count;
     182           0 :           __rep_count.first = _M_current;
     183           0 :           __rep_count.second = 1;
     184           0 :           _M_dfs(__match_mode, __state._M_alt);
     185           0 :           __rep_count = __back;
     186             :         }
     187             :       else
     188             :         {
     189           0 :           if (__rep_count.second < 2)
     190             :             {
     191           0 :               __rep_count.second++;
     192           0 :               _M_dfs(__match_mode, __state._M_alt);
     193           0 :               __rep_count.second--;
     194             :             }
     195             :         }
     196           0 :     }
     197             : 
     198             :   // _M_alt branch is "match once more", while _M_next is "get me out
     199             :   // of this quantifier". Executing _M_next first or _M_alt first don't
     200             :   // mean the same thing, and we need to choose the correct order under
     201             :   // given greedy mode.
     202             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     203             :            bool __dfs_mode>
     204           0 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     205             :     _M_handle_repeat(_Match_mode __match_mode, _StateIdT __i)
     206             :     {
     207           0 :       const auto& __state = _M_nfa[__i];
     208             : 
     209             :       // Greedy.
     210           0 :       if (!__state._M_neg)
     211             :         {
     212           0 :           _M_rep_once_more(__match_mode, __i);
     213             :           // If it's DFS executor and already accepted, we're done.
     214           0 :           if (!__dfs_mode || !_M_has_sol)
     215           0 :             _M_dfs(__match_mode, __state._M_next);
     216             :         }
     217             :       else // Non-greedy mode
     218             :         {
     219             :           if (__dfs_mode)
     220             :             {
     221             :               // vice-versa.
     222           0 :               _M_dfs(__match_mode, __state._M_next);
     223           0 :               if (!_M_has_sol)
     224           0 :                 _M_rep_once_more(__match_mode, __i);
     225             :             }
     226             :           else
     227             :             {
     228             :               // DON'T attempt anything, because there's already another
     229             :               // state with higher priority accepted. This state cannot
     230             :               // be better by attempting its next node.
     231           0 :               if (!_M_has_sol)
     232             :                 {
     233           0 :                   _M_dfs(__match_mode, __state._M_next);
     234             :                   // DON'T attempt anything if it's already accepted. An
     235             :                   // accepted state *must* be better than a solution that
     236             :                   // matches a non-greedy quantifier one more time.
     237           0 :                   if (!_M_has_sol)
     238           0 :                     _M_rep_once_more(__match_mode, __i);
     239             :                 }
     240             :             }
     241             :         }
     242           0 :     }
     243             : 
     244             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     245             :            bool __dfs_mode>
     246         955 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     247             :     _M_handle_subexpr_begin(_Match_mode __match_mode, _StateIdT __i)
     248             :     {
     249         955 :       const auto& __state = _M_nfa[__i];
     250             : 
     251         955 :       auto& __res = _M_cur_results[__state._M_subexpr];
     252         955 :       auto __back = __res.first;
     253         955 :       __res.first = _M_current;
     254         955 :       _M_dfs(__match_mode, __state._M_next);
     255         955 :       __res.first = __back;
     256         955 :     }
     257             : 
     258             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     259             :            bool __dfs_mode>
     260         114 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     261             :     _M_handle_subexpr_end(_Match_mode __match_mode, _StateIdT __i)
     262             :     {
     263         114 :       const auto& __state = _M_nfa[__i];
     264             : 
     265         114 :       auto& __res = _M_cur_results[__state._M_subexpr];
     266         114 :       auto __back = __res;
     267         114 :       __res.second = _M_current;
     268         114 :       __res.matched = true;
     269         114 :       _M_dfs(__match_mode, __state._M_next);
     270         114 :       __res = __back;
     271         114 :     }
     272             : 
     273             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     274             :            bool __dfs_mode>
     275           0 :     inline void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     276             :     _M_handle_line_begin_assertion(_Match_mode __match_mode, _StateIdT __i)
     277             :     {
     278           0 :       const auto& __state = _M_nfa[__i];
     279           0 :       if (_M_at_begin())
     280           0 :         _M_dfs(__match_mode, __state._M_next);
     281           0 :     }
     282             : 
     283             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     284             :            bool __dfs_mode>
     285           0 :     inline void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     286             :     _M_handle_line_end_assertion(_Match_mode __match_mode, _StateIdT __i)
     287             :     {
     288           0 :       const auto& __state = _M_nfa[__i];
     289           0 :       if (_M_at_end())
     290           0 :         _M_dfs(__match_mode, __state._M_next);
     291           0 :     }
     292             : 
     293             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     294             :            bool __dfs_mode>
     295           0 :     inline void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     296             :     _M_handle_word_boundary(_Match_mode __match_mode, _StateIdT __i)
     297             :     {
     298           0 :       const auto& __state = _M_nfa[__i];
     299           0 :       if (_M_word_boundary() == !__state._M_neg)
     300           0 :         _M_dfs(__match_mode, __state._M_next);
     301           0 :     }
     302             : 
     303             :   // Here __state._M_alt offers a single start node for a sub-NFA.
     304             :   // We recursively invoke our algorithm to match the sub-NFA.
     305             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     306             :            bool __dfs_mode>
     307           0 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     308             :     _M_handle_subexpr_lookahead(_Match_mode __match_mode, _StateIdT __i)
     309             :     {
     310           0 :       const auto& __state = _M_nfa[__i];
     311           0 :       if (_M_lookahead(__state._M_alt) == !__state._M_neg)
     312           0 :         _M_dfs(__match_mode, __state._M_next);
     313           0 :     }
     314             : 
     315             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     316             :            bool __dfs_mode>
     317        1411 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     318             :     _M_handle_match(_Match_mode __match_mode, _StateIdT __i)
     319             :     {
     320        1411 :       const auto& __state = _M_nfa[__i];
     321             : 
     322        1411 :       if (_M_current == _M_end)
     323             :         return;
     324             :       if (__dfs_mode)
     325             :         {
     326        2822 :           if (__state._M_matches(*_M_current))
     327             :             {
     328         570 :               ++_M_current;
     329         570 :               _M_dfs(__match_mode, __state._M_next);
     330         570 :               --_M_current;
     331             :             }
     332             :         }
     333             :       else
     334           0 :         if (__state._M_matches(*_M_current))
     335           0 :           _M_states._M_queue(__state._M_next, _M_cur_results);
     336             :     }
     337             : 
     338             :   template<typename _BiIter, typename _TraitsT>
     339             :     struct _Backref_matcher
     340             :     {
     341             :       _Backref_matcher(bool __icase, const _TraitsT& __traits)
     342             :       : _M_traits(__traits) { }
     343             : 
     344             :       bool
     345             :       _M_apply(_BiIter __expected_begin,
     346             :                _BiIter __expected_end, _BiIter __actual_begin,
     347             :                _BiIter __actual_end)
     348             :       {
     349             :         return _M_traits.transform(__expected_begin, __expected_end)
     350             :             == _M_traits.transform(__actual_begin, __actual_end);
     351             :       }
     352             : 
     353             :       const _TraitsT& _M_traits;
     354             :     };
     355             : 
     356             :   template<typename _BiIter, typename _CharT>
     357             :     struct _Backref_matcher<_BiIter, std::regex_traits<_CharT>>
     358             :     {
     359             :       using _TraitsT = std::regex_traits<_CharT>;
     360           0 :       _Backref_matcher(bool __icase, const _TraitsT& __traits)
     361           0 :       : _M_icase(__icase), _M_traits(__traits) { }
     362             : 
     363             :       bool
     364           0 :       _M_apply(_BiIter __expected_begin,
     365             :                _BiIter __expected_end, _BiIter __actual_begin,
     366             :                _BiIter __actual_end)
     367             :       {
     368           0 :         if (!_M_icase)
     369           0 :           return _GLIBCXX_STD_A::__equal4(__expected_begin, __expected_end,
     370             :                                __actual_begin, __actual_end);
     371             :         typedef std::ctype<_CharT> __ctype_type;
     372           0 :         const auto& __fctyp = use_facet<__ctype_type>(_M_traits.getloc());
     373           0 :         return _GLIBCXX_STD_A::__equal4(__expected_begin, __expected_end,
     374             :                              __actual_begin, __actual_end,
     375           0 :                              [this, &__fctyp](_CharT __lhs, _CharT __rhs)
     376             :                              {
     377             :                                return __fctyp.tolower(__lhs)
     378           0 :                                  == __fctyp.tolower(__rhs);
     379           0 :                              });
     380             :       }
     381             : 
     382             :       bool _M_icase;
     383             :       const _TraitsT& _M_traits;
     384             :     };
     385             : 
     386             :   // First fetch the matched result from _M_cur_results as __submatch;
     387             :   // then compare it with
     388             :   // (_M_current, _M_current + (__submatch.second - __submatch.first)).
     389             :   // If matched, keep going; else just return and try another state.
     390             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     391             :            bool __dfs_mode>
     392           0 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     393             :     _M_handle_backref(_Match_mode __match_mode, _StateIdT __i)
     394             :     {
     395             :       __glibcxx_assert(__dfs_mode);
     396             : 
     397           0 :       const auto& __state = _M_nfa[__i];
     398           0 :       auto& __submatch = _M_cur_results[__state._M_backref_index];
     399           0 :       if (!__submatch.matched)
     400           0 :         return;
     401           0 :       auto __last = _M_current;
     402           0 :       for (auto __tmp = __submatch.first;
     403           0 :            __last != _M_end && __tmp != __submatch.second;
     404           0 :            ++__tmp)
     405           0 :         ++__last;
     406           0 :       if (_Backref_matcher<_BiIter, _TraitsT>(
     407           0 :               _M_re.flags() & regex_constants::icase,
     408           0 :               _M_re._M_automaton->_M_traits)._M_apply(
     409             :                   __submatch.first, __submatch.second, _M_current, __last))
     410             :         {
     411           0 :           if (__last != _M_current)
     412             :             {
     413           0 :               auto __backup = _M_current;
     414           0 :               _M_current = __last;
     415           0 :               _M_dfs(__match_mode, __state._M_next);
     416           0 :               _M_current = __backup;
     417             :             }
     418             :           else
     419           0 :             _M_dfs(__match_mode, __state._M_next);
     420             :         }
     421             :     }
     422             : 
     423             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     424             :            bool __dfs_mode>
     425         114 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     426             :     _M_handle_accept(_Match_mode __match_mode, _StateIdT __i)
     427             :     {
     428             :       if (__dfs_mode)
     429             :         {
     430             :           __glibcxx_assert(!_M_has_sol);
     431         114 :           if (__match_mode == _Match_mode::_Exact)
     432         114 :             _M_has_sol = _M_current == _M_end;
     433             :           else
     434           0 :             _M_has_sol = true;
     435         114 :           if (_M_current == _M_begin
     436         114 :               && (_M_flags & regex_constants::match_not_null))
     437           0 :             _M_has_sol = false;
     438         114 :           if (_M_has_sol)
     439             :             {
     440         114 :               if (_M_nfa._M_flags & regex_constants::ECMAScript)
     441         114 :                 _M_results = _M_cur_results;
     442             :               else // POSIX
     443             :                 {
     444             :                   __glibcxx_assert(_M_states._M_get_sol_pos());
     445             :                   // Here's POSIX's logic: match the longest one. However
     446             :                   // we never know which one (lhs or rhs of "|") is longer
     447             :                   // unless we try both of them and compare the results.
     448             :                   // The member variable _M_sol_pos records the end
     449             :                   // position of the last successful match. It's better
     450             :                   // to be larger, because POSIX regex is always greedy.
     451             :                   // TODO: This could be slow.
     452           0 :                   if (*_M_states._M_get_sol_pos() == _BiIter()
     453           0 :                       || std::distance(_M_begin,
     454           0 :                                        *_M_states._M_get_sol_pos())
     455           0 :                          < std::distance(_M_begin, _M_current))
     456             :                     {
     457           0 :                       *_M_states._M_get_sol_pos() = _M_current;
     458           0 :                       _M_results = _M_cur_results;
     459             :                     }
     460             :                 }
     461             :             }
     462             :         }
     463             :       else
     464             :         {
     465           0 :           if (_M_current == _M_begin
     466           0 :               && (_M_flags & regex_constants::match_not_null))
     467             :             return;
     468           0 :           if (__match_mode == _Match_mode::_Prefix || _M_current == _M_end)
     469           0 :             if (!_M_has_sol)
     470             :               {
     471           0 :                 _M_has_sol = true;
     472           0 :                 _M_results = _M_cur_results;
     473             :               }
     474             :         }
     475             :     }
     476             : 
     477             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     478             :            bool __dfs_mode>
     479           0 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     480             :     _M_handle_alternative(_Match_mode __match_mode, _StateIdT __i)
     481             :     {
     482           0 :       const auto& __state = _M_nfa[__i];
     483             : 
     484           0 :       if (_M_nfa._M_flags & regex_constants::ECMAScript)
     485             :         {
     486             :           // TODO: Fix BFS support. It is wrong.
     487           0 :           _M_dfs(__match_mode, __state._M_alt);
     488             :           // Pick lhs if it matches. Only try rhs if it doesn't.
     489           0 :           if (!_M_has_sol)
     490           0 :             _M_dfs(__match_mode, __state._M_next);
     491             :         }
     492             :       else
     493             :         {
     494             :           // Try both and compare the result.
     495             :           // See "case _S_opcode_accept:" handling above.
     496           0 :           _M_dfs(__match_mode, __state._M_alt);
     497           0 :           auto __has_sol = _M_has_sol;
     498           0 :           _M_has_sol = false;
     499           0 :           _M_dfs(__match_mode, __state._M_next);
     500           0 :           _M_has_sol |= __has_sol;
     501             :         }
     502           0 :     }
     503             : 
     504             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     505             :            bool __dfs_mode>
     506        2594 :     void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     507             :     _M_dfs(_Match_mode __match_mode, _StateIdT __i)
     508             :     {
     509        2594 :       if (_M_states._M_visited(__i))
     510             :         return;
     511             : 
     512        2594 :       switch (_M_nfa[__i]._M_opcode())
     513             :         {
     514           0 :         case _S_opcode_repeat:
     515           0 :           _M_handle_repeat(__match_mode, __i); break;
     516         955 :         case _S_opcode_subexpr_begin:
     517         955 :           _M_handle_subexpr_begin(__match_mode, __i); break;
     518         114 :         case _S_opcode_subexpr_end:
     519         114 :           _M_handle_subexpr_end(__match_mode, __i); break;
     520           0 :         case _S_opcode_line_begin_assertion:
     521           0 :           _M_handle_line_begin_assertion(__match_mode, __i); break;
     522           0 :         case _S_opcode_line_end_assertion:
     523           0 :           _M_handle_line_end_assertion(__match_mode, __i); break;
     524           0 :         case _S_opcode_word_boundary:
     525           0 :           _M_handle_word_boundary(__match_mode, __i); break;
     526           0 :         case _S_opcode_subexpr_lookahead:
     527           0 :           _M_handle_subexpr_lookahead(__match_mode, __i); break;
     528        1411 :         case _S_opcode_match:
     529        1411 :           _M_handle_match(__match_mode, __i); break;
     530           0 :         case _S_opcode_backref:
     531           0 :           _M_handle_backref(__match_mode, __i); break;
     532         114 :         case _S_opcode_accept:
     533         114 :           _M_handle_accept(__match_mode, __i); break;
     534           0 :         case _S_opcode_alternative:
     535           0 :           _M_handle_alternative(__match_mode, __i); break;
     536        2594 :         default:
     537             :           __glibcxx_assert(false);
     538             :         }
     539             :     }
     540             : 
     541             :   // Return whether now is at some word boundary.
     542             :   template<typename _BiIter, typename _Alloc, typename _TraitsT,
     543             :            bool __dfs_mode>
     544           0 :     bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
     545             :     _M_word_boundary() const
     546             :     {
     547           0 :       if (_M_current == _M_begin && (_M_flags & regex_constants::match_not_bow))
     548             :         return false;
     549           0 :       if (_M_current == _M_end && (_M_flags & regex_constants::match_not_eow))
     550             :         return false;
     551             : 
     552           0 :       bool __left_is_word = false;
     553           0 :       if (_M_current != _M_begin
     554           0 :           || (_M_flags & regex_constants::match_prev_avail))
     555             :         {
     556           0 :           auto __prev = _M_current;
     557           0 :           if (_M_is_word(*std::prev(__prev)))
     558           0 :             __left_is_word = true;
     559             :         }
     560           0 :       bool __right_is_word =
     561           0 :         _M_current != _M_end && _M_is_word(*_M_current);
     562             : 
     563           0 :       return __left_is_word != __right_is_word;
     564             :     }
     565             : } // namespace __detail
     566             : 
     567             : _GLIBCXX_END_NAMESPACE_VERSION
     568             : } // namespace

Generated by: LCOV version 1.14