JH-Toolkit v1.4.1
An engineering-oriented C++20 toolkit with duck-typed concepts, static design, async coroutines, and semantic containers — header-only, RTTI-free, and concurrency-friendly.
Loading...
Searching...
No Matches
jh::sync::control_buf< T, Alloc > Class Template Referencefinal

Fixed-capacity, block-allocated container for control-only types (e.g., mutexes, atomics). More...

#include <jh/synchronous/control_buf.h>

Public Types

using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<T>
 Type of allocator used for element construction.

Public Member Functions

 control_buf ()=default
 Constructs an empty control buffer.
 control_buf (const Alloc &alloc)
 Constructs an empty control buffer with a custom allocator.
 control_buf (std::size_t n)
 Constructs a control buffer with exactly n default-constructed elements.
 control_buf (std::size_t n, const Alloc &alloc)
 Constructs a control buffer with n elements using a custom allocator.
 control_buf (const control_buf &other)
 Copy-constructs the buffer topology from another instance.
control_bufoperator= (const control_buf &other)
 Copy-assigns the buffer topology from another instance.
 control_buf (control_buf &&other) noexcept
 Move-constructs a control buffer from another instance.
control_bufoperator= (control_buf &&other) noexcept
 Move-assigns a control buffer from another buffer.
std::size_t size () const noexcept
 Returns the current number of constructed elements.
std::size_t capacity () const noexcept
 Returns the total number of elements that can be stored without further allocation.
T & emplace_back ()
 Appends a default-constructed element to the end of the buffer.
T & operator[] (std::size_t i) noexcept
 Provides unchecked access to the element at index i.
const T & operator[] (std::size_t i) const noexcept
 Provides unchecked, read-only access to the element at index i.
T & at (std::size_t i)
 Returns a reference to the element at index i, with bounds checking.
const T & at (std::size_t i) const
 Returns a const reference to the element at index i, with bounds checking.
void reserve (std::size_t n) noexcept(noexcept(std::declval< std::vector< block_ptr > & >().reserve(n)))
 Reserves space in the internal block index for at least n elements.
void clear () noexcept(noexcept(std::declval< std::vector< block_ptr > & >().clear()))
 Destroys all constructed elements and deallocates all blocks.
void shrink_to_fit () noexcept
 Attempts to reduce the capacity of the internal block index vector to fit its size.
void resize (std::size_t n)
 Resizes the container to contain exactly n elements.

Static Public Attributes

static constexpr std::size_t BLOCK_SIZE = JH_CTRL_BUFFER_BLOCK_SIZE
 Number of elements per allocation block.

Detailed Description

template<typename T, typename Alloc = std::allocator<T>>
requires (std::is_default_constructible_v<T> && !jh::concepts::is_contiguous_reallocable<T>)
class jh::sync::control_buf< T, Alloc >

Fixed-capacity, block-allocated container for control-only types (e.g., mutexes, atomics).

Template Parameters
TType to store (must be default-constructible and non-reallocable).
AllocOptional allocator type (defaults to std::allocator<T>).

Design Constraints

  • T must be default-constructible.
  • T must NOT be copyable or movable.
  • control_buf is not intended for data storage or iteration.

Constructor & Destructor Documentation

◆ control_buf() [1/6]

template<typename T, typename Alloc = std::allocator<T>>
jh::sync::control_buf< T, Alloc >::control_buf ( )
default

Constructs an empty control buffer.

No memory is allocated and no elements are constructed. The container starts with zero size and zero blocks.

◆ control_buf() [2/6]

template<typename T, typename Alloc = std::allocator<T>>
jh::sync::control_buf< T, Alloc >::control_buf ( const Alloc & alloc)
inlineexplicit

Constructs an empty control buffer with a custom allocator.

Parameters
allocAllocator instance used for all future block allocations.

The allocator is stored internally and copied into each block deleter. No memory allocation occurs at construction time.

◆ control_buf() [3/6]

template<typename T, typename Alloc = std::allocator<T>>
jh::sync::control_buf< T, Alloc >::control_buf ( std::size_t n)
inlineexplicit

Constructs a control buffer with exactly n default-constructed elements.

Parameters
nNumber of elements to construct.

Elements are constructed incrementally using the block-based growth strategy. Each element is default-constructed in-place and never relocated.

◆ control_buf() [4/6]

template<typename T, typename Alloc = std::allocator<T>>
jh::sync::control_buf< T, Alloc >::control_buf ( std::size_t n,
const Alloc & alloc )
inline

Constructs a control buffer with n elements using a custom allocator.

Parameters
nNumber of elements to construct.
allocAllocator used for block allocation and element construction.

◆ control_buf() [5/6]

template<typename T, typename Alloc = std::allocator<T>>
jh::sync::control_buf< T, Alloc >::control_buf ( const control_buf< T, Alloc > & other)
inline

Copy-constructs the buffer topology from another instance.

Parameters
otherSource buffer.

