|
|
constexpr | small_vec () noexcept |
| | Constructs an empty vector in the inline state.
|
| |
|
constexpr | ~small_vec () |
| | Destroys elements and frees any heap block.
|
| |
| constexpr void | push_back (const T &value) |
| | Appends value, growing to the heap if the inline buffer is full.
|
| |
| constexpr void | assign (std::size_t count, const T &value) |
| | Resizes to count copies of value.
|
| |
| constexpr void | ensure_size (std::size_t count) |
| | Ensures at least count live elements without re-filling or shrinking.
|
| |
| constexpr std::size_t | size () const noexcept |
| | Returns the number of elements.
|
| |
| constexpr bool | empty () const noexcept |
| | Returns true if empty.
|
| |
| constexpr T & | operator[] (std::size_t i) noexcept |
| | Returns reference to the element at i.
|
| |
| constexpr const T & | operator[] (std::size_t i) const noexcept |
| | Returns const reference to the element at i.
|
| |
|
constexpr void | clear () noexcept |
| | Removes all elements (capacity and heap state unchanged).
|
| |
| constexpr T & | back () noexcept |
| | Returns reference to the last element. Precondition: the vector is non-empty.
|
| |
| constexpr const T & | back () const noexcept |
| | Returns const reference to the last element. Precondition: the vector is non-empty.
|
| |
| constexpr void | pop_back () noexcept |
| | Removes the last element. Precondition: the vector is non-empty.
|
| |
| constexpr void | reserve (std::size_t new_capacity) |
| | Ensures capacity for at least new_capacity elements (heap-backed).
|
| |
| constexpr | small_vec (small_vec &&other) noexcept |
| | Move constructor: steals other's heap block or moves inline elements.
|
| |
| constexpr small_vec & | operator= (small_vec &&other) noexcept |
| | Move assignment.
|
| |
| constexpr | small_vec (const small_vec &other) |
| | Copy constructor (needed for vector<match_result> in find_all).
|
| |
| constexpr small_vec & | operator= (const small_vec &other) |
| | Copy assignment.
|
| |
|
|
constexpr void | refresh_data () noexcept |
| | Refreshes data_ to the active storage base (run time only).
|
| |
| constexpr T * | inline_data () noexcept |
| | Returns pointer to the inline buffer.
|
| |
| constexpr const T * | inline_data () const noexcept |
| | Returns const pointer to the inline buffer.
|
| |
| template<bool Move> |
| constexpr void | transfer_range (const T *src, std::size_t count, T *dest) |
| | Copies or moves count elements from src to dest.
|
| |
| template<bool Move> |
| constexpr void | transfer_inline_from (const small_vec &other) |
| | Transfers other's inline elements into this vector's inline buffer.
|
| |
| constexpr void | adopt_heap (T *p) noexcept |
| | Points the union at p, making Storage::heap_ptr the active member.
|
| |
| constexpr void | revert_to_inline () noexcept |
| | Makes the inline buffer the active union member again, after the heap block is gone.
|
| |
|
constexpr void | cleanup () noexcept |
| | Frees the heap block, if any. T is trivially destructible (see the class static_assert), so no element destructors run — and inline storage needs no cleanup at all.
|
| |
|
constexpr void | extend_capacity () |
| | Doubles the capacity (saturating), spilling to the heap as needed.
|
| |
template<typename T, std::size_t InlineCapacity>
class real::detail::small_vec< T, InlineCapacity >
Small-buffer-optimized vector for the dynamic hot paths.
Keeps up to InlineCapacity elements inline (no heap), spilling to the heap beyond that — so the common small-group match avoids allocation entirely. Used for capture slots and working state in the dynamic mode.
- Note
T must be trivially destructible (enforced by a static_assert): small_vec runs no element destructors — inline elements in particular are never individually destroyed — which suits its POD-like VM use and keeps the hot path allocation- and bookkeeping-free.
- Warning
- Run-time invariant — the inline buffer is left UNINITIALIZED (value-initialized only under
std::is_constant_evaluated(), in the Storage union constructor). Every element's lifetime is begun by std::construct_at (placement-new) before it is read, and reads stay within [0, size_). Any accessor added here must preserve that write-before-read order, or it reads indeterminate memory — a silent UB value-init would mask. MemorySanitizer is the detector — the CI sanitize leg is ASan/UBSan, which does not catch this — so run an MSan build when changing how small_vec accesses its elements.
- Template Parameters
-
| T | Element type. |
| InlineCapacity | Number of elements held inline before spilling. |
template<typename T , std::size_t InlineCapacity>
|
|
inlineconstexprprivatenoexcept |
Points the union at p, making Storage::heap_ptr the active member.
Constant evaluation has no inactive-member assignment: switching to the pointer requires beginning its lifetime, which ends the inline buffer's. The run-time statement is left as a plain assignment — it is on the spill path of every container in the VM.
- Parameters
-
| [in] | p | The heap block to adopt. |
template<typename T , std::size_t InlineCapacity>
|
|
inlinestaticconstexprprivate |
Obtains storage for n elements, from whichever allocator the current regime allows.
A raw allocation operator cannot be called in a constant expression, so constant evaluation goes through std::allocator, which C++20 makes usable there. Its blocks are transient: every one must be released before the evaluation ends, which cleanup does.
- Parameters
-
- Returns
- Uninitialized storage for
n elements.
template<typename T , std::size_t InlineCapacity>
Ensures at least count live elements without re-filling or shrinking.
Fast-path find_iter: after the first match, size already equals the program slot count and the writer overwrites every used index — a full assign of npos is dead work. Growing default-constructs only the new tail (caller must write every slot it later reads). Never shrinks — multi-group fixed-shape may already be sized to slot_count before a span-only write of slots 0/1.
- Parameters
-
template<typename T , std::size_t InlineCapacity>
|
|
inlineconstexprprivatenoexcept |
Makes the inline buffer the active union member again, after the heap block is gone.
The moved-from side of a move needs this: it is left inline, so a later constant-evaluated read through inline_data would otherwise touch an inactive member.
template<typename T , std::size_t InlineCapacity>
template<bool Move>
Transfers other's inline elements into this vector's inline buffer.
The copy/move paths use this when other has not spilled. The count is clamped to InlineCapacity — a no-op on the value, since this runs only when the elements are inline (size_ <= InlineCapacity) — but it lets the optimizer see the inline buffer cannot overflow. Without it, g++ -O3 value-propagates a spilled source's large size_ into this then-dead branch and reports a spurious -Wstringop-overflow on the memcpy in transfer_range.
- Template Parameters
-
| Move | If true, move-construct the elements; otherwise copy-construct. |
- Parameters
-
| [in] | other | The not-yet-spilled source vector. |