REAL
Regular Expression Algorithmic Library — constexpr C++20 regex
Loading...
Searching...
No Matches
real::detail::static_storage< Pat, F > Struct Template Reference

Storage policy backing real::static_regex: compile-time, stateless. More...

#include <storage.hpp>

Collaboration diagram for real::detail::static_storage< Pat, F >:
[legend]

Classes

struct  measured
 Everything build yields that is NOT a range, measured in ONE evaluation. More...
 

Public Types

using name_owner = borrowed_names
 Name-resolution owner: empty, the tables having static storage duration.
 
using slot_storage = static_vec< std::size_t, slot_count >
 Capture-slot storage, sized exactly to the program's slot count (no heap).
 
using il_guard_fields = static_il_guard_fields
 IL guard fields for this storage — lifted to static_il_guard_fields, which carries the rationale; kept as a name here because wants_inner_literal reads next to it.
 
using no_il_guard_fields = static_no_il_guard_fields
 No IL fields: the route is not compiled for this pattern (see wants_inner_literal).
 
using state_type = static_pike_scratch< scratch_code_tier(code_size), slot_count, wants_inner_literal >
 This pattern's VM scratch — nothing but static_pike_scratch at this pattern's dimensions, so two patterns of the same shape name the same type.
 

Public Member Functions

constexpr const program_viewview () const
 Returns a non-owning view of the compile-time program, by reference.
 
constexpr std::string_view pattern () const
 Returns the pattern text.
 
constexpr flags compiled_flags () const
 Returns the flag set in force: constructor flags, plus a leading global-flags group's additions, minus its -removal – see real::basic_regex::compile_flags.
 

Static Public Attributes

static constexpr bool is_compile_time {true}
 Selects the default constructor.
 
static constexpr bool viable {requires { typename std::bool_constant<(build(), true)>; }}
 Whether build is a constant expression for this pattern.
 
static constexpr measured survey
 The one measuring evaluation. Never emitted: nothing takes its address, and every member below reads it at compile time only.
 
static constexpr flags effective_flags
 The flag set in force: F plus what a leading (?imsxaU) group added, minus what a (?flags-flags) removal cleared. Mirrors dynamic_storage::compile, so the two storages report the same thing for the same pattern. Parsed ONCE – the two-call form this replaces ran the parser twice for one answer, the same defect as the seven-call measure above in miniature.
 
static constexpr pattern_hints hints {survey.hints}
 Search hints.
 
static constexpr std::size_t code_size {survey.code_size}
 Instruction count.
 
static constexpr std::size_t class_count {survey.class_count}
 Distinct class count.
 
static constexpr std::size_t name_count {survey.name_count}
 Named-group count.
 
static constexpr std::size_t cp_class_count {survey.cp_class_count}
 Code-point class count (klass_cp).
 
static constexpr std::size_t cp_range_count {survey.cp_range_count}
 Total code-point ranges.
 
static constexpr std::uint16_t slot_count {survey.slot_count}
 2*(groups+1).
 
static constexpr std::array< instr, code_sizecode {take<instr, code_size>(build().code)}
 The program.
 
static constexpr std::array< char_class, class_countclasses
 Interned classes.
 
static constexpr std::array< named_group, name_countnames
 Named groups.
 
static constexpr std::array< cp_class, cp_class_countcp_classes
 Code-point classes.
 
static constexpr std::array< code_range, cp_range_countcp_ranges
 Flat range buffer.
 
static constexpr std::array< std::uint8_t,(class_count==0 ? 1 :class_count) *256 > class_tables
 Flat byte-class membership tables, built at compile time: class_tables[i*256 + b]. Reuses the classes member rather than calling build again — an extra build() per table pushes the whole instantiation past clang's constexpr step budget.
 
static constexpr std::array< std::uint8_t,(cp_class_count==0 ? 1 :cp_class_count) *256 > cp_ascii_tables
 Flat ASCII tables for the code-point classes: cp_ascii_tables[i*256 + b].
 
