|
REAL
Regular Expression Algorithmic Library — constexpr C++20 regex
|
Functions | |
| bool | grammar_forces_std (regex_constants::syntax_option_type f) noexcept |
Grammars/options that force the std backend (real implements default-traits ECMAScript, reporting every group — so nosubs, which std answers by exposing only group 0, also routes to std to avoid a structural both-accept divergence). | |
| bool | pattern_forces_std (std::string_view p) noexcept |
| Pattern text that real accepts but matches differently from libstdc++ — a both-accept silent divergence, so it must route to std up front (real's accept hides it otherwise). | |
| bool | format_forces_std (std::string_view fmt) noexcept |
Replacement format text that must route to std: $0. $0 is platform-variant (libstdc++ = the whole match, strict-ECMAScript/MSVC = a literal), so real cannot pick one without risking a silent divergence — route to std, which is authoritative for its own platform. $$ is skipped (an escaped literal $). | |
| std::string | posix_class_ranges (std::string_view name) |
A POSIX bracket-class name to its ASCII (C-locale) range content, appended inside a [...] during ERE translation. Empty for an unknown name (the caller then falls back to std). | |
| bool | translate_bracket (std::string_view p, std::size_t &i, std::string &out) |
Translates a POSIX bracket expression [...] — identical syntax in BRE and ERE, so shared by both translators. POSIX classes ([[:alpha:]]) become ASCII ranges; other members pass through. i must point at the opening [; on success it advances past the ] and appends the class to out. Returns false (the caller then declines to std) on an unterminated class or an unknown / collating [[:foo:]] / [.x.] / [=x=]. | |
| bool | append_awk_escape (std::string_view p, std::size_t &i, std::string &out) |
Appends the REAL translation of an awk C-escape at i (which points at the backslash), advancing i; returns false to decline (→ std). awk's escapes beyond ERE: \b is BACKSPACE (0x08) — not a word boundary, the inverse of the ERE decline — \a=BEL, \n\t\r\f\v the usual controls, \/ and \" literals, and a 1-to-3-digit octal \ddd (both std libraries agree; an overflow > 0377 declines). Emitted as \xHH so REAL matches the exact byte. | |
| bool | has_empty_alternation_branch (std::string_view p) |
Whether p has an empty alternation branch — a | with nothing on one side: (|, |), ||, or a | at the pattern start or end. Two reasons this matters: (a) std::regex rejects these in the POSIX grammars, so translating one would make compat over-accept vs std; (b) REAL's leftmost-first star semantics over an empty-first branch ((|a)*) diverge from re / std on repetition. Conservative — a | merely adjacent to a group boundary or the pattern edge counts, an escaped \| or a | inside a class does not — because a false positive only costs linear coverage (safe) while a false negative is a silent divergence (forbidden). | |
| std::optional< std::string > | translate_ere (std::string_view p, bool awk=false) |
Translates a POSIX extended (ERE) — or, with awk, an awk — pattern to an equivalent REAL pattern, or nullopt when it uses a construct the two grammars read differently (an ECMAScript shorthand \d\w\s — undefined/literal in ERE; an ambiguous {; an unknown/collating [[:…:]]; an empty alternation branch, which std rejects — see has_empty_alternation_branch). awk adds the C-escapes (see append_awk_escape). POSIX classes become ASCII ranges (C locale); the common productions pass through, since REAL reads them like ERE. Validated by a bounds differential. | |
| std::optional< std::string > | translate_bre (std::string_view p) |
Translates a POSIX basic (BRE) pattern to an equivalent REAL pattern, or nullopt. BRE differs from ERE: \( \) group and \{n\} quantify, while bare ( ) { } | + ? are LITERALS (escaped for REAL); * at an expression start and ^/$ off the ends are literals too. Declines (→ std) on a backreference \1-\9 (std's residual value), an ECMAScript-ism, a non-strict \{, an unknown / collating class, or a POSIX-undefined corner (^/$/* at a subexpression boundary). | |
| template<typename LineFn > | |
| std::optional< std::string > | translate_newline_alt (std::string_view p, LineFn translate_line) |
grep / egrep: a newline in the pattern is a top-level alternation of the lines (grep = BRE lines, egrep = ERE lines). Each line is translated by translate_line and the results are joined with | — correct precedence by construction, since | is the lowest, and each line's ^/$ stay branch-relative. A line that declines, or an empty line (a blank branch — a std edge best left to std), declines the whole pattern. | |
| std::optional< std::string > | translate_posix (std::string_view p, regex_constants::syntax_option_type f) |
Dispatches a single POSIX grammar to its translator, or nullopt (→ std). Exactly one grammar bit must be set, and neither collate nor nosubs (which force std). extended → ERE, basic → BRE, awk → ERE + C-escapes, grep → BRE lines joined by |, egrep → ERE lines joined by |. | |
| real::flags | to_real (regex_constants::syntax_option_type f) noexcept |
| Maps compat options to real::flags (always with bytes|ecma for std-char alignment). | |
| std::regex_constants::syntax_option_type | to_std (regex_constants::syntax_option_type f) noexcept |
| Maps compat options to std::regex syntax flags (the fallback 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. | |
| bool | replace_stays_real (regex_constants::match_flag_type f) noexcept |
Whether regex_replace can run its substitution on real. The real expander honors only format_first_only / format_no_copy (plus the match_any hint); ANY other bit — a constraining match flag (not_bol, continuous, …) OR format_sed (POSIX syntax) — would be silently ignored by the ECMAScript expander, so the whole substitution routes to std. (This subsumes the explicit format_sed screen; $0 stays content-based.) | |
| 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). | |
| template<typename BidirIt , typename CharT , typename Traits > | |
| bool | run (BidirIt first, BidirIt last, match_results< BidirIt > &m, const basic_regex< CharT, Traits > &re, bool anchored, regex_constants::match_flag_type mf) |
Runs the active backend over [first, last) and fills m. anchored selects whole-sequence match (regex_match) vs leftmost search (regex_search). A constraining match flag (see real_honors) routes to std even for a real-backed pattern. | |
| template<typename BidirIt , typename CharT , typename Traits > | |
| bool | run_nocapture (BidirIt first, BidirIt last, const basic_regex< CharT, Traits > &re, bool anchored, regex_constants::match_flag_type mf) |
| Backend run without capturing (no match_results to fill). | |
| template<typename RealMatch > | |
| void | expand_format (std::string &out, const RealMatch &m, std::string_view fmt, std::string_view text, std::size_t prefix_start) |
| Appends one match's ECMAScript-expanded replacement. | |
Variables | |
| template<typename CharT , typename Traits > | |
| constexpr bool | real_eligible |
Whether real is even eligible for this basic_regex instantiation. real runs only the char path with default traits; wchar_t/char8_t/… and custom traits are always std. This is a compile-time gate: it must compile real's char-only code (the byte string_view, fill_from_real) out for other CharT, not merely skip it at runtime. | |
|
inline |
Appends the REAL translation of an awk C-escape at i (which points at the backslash), advancing i; returns false to decline (→ std). awk's escapes beyond ERE: \b is BACKSPACE (0x08) — not a word boundary, the inverse of the ERE decline — \a=BEL, \n\t\r\f\v the usual controls, \/ and \" literals, and a 1-to-3-digit octal \ddd (both std libraries agree; an overflow > 0377 declines). Emitted as \xHH so REAL matches the exact byte.
Definition at line 288 of file regex_core.hpp.
|
private |
Appends one match's ECMAScript-expanded replacement.
The ECMAScript replacement references: dollar-dollar to a literal $, dollar-ampersand to the whole match, dollar-backtick to the prefix, dollar-quote to the suffix, and $N/$NN to a group. Offsets come from the match's group spans relative to text. The prefix is the unmatched text since the previous match ([prefix_start, start)) and the suffix runs to the end — matching std::regex_replace (which uses match_results prefix/suffix), the parity oracle. A $N/$NN for a non-participating group inserts nothing; an invalid $ is literal.
Definition at line 575 of file regex_match.hpp.
|
inlinenoexcept |
Replacement format text that must route to std: $0. $0 is platform-variant (libstdc++ = the whole match, strict-ECMAScript/MSVC = a literal), so real cannot pick one without risking a silent divergence — route to std, which is authoritative for its own platform. $$ is skipped (an escaped literal $).
Definition at line 210 of file regex_core.hpp.
|
inlinenoexcept |
Grammars/options that force the std backend (real implements default-traits ECMAScript, reporting every group — so nosubs, which std answers by exposing only group 0, also routes to std to avoid a structural both-accept divergence).
Definition at line 166 of file regex_core.hpp.
|
inline |
Whether p has an empty alternation branch — a | with nothing on one side: (|, |), ||, or a | at the pattern start or end. Two reasons this matters: (a) std::regex rejects these in the POSIX grammars, so translating one would make compat over-accept vs std; (b) REAL's leftmost-first star semantics over an empty-first branch ((|a)*) diverge from re / std on repetition. Conservative — a | merely adjacent to a group boundary or the pattern edge counts, an escaped \| or a | inside a class does not — because a false positive only costs linear coverage (safe) while a false negative is a silent divergence (forbidden).
Definition at line 336 of file regex_core.hpp.
|
inlinenoexcept |
Pattern text that real accepts but matches differently from libstdc++ — a both-accept silent divergence, so it must route to std up front (real's accept hides it otherwise).
\0 followed by a digit: real reads it as a legacy octal escape (Annex B, e.g. \012 → newline) while libstdc++ reads \0 as NUL then a literal digit. Strict ECMAScript makes \0+ digit a syntax error (no valid production), so neither is "the" spec answer — routing to std keeps compat ≡ its secondary oracle and the contract (never a silent divergence). The fuzzer found this. (\1-\9 already route to std via real's backreference rejection.)
Definition at line 182 of file regex_core.hpp.
|
inline |
A POSIX bracket-class name to its ASCII (C-locale) range content, appended inside a [...] during ERE translation. Empty for an unknown name (the caller then falls back to std).
Definition at line 227 of file regex_core.hpp.
|
inlineprivatenoexcept |
Whether real can honor the requested match flags, so the operation may stay on it.
Only match_default and the non-constraining match_any hint stay on real (which satisfies match_any by returning the leftmost match, so ignoring it is sound). Any constraining bit — not_bol, not_eol, not_bow, not_eow, not_null, match_continuous, match_prev_avail — is not expressible through real's API, so the operation routes to std (§0: a constraining flag is never accepted-then-ignored). Affining this (e.g. continuous→real.match(pos)) is a measured optimization for later, not a hand-coded partition the fuzzer would have to police.
Definition at line 320 of file regex_match.hpp.
|
inlineprivatenoexcept |
Whether regex_replace can run its substitution on real. The real expander honors only format_first_only / format_no_copy (plus the match_any hint); ANY other bit — a constraining match flag (not_bol, continuous, …) OR format_sed (POSIX syntax) — would be silently ignored by the ECMAScript expander, so the whole substitution routes to std. (This subsumes the explicit format_sed screen; $0 stays content-based.)
Definition at line 332 of file regex_match.hpp.
|
private |
Runs the active backend over [first, last) and fills m. anchored selects whole-sequence match (regex_match) vs leftmost search (regex_search). A constraining match flag (see real_honors) routes to std even for a real-backed pattern.
Definition at line 370 of file regex_match.hpp.
|
private |
Backend run without capturing (no match_results to fill).
Definition at line 410 of file regex_match.hpp.
|
inlinenoexcept |
Maps compat options to real::flags (always with bytes|ecma for std-char alignment).
Definition at line 543 of file regex_core.hpp.
|
inlinenoexcept |
Maps compat options to std::regex syntax flags (the fallback path).
Definition at line 552 of file regex_core.hpp.
|
inlineprivatenoexcept |
Maps compat match/format flags to std::regex_constants — exhaustive (the std path).
Every compat bit has an entry: a forgotten bit would be silently lost on the std path, which is exactly the divergence §0 forbids. Both the match-control flags (search/match/iterate) and the format flags (replace) are mapped here.
Definition at line 347 of file regex_match.hpp.
|
inline |
Translates a POSIX bracket expression [...] — identical syntax in BRE and ERE, so shared by both translators. POSIX classes ([[:alpha:]]) become ASCII ranges; other members pass through. i must point at the opening [; on success it advances past the ] and appends the class to out. Returns false (the caller then declines to std) on an unterminated class or an unknown / collating [[:foo:]] / [.x.] / [=x=].
Definition at line 249 of file regex_core.hpp.
|
inline |
Translates a POSIX basic (BRE) pattern to an equivalent REAL pattern, or nullopt. BRE differs from ERE: \( \) group and \{n\} quantify, while bare ( ) { } | + ? are LITERALS (escaped for REAL); * at an expression start and ^/$ off the ends are literals too. Declines (→ std) on a backreference \1-\9 (std's residual value), an ECMAScript-ism, a non-strict \{, an unknown / collating class, or a POSIX-undefined corner (^/$/* at a subexpression boundary).
Definition at line 419 of file regex_core.hpp.
|
inline |
Translates a POSIX extended (ERE) — or, with awk, an awk — pattern to an equivalent REAL pattern, or nullopt when it uses a construct the two grammars read differently (an ECMAScript shorthand \d\w\s — undefined/literal in ERE; an ambiguous {; an unknown/collating [[:…:]]; an empty alternation branch, which std rejects — see has_empty_alternation_branch). awk adds the C-escapes (see append_awk_escape). POSIX classes become ASCII ranges (C locale); the common productions pass through, since REAL reads them like ERE. Validated by a bounds differential.
Definition at line 362 of file regex_core.hpp.
|
inline |
grep / egrep: a newline in the pattern is a top-level alternation of the lines (grep = BRE lines, egrep = ERE lines). Each line is translated by translate_line and the results are joined with | — correct precedence by construction, since | is the lowest, and each line's ^/$ stay branch-relative. A line that declines, or an empty line (a blank branch — a std edge best left to std), declines the whole pattern.
Definition at line 499 of file regex_core.hpp.
|
inline |
Dispatches a single POSIX grammar to its translator, or nullopt (→ std). Exactly one grammar bit must be set, and neither collate nor nosubs (which force std). extended → ERE, basic → BRE, awk → ERE + C-escapes, grep → BRE lines joined by |, egrep → ERE lines joined by |.
Definition at line 523 of file regex_core.hpp.
|
inlineconstexpr |
Whether real is even eligible for this basic_regex instantiation. real runs only the char path with default traits; wchar_t/char8_t/… and custom traits are always std. This is a compile-time gate: it must compile real's char-only code (the byte string_view, fill_from_real) out for other CharT, not merely skip it at runtime.
Definition at line 160 of file regex_core.hpp.