libstdc++
regex_executor.h
Go to the documentation of this file.
1// class template regex -*- C++ -*-
2
3// Copyright (C) 2013-2026 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.h
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// FIXME convert comments to doxygen format.
32
33namespace std _GLIBCXX_VISIBILITY(default)
34{
35_GLIBCXX_BEGIN_NAMESPACE_VERSION
36
37namespace __detail
38{
39 /**
40 * @addtogroup regex-detail
41 * @{
42 */
43
44 template<typename _BiIter, bool _Trivial = is_trivially_copyable<_BiIter>::value>
45 struct _ExecutorFrame;
46
47_GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
48 /**
49 * @brief Takes a regex and an input string and does the matching.
50 *
51 * The %_Executor class has two modes: DFS mode and BFS mode, controlled
52 * by the function parameter %__search_mode.
53 */
54 enum class _Search_mode : unsigned char { _Bfs = 0, _Dfs = 1 };
55
56 template<typename _BiIter, typename _Alloc, typename _TraitsT>
57 class _Executor
58 {
59 enum class _Match_mode : unsigned char { _Exact, _Prefix };
60
61 public:
62 typedef typename iterator_traits<_BiIter>::value_type _CharT;
63 typedef basic_regex<_CharT, _TraitsT> _RegexT;
64 typedef _GLIBCXX_STD_C::vector<sub_match<_BiIter>, _Alloc> _ResultsVec;
66 typedef typename _TraitsT::char_class_type _ClassT;
67 typedef _NFA<_TraitsT> _NFAT;
68
69 public:
70 _Executor(_BiIter __begin,
71 _BiIter __end,
72 _ResultsVec& __results,
73 const _RegexT& __re,
74 _FlagT __flags,
75 bool __use_dfs)
76 : _M_cur_results(__results.get_allocator()),
77 _M_begin(__begin),
78 _M_end(__end),
79 _M_re(__re),
80 _M_nfa(*__re._M_automaton),
81 _M_results(__results),
82 _M_rep_count(_M_nfa.size()),
83 _M_start(_M_nfa._M_start()),
84 _M_visited_states(nullptr),
85 _M_flags(__flags),
86 _M_search_mode(__use_dfs ? _Search_mode::_Dfs : _Search_mode::_Bfs)
87 {
88 using namespace regex_constants;
89 if (__flags & match_prev_avail) // ignore not_bol and not_bow
90 _M_flags &= ~(match_not_bol | match_not_bow);
91 if (_M_search_mode == _Search_mode::_Bfs)
92 _M_visited_states = new bool[_M_nfa.size()];
93 }
94
95 ~_Executor()
96 { delete[] _M_visited_states; }
97
98 // Set matched when string exactly matches the pattern.
99 bool
100 _M_match()
101 {
102 _M_current = _M_begin;
103 return _M_main(_Match_mode::_Exact);
104 }
105
106 // Set matched when some prefix of the string matches the pattern.
107 bool
108 _M_search_from_first()
109 {
110 _M_current = _M_begin;
111 // Fast reject for DFS prefix search. regex_search and
112 // regex_token_iterator try the pattern at each possible starting
113 // position. If the regex can only start with a digit, running the full
114 // DFS executor at a space, letter, or punctuation character only builds
115 // frames to discover the first match state rejects that character.
116 //
117 // Example: for the IPv4 pattern
118 // (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9])\.){3}...
119 // a current input character of 'x' cannot match any first consuming
120 // state. _M_maybe_start_match returns false and this starting position
121 // is skipped. At '2' it returns true, because at least one branch
122 // might match, so the normal executor still decides the complete
123 // result.
124 //
125 // This is intentionally disabled for backreferences. Pruning the
126 // search space for DFS reduces the number of frames we build and the
127 // time to find an actual match.
128 if (_M_search_mode == _Search_mode::_Dfs
129 && !_M_nfa._M_has_backref
130 && _M_current != _M_end
131 && !_M_maybe_start_match(_M_start, 0))
132 return false;
133 return _M_main(_Match_mode::_Prefix);
134 }
135
136 bool
137 _M_search();
138
139 private:
140 _StateIdT
141 _M_rep_once_more(_Match_mode __match_mode, _StateIdT);
142
143 _StateIdT
144 _M_match_simple_repeat_body(_StateIdT, _StateIdT);
145
146 template<_Search_mode __search_mode>
147 _StateIdT
148 _M_handle_repeat(_Match_mode, _StateIdT);
149
150 template<_Search_mode __search_mode>
151 _StateIdT
152 _M_handle_subexpr_begin(_Match_mode, _StateIdT);
153
154 template<_Search_mode __search_mode>
155 _StateIdT
156 _M_handle_subexpr_end(_Match_mode, _StateIdT);
157
158 _StateIdT
159 _M_handle_line_begin_assertion(_Match_mode, _StateIdT);
160
161 _StateIdT
162 _M_handle_line_end_assertion(_Match_mode, _StateIdT);
163
164 _StateIdT
165 _M_handle_word_boundary(_Match_mode, _StateIdT);
166
167 _StateIdT
168 _M_handle_subexpr_lookahead(_Match_mode, _StateIdT);
169
170 template<_Search_mode __search_mode>
171 _StateIdT
172 _M_handle_match(_Match_mode, _StateIdT);
173
174 _StateIdT
175 _M_handle_backref(_Match_mode, _StateIdT);
176
177 template<_Search_mode __search_mode>
178 _StateIdT
179 _M_handle_accept(_Match_mode, _StateIdT);
180
181 _StateIdT
182 _M_handle_alternative(_Match_mode, _StateIdT);
183
184 template<_Search_mode __search_mode>
185 _StateIdT
186 _M_node(_Match_mode, _StateIdT);
187
188 template<_Search_mode __search_mode>
189 void
190 _M_dfs(_Match_mode __match_mode, _StateIdT __start);
191
192 bool
193 _M_main(_Match_mode __match_mode)
194 {
195 if (_M_search_mode == _Search_mode::_Dfs)
196 return _M_main_dfs(__match_mode);
197 else
198 return _M_main_bfs(__match_mode);
199 }
200
201 bool
202 _M_main_dfs(_Match_mode __match_mode);
203
204 bool
205 _M_maybe_start_match(_StateIdT, size_t);
206
207 bool
208 _M_main_bfs(_Match_mode __match_mode);
209
210 bool
211 _M_is_word(_CharT __ch) const
212 {
213 static const _CharT __s[2] = { 'w' };
214 return _M_re._M_automaton->_M_traits.isctype
215 (__ch, _M_re._M_automaton->_M_traits.lookup_classname(__s, __s+1));
216 }
217
218 bool
219 _M_at_begin() const
220 {
221 if (_M_current == _M_begin)
222 {
223 // match_not_bol means ^ does not match [_M_begin,_M_begin)
224 if (_M_flags & regex_constants::match_not_bol)
225 return false;
226 // match_prev_avail means _M_begin is not the start of the input.
228 {
229 // For ECMAScript multiline matches, check if the previous
230 // character is a line terminator.
231 if (_M_match_multiline())
232 return _M_is_line_terminator(*std::prev(_M_current));
233 else
234 return false;
235 }
236 else // ^ matches at _M_begin
237 return true;
238 }
239 else if (_M_match_multiline())
240 return _M_is_line_terminator(*std::prev(_M_current));
241 else
242 return false;
243 }
244
245 bool
246 _M_at_end() const
247 {
248 if (_M_current == _M_end)
249 return !(_M_flags & regex_constants::match_not_eol);
250 else if (_M_match_multiline())
251 return _M_is_line_terminator(*_M_current);
252 else
253 return false;
254 }
255
256 bool
257 _M_word_boundary() const;
258
259 bool
260 _M_lookahead(_StateIdT __next);
261
262 bool
263 _M_is_line_terminator(_CharT __c) const
264 {
265 const auto& __traits = _M_re._M_automaton->_M_traits;
266 const auto& __ct = use_facet<ctype<_CharT>>(__traits.getloc());
267 const char __n{ __ct.narrow(__c, ' ') };
268 if (__n == '\n')
269 return true;
270 if (_M_re._M_automaton->_M_options() & regex_constants::ECMAScript)
271 {
272 if (__n == '\r')
273 return true;
274 // FIXME: U+2028 (line separator) and U+2029 (paragraph separator)
275 }
276 return false;
277 }
278
279 bool
280 _M_match_multiline() const noexcept
281 {
282 constexpr auto __m
284 return (_M_re._M_automaton->_M_options() & __m) == __m;
285 }
286
287 inline bool
288 _M_visited(_StateIdT __i)
289 {
290 if (_M_visited_states)
291 {
292 if (_M_visited_states[__i])
293 return true;
294 _M_visited_states[__i] = true;
295 }
296 return false;
297 }
298
299 _BiIter* _M_get_sol_pos() { return &_M_sol_pos; }
300
301 public:
302 _GLIBCXX_STD_C::vector<_ExecutorFrame<_BiIter>> _M_frames;
303 _ResultsVec _M_cur_results;
304 _BiIter _M_current;
305 _BiIter _M_begin;
306 const _BiIter _M_end;
307 const _RegexT& _M_re;
308 const _NFAT& _M_nfa;
309 _ResultsVec& _M_results;
310 _GLIBCXX_STD_C::vector<pair<_BiIter, int>> _M_rep_count;
311 // To record current solution.
312 _StateIdT _M_start;
313 _BiIter _M_sol_pos;
314 // (BFS only) Saves states that need to be considered for the next character.
315 _GLIBCXX_STD_C::vector<pair<_StateIdT, _ResultsVec>> _M_match_queue;
316 // (BFS only) Indicates which states are already visited.
317 bool* _M_visited_states;
318 _FlagT _M_flags;
319 const _Search_mode _M_search_mode;
320 // Do we have a solution so far?
321 bool _M_has_sol;
322 };
323_GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
324
325 ///@} regex-detail
326} // namespace __detail
327_GLIBCXX_END_NAMESPACE_VERSION
328} // namespace std
329
const _Facet & use_facet(const locale &__loc)
Return a facet.
_Search_mode
Takes a regex and an input string and does the matching.
ISO C++ entities toplevel namespace is std.
constexpr auto size(const _Container &__cont) noexcept(noexcept(__cont.size())) -> decltype(__cont.size())
Return the size of a container.
Implementation details not part of the namespace std interface.
constexpr match_flag_type match_not_bol
constexpr syntax_option_type ECMAScript
constexpr syntax_option_type __multiline
Extension: Equivalent to regex_constants::multiline for C++11 and C++14.
constexpr match_flag_type match_not_eol
match_flag_type
This is a bitmask type indicating regex matching rules.
constexpr match_flag_type match_prev_avail
constexpr size_type size() const noexcept