static constexpr std::array< std::uint64_t,(cp_class_count==0 ? 1 :cp_class_count) *30 > cp_page_tables
 Two-byte-range membership bitmaps (U+0080..U+07FF) for the code-point classes, 30 words each.
 
static constexpr bool wants_inner_literal
 Whether the inner-literal route is worth compiling into this pattern's run().
 

Static Private Member Functions

static constexpr dynamic_program build ()
 Returns the freshly built program (used for both measuring and filling).
 
template<typename T , std::size_t N, typename Vec >
static constexpr std::array< T, N > take (const Vec &source)
 Copies the first N elements of v into a fixed array.
 

Static Private Attributes

static constexpr program_view view_
 The view itself, materialised once at compile time. See view.
 

Detailed Description

template<fixed_string Pat, flags F = flags::none>
struct real::detail::static_storage< Pat, F >

Storage policy backing real::static_regex: compile-time, stateless.

Every array is a static constexpr member sized exactly by a measuring pass over the same compilation, so a static_regex object is stateless (sizeof 1) and matching allocates nothing.

Template Parameters
PatThe pattern, as a real::fixed_string non-type parameter.
FCompilation flags.

Member Typedef Documentation

◆ state_type

This pattern's VM scratch — nothing but static_pike_scratch at this pattern's dimensions, so two patterns of the same shape name the same type.

Nothing here depends on the pattern's value any more. The three byte-class table addresses that used to live in this type now travel in real::detail::program_view, which is where runtime program data belongs; they remain static constexpr arrays, so a constant-folding compiler still reaches them without a load. What that buys, and what it cost to establish, is in 10.1 The inlining budget.

Member Function Documentation

◆ build()

template<fixed_string Pat, flags F = flags::none>
static constexpr dynamic_program real::detail::static_storage< Pat, F >::build ( )
inlinestaticconstexprprivate

Returns the freshly built program (used for both measuring and filling).

Runs only at compile time (a static_regex instantiation), so it is invisible to the runtime coverage report; it is exercised by the constexpr static_asserts in tests/test_static.cpp and tests/test_constexpr.cpp.

Returns
The compiled program.

◆ compiled_flags()

template<fixed_string Pat, flags F = flags::none>
constexpr flags real::detail::static_storage< Pat, F >::compiled_flags ( ) const
inlineconstexpr

Returns the flag set in force: constructor flags, plus a leading global-flags group's additions, minus its -removal – see real::basic_regex::compile_flags.

Returns
The effective flag set.

◆ pattern()

template<fixed_string Pat, flags F = flags::none>
constexpr std::string_view real::detail::static_storage< Pat, F >::pattern ( ) const
inlineconstexpr

Returns the pattern text.

Returns
A view of the compile-time pattern string.

◆ take()

template<fixed_string Pat, flags F = flags::none>
template<typename T , std::size_t N, typename Vec >
static constexpr std::array< T, N > real::detail::static_storage< Pat, F >::take ( const Vec &  source)
inlinestaticconstexprprivate

Copies the first N elements of v into a fixed array.

Template Parameters
TElement type.
NExact size (measured from build).
VecSource container type.
Parameters
[in]sourceThe source vector.
Returns
The exactly-sized array.

◆ view()

template<fixed_string Pat, flags F = flags::none>
constexpr const program_view & real::detail::static_storage< Pat, F >::view ( ) const
inlineconstexpr

Returns a non-owning view of the compile-time program, by reference.

Every field is a compile-time constant here — the spans point at static constexpr arrays and immut is null — so the whole view is one too, and handing back a reference costs nothing where returning by value copied the whole thing per call. 232 of its 432 bytes are pattern_hints, and view() is called once per search(): line-level profiling of a single [a-z]+ search put that one aggregate initialiser at 93 of the ~325 instructions the call spends, against 17 for the class scan itself. The measurement was taken at 408 bytes, before the three table bases moved into the view; the dynamic storage still returns by value and so still pays a construction of that size once per search — the one place this reasoning has not been applied.

