Common System 0.2.0
Common interfaces and patterns for system integration
Loading...
Searching...
No Matches
object_pool.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
14#pragma once
15
16#include <cstddef>
17#include <memory>
18#include <mutex>
19#include <stack>
20#include <utility>
21#include <new>
22#include <vector>
23
24namespace kcenon::common::utils {
25
26namespace detail {
27template<typename T>
28struct RawDelete {
29 void operator()(T* ptr) const noexcept {
30 ::operator delete(static_cast<void*>(ptr));
31 }
32};
33} // namespace detail
34
42template<typename T>
43class ObjectPool;
44
51template<typename T>
53 ObjectPool<T>* pool = nullptr;
54 void operator()(T* ptr) const noexcept {
55 if (pool) {
56 pool->release(ptr);
57 }
58 }
59};
60
61template<typename T>
62class ObjectPool {
63public:
64 using value_type = T;
66 using pointer_type = std::unique_ptr<T, deleter_type>;
67
72 explicit ObjectPool(std::size_t growth = 32)
73 : growth_(growth == 0 ? 1 : growth) {}
74
81 template<typename... Args>
82 pointer_type acquire(bool* reused, Args&&... args) {
83 T* raw = nullptr;
84 bool reused_local = false;
85 {
86 std::lock_guard<std::mutex> lock(mutex_);
87 if (free_list_.empty()) {
89 } else {
90 reused_local = true;
91 }
92
93 raw = free_list_.top();
94 free_list_.pop();
95 }
96
97 if (reused) {
98 *reused = reused_local;
99 }
100
101 new (raw) T(std::forward<Args>(args)...);
102 return pointer_type(raw, deleter_type{this});
103 }
104
105 template<typename... Args>
106 pointer_type acquire(Args&&... args) {
107 return acquire(static_cast<bool*>(nullptr), std::forward<Args>(args)...);
108 }
109
113 void release(T* ptr) noexcept {
114 if (!ptr) {
115 return;
116 }
117
118 ptr->~T();
119 std::lock_guard<std::mutex> lock(mutex_);
120 free_list_.push(ptr);
121 }
122
126 void reserve(std::size_t count) {
127 if (count == 0) {
128 return;
129 }
130 std::lock_guard<std::mutex> lock(mutex_);
132 }
133
137 void clear() {
138 std::lock_guard<std::mutex> lock(mutex_);
139 free_list_ = std::stack<T*>();
140 storage_.clear();
141 }
142
143 [[nodiscard]] std::size_t available() const {
144 std::lock_guard<std::mutex> lock(mutex_);
145 return free_list_.size();
146 }
147
148private:
149 using RawPtr = std::unique_ptr<T, detail::RawDelete<T>>;
150
151 void allocate_block_unlocked(std::size_t count) {
152 for (std::size_t i = 0; i < count; ++i) {
153 RawPtr block(static_cast<T*>(::operator new(sizeof(T))));
154 free_list_.push(block.get());
155 storage_.push_back(std::move(block));
156 }
157 }
158
159 std::size_t growth_;
160 mutable std::mutex mutex_;
161 std::stack<T*> free_list_;
162 std::vector<RawPtr> storage_;
163};
164
165} // namespace kcenon::common::utils
Thread-safe object pool that reuses raw storage for expensive objects.
Definition utils.cppm:218
void release(T *ptr) noexcept
Return raw storage to the pool (destructor already run).
void allocate_block_unlocked(std::size_t count)
std::vector< RawPtr > storage_
pointer_type acquire(bool *reused, Args &&... args)
Acquire an object constructed with the provided arguments.
Definition object_pool.h:82
ObjectPool(std::size_t growth=32)
Construct an object pool with the specified growth factor.
Definition object_pool.h:72
void reserve(std::size_t count)
Add count additional blocks to the pool.
std::unique_ptr< T, detail::RawDelete< T > > RawPtr
std::unique_ptr< T, deleter_type > pointer_type
Definition object_pool.h:66
pointer_type acquire(Args &&... args)
void clear()
Destroy all cached instances and release memory.
Zero-overhead deleter for ObjectPool-managed objects.
Definition object_pool.h:52
void operator()(T *ptr) const noexcept
Definition object_pool.h:54
void operator()(T *ptr) const noexcept
Definition object_pool.h:29