Drop-in for std::regex#
Full drop-in, per-pattern fallback — the same <regex> surface; every pattern
REAL can prove identical runs on the linear, ReDoS-safe engine, everything else
falls back to std::regex at construction. Never a silent divergence.
Adopt / swap#
Swap the include, alias the namespace, and your std::regex code compiles unchanged:
#include <real/compat/std/regex.hpp> // was: #include <regex>
namespace re = real::compat; // then use re::regex / re::smatch / re::regex_search / …
Under the default strict policy every accepted pattern runs regex_search /
regex_match in time linear in the input — no accepted pattern can go
super-linear, where a std::regex blows up exponentially on (a+)+b.
API offered#
The types (regex, smatch / cmatch, sub_match, match_results, regex_error),
the free functions (regex_search, regex_match, regex_replace) and the iterators
(regex_iterator, regex_token_iterator) keep their std::regex signatures and
semantics — at the call sites only the std:: qualifier changes to re::. The
ECMAScript default and all five POSIX grammars (basic/extended/awk/grep/egrep)
run on REAL when the pattern translates.
re::regex r(R"((\w+)=(\d+))");
re::smatch m;
std::string line = "answer=42";
if (re::regex_search(line, m, r)) {
auto key = m[1].str(); // "answer"
auto val = m[2].str(); // "42"
}
Which backend won, and why — introspection for performance debugging:
r.uses_real(); // true -> the linear REAL engine
r.uses_real_traversal(); // true -> replace/iterate also run on REAL
r.nullable(); // true -> can match empty; replace/iterators defer to std
r.mark_count(); // capture-group count (std::regex parity)
Object-level reference: std::regex compatibility.
Differences & limitations#
Per-pattern fallback. A backreference, an oversized or unbounded lookaround, a non-ASCII
[...]member — anything REAL cannot prove equivalent routes tostd::regextransparently, at construction;uses_real()surfaces it. Every routing rule lives in the compatibility reference.Always std by construction:
wregexand any non-charCharTor custom traits;collate;nosubs. There is deliberately no switch to force REAL there — forcing could diverge, which the contract forbids.regex_replaceand the iterators compose O(n) operations — quadratic worst case, never exponential; a nullable pattern’s replace/iteration delegates to std.One tolerated capture divergence — a nullable loop’s final empty iteration: rationale. The exhaustive contract, including the platform-variant (MSVC) pins, is the compatibility reference.
Comparison#
Four-engine numbers live in the performance ledger; the reading is Performance. Where a backtracker is ReDoS-able on a crafted lookaround and RE2 refuses the pattern, REAL’s bounded lookarounds stay linear.