Returns
A reference to the single compile-time view; it outlives every caller.

Member Data Documentation

◆ class_tables

template<fixed_string Pat, flags F = flags::none>
constexpr std::array< std::uint8_t, (class_count == 0 ? 1 : class_count) * 256 > real::detail::static_storage< Pat, F >::class_tables
staticconstexpr
Initial value:
{[] {
std::array < std::uint8_t, (class_count == 0 ? 1 : class_count) * 256 > t {};
for (std::size_t i = 0; i < class_count; ++i) {
for (std::size_t b = 0; b < 256; ++b) {
t[(i * 256) + b] = classes[i].test(static_cast<std::uint8_t>(b)) ? std::uint8_t {1} : std::uint8_t {0};
}
}
return t;
}()}
static constexpr std::array< char_class, class_count > classes
Interned classes.
Definition storage.hpp:1473
static constexpr std::size_t class_count
Distinct class count.
Definition storage.hpp:1466

Flat byte-class membership tables, built at compile time: class_tables[i*256 + b]. Reuses the classes member rather than calling build again — an extra build() per table pushes the whole instantiation past clang's constexpr step budget.

Note
A pack-expansion tabulate<N>(f) here was written, measured and REFUSED. The loop below cannot be one pass: constant evaluation rejects indeterminate subobjects, so the array is zeroed and then overwritten — 2N element operations where a pack expansion needs N. The argument is sound and buys nothing. Compile time is indistinguishable between the two forms, with the direction flipping between paired runs; and bisecting -fconstexpr-steps to the failure point gives the SAME budget for both, so there is no headroom in it either — the compiler's own cost for a large pack cancels the halved element count. The loop stays: same speed, same budget, no helper to maintain.

◆ classes

template<fixed_string Pat, flags F = flags::none>
constexpr std::array<char_class, class_count> real::detail::static_storage< Pat, F >::classes
staticconstexpr
Initial value:
=
static constexpr dynamic_program build()
Returns the freshly built program (used for both measuring and filling).
Definition storage.hpp:1365
static constexpr std::array< T, N > take(const Vec &source)
Copies the first N elements of v into a fixed array.
Definition storage.hpp:1386

Interned classes.

◆ cp_ascii_tables

template<fixed_string Pat, flags F = flags::none>
constexpr std::array< std::uint8_t, (cp_class_count == 0 ? 1 : cp_class_count) * 256 > real::detail::static_storage< Pat, F >::cp_ascii_tables
staticconstexpr
Initial value:
{[] {
std::array < std::uint8_t, (cp_class_count == 0 ? 1 : cp_class_count) * 256 > t {};
for (std::size_t i = 0; i < cp_class_count; ++i) {
for (std::size_t b = 0; b < 256; ++b) {
t[(i * 256) + b] = cp_classes[i].ascii.test(static_cast<std::uint8_t>(b)) ? std::uint8_t {1}
: std::uint8_t {0};
}
}
return t;
}()}
@ ascii
ASCII mode (re.A): \d \w \s \b stay ASCII and icase folds ASCII only, even in text mode....
static constexpr std::array< cp_class, cp_class_count > cp_classes
Code-point classes.
Definition storage.hpp:1477
static constexpr std::size_t cp_class_count
Code-point class count (klass_cp).
Definition storage.hpp:1468

Flat ASCII tables for the code-point classes: cp_ascii_tables[i*256 + b].

◆ cp_classes

template<fixed_string Pat, flags F = flags::none>
constexpr std::array<cp_class, cp_class_count> real::detail::static_storage< Pat, F >::cp_classes
staticconstexpr
Initial value:

Code-point classes.

◆ cp_page_tables

