21template<
typename T,
typename TableType = shm_table>
22 requires std::is_trivially_copyable_v<T>
26 std::atomic<uint32_t> free_head{0};
27 std::atomic<uint32_t> num_allocated{0};
29 uint32_t next_array[];
33 static constexpr uint32_t NULL_INDEX = std::numeric_limits<uint32_t>::max();
35 PoolHeader* header_{
nullptr};
37 const typename TableType::entry* table_entry_{
nullptr};
39 PoolHeader* get_header(
void* base_addr,
size_t offset) {
40 return reinterpret_cast<PoolHeader*
>(
41 static_cast<char*
>(base_addr) + offset
52 template<
typename ShmType>
54 static_assert(std::is_same_v<typename ShmType::table_type, TableType>,
55 "SharedMemory table type must match pool table type");
57 auto* table =
static_cast<TableType*
>(shm.get_base_addr());
59 char name_buf[TableType::MAX_NAME_SIZE]{};
60 size_t copy_len = std::min(
name.size(),
sizeof(name_buf) - 1);
61 std::copy_n(
name.begin(), copy_len, name_buf);
63 auto* entry = table->find(name_buf);
67 header_ = get_header(shm.get_base_addr(), entry->offset);
68 objects_ =
reinterpret_cast<T*
>(
69 reinterpret_cast<char*
>(header_) +
70 sizeof(PoolHeader) +
sizeof(uint32_t) * header_->capacity
75 size_t header_size =
sizeof(PoolHeader) +
sizeof(uint32_t) *
capacity;
76 size_t objects_size =
sizeof(T) *
capacity;
77 size_t total_size = header_size + objects_size;
79 size_t table_size =
sizeof(TableType);
80 size_t current_used = table->get_total_allocated_size();
81 size_t offset = table_size + current_used;
83 header_ = get_header(shm.get_base_addr(), offset);
86 new (header_) PoolHeader();
87 header_->capacity =
static_cast<uint32_t
>(
capacity);
88 header_->free_head = 0;
89 header_->num_allocated = 0;
92 for (uint32_t i = 0; i <
capacity; ++i) {
93 header_->next_array[i] = i + 1;
95 header_->next_array[
capacity - 1] = NULL_INDEX;
97 objects_ =
reinterpret_cast<T*
>(
98 reinterpret_cast<char*
>(header_) + header_size
102 if (!table->add(name_buf, offset, total_size,
sizeof(T),
capacity)) {
103 throw std::runtime_error(
"Failed to add pool to table");
105 table_entry_ = table->find(name_buf);
107 throw std::runtime_error(
"Pool not found and capacity not specified");
116 uint32_t old_head = header_->free_head.load(std::memory_order_acquire);
118 while (old_head != NULL_INDEX) {
119 uint32_t new_head = header_->next_array[old_head];
121 if (header_->free_head.compare_exchange_weak(
123 std::memory_order_release,
124 std::memory_order_acquire)) {
126 header_->num_allocated.fetch_add(1, std::memory_order_relaxed);
138 template<
typename... Args>
142 new (&objects_[handle]) T(std::forward<Args>(args)...);
152 if (handle >= header_->capacity)
return;
155 uint32_t old_head = header_->free_head.load(std::memory_order_acquire);
157 header_->next_array[handle] = old_head;
158 }
while (!header_->free_head.compare_exchange_weak(
160 std::memory_order_release,
161 std::memory_order_acquire));
163 header_->num_allocated.fetch_sub(1, std::memory_order_relaxed);
170 return objects_[handle];
174 return objects_[handle];
178 if (handle >= header_->capacity)
return nullptr;
179 return &objects_[handle];
183 if (handle >= header_->capacity)
return nullptr;
184 return &objects_[handle];
191 return handle < header_->capacity;
198 return header_->capacity;
202 return header_->num_allocated.load(std::memory_order_relaxed);
209 [[nodiscard]]
bool empty() const noexcept {
213 [[nodiscard]]
bool full() const noexcept {
222 return std::span<T>(objects_, header_->capacity);
226 return std::span<const T>(objects_, header_->capacity);
229 [[nodiscard]] std::string_view
name() const noexcept {
230 return table_entry_ ? std::string_view(table_entry_->name.data()) : std::string_view{};
241 for (
size_t i = 0; i < count; ++i) {
244 handles[acquired++] = h;
High-performance object pool for shared memory.
handle_type acquire() noexcept
Acquire an object from the pool.
const T * get(handle_type handle) const noexcept
T * get(handle_type handle) noexcept
bool full() const noexcept
shm_object_pool(ShmType &shm, std::string_view name, size_t capacity=0)
T & operator[](handle_type handle) noexcept
Access object by handle.
std::span< const T > unsafe_all_objects() const noexcept
const T & operator[](handle_type handle) const noexcept
std::span< T > unsafe_all_objects() noexcept
Get view of all objects (including free ones) Use with caution - includes uninitialized objects.
size_t acquire_batch(size_t count, handle_type *handles) noexcept
Batch acquire multiple objects.
size_t num_available() const noexcept
std::string_view name() const noexcept
bool empty() const noexcept
void release(handle_type handle) noexcept
Release an object back to the pool.
size_t capacity() const noexcept
Get pool statistics.
std::optional< handle_type > acquire_construct(Args &&... args)
Acquire and construct an object.
bool is_valid(handle_type handle) const noexcept
Check if handle is valid.
static constexpr handle_type invalid_handle
void release_batch(std::span< const handle_type > handles) noexcept
Batch release multiple objects.
size_t num_allocated() const noexcept
Core POSIX shared memory management with automatic reference counting.