REAL
Regular Expression Algorithmic Library — constexpr C++20 regex
Loading...
Searching...
No Matches
regex_iter.hpp
Go to the documentation of this file.
1
6#ifndef REAL_STD_REGEX_ITER_HPP
7#define REAL_STD_REGEX_ITER_HPP
8
9// Internal — do not include directly.
10// Users: #include <real/real.hpp> (or the documented opt-ins <real/dfa.hpp>, <real/std/regex.hpp>).
11
12#include "regex_match.hpp"
13
14#include <iterator>
15
16namespace real::compat {
28 template <typename BidirIt,
29 typename CharT = typename std::iterator_traits<BidirIt>::value_type,
30 typename Traits = std::regex_traits<CharT>>
32 {
33 public:
34
36 using difference_type = std::ptrdiff_t;
37 using pointer = const value_type*;
38 using reference = const value_type&;
39 using iterator_category = std::forward_iterator_tag;
41
43 regex_iterator() = default;
44
49 BidirIt last,
50 const regex_type& re,
52 : begin_(first), end_(last), re_(&re), flags_(flags)
53 {
54 // The real traversal exists only for the char/default-traits path; for wide/custom-traits
55 // CharT the branch is compiled out, so next_real() (char-only) is never instantiated.
56 if constexpr (detail::real_eligible<CharT, Traits>) {
58 real_path_ = true;
59 next_real();
60 return;
61 }
62 }
63 std_it_.emplace(first, last, re.std_engine(), detail::to_std_match(flags));
64 sync_std();
65 }
66
69 BidirIt last,
70 const regex_type&& re,
72
73 [[nodiscard]] reference operator*() const
74 {
75 return match_;
76 }
77
78 [[nodiscard]] pointer operator->() const
79 {
80 return &match_;
81 }
82
84 {
85 if (at_end_) {
86 return *this;
87 }
88 // Guarded so next_real() (char-only) is not instantiated for wide/custom-traits CharT, where
89 // real_path_ is always false anyway (the ctor's real branch is compiled out).
90 if constexpr (detail::real_eligible<CharT, Traits>) {
91 if (real_path_) {
92 next_real();
93 return *this;
94 }
95 }
96 ++(*std_it_);
97 sync_std();
98 return *this;
99 }
100
102 {
103 regex_iterator previous {*this};
104 ++(*this);
105 return previous;
106 }
107
108 [[nodiscard]] bool operator==(const regex_iterator& other) const
109 {
110 if (at_end_ || other.at_end_) {
111 return at_end_ == other.at_end_;
112 }
113 // std-conformant: two non-end iterators are equal only for the same regex + sequence at the
114 // same current match (not just a coincidental same-position/length across different regexes).
115 return re_ == other.re_ && begin_ == other.begin_ && end_ == other.end_ && flags_ == other.flags_
116 && match_.position(0) == other.match_.position(0)
117 && match_.length(0) == other.match_.length(0);
118 }
119
120 [[nodiscard]] bool operator!=(const regex_iterator& other) const
121 {
122 return !(*this == other);
123 }
124
125 private:
126
127 BidirIt begin_ {};
128 BidirIt end_ {};
129 const regex_type* re_ {nullptr};
131 bool real_path_ {false};
132 std::size_t real_pos_ {};
133 std::optional<std::regex_iterator<BidirIt>> std_it_;
135 bool at_end_ {true};
136
139 {
140 const std::string_view sv {std::to_address(begin_),
141 static_cast<std::size_t>(std::distance(begin_, end_))};
142 // POSIX ERE drives the iteration with leftmost-longest bounds; the ECMAScript default keeps first.
143 const real::regex& engine {std::get<real::regex>(re_->engine())};
144 const auto result {re_->posix_longest() ? engine.search_longest(sv, real_pos_)
145 : engine.search(sv, real_pos_)};
146 if (!result.matched()) {
147 at_end_ = true;
148 return;
149 }
151 match_.fill_from_real(result);
152 // Iteration: the prefix runs from the previous match end (== real_pos_ here), not the start.
154 real_pos_ = result.end(0); // non-nullable: end > start >= pos, so this always advances
155 at_end_ = false;
156 }
157
159 void sync_std()
160 {
161 if (*std_it_ == std::regex_iterator<BidirIt> {}) {
162 at_end_ = true;
163 return;
164 }
167 at_end_ = false;
168 }
169 };
170
175
176 // --- regex_token_iterator ----------------------------------------------------------------------
177
191 template <typename BidirIt,
192 typename CharT = typename std::iterator_traits<BidirIt>::value_type,
193 typename Traits = std::regex_traits<CharT>>
195 {
196 public:
197
200 using difference_type = std::ptrdiff_t;
201 using pointer = const value_type*;
202 using reference = const value_type&;
203 using iterator_category = std::forward_iterator_tag;
204
207
210 BidirIt last,
211 const regex_type& re,
212 int submatch = 0,
215 last,
216 re,
217 std::vector<int> {submatch},
218 flags)
219 {}
220
224 BidirIt last,
225 const regex_type& re,
226 const std::vector<int>& submatches,
228 : position_(first, last, re, flags), subs_(submatches)
229 {
230 if (subs_.empty()) {
231 subs_.push_back(0);
232 }
233 for (const int s : subs_) {
234 if (s == -1) {
235 has_m1_ = true;
236 break;
237 }
238 }
239 init(first, last);
240 }
241
244 BidirIt last,
245 const regex_type& re,
246 std::initializer_list<int> submatches,
249 last,
250 re,
251 std::vector<int>(submatches),
252 flags)
253 {}
254
257 BidirIt last,
258 const regex_type&& re,
259 int submatch = 0,
262 BidirIt last,
263 const regex_type&& re,
264 const std::vector<int>& submatches,
266
267 [[nodiscard]] reference operator*() const
268 {
269 return current_;
270 }
271
272 [[nodiscard]] pointer operator->() const
273 {
274 return &current_;
275 }
276
278 {
279 if (at_end_) {
280 return *this;
281 }
282 if (suffix_mode_) { // the trailing -1 field was the last token
283 *this = regex_token_iterator {};
284 return *this;
285 }
287 if (n_ + 1 < subs_.size()) {
288 ++n_; // more fields for the same match
289 set_field();
290 }
291 else {
292 n_ = 0;
293 ++position_;
295 set_field(); // first field of the next match
296 }
297 else if (has_m1_ && prev->suffix().length() != 0) {
298 current_ = prev->suffix(); // trailing split field, only when non-empty
299 suffix_mode_ = true;
300 }
301 else {
302 at_end_ = true;
303 }
304 }
305 return *this;
306 }
307
309 {
310 regex_token_iterator previous {*this};
311 ++(*this);
312 return previous;
313 }
314
315 [[nodiscard]] bool operator==(const regex_token_iterator& other) const
316 {
317 if (at_end_ || other.at_end_) {
318 return at_end_ == other.at_end_;
319 }
320 // std-conformant: same underlying match walk, same field selectors, same field index / suffix
321 // state, same current token — not just a coincidental same current token across different lists.
322 return position_ == other.position_ && subs_ == other.subs_ && n_ == other.n_
323 && suffix_mode_ == other.suffix_mode_ && current_.first == other.current_.first
324 && current_.second == other.current_.second;
325 }
326
327 [[nodiscard]] bool operator!=(const regex_token_iterator& other) const
328 {
329 return !(*this == other);
330 }
331
332 private:
333
335 std::vector<int> subs_;
336 std::size_t n_ {0};
338 bool has_m1_ {false};
339 bool suffix_mode_ {false};
340 bool at_end_ {true};
341
344 {
345 current_ = (subs_[n_] == -1) ? position_->prefix() : (*position_)[subs_[n_]];
346 }
347
349 void init(BidirIt first,
350 BidirIt last)
351 {
353 at_end_ = false;
354 set_field();
355 }
356 else if (has_m1_) { // no match at all: the whole sequence is ONE split token, then end
357 at_end_ = false;
358 suffix_mode_ = true; // terminal — the standard yields exactly one token here, no field cycling
359 // std marks this whole-sequence suffix token as participating even when empty (matched=true),
360 // unlike an empty field *between* matches (a prefix, matched=false). The fuzzer pinned this.
361 // (Per [re.tokiter.cnstr] "one of the elements of subs is -1" — has_m1; libstdc++ conforms,
362 // libc++ has a bug here that checks only subs[0], so it drops the token for e.g. {1,-1}.)
363 current_ = value_type {.first = first, .second = last, .matched = true};
364 }
365 }
366 };
367
372} // namespace real::compat
373
374#endif // REAL_STD_REGEX_ITER_HPP
A compiled regular expression, parameterized on its storage policy.
Definition real.hpp:468
A std::basic_regex-compatible pattern, backed by real where proven, else std.
bool posix_longest() const noexcept
Whether this is a POSIX-ERE pattern routed to REAL: search/match must use leftmost-**longest** bounds...
const std::basic_regex< CharT, Traits > & std_engine() const
The std::regex for the std / lazy-std path (built once on demand for a real-backed pattern reached vi...
const std::variant< std::basic_regex< CharT, Traits >, real::regex > & engine() const noexcept
Access the active backend (engine-facing; used by the free functions).
bool uses_real_traversal() const noexcept
Whether replace/iterate run on the real traversal (real-backed AND non-nullable). A nullable pattern ...
The result of a match: group sub-matches plus the prefix and suffix.
void fill_from_real(const RealMatch &match)
Fills from real's byte offsets over the sequence [first_, last_). Templated on the match type — real:...
difference_type position(size_type n=0) const
Start offset of group n from the sequence start. For an out-of-range group std anchors the sub_match ...
void fill_from_std(const StdMatch &match)
Copies from a std::match_results (the fallback path) over the same sequence.
void rebase_prefix(BidirIt first)
Re-bases the unmatched prefix to start at first — for iteration, where a match's prefix runs from the...
void reset(BidirIt first, BidirIt last)
Resets to the not-ready (no-match) state over the sequence [first, last).
difference_type length(size_type n=0) const
Length of group n (0 if out of range or unmatched).
Iterates the non-overlapping matches of a pattern in a sequence (std::regex_iterator).
std::ptrdiff_t difference_type
Iterator traits.
std::forward_iterator_tag iterator_category
std::regex_iterator parity.
regex_iterator(BidirIt first, BidirIt last, const regex_type &&re, regex_constants::match_flag_type flags=regex_constants::match_default)=delete
Constructing from a temporary regex would dangle (std::regex_iterator parity).
void next_real()
Advances the real path: next region search from real_pos_.
bool operator!=(const regex_iterator &other) const
regex_iterator operator++(int)
regex_iterator(BidirIt first, BidirIt last, const regex_type &re, regex_constants::match_flag_type flags=regex_constants::match_default)
Constructs a begin iterator over [first, last) and finds the first match. A constraining match flag (...
regex_constants::match_flag_type flags_
regex_iterator & operator++()
reference operator*() const
bool operator==(const regex_iterator &other) const
void sync_std()
Syncs the std path from the wrapped std::regex_iterator.
std::optional< std::regex_iterator< BidirIt > > std_it_
regex_iterator()=default
Constructs the end sentinel.
Enumerates selected sub-matches (or the text between matches) — std::regex_token_iterator.
void init(BidirIt first, BidirIt last)
Establishes the first token (or the whole-sequence token when there is no match).
regex_token_iterator(BidirIt first, BidirIt last, const regex_type &re, int submatch=0, regex_constants::match_flag_type flags=regex_constants::match_default)
Selects a single sub-match field (0 = whole match, N = group N, -1 = split).
bool operator==(const regex_token_iterator &other) const
value_type current_
Current token (by value — no aliasing).
bool has_m1_
Whether a -1 (split) field is present.
regex_token_iterator(BidirIt first, BidirIt last, const regex_type &&re, int submatch=0, regex_constants::match_flag_type flags=regex_constants::match_default)=delete
Constructing from a temporary regex would dangle (std::regex_token_iterator parity).
bool operator!=(const regex_token_iterator &other) const
bool suffix_mode_
Emitting the trailing split suffix.
regex_token_iterator & operator++()
regex_iterator< BidirIt, CharT, Traits > position_
The underlying match walk.
regex_token_iterator(BidirIt first, BidirIt last, const regex_type &re, const std::vector< int > &submatches, regex_constants::match_flag_type flags=regex_constants::match_default)
Selects a list of fields, cycled per match (e.g. {1, 2}, {-1}). The match flags are forwarded to the ...
void set_field()
Computes the current token from the current match and subs_[n_].
std::vector< int > subs_
Field selectors, cycled per match.
regex_token_iterator()=default
Constructs the end sentinel.
std::forward_iterator_tag iterator_category
std::regex_token_iterator parity.
std::ptrdiff_t difference_type
Iterator traits.
regex_token_iterator(BidirIt first, BidirIt last, const regex_type &re, std::initializer_list< int > submatches, regex_constants::match_flag_type flags=regex_constants::match_default)
Selects a list of fields from a braced list (e.g. {-1}).
std::size_t n_
Current field index into subs_.
regex_token_iterator operator++(int)
regex_token_iterator(BidirIt first, BidirIt last, const regex_type &&re, const std::vector< int > &submatches, regex_constants::match_flag_type flags=regex_constants::match_default)=delete
This is an overloaded member function, provided for convenience. It differs from the above function o...
A matched sub-expression: a [first, second) range into the searched sequence.
BidirIt second
One past the end of the sub-match.
BidirIt first
Start of the sub-match.
std::regex_constants::match_flag_type to_std_match(regex_constants::match_flag_type f) noexcept
Maps compat match/format flags to std::regex_constants — exhaustive (the std path).
bool real_honors(regex_constants::match_flag_type mf) noexcept
Whether real can honor the requested match flags, so the operation may stay on it.
match_flag_type
Match-control flags: the common subset.
@ first
Leftmost-first (Perl / Python re / the crate): source-order thread priority decides....
flags
Compilation flags, mirroring Python's re.I, re.M and re.S.
Definition program.hpp:42
std::regex-compatibility layer, part 2/3: sub_match, match_results, the shared runner,...