template<fixed_string Pat, flags F = flags::none>
constexpr std::array< std::uint64_t, (cp_class_count == 0 ? 1 : cp_class_count) * 30 > real::detail::static_storage< Pat, F >::cp_page_tables
staticconstexpr
Initial value:
{[] {
std::array < std::uint64_t, (cp_class_count == 0 ? 1 : cp_class_count) * 30 > t {};
for (std::size_t i = 0; i < cp_class_count; ++i) {
for (std::uint32_t k = 0; k < cp_classes[i].range_count; ++k) {
const code_range& r {cp_ranges[cp_classes[i].range_begin + k]};
if (r.lo > 0x7FFU) {
break;
}
const std::uint32_t lo {r.lo < 0x80U ? 0x80U : r.lo};
const std::uint32_t hi {r.hi > 0x7FFU ? 0x7FFU : r.hi};
for (std::uint32_t c = lo; c <= hi; ++c) {
const std::uint32_t bit {c - 0x80U};
t[(i * 30) + (bit >> 6U)] |= std::uint64_t {1} << (bit & 63U);
}
}
}
return t;
}()}
An inclusive code-point range [lo, hi]. Shared by character classes (ast.hpp) and the generated Unico...
Definition program.hpp:212
std::uint32_t lo
First code point (inclusive).
Definition program.hpp:213
static constexpr std::array< code_range, cp_range_count > cp_ranges
Flat range buffer.
Definition storage.hpp:1479

Two-byte-range membership bitmaps (U+0080..U+07FF) for the code-point classes, 30 words each.

◆ cp_ranges

template<fixed_string Pat, flags F = flags::none>
constexpr std::array<code_range, cp_range_count> real::detail::static_storage< Pat, F >::cp_ranges
staticconstexpr
Initial value:

Flat range buffer.

◆ effective_flags

template<fixed_string Pat, flags F = flags::none>
constexpr flags real::detail::static_storage< Pat, F >::effective_flags
staticconstexpr
Initial value:
{[] {
const auto parsed {detail::parse(Pat.view(), F)};
return flags_without(F | parsed.inline_flags,
parsed.inline_removed);
}()}
constexpr ast parse(std::string_view pattern, flags initial_flags=flags::none)
Parses pattern into an ast (convenience over parser).
Definition ast.hpp:2403
constexpr flags flags_without(flags value, flags removed)
value with every flag in removed cleared – the (?flags-flags) removal.
Definition program.hpp:106

The flag set in force: F plus what a leading (?imsxaU) group added, minus what a (?flags-flags) removal cleared. Mirrors dynamic_storage::compile, so the two storages report the same thing for the same pattern. Parsed ONCE – the two-call form this replaces ran the parser twice for one answer, the same defect as the seven-call measure above in miniature.

◆ names

template<fixed_string Pat, flags F = flags::none>
constexpr std::array<named_group, name_count> real::detail::static_storage< Pat, F >::names
staticconstexpr
Initial value:
=
static constexpr std::array< named_group, name_count > names
Named groups.
Definition storage.hpp:1475

Named groups.

◆ survey

template<fixed_string Pat, flags F = flags::none>
constexpr measured real::detail::static_storage< Pat, F >::survey
staticconstexpr
Initial value:
{[] {
const dynamic_program p {build()};
return measured {.hints = p.hints,
.code_size = p.code.size(),
.class_count = p.classes.size(),
.name_count = p.names.size(),
.cp_class_count = p.cp_classes.size(),
.cp_range_count = p.cp_ranges.size(),
.slot_count = p.slot_count};
}()}
Everything build yields that is NOT a range, measured in ONE evaluation.
Definition storage.hpp:1412
pattern_hints hints
Search hints.
Definition storage.hpp:1413

The one measuring evaluation. Never emitted: nothing takes its address, and every member below reads it at compile time only.

◆ viable