This is a topological copy:

  • The resulting buffer has the same size() as other.
  • Elements are default-constructed, not copied.
  • No element-wise copy or move is performed.

This behavior is intentional and required for control-type objects whose state must not be duplicated.

◆ control_buf() [6/6]

template<typename T, typename Alloc = std::allocator<T>>
jh::sync::control_buf< T, Alloc >::control_buf ( control_buf< T, Alloc > && other)
inlinenoexcept

Move-constructs a control buffer from another instance.

Parameters
otherSource buffer to move from.

Transfers ownership of all internal blocks and allocator state from other to the newly constructed buffer.

  • No elements are copied, moved, or relocated.
  • Only block ownership and allocator state are transferred.
  • Block-level address stability is preserved.
Note
After the move, other is left in a valid but unspecified state, consistent with standard C++ container move semantics. The moved-from object is safe to destroy. If reuse is required, the caller must explicitly call clear().

Member Function Documentation

◆ at() [1/2]

template<typename T, typename Alloc = std::allocator<T>>
T & jh::sync::control_buf< T, Alloc >::at ( std::size_t i)
inline

Returns a reference to the element at index i, with bounds checking.

Parameters
iZero-based index of the element to access.
Returns
Reference to the element at index i.
Exceptions
std::out_of_rangeIf i is greater than or equal to size().

This function performs runtime bounds checking before accessing the element. If the index is invalid, an exception is thrown.

  • Semantically equivalent to std::vector::at().
  • Access is internally delegated to operator[] after validation.
  • Provides a safer alternative to unchecked access via operator[].
Note
Prefer this method over operator[] when index validity is uncertain.

◆ at() [2/2]

template<typename T, typename Alloc = std::allocator<T>>
const T & jh::sync::control_buf< T, Alloc >::at ( std::size_t i) const
inlinenodiscard

Returns a const reference to the element at index i, with bounds checking.

Parameters
iZero-based index of the element to access.
Returns
Const reference to the element at index i.
Exceptions
std::out_of_rangeIf i is greater than or equal to size().

This overload provides read-only, bounds-checked access to an element.

  • Returns the same result as the non-const version but guarantees const access.
  • Delegates to operator[] after index validation.
Note
Use this method when accessing elements in a const context with safety guarantees.

◆ capacity()

template<typename T, typename Alloc = std::allocator<T>>
std::size_t jh::sync::control_buf< T, Alloc >::capacity ( ) const
inlinenodiscardnoexcept

Returns the total number of elements that can be stored without further allocation.

Returns
The maximum number of elements that can be emplaced before triggering a new block allocation.
Note
Capacity is managed in blocks of fixed size (BLOCK_SIZE) and is calculated as: blocks.capacity() * BLOCK_SIZE.

◆ clear()

template<typename T, typename Alloc = std::allocator<T>>
void jh::sync::control_buf< T, Alloc >::clear ( )
inlinenoexcept

Destroys all constructed elements and deallocates all blocks.

This function releases all memory held by the container and resets its size to zero. It also clears the internal block index vector.

  • All constructed elements are destroyed via allocator-aware destruction.
  • All blocks are properly deallocated via their bound deleters.
  • The internal block pointer vector is also cleared.
Note
After calling clear(), the container is empty and has no allocated blocks.

◆ emplace_back()

template<typename T, typename Alloc = std::allocator<T>>
T & jh::sync::control_buf< T, Alloc >::emplace_back ( )
inline

Appends a default-constructed element to the end of the buffer.

Returns
Reference to the newly constructed element.

This method constructs a new element in-place at the logical end of the buffer. If the current block is full, a new block is allocated and all its elements are default-constructed.

  • Elements are constructed using allocator_traits::construct.
  • New memory is allocated in chunks of BLOCK_SIZE elements.
  • Each block is allocated only once and never reallocated or moved.
  • Element addresses remain stable for the lifetime of the container.

This function's interface is intentionally consistent with std::vector<T>::emplace_back() and std::deque<T>::emplace_back() (default-construction form), even though this container does not support in-place argument forwarding.

  • This design choice lowers the learning curve for users familiar with STL containers.
  • It enables generic code to use emplace_back() in the same way across both control and data containers.
  • It allows working with types like std::mutex and std::atomic, which cannot be stored in std::vector due to relocation or copying constraints, but still benefit from a consistent push-back interface.
Note
This function always performs default-construction only. Argument forwarding is not supported.

◆ operator=() [1/2]

template<typename T, typename Alloc = std::allocator<T>>
control_buf & jh::sync::control_buf< T, Alloc >::operator= ( const control_buf< T, Alloc > & other)
inline

Copy-assigns the buffer topology from another instance.

Parameters
otherSource buffer.
Returns
Reference to this buffer.

Equivalent to:

  1. Destroying all existing blocks.
  2. Copying the allocator.
  3. Default-constructing other.size() elements.

Element contents are never copied.

◆ operator=() [2/2]

