REAL
Regular Expression Algorithmic Library — constexpr C++20 regex
Loading...
Searching...
No Matches
real::detail::small_vec< T, InlineCapacity > Class Template Reference

Small-buffer-optimized vector for the dynamic hot paths. More...

#include <storage.hpp>

Collaboration diagram for real::detail::small_vec< T, InlineCapacity >:
[legend]

Classes

struct  inline_block
 Inline element block. A struct (not a bare C array) so the union ctor can activate it as a whole with construct_at in a constant expression, while inline_data still indexes a plain C array — which the static analyzer can bound (a std::array's operator[] hides the extent and trips a false out-of-bounds on transfer_range). More...
 
union  Storage
 The either-or storage: the inline buffer, or a pointer to the heap block once the vector has spilled. is_heap_ says which member is active. More...
 

Public Types

using value_type = T
 Element type.
 
using size_type_ = std::size_t
 Size type (for std-container API compat).
 

Public Member Functions

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_vecoperator= (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_vecoperator= (const small_vec &other)
 Copy assignment.
 

Private Member Functions

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.
 

Static Private Member Functions

static constexpr T * allocate_block (std::size_t n)
 Obtains storage for n elements, from whichever allocator the current regime allows.
 
static constexpr void deallocate_block (T *p, std::size_t n) noexcept
 Releases a block from allocate_block.
 

Private Attributes

std::size_t size_ {}
 Number of elements in use.
 
std::size_t capacity_ {InlineCapacity}
 Current capacity.
 
bool is_heap_ {}
 True once spilled to the heap.
 
union real::detail::small_vec::Storage storage_
 The active storage, inline or heap.
 
T * data_ {}
 Cached base of the active storage; see the note above, and refresh_data.
 

Detailed Description

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
TElement type.
InlineCapacityNumber of elements held inline before spilling.

Constructor & Destructor Documentation

◆ small_vec() [1/2]

template<typename T , std::size_t InlineCapacity>
constexpr real::detail::small_vec< T, InlineCapacity >::small_vec ( small_vec< T, InlineCapacity > &&  other)
inlineconstexprnoexcept

Move constructor: steals other's heap block or moves inline elements.

Parameters
[in,out]otherThe vector to move from; left empty and inline.

◆ small_vec() [2/2]

template<typename T , std::size_t InlineCapacity>
constexpr real::detail::small_vec< T, InlineCapacity >::small_vec ( const small_vec< T, InlineCapacity > &  other)
inlineconstexpr

Copy constructor (needed for vector<match_result> in find_all).

Parameters
[in]otherThe vector to copy.

Member Function Documentation

◆ adopt_heap()

template<typename T , std::size_t InlineCapacity>
constexpr void real::detail::small_vec< T, InlineCapacity >::adopt_heap ( T *  p)
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]pThe heap block to adopt.

◆ allocate_block()

template<typename T , std::size_t InlineCapacity>
static constexpr T * real::detail::small_vec< T, InlineCapacity >::allocate_block ( std::size_t  n)
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
[in]nElement count.
Returns
Uninitialized storage for n elements.

◆ assign()

template<typename T , std::size_t InlineCapacity>
constexpr void real::detail::small_vec< T, InlineCapacity >::assign ( std::size_t  count,
const T &  value 
)
inlineconstexpr

Resizes to count copies of value.

Parameters
[in]countNumber of elements.
[in]valueThe value to fill with.

◆ back() [1/2]

template<typename T , std::size_t InlineCapacity>
constexpr const T & real::detail::small_vec< T, InlineCapacity >::back ( ) const
inlineconstexprnoexcept

Returns const reference to the last element. Precondition: the vector is non-empty.

Returns
A const reference to the last element.

◆ back() [2/2]

template<typename T , std::size_t InlineCapacity>
constexpr T & real::detail::small_vec< T, InlineCapacity >::back ( )
inlineconstexprnoexcept

Returns reference to the last element. Precondition: the vector is non-empty.

Returns
A reference to the last element.

◆ deallocate_block()

template<typename T , std::size_t InlineCapacity>
static constexpr void real::detail::small_vec< T, InlineCapacity >::deallocate_block ( T *  p,
std::size_t  n 
)
inlinestaticconstexprprivatenoexcept

Releases a block from allocate_block.

Parameters
[in]pBlock base.
[in]nThe capacity it was allocated with — std::allocator requires the exact count.

◆ empty()

template<typename T , std::size_t InlineCapacity>
constexpr bool real::detail::small_vec< T, InlineCapacity >::empty ( ) const
inlineconstexprnoexcept

Returns true if empty.

Returns
Whether the vector holds no elements.

◆ ensure_size()

template<typename T , std::size_t InlineCapacity>
constexpr void real::detail::small_vec< T, InlineCapacity >::ensure_size ( std::size_t  count)
inlineconstexpr

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
[in]countMinimum size.

◆ inline_data() [1/2]

template<typename T , std::size_t InlineCapacity>
constexpr const T * real::detail::small_vec< T, InlineCapacity >::inline_data ( ) const
inlineconstexprprivatenoexcept

Returns const pointer to the inline buffer.

Returns
A const pointer to its first element, whether or not the inline state is active.

◆ inline_data() [2/2]

template<typename T , std::size_t InlineCapacity>
constexpr T * real::detail::small_vec< T, InlineCapacity >::inline_data ( )
inlineconstexprprivatenoexcept

Returns pointer to the inline buffer.

Returns
A pointer to its first element, whether or not the inline state is active.

◆ operator=() [1/2]

template<typename T , std::size_t InlineCapacity>
constexpr small_vec & real::detail::small_vec< T, InlineCapacity >::operator= ( const small_vec< T, InlineCapacity > &  other)
inlineconstexpr

Copy assignment.

Parameters
[in]otherSource.
Returns
*this.

◆ operator=() [2/2]

template<typename T , std::size_t InlineCapacity>
constexpr small_vec & real::detail::small_vec< T, InlineCapacity >::operator= ( small_vec< T, InlineCapacity > &&  other)
inlineconstexprnoexcept

Move assignment.

Parameters
[in,out]otherSource (left empty).
Returns
*this.

◆ operator[]() [1/2]

template<typename T , std::size_t InlineCapacity>
constexpr const T & real::detail::small_vec< T, InlineCapacity >::operator[] ( std::size_t  i) const
inlineconstexprnoexcept

Returns const reference to the element at i.

Parameters
[in]iIndex.
Returns
Const reference to the element at i.

◆ operator[]() [2/2]

template<typename T , std::size_t InlineCapacity>
constexpr T & real::detail::small_vec< T, InlineCapacity >::operator[] ( std::size_t  i)
inlineconstexprnoexcept

Returns reference to the element at i.

Parameters
[in]iIndex.
Returns
Reference to the element at i.

◆ pop_back()

template<typename T , std::size_t InlineCapacity>
constexpr void real::detail::small_vec< T, InlineCapacity >::pop_back ( )
inlineconstexprnoexcept

Removes the last element. Precondition: the vector is non-empty.

For VM-internal use (POD types like size_t, eps_entry) explicit destroy is unnecessary; full cleanup happens in the destructor / clear when on the heap.

◆ push_back()

template<typename T , std::size_t InlineCapacity>
constexpr void real::detail::small_vec< T, InlineCapacity >::push_back ( const T &  value)
inlineconstexpr

Appends value, growing to the heap if the inline buffer is full.

Parameters
[in]valueThe element to append.

◆ reserve()

template<typename T , std::size_t InlineCapacity>
constexpr void real::detail::small_vec< T, InlineCapacity >::reserve ( std::size_t  new_capacity)
inlineconstexpr

Ensures capacity for at least new_capacity elements (heap-backed).

Parameters
[in]new_capacityDesired minimum capacity; smaller is a no-op.

◆ revert_to_inline()

template<typename T , std::size_t InlineCapacity>
constexpr void real::detail::small_vec< T, InlineCapacity >::revert_to_inline ( )
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.

◆ size()

template<typename T , std::size_t InlineCapacity>
constexpr std::size_t real::detail::small_vec< T, InlineCapacity >::size ( ) const
inlineconstexprnoexcept

Returns the number of elements.

Returns
The element count.

◆ transfer_inline_from()

template<typename T , std::size_t InlineCapacity>
template<bool Move>
constexpr void real::detail::small_vec< T, InlineCapacity >::transfer_inline_from ( const small_vec< T, InlineCapacity > &  other)
inlineconstexprprivate

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
MoveIf true, move-construct the elements; otherwise copy-construct.
Parameters
[in]otherThe not-yet-spilled source vector.

◆ transfer_range()

template<typename T , std::size_t InlineCapacity>
template<bool Move>
constexpr void real::detail::small_vec< T, InlineCapacity >::transfer_range ( const T *  src,
std::size_t  count,
T *  dest 
)
inlineconstexprprivate

Copies or moves count elements from src to dest.

Template Parameters
MoveIf true, move-construct; otherwise copy-construct.
Parameters
[in]srcSource range.
[in]countElement count.
[out]destDestination (uninitialized) range.

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