template<fixed_string Pat, flags F = flags::none>
constexpr bool real::detail::static_storage< Pat, F >::viable {requires { typename std::bool_constant<(build(), true)>; }}
staticconstexpr

Whether build is a constant expression for this pattern.

A requires expression is a SFINAE context: forming the bool_constant template argument needs a constant expression, and build throwing makes it one substitution failure rather than a hard error. That is what lets viable be asked instead of crashed into.

◆ view_

template<fixed_string Pat, flags F = flags::none>
constexpr program_view real::detail::static_storage< Pat, F >::view_
staticconstexprprivate
Initial value:
{.code = code,
.classes = classes,
.names = names,
.lookarounds = {},
.cp_classes = cp_classes,
.cp_ranges = cp_ranges,
.prefix_code = {},
.prefix_classes = {},
.prefix_cp_classes = {},
.prefix_cp_ranges = {},
.slot_count = slot_count,
.hints = hints,
.immut = nullptr,
.class_tables = class_tables.data(),
.cp_ascii_tables = cp_ascii_tables.data(),
.cp_page_tables = cp_page_tables.data()}
constexpr bool has_flag(flags value, flags flag)
Tests whether flag is set in value.
Definition program.hpp:119
@ bytes
Binary mode: . and [^…] match raw bytes, not codepoints.
static constexpr std::array< std::uint8_t,(class_count==0 ? 1 :class_count) *256 > class_tables
Flat byte-class membership tables, built at compile time: class_tables[i*256 + b]....
Definition storage.hpp:1494
static constexpr std::array< std::uint8_t,(cp_class_count==0 ? 1 :cp_class_count) *256 > cp_ascii_tables
Flat ASCII tables for the code-point classes: cp_ascii_tables[i*256 + b].
Definition storage.hpp:1506
static constexpr std::array< instr, code_size > code
The program.
Definition storage.hpp:1472
static constexpr std::uint16_t slot_count
2*(groups+1).
Definition storage.hpp:1470
static constexpr flags effective_flags
The flag set in force: F plus what a leading (?imsxaU) group added, minus what a (?...
Definition storage.hpp:1459
static constexpr std::array< std::uint64_t,(cp_class_count==0 ? 1 :cp_class_count) *30 > cp_page_tables
Two-byte-range membership bitmaps (U+0080..U+07FF) for the code-point classes, 30 words each.
Definition storage.hpp:1519
static constexpr pattern_hints hints
Search hints.
Definition storage.hpp:1464

The view itself, materialised once at compile time. See view.

◆ wants_inner_literal

template<fixed_string Pat, flags F = flags::none>
constexpr bool real::detail::static_storage< Pat, F >::wants_inner_literal
staticconstexpr
Initial value:
std::int32_t inner_literal_prefix
Top-level children before the literal; 0 = at the head, -1 = nested with no clean boundary.
Definition program.hpp:527
bool fixed_shape
Whole pattern is a fixed-width byte/klass sequence (no branches/asserts/captures).
Definition program.hpp:466
std::uint8_t inner_literal_len
Bytes held in inner_literal; 0 means the pattern has no required inner literal.
Definition program.hpp:526

Whether the inner-literal route is worth compiling into this pattern's run().

A required literal at offset >= 1 is necessary but not sufficient. fixed_shape means the core already has an arithmetic-width scan for the whole pattern, and then memmem has nothing to add; without it the core falls to the general VM, which is what the literal sweep rescues. The shape of the result is the same on every pattern measured: a non-fixed-shape pattern gains by orders of magnitude on a subject with NO match – where the literal scan rejects the whole corpus and the general VM would walk it – and is neutral once matches are dense enough that the scan finds one immediately. A fixed_shape pattern gains nothing and pays for the attempt.

Excluding it HERE rather than at run time is what keeps the cost off the patterns that do not use the route: compiling the block into run() at all is measurable on a pattern with no inner literal, which never enters it.


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