template<typename T, typename Alloc = std::allocator<T>>
control_buf & jh::sync::control_buf< T, Alloc >::operator= ( control_buf< T, Alloc > && other)
inlinenoexcept

Move-assigns a control buffer from another buffer.

Parameters
otherThe source buffer to move from.
Returns
Reference to this buffer after assignment.

Clears current contents and transfers ownership of all internal blocks and allocator state from other to this buffer.

  • All previously allocated memory is destroyed before the move.
  • Element memory is not copied; blocks are moved as raw pointers.
  • The moved-from buffer is left in a valid but unspecified state.
Note
As with move construction, reusing the moved-from buffer requires an explicit call to clear().

◆ operator[]() [1/2]

template<typename T, typename Alloc = std::allocator<T>>
const T & jh::sync::control_buf< T, Alloc >::operator[] ( std::size_t i) const
inlinenoexcept

Provides unchecked, read-only access to the element at index i.

Parameters
iZero-based index of the element to access.
Returns
Const reference to the element at the specified index.

This overload offers const access to the same element as the non-const version.

  • No bounds checking is performed.
  • Safe to call as long as i is within [0, size()).
  • Useful in const contexts and read-only algorithms.
Note
Use at(i) for bounds-checked access.

◆ operator[]() [2/2]

template<typename T, typename Alloc = std::allocator<T>>
T & jh::sync::control_buf< T, Alloc >::operator[] ( std::size_t i)
inlinenoexcept

Provides unchecked access to the element at index i.

Parameters
iZero-based index of the element to access.
Returns
Reference to the element at the specified index.

This function does not perform bounds checking. It assumes the index is valid (i.e., less than size()).

  • Equivalent in usage to std::vector::operator[].
  • Allows direct indexed access for integration with generic code.
  • Performs internal block lookup via division and modulus on BLOCK_SIZE.
Note
Use at(i) if you need bounds checking.

◆ reserve()

template<typename T, typename Alloc = std::allocator<T>>
void jh::sync::control_buf< T, Alloc >::reserve ( std::size_t n)
inlinenoexcept

Reserves space in the internal block index for at least n elements.

Parameters
nDesired minimum number of elements the buffer should be able to hold without reallocation.

This function performs a preallocation on the internal std::vector<block_ptr> that manages block pointers. It does not preallocate the actual element blocks themselves.

  • Internally reserves ceil(n / BLOCK_SIZE) block pointer slots.
  • Does not allocate or construct any elements or blocks.
  • Useful mostly for reducing index vector reallocations during bulk appends.
  • Cannot avoid per-block allocation due to the semantics of control_buf.
Note
The usefulness of reserve() is limited because control-type elements (e.g. mutexes) cannot be preconstructed or relocated. This function primarily exists for interface consistency and intent declaration.

◆ resize()

template<typename T, typename Alloc = std::allocator<T>>
void jh::sync::control_buf< T, Alloc >::resize ( std::size_t n)
inline

Resizes the container to contain exactly n elements.

Parameters
nThe desired number of elements after resizing.

This function adjusts the logical size of the container to n.

  • If n > size(), new elements are added via emplace_back(), which default-constructs new elements in-place.
  • If n < size(), blocks beyond the necessary range are destroyed and released.
  • If the new size does not align exactly to BLOCK_SIZE, the tail block may contain partially used space that remains physically allocated but is treated as logically unused.

These remaining elements are not destroyed and retain their previous state. They are considered logically uninitialized, and the next call to emplace_back() will continue from where resize() left off — it does not reinitialize the tail.

Note
This behavior is safe and expected for most control types (e.g., std::atomic), where default-construction does not guarantee value initialization. However, if you rely on a default-constructed value having a known state (e.g., user-defined types), you must ensure to explicitly reset such objects after resize().
Warning
Do not assume that elements beyond the new logical size are reset or zeroed. Treat them as undefined and reinitialize as needed.

◆ shrink_to_fit()

template<typename T, typename Alloc = std::allocator<T>>
void jh::sync::control_buf< T, Alloc >::shrink_to_fit ( )
inlinenoexcept

Attempts to reduce the capacity of the internal block index vector to fit its size.

This function operates only on the internal std::vector<block_ptr> that stores pointers to element blocks. It does not modify or deallocate any element storage.

  • Does not affect the actual element blocks or constructed elements.
  • Has no observable effect on memory usage unless the vector itself has excess capacity.
  • Provided for interface symmetry with standard containers like std::vector.
Note
This function behaves similarly to std::vector::shrink_to_fit(), which in C++20 and beyond also has no mandated effect.

◆ size()

template<typename T, typename Alloc = std::allocator<T>>
std::size_t jh::sync::control_buf< T, Alloc >::size ( ) const
inlinenodiscardnoexcept

Returns the current number of constructed elements.

Returns
Number of elements currently held in the buffer.
Note
This reflects the logical size (i.e., how many elements were constructed via emplace or resize), not the total memory capacity.

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