REAL
Regular Expression Algorithmic Library — constexpr C++20 regex
Loading...
Searching...
No Matches
real::detail::onepass Class Reference

Builds and holds the one-pass classification (and table, when eligible) of a byte-program. More...

#include <onepass.hpp>

Collaboration diagram for real::detail::onepass:
[legend]

Public Member Functions

constexpr onepass (const byte_program &bp, std::size_t max_bytes=max_table_bytes, std::size_t node_cap=max_nodes, std::uint64_t work_cap=max_minimize_work)
 Classifies bp and, when it is one-pass, builds the table. A smaller cap is a test hook.
 
bool eligible () const
 Whether the table was built and may be used.
 
const std::string & bail_reason () const
 Why the build declined, when it did.
 
std::size_t node_count () const
 Size of the built table.
 
std::uint16_t num_classes () const
 Width of each node's edge row.
 
const std::vector< onepass_node > & nodes () const
 The nodes, for tests that pin the table's shape. A built table keeps its edges in steps_ alone, so each node's onepass_node::edge row is empty once the build is over.
 
std::uint8_t class_of (std::uint8_t byte) const
 The byte-class of byte, for a runtime that walks this table.
 
std::size_t slot_count () const
 The number of capture slots (group 0 start/end plus each group's).
 
template<typename OutSlots >
bool extract (std::string_view text, std::size_t s, std::size_t e, OutSlots &out) const
 Fills out with the capture slots of the one-pass match on text[s, e): fullmatch on the span the router located, anchored at s and accepting exactly at e. A slot no edge wrote is real::npos.
 
bool ends_known () const
 Whether extract_leftmost applies: no node accepts with edges on both sides of its match.
 
template<typename OutSlots >
std::size_t extract_leftmost (std::string_view text, std::size_t s, OutSlots &out, std::size_t &reach) const
 The leftmost-first match anchored at s, found and captured in one pass: no end needs to be known beforehand, unlike extract.
 
bool asserts_hold (std::uint32_t mask, std::string_view text, std::size_t pos) const
 Whether every assertion in mask (a set of assert_kind bits) holds at pos in text.
 

Static Public Member Functions

static constexpr std::uint8_t accept_rank (const onepass_node &node) noexcept
 How a node accepts, from the priority order its closure was walked in.
 

Static Public Attributes

static constexpr std::uint32_t no_node {0xFFFFFFFFU}
 "No node yet" sentinel in the pc->node map.
 
static constexpr std::uint32_t no_row {0xFFFFFFFFU}
 onepass_step::row of an unassigned edge.
 
static constexpr std::uint8_t rank_none {0}
 accept_rank of a node that does not accept.
 
static constexpr std::uint8_t rank_continue {1}
 Accepts, and every edge outranks the match.
 
static constexpr std::uint8_t rank_match {2}
 Accepts, and the match outranks every edge.
 
static constexpr std::uint8_t rank_mixed {3}
 Accepts, with edges on both sides of the match.
 
static constexpr std::size_t max_nodes {65000}
 Node cap, a memory/DoS bound.
 
static constexpr std::size_t max_slots {10}
 Slot-pointer cap: group 0 + four user groups.
 
static constexpr std::size_t minimize_buckets {4096}
 Moore-refinement dedup buckets; sizing only (a collision costs a comparison).
 
static constexpr std::size_t max_table_bytes {8U << 20}
 
static constexpr std::uint64_t max_minimize_work {100'000'000ULL}
 

Private Member Functions

constexpr void bail (const char *reason, std::int32_t node=-1, std::int32_t klass=-1, std::int32_t pc=-1)
 Reject as not one-pass, recording a category and the offending node / byte-class / pc.
 
constexpr std::int32_t follow_jumps (std::int32_t pc) const
 The first non-jump pc reachable from pc by following unconditional jumps.
 
constexpr std::uint32_t node_of (std::int32_t pc, std::vector< std::int32_t > &queue)
 Get-or-create the node whose entry pc is pc, enqueueing a fresh one for the flood.
 
constexpr void build (const byte_program &bp)
 Builds the table: flood the byte program into nodes, write their edges, then minimize.
 
constexpr std::uint32_t ranked (std::uint32_t node) const
 A node id with its accept_rank in the top byte, as onepass_step::target holds it.
 
REAL_BUILD_COLD constexpr void minimize ()
 Moore partition refinement: merges nodes with the same accept, match masks and, per byte-class, the same edge (target partition and masks). The graph has cycles (\w+), so bottom-up hash-consing is not enough; refinement runs to a fixpoint. Merged nodes share their masks by construction, and each keeps a dense edge row.
 
constexpr void build_edges (std::int32_t pc, std::uint64_t cap_mask, std::uint32_t assert_mask, std::vector< char > &on_path, std::uint32_t node_id, std::vector< std::int32_t > &queue)
 Walk the epsilon-closure from pc, writing this node's edges.
 

Static Private Member Functions

static constexpr std::size_t sig_hash (std::span< const std::uint64_t > v)
 FNV-1a hash of a partition signature, for the constexpr-friendly bucket dedup.
 

Private Attributes

std::span< const instr > code_
 The byte program being compiled; borrowed, not owned.
 
std::span< const char_class > classes_
 Its interned byte classes; borrowed alongside code_.
 
lazy_byte_alphabet alpha_
 Byte-equivalence classes: what class_of answers with.
 
std::vector< std::vector< std::uint16_t > > class_cover_
 char-class index -> the byte-classes it consumes.
 
std::vector< std::uint32_t > pc_to_node_
 pc -> node id (or no_node).
 
std::vector< onepass_node > nodes_
 The table, node 0 being the start; empty until built.
 
std::size_t slot_count_ {0}
 Capture slots the program uses (slot_count).
 
std::vector< onepass_step > steps_
 nodes_' edges in one array, row by row: what extract walks.
 
std::uint32_t start_ {0}
 Node 0 packed as onepass_step::target is.
 
bool ends_known_ {true}
 No node is rank_mixed, so extract_leftmost applies.
 
std::size_t max_bytes_ {max_table_bytes}
 Table-memory cap (a constructor test hook).
 
std::size_t node_cap_ {max_nodes}
 Node-count cap; same test-hook role.
 
std::uint64_t work_cap_ {max_minimize_work}
 Moore-refinement work cap; same role.
 
bool ascii_word_ {true}
 ASCII word-ness for \b \B \< \> edge conditions unless byte_program::unicode_word.
 
std::int32_t bail_node_ {-1}
 Node the decline was found at, or -1. Diagnostic only.
 
std::int32_t bail_class_ {-1}
 Byte-class involved in the decline, or -1.
 
std::int32_t bail_pc_ {-1}
 Program counter involved in the decline, or -1.
 
bool eligible_ {true}
 Cleared by bail; read through eligible.
 
std::string bail_reason_
 Human-readable decline reason (bail_reason).
 

Detailed Description

Builds and holds the one-pass classification (and table, when eligible) of a byte-program.

Construction floods the program from the start: each node walks its epsilon-closure (split, jump, save, assertions) accumulating masks, and each consuming instruction (byte, klass) writes the edge for its byte-classes. A byte-class written twice with different edges, a second reachable match with different captures, or an epsilon cycle (a nullable loop) means not one-pass, and the build bails with a reason. Node, slot, memory and refinement-work caps bound a pathological program.

Constructor & Destructor Documentation

◆ onepass()

constexpr real::detail::onepass::onepass ( const byte_program &  bp,
std::size_t  max_bytes = max_table_bytes,
std::size_t  node_cap = max_nodes,
std::uint64_t  work_cap = max_minimize_work 
)
inlineexplicitconstexpr

Classifies bp and, when it is one-pass, builds the table. A smaller cap is a test hook.

Parameters
[in]bpThe byte-program to classify.
[in]max_bytesTable-memory cap (max_table_bytes).
[in]node_capNode-count cap (max_nodes).
[in]work_capMoore-refinement work cap (max_minimize_work).

Member Function Documentation

◆ accept_rank()

static constexpr std::uint8_t real::detail::onepass::accept_rank ( const onepass_node &  node)
inlinestaticconstexprnoexcept

How a node accepts, from the priority order its closure was walked in.

Parameters
[in]nodeThe node.
Returns
rank_none, rank_continue, rank_match or rank_mixed. A node that accepts with no edge has nothing to continue with, so it ranks as rank_match does.

◆ asserts_hold()

bool real::detail::onepass::asserts_hold ( std::uint32_t  mask,
std::string_view  text,
std::size_t  pos 
) const
inline

Whether every assertion in mask (a set of assert_kind bits) holds at pos in text.

Parameters
[in]maskThe assertions an edge carries; an empty mask holds trivially.
[in]textThe full subject the position is inside.
[in]posByte offset to test the assertions at.
Returns
true if all of them hold.

◆ bail()

constexpr void real::detail::onepass::bail ( const char *  reason,
std::int32_t  node = -1,
std::int32_t  klass = -1,
std::int32_t  pc = -1 
)
inlineconstexprprivate

Reject as not one-pass, recording a category and the offending node / byte-class / pc.

Locations stay integers, not formatted text, so the builder stays constexpr: a constexpr real::regex embeds an (empty) one-pass table in its literal state.

Parameters
[in]reasonCategory, surfaced by bail_reason.
[in]nodeOffending node id, or -1 when not applicable.
[in]klassOffending byte-class, or -1.
[in]pcOffending program counter, or -1.

◆ bail_reason()

const std::string & real::detail::onepass::bail_reason ( ) const
inline

Why the build declined, when it did.

Returns
The reason bail recorded, or an empty string if eligible is true.

◆ build()

constexpr void real::detail::onepass::build ( const byte_program &  bp)
inlineconstexprprivate

Builds the table: flood the byte program into nodes, write their edges, then minimize.

Declines by calling bail, which leaves eligible false and bail_reason set.

Parameters
[in]bpThe klass_cp-expanded byte program to compile.

◆ build_edges()

constexpr void real::detail::onepass::build_edges ( std::int32_t  pc,
std::uint64_t  cap_mask,
std::uint32_t  assert_mask,
std::vector< char > &  on_path,
std::uint32_t  node_id,
std::vector< std::int32_t > &  queue 
)
inlineconstexprprivate

Walk the epsilon-closure from pc, writing this node's edges.

Parameters
[in]pcProgram counter to walk from.
[in]cap_maskCapture slots crossed on the way here; accumulates down the closure.
[in]assert_maskAssertions crossed on the way here, as assert_kind bits.
[in,out]on_pathPer-pc marks detecting an epsilon CYCLE — a nullable loop is not one-pass.
[in]node_idThe node whose edge row is being written.
[in,out]queueWork list new nodes are appended to.

◆ class_of()

std::uint8_t real::detail::onepass::class_of ( std::uint8_t  byte) const
inline

The byte-class of byte, for a runtime that walks this table.

Parameters
[in]byteThe subject byte to classify.
Returns
Its index into a node's edge row, below num_classes.

◆ eligible()

bool real::detail::onepass::eligible ( ) const
inline

Whether the table was built and may be used.

Returns
false when the pattern is not one-pass or a cap was exceeded; bail_reason then says why.

◆ ends_known()

bool real::detail::onepass::ends_known ( ) const
inline

Whether extract_leftmost applies: no node accepts with edges on both sides of its match.

Returns
False when the table is ineligible or some node is rank_mixed.

◆ extract()

template<typename OutSlots >
bool real::detail::onepass::extract ( std::string_view  text,
std::size_t  s,
std::size_t  e,
OutSlots &  out 
) const
inline

Fills out with the capture slots of the one-pass match on text[s, e): fullmatch on the span the router located, anchored at s and accepting exactly at e. A slot no edge wrote is real::npos.

Parameters
[in]textThe full subject, never a substring: assertions read s - 1 and e.
[in]sMatch start (anchor).
[in]eMatch end (the run must accept here).
[out]outCapture slots, sized to slot_count.
Returns
true on a successful extraction; false (ineligible table, or the span does not match) leaves out unspecified.

◆ extract_leftmost()

template<typename OutSlots >
std::size_t real::detail::onepass::extract_leftmost ( std::string_view  text,
std::size_t  s,
OutSlots &  out,
std::size_t &  reach 
) const
inline

The leftmost-first match anchored at s, found and captured in one pass: no end needs to be known beforehand, unlike extract.

Each accepting node met is a candidate end. Where its edges outrank the match (rank_continue) the walk goes on and a later end replaces it, as backtracking would; where the match outranks them (rank_match) the walk stops. The groups are those of the last end kept: a slot written past it is discarded.

Precondition
ends_known().
Parameters
[in]textThe full subject (assertions read around a position).
[in]sMatch start.
[out]outCapture slots, sized to slot_count, filled on a match.
[out]reachHow far the walk read, the match's end on a match.
Returns
The match's end, or real::npos when none begins at s.

◆ follow_jumps()

constexpr std::int32_t real::detail::onepass::follow_jumps ( std::int32_t  pc) const
inlineconstexprprivate

The first non-jump pc reachable from pc by following unconditional jumps.

A jump is pure epsilon, so a jump's node and its target's get identical edges. emit_utf8_trie writes klass then jump(target) per trie edge: without this, the flood copies every shared trie subgraph for minimize to merge back; resolving the chain builds the shared node directly.

Bounded by the code size: on a jump cycle the pc comes back as-is and build_edges bails on it.

Parameters
[in]pcStarting pc.
Returns
The resolved pc (pc itself when it is not a jump, or on running out of steps).

◆ node_count()

std::size_t real::detail::onepass::node_count ( ) const
inline

Size of the built table.

Returns
Node count after minimization, or 0 if the build declined.

◆ node_of()

constexpr std::uint32_t real::detail::onepass::node_of ( std::int32_t  pc,
std::vector< std::int32_t > &  queue 
)
inlineconstexprprivate

Get-or-create the node whose entry pc is pc, enqueueing a fresh one for the flood.

Parameters
[in]pcEntry program counter the node stands for.
[in,out]queueWork list a newly created node is appended to.
Returns
The node's id, existing or just created.

◆ nodes()

const std::vector< onepass_node > & real::detail::onepass::nodes ( ) const
inline

The nodes, for tests that pin the table's shape. A built table keeps its edges in steps_ alone, so each node's onepass_node::edge row is empty once the build is over.

Returns
The nodes, indexed by node id; node 0 is the start.

◆ num_classes()

std::uint16_t real::detail::onepass::num_classes ( ) const
inline

Width of each node's edge row.

Returns
The number of byte-equivalence classes the alphabet collapsed to.

◆ ranked()

constexpr std::uint32_t real::detail::onepass::ranked ( std::uint32_t  node) const
inlineconstexprprivate

A node id with its accept_rank in the top byte, as onepass_step::target holds it.

Parameters
[in]nodeThe node id, below 2^24 (max_nodes is far below).
Returns
The packed value.

◆ sig_hash()

static constexpr std::size_t real::detail::onepass::sig_hash ( std::span< const std::uint64_t >  v)
inlinestaticconstexprprivate

FNV-1a hash of a partition signature, for the constexpr-friendly bucket dedup.

Accumulates in a fixed 64-bit width and truncates only at the return, so a 32-bit size_t (Win32) never sees a narrowing brace-init of the 64-bit offset basis.

Parameters
[in]vThe signature words to hash.
Returns
The hash, truncated to size_t.

◆ slot_count()

std::size_t real::detail::onepass::slot_count ( ) const
inline

The number of capture slots (group 0 start/end plus each group's).

Returns
Twice the group count plus two.

Member Data Documentation

◆ max_minimize_work

constexpr std::uint64_t real::detail::onepass::max_minimize_work {100'000'000ULL}
staticconstexpr

Moore-refinement work cap (rounds x nodes x signature width); larger declines to the VM. A repeated large class (\w{k}) forms a chain needing ~k rounds of O(nodes x alphabet) each, quadratic in k: capping CUMULATIVE work, not rounds, lets a small automaton refine fully while a long chain declines early.

◆ max_table_bytes

constexpr std::size_t real::detail::onepass::max_table_bytes {8U << 20}
staticconstexpr

Table-memory cap (~8 MB): larger declines to the VM.


The documentation for this class was generated from the following file: