|
| | runtime_arr (std::uint64_t size) |
| | Constructs a bit-packed boolean runtime array with all bits zero-initialized.
|
| | runtime_arr (std::vector< bool > &&vec) |
| | Constructs a bit-packed array by moving data from a std::vector<bool>.
|
| | runtime_arr (std::initializer_list< bool > init) |
| | Constructs a bit-packed boolean runtime array from an initializer list.
|
template<typename ForwardIt>
requires (jh::concepts::forward_iterator<ForwardIt> && std::convertible_to<typename ForwardIt::value_type, value_type>) |
| | runtime_arr (ForwardIt first, ForwardIt last) |
| | Constructs a bit-packed array from a range of boolean values.
|
| size_type | size () const noexcept |
| | Returns the number of elements in the array.
|
| bool | empty () const noexcept |
| | Checks whether the array is empty.
|
| raw_type * | raw_data () noexcept |
| | Provides mutable access to the underlying word buffer.
|
| const raw_type * | raw_data () const noexcept |
| | Provides const access to the underlying word buffer.
|
| size_type | raw_word_count () const noexcept |
| | Returns the number of 64-bit words used internally to store all bits.
|
| reference | operator[] (std::uint64_t i) noexcept |
| | Unchecked bit access (read/write).
|
| value_type | operator[] (std::uint64_t i) const noexcept |
| | Unchecked const bit access (read-only).
|
| reference | at (std::uint64_t i) |
| | Bounds-checked bit access (read/write).
|
| value_type | at (std::uint64_t i) const |
| | Const bounds-checked bit access (read-only).
|
| void | set (std::uint64_t i, bool val=true) |
| | Sets or clears the bit at given index.
|
| void | unset (std::uint64_t i) |
| | Clears the bit at given index.
|
| value_type | test (std::uint64_t i) const |
| | Tests if the bit at index is set.
|
| void | reset_all () noexcept |
| | Resets all bits in the bit-packed array to zero.
|
| | runtime_arr (runtime_arr &&other) noexcept |
| | Move constructor — transfers ownership of the bit-packed buffer.
|
| runtime_arr< bool > & | operator= (runtime_arr &&other) noexcept |
| | Move assignment operator — transfers ownership of the bit-packed buffer.
|
| | operator std::vector< bool > () && |
| | Converts the bit array into std::vector<bool>. Elements are copied bit-by-bit.
|
|
iterator | begin () noexcept |
| | Mutable begin iterator over bits.
|
|
iterator | end () noexcept |
| | Mutable end iterator over bits.
|
|
const_iterator | begin () const noexcept |
| | Const begin iterator over bits.
|
|
const_iterator | end () const noexcept |
| | Const end iterator over bits.
|
|
const_iterator | cbegin () const noexcept |
| | Const begin iterator over bits.
|
|
const_iterator | cend () const noexcept |
| | Const end iterator over bits.
|
| void | data () const =delete |
| | Deleted data() function — raw pointer access is not valid for bit-packed layout.
|
| | runtime_arr (std::uint64_t size, auto)=delete |
| | Deleted allocator-based constructor.
|
|
std::span< value_type > | as_span ()=delete |
| | Deleted — bit-packed array cannot expose a contiguous span of bools.
|
|
std::span< const value_type > | as_span () const =delete |
| | Deleted — const version; contiguous view over bits is not representable.
|
|
| runtime_arr (const runtime_arr &)=delete |
| | Copy constructor deleted — bit array is non-copyable by design.
|
|
runtime_arr & | operator= (const runtime_arr &)=delete |
| | Copy assignment deleted — bit array is non-copyable by design.
|
| | operator std::vector< bool > () && |
| | Converts the array into a std::vector<T> by moving its contents.
|
Specialized implementation of jh::runtime_arr<bool> — a compact, bit-packed boolean array.
Overview
This specialization provides a memory-efficient representation for bool values, storing them as individual bits within 64-bit words (uint64_t[]). Each bit represents a boolean value, achieving 8× memory compression compared to the generic runtime_arr<T, Alloc> template (which stores one byte per bool).
Its purpose is not raw speed but spatial density and fragmentation reduction — ideal for large logical masks, flags, and occupancy bitfields.
Relation to Generic Template
This specialization mirrors the structure of the generic runtime_arr<T, Alloc>, but modifies or disables certain operations that are incompatible with bit-level storage.
| Semantics | Generic Member | Bool Specialization Equivalent | Notes |
| Raw access | data(), as_span() | ❌ Deleted | Direct pointer access invalid for bit-packed layout. |
| Element access | operator[](i) | ✅ Reimplemented | Non-const returns bit_ref, const returns bool. |
| Bounded access | at(i) | ✅ Reimplemented | Same proxy/value semantics with range checking. |
| Bulk reset | reset_all() | ✅ Implemented | Clears all bits via std::memset(). |
| Bit manipulation | (none) | ✅ set(), unset(), test() | New API for direct bit operations. |
| Allocator constructor | runtime_arr(size, Alloc) | ❌ Deleted | Custom allocators not supported for bit layout. |
| Copy semantics | ❌ Deleted | ❌ Deleted | Copying disallowed to prevent shallow duplication. |
| Move semantics | ✅ Supported | ✅ Supported | Safe ownership transfer via RAII. |
Core Characteristics
-
Stores bits compactly in 64-bit words (
uint64_t[]).
-
Uses
bit_ref proxies for writable element access.
-
Const accessors return plain
bool values.
-
Implements
bit_iterator for STL-style traversal.
-
Provides low-level access via
raw_data() and raw_word_count().
-
Not a contiguous range (proxy elements are non-trivial).
Usage Guidance
This specialization is automatically selected when T == bool and the allocator parameter is omitted:
bits.set(3);
bits.unset(1);
bool b = bits.test(3);
A move-only, fixed-capacity array with runtime-determined length and RAII-based ownership.
Definition runtime_arr.h:367
To disable bit packing:
Use jh::runtime_arr<bool, jh::runtime_arr_helper::bool_flat_alloc> to obtain a byte-based layout (one byte per bool). This form is also the baseline used in all performance comparisons below.
Behavior Summary
| Aspect | Generic runtime_arr<T> | Specialized runtime_arr<bool> |
| Storage layout | Contiguous T[] | Bit-packed (uint64_t[]) |
| Element access | Direct reference | Proxy (bit_ref) / value (bool) |
data() / as_span() | ✅ | ❌ Deleted |
| Allocator awareness | ✅ | ❌ Deleted |
| Copy semantics | ❌ | ❌ |
| Move semantics | ✅ | ✅ |
reset_all() | Element-wise reset | Zero bits via memset() |
| Primary use | General runtime array | Compact boolean bitset |
Performance Characteristics
Microbenchmark results for jh::runtime_arr<bool> versus its byte-based counterpart jh::runtime_arr<bool, jh::runtime_arr_helper::bool_flat_alloc>, collected on Apple Silicon M3 with LLVM clang++ 20 (2025), under the following setup:
-
Array sizes: 1,024 and 1,000,000 elements
-
Bernoulli(0.5) data distribution
-
Catch2 microbenchmark harness
-
Single-threaded, in-cache workload
Empirical results
| Optimization | N = 1,000,000 elements | N = 1,024 elements |
| set() | read() | reset_all() | set() | read() | reset_all() |
| -O0 | ~20× slower | ~2.8× slower | ~2.8× slower | ~0.3× faster | ~2.3× slower | ~2.3× slower |
| -O2 | ~38× slower | ~160× slower | ~130× slower | ~0.55× faster | ~61× slower | ~60× slower |
| -O3 | ~59× slower | ~140× slower | ~130× slower | ~0.6× faster | ~62× slower | ~61× slower |
| -Ofast | ~51× slower | ~150× slower | ~125× slower | ~0.5× faster | ~61× slower | ~59× slower |
Interpretation
-
Small arrays (≤1K): Bit-packing may outperform byte-based storage in write-heavy scenarios due to 8× lower memory bandwidth usage. Reads and resets remain slower due to bit masking overhead.
-
Large arrays (≥1M): Bitwise access overhead dominates;
set() is typically ~30-60× slower, and read() / reset_all() are ~120-160×± slower but mostly memory-bound.
-
Optimization scaling:
-O2 already achieves full inlining; -O3 and -Ofast differences are within measurement noise (±2%).
-
Static instantiation: A precompiled specialization provides a debug fallback, mitigating
-O0 template inlining overhead.
In summary, this specialization trades raw performance for memory compactness. It is most useful for boolean masks, sparse flags, and occupancy grids where space efficiency outweighs per-bit access cost.
Notes
-
Each bit resides in a 64-bit word.
-
Thread safety is not guaranteed for concurrent modification.
-
RAII-managed, deterministic destruction.
- See also
-
Converts the array into a std::vector<T> by moving its contents.
This conversion performs a one-way ownership transfer from runtime_arr<T> to std::vector<T>, consuming the source in the process. After the conversion, the original runtime_arr becomes an empty, valid but unspecified object (size() == 0, data() == nullptr).
Behavior
-
POD-like types (
jh::pod_like<T>): Performs a raw std::memcpy for maximal performance. The operation is equivalent to copying a contiguous byte buffer.
-
Non-POD types: Uses
std::make_move_iterator to move-construct each element into the target vector, ensuring proper object semantics.
Symmetry
This operator complements the constructor runtime_arr(std::vector<T>&&), enabling seamless two-way transfer between std::vector<T> and runtime_arr<T> with full move semantics. Both conversions leave the source container in a valid but empty state, ensuring safe RAII destruction.
- Note
- This operator is only available on rvalues (
runtime_arr<T>&&), preventing accidental copies.
- See also
- runtime_arr(std::vector<T>&&)