|
REAL
Regular Expression Algorithmic Library — constexpr C++20 regex
|
A lazy priority-preserving forward DFA over a Pike program (the kFirstMatch forward pass). More...
#include <lazy_dfa.hpp>
Classes | |
| struct | counters |
| Cache-behaviour counters, for the policy tests and later tuning. More... | |
Public Member Functions | |
| constexpr | lazy_dfa (std::span< const instr > code, std::span< const char_class > classes, std::size_t budget=state_budget, const lazy_byte_alphabet *shared_alpha=nullptr) |
| Builds the (initially empty) lazy DFA over a Pike program. | |
| bool | eligible () const |
| std::uint16_t | num_classes () const |
| std::uint32_t | start_state () const |
| void | begin_scan () |
| Begin a search: clear the per-scan flush counter and the thrash flag. (No cache flush — the states carry over between searches on the same text, which is where the cache pays.) | |
| bool | thrashing () const |
| const counters & | stats () const |
| std::size_t | forward_end (std::string_view text) |
The end offset of the leftmost-first match in text (kFirstMatch), or real::npos. | |
| bool | is_match (std::uint32_t state) const |
Whether state accepts here (its ordered set contains a match PC). | |
| std::uint32_t | step (std::uint32_t state, std::uint8_t byte) |
Transition state on byte to the next DFA state, computing and caching it on first use. Returns dead_state when no thread survives the byte. | |
Static Public Attributes | |
| static constexpr std::uint32_t | dead_state {0} |
| The empty state: every transition from it stays here. | |
| static constexpr std::uint32_t | no_transition {0xFFFFFFFFU} |
| A not-yet-computed cached transition. | |
| static constexpr std::uint32_t | no_match_idx {0xFFFFFFFFU} |
| A state whose ordered set holds no accept. | |
| static constexpr std::size_t | state_budget {4096} |
| Cached states before a flush (the memory cap). | |
| static constexpr std::size_t | thrash_flushes {2} |
| Flushes within one scan that trip thrashing. | |
Private Member Functions | |
| std::uint32_t | step_seeded (std::uint32_t state, std::uint8_t byte) |
| Like step, but re-seeds: the unanchored-search variant appends pc 0's closure at the lowest priority, so a fresh thread starts at every position until a match is found. Cached in its own transition row (the pre-match state family). | |
| std::uint32_t | cut (std::uint32_t state, std::uint32_t m) |
The priority-cut at an accept: intern the prefix of state's ordered pc-set before index m (dropping the accept and every lower-priority thread). Returns dead_state if empty. | |
| std::uint32_t | cut_cached (std::uint32_t state) |
The priority-cut of state at its own accept, memoized. cut is O(state size) — it rebuilds and re-interns the prefix — and a Unicode klass_cp byte-program makes states thousands of PCs wide, so recomputing it once per match (per find_iter step) dominated. Cached per state, it is computed once and then O(1). The state's accept index is fixed, so the cut is deterministic. | |
| bool | consumes (std::int32_t pc, std::uint8_t byte) const |
| constexpr void | close_into (std::int32_t pc, std::vector< std::int32_t > &out, std::vector< char > &seen) const |
Append the ordered epsilon-closure of pc to out (split priority; save/jump crossed), collecting the consuming and match PCs. Uses seen to dedup within this closure. | |
| constexpr std::uint32_t | intern (const std::vector< std::int32_t > &pcs) |
| Intern an ordered pc-set into a state id (cached). Flushes the cache when the budget is hit. | |
| constexpr std::uint32_t | intern_fresh (const std::vector< std::int32_t > &pcs) |
| constexpr void | flush () |
| Empty the cache back to the dead + start states (the eviction: bounded memory). | |
Static Private Member Functions | |
| static constexpr bool | compute_eligibility (std::span< const instr > code) |
| static std::int32_t | consumed_width (std::int32_t) |
Private Attributes | |
| std::span< const instr > | code_ |
| std::span< const char_class > | classes_ |
| lazy_byte_alphabet | alpha_ |
| bool | eligible_ {false} |
| std::uint32_t | start_state_ {0} |
| std::vector< std::vector< std::int32_t > > | state_pcs_ |
| state id -> ordered pc-set. | |
| std::vector< std::uint32_t > | trans_ |
| flat [state*stride + class] -> next, unseeded (post-match); stride = alpha_.count. | |
| std::vector< std::uint32_t > | trans_seeded_ |
| flat [state*stride + class] -> next, re-seeding (pre-match). | |
| std::vector< std::uint32_t > | state_match_idx_ |
| state id -> index of its first accept, or no_match_idx. | |
| std::vector< std::uint32_t > | state_cut_ |
| state id -> memoized priority-cut result (no_transition = not yet computed). | |
| pc_set_cache | cache_ |
| std::size_t | budget_ {state_budget} |
| counters | stats_ {} |
| bool | thrashing_ {false} |
A lazy priority-preserving forward DFA over a Pike program (the kFirstMatch forward pass).
A DFA state is the ordered epsilon-closure of a set of program counters (the Pike thread list's PCs, in split priority). step transitions on a byte by consuming it from each PC and re-closing, then interns the resulting ordered set into a cached state — the subset construction, memoized on demand.
The cache is bounded: once it reaches state_budget states it is flushed and rebuilt (states are cheap to recompute; a bounded cache keeps memory flat). state_budget flushes crossed within one scan (see begin_scan) trips thrashing — the signal an eventual caller uses to abandon the DFA and finish that one search on the Pike VM, per-scan and linear, never re-attempting per position.
A program with an op no forward DFA can represent — a position assertion (\b, ^, $), a klass_cp, or a lookaround — is ineligible; this only builds the machinery, it does not decide policy.
Definition at line 489 of file lazy_dfa.hpp.
|
inlineexplicitconstexpr |
Builds the (initially empty) lazy DFA over a Pike program.
| [in] | code | The program's instruction stream (must outlive this object — held as a span). |
| [in] | classes | The program's interned character classes (likewise held as a span). |
| [in] | budget | Cached states before a flush; defaults to state_budget. A smaller value is a test hook to exercise eviction and thrash without a state-exploding pattern. |
| [in] | shared_alpha | A precomputed alphabet the caller shares per regex, or null to compute it here. Recomputing is O(256 x classes) and a Unicode byte-program has thousands, so the router passes the shared one rather than paying it on every scan. |
Definition at line 518 of file lazy_dfa.hpp.
|
inline |
Begin a search: clear the per-scan flush counter and the thrash flag. (No cache flush — the states carry over between searches on the same text, which is where the cache pays.)
Definition at line 546 of file lazy_dfa.hpp.
|
inlineconstexprprivate |
Append the ordered epsilon-closure of pc to out (split priority; save/jump crossed), collecting the consuming and match PCs. Uses seen to dedup within this closure.
Definition at line 738 of file lazy_dfa.hpp.
|
inlinestaticconstexprprivate |
Definition at line 707 of file lazy_dfa.hpp.
|
inlinestaticprivate |
Definition at line 731 of file lazy_dfa.hpp.
|
inlineprivate |
Definition at line 718 of file lazy_dfa.hpp.
|
inlineprivate |
The priority-cut at an accept: intern the prefix of state's ordered pc-set before index m (dropping the accept and every lower-priority thread). Returns dead_state if empty.
Definition at line 675 of file lazy_dfa.hpp.
|
inlineprivate |
The priority-cut of state at its own accept, memoized. cut is O(state size) — it rebuilds and re-interns the prefix — and a Unicode klass_cp byte-program makes states thousands of PCs wide, so recomputing it once per match (per find_iter step) dominated. Cached per state, it is computed once and then O(1). The state's accept index is fixed, so the cut is deterministic.
Definition at line 693 of file lazy_dfa.hpp.
|
inline |
Definition at line 529 of file lazy_dfa.hpp.
|
inlineconstexprprivate |
Empty the cache back to the dead + start states (the eviction: bounded memory).
Definition at line 813 of file lazy_dfa.hpp.
|
inline |
The end offset of the leftmost-first match in text (kFirstMatch), or real::npos.
The forward pass the contract in the design guide (§7.6) specifies: an unanchored priority-ordered closure that seeds a fresh thread at every position (at the lowest priority) until a match is found, then reports the end of the highest-priority thread that reaches match — a lower-priority accept is suppressed while a higher one lives. It is a single left-to-right pass over the ordered PC-sets, so it is linear per search regardless of how the state space would explode under memoization. Eligible programs only (an ineligible one returns real::npos; the caller keeps the Pike VM). No captures: this reports the end; the windowed Pike pass fills the span and applies the empty-match rule.
Definition at line 573 of file lazy_dfa.hpp.
|
inlineconstexprprivate |
Intern an ordered pc-set into a state id (cached). Flushes the cache when the budget is hit.
Definition at line 777 of file lazy_dfa.hpp.
|
inlineconstexprprivate |
Definition at line 793 of file lazy_dfa.hpp.
|
inline |
Whether state accepts here (its ordered set contains a match PC).
Definition at line 605 of file lazy_dfa.hpp.
|
inline |
Definition at line 534 of file lazy_dfa.hpp.
|
inline |
Definition at line 539 of file lazy_dfa.hpp.
|
inline |
Definition at line 557 of file lazy_dfa.hpp.
|
inline |
Transition state on byte to the next DFA state, computing and caching it on first use. Returns dead_state when no thread survives the byte.
Definition at line 614 of file lazy_dfa.hpp.
|
inlineprivate |
Like step, but re-seeds: the unanchored-search variant appends pc 0's closure at the lowest priority, so a fresh thread starts at every position until a match is found. Cached in its own transition row (the pre-match state family).
Definition at line 646 of file lazy_dfa.hpp.
|
inline |
Definition at line 552 of file lazy_dfa.hpp.
|
private |
Definition at line 843 of file lazy_dfa.hpp.
|
private |
Definition at line 854 of file lazy_dfa.hpp.
|
private |
Definition at line 852 of file lazy_dfa.hpp.
|
private |
Definition at line 842 of file lazy_dfa.hpp.
|
private |
Definition at line 841 of file lazy_dfa.hpp.
|
staticconstexpr |
The empty state: every transition from it stays here.
Definition at line 493 of file lazy_dfa.hpp.
|
private |
Definition at line 844 of file lazy_dfa.hpp.
|
staticconstexpr |
A state whose ordered set holds no accept.
Definition at line 495 of file lazy_dfa.hpp.
|
staticconstexpr |
A not-yet-computed cached transition.
Definition at line 494 of file lazy_dfa.hpp.
|
private |
Definition at line 845 of file lazy_dfa.hpp.
|
staticconstexpr |
Cached states before a flush (the memory cap).
Definition at line 496 of file lazy_dfa.hpp.
|
private |
state id -> memoized priority-cut result (no_transition = not yet computed).
Definition at line 851 of file lazy_dfa.hpp.
|
private |
state id -> index of its first accept, or no_match_idx.
Definition at line 850 of file lazy_dfa.hpp.
|
private |
state id -> ordered pc-set.
Definition at line 847 of file lazy_dfa.hpp.
|
private |
Definition at line 855 of file lazy_dfa.hpp.
|
staticconstexpr |
Flushes within one scan that trip thrashing.
Definition at line 497 of file lazy_dfa.hpp.
|
private |
Definition at line 856 of file lazy_dfa.hpp.
|
private |
flat [state*stride + class] -> next, unseeded (post-match); stride = alpha_.count.
Definition at line 848 of file lazy_dfa.hpp.
|
private |
flat [state*stride + class] -> next, re-seeding (pre-match).
Definition at line 849 of file lazy_dfa.hpp.