intnslib 0.1
A library to hold common functionality used across multiple projects.
Loading...
Searching...
No Matches
ObjectPool.hpp
1#ifndef INTNS_MEMORY_OBJECTPOOL_HPP
2#define INTNS_MEMORY_OBJECTPOOL_HPP
3
4#include <cassert>
5#include <deque>
6#include <mutex>
7#include <optional>
8#include <stdexcept>
9#include <string>
10#include <type_traits>
11#include <utility>
12
13namespace intns::memory {
19template <typename Policy, typename T>
20concept AcquireHook = requires(T& obj) {
21 { Policy::on_acquire(obj) } noexcept;
22};
23
29template <typename Policy, typename T>
30concept ReleaseHook = requires(T& obj) {
31 { Policy::on_release(obj) } noexcept;
32};
33
43template <typename U>
45 static void on_acquire(U&) noexcept {}
46 static void on_release(U&) noexcept {}
47};
48
71template <typename T, typename AcquirePolicy = NoOpPoolPolicy<T>,
72 typename ReleasePolicy = AcquirePolicy>
75 static_assert(std::is_default_constructible_v<T>,
76 "T must be default constructible");
77 static_assert(std::is_move_constructible_v<T>,
78 "T must be move constructible");
79
80 public:
81 using queue_type = std::deque<T>;
82 using size_type = size_t;
83 using value_type = T;
84
85 ObjectPool() = default;
86 ~ObjectPool() = default;
87
94 ObjectPool(queue_type&& src) : objects_(std::move(src)) {}
95
110 ObjectPool(size_type init_size,
111 std::optional<size_type> limit = std::nullopt);
112
119 [[nodiscard]] value_type take();
120
127 [[nodiscard]] std::optional<value_type> try_take();
128
135 void add(value_type&& back);
136
144 [[nodiscard]] bool try_add(value_type&& back);
145
153 void reserve(size_type target_size) { reserve_impl<true>(target_size); }
154
162 [[nodiscard]] bool try_reserve(size_type target_size) {
163 return reserve_impl<false>(target_size);
164 }
165
171 std::scoped_lock<std::mutex> lock(mutex_);
172 objects_.shrink_to_fit();
173 }
174
179 size_type capacity() const {
180 std::scoped_lock<std::mutex> lock(mutex_);
181 return objects_.capacity();
182 }
183
188 [[nodiscard]] size_type size() const {
189 std::scoped_lock<std::mutex> lock(mutex_);
190 return objects_.size();
191 }
192
197 [[nodiscard]] bool empty() const {
198 std::scoped_lock<std::mutex> lock(mutex_);
199 return objects_.empty();
200 }
201
207 [[nodiscard]] std::optional<size_type> size_limit() const noexcept {
208 std::scoped_lock<std::mutex> lock(mutex_);
209 return size_limit_;
210 }
211
216 void set_size_limit(std::optional<size_type> limit) noexcept {
217 std::scoped_lock<std::mutex> lock(mutex_);
218 size_limit_ = limit;
219 }
220
221 private:
234 template <bool ThrowOnError>
235 [[nodiscard]] bool reserve_impl(size_type target_size);
236
237 // The internal queue object
238 queue_type objects_;
239
240 // Mutex for thread safety
241 mutable std::mutex mutex_;
242
243 // Customizable size limit object, unlimited unless specified
244 std::optional<size_type> size_limit_ = std::nullopt;
245};
246
256template <typename Pool>
258 using value_type = typename Pool::value_type;
259
260 public:
265 PoolLease(Pool& p) : pool_(&p), obj_(p.take()) {}
266
273 PoolLease(PoolLease&& o) noexcept
274 : pool_(o.pool_), obj_(std::move(o.obj_)), active_(o.active_) {
275 o.active_ = false;
276 }
277
278 PoolLease(const PoolLease&) = delete;
279 PoolLease& operator=(const PoolLease&) = delete;
280
285 if (active_) {
286 pool_->add(std::move(obj_));
287 }
288 }
289
294 [[nodiscard]] auto& get() noexcept { return obj_; }
295
300 [[nodiscard]] value_type* operator->() noexcept { return &obj_; }
301
306 [[nodiscard]] const auto& get() const noexcept { return obj_; }
307
312 [[nodiscard]] const value_type* operator->() const noexcept { return &obj_; }
313
323 [[nodiscard]] value_type release() noexcept {
324 active_ = false;
325 return std::move(obj_);
326 }
327
328 private:
329 // Pointer to the pool from which the object was leased
330 Pool* pool_;
331
332 // The object being managed by this lease
333 value_type obj_;
334
335 // Indicates whether the lease is still active
336 bool active_ = true;
337};
338
339} // namespace intns::memory
340
341#include "ObjectPool.tpp"
342
343#endif // NSLIB_MEMORY_OBJECTPOOL_HPP
A thread-safe object pool for managing reusable objects of type T.
Definition ObjectPool.hpp:74
void add(value_type &&back)
Adds a new object to the pool.
ObjectPool(size_type init_size, std::optional< size_type > limit=std::nullopt)
Creates an ObjectPool with a set initial size and optional max limit. Objects are default-constructed...
value_type take()
Removes and returns an object from the pool.
ObjectPool(queue_type &&src)
Constructs an ObjectPool by moving the given queue of objects.
Definition ObjectPool.hpp:94
size_type size() const
Returns the number of objects currently managed.
Definition ObjectPool.hpp:188
std::optional< value_type > try_take()
Attempts to take an object from the container.
void set_size_limit(std::optional< size_type > limit) noexcept
Sets the max pool size; nullopt makes it unlimited.
Definition ObjectPool.hpp:216
size_type capacity() const
Returns the pool's maximum capacity without reallocation.
Definition ObjectPool.hpp:179
void shrink_to_fit()
Reduces the memory usage of the internal object storage to fit its current size. This may free unused...
Definition ObjectPool.hpp:170
bool try_reserve(size_type target_size)
Reserves space for a minimum number of objects in the pool without throwing exceptions.
Definition ObjectPool.hpp:162
bool empty() const
Checks if the object pool is empty.
Definition ObjectPool.hpp:197
std::optional< size_type > size_limit() const noexcept
Returns the maximum allowed size for the container.
Definition ObjectPool.hpp:207
bool try_add(value_type &&back)
Attempts to add a new object to the container.
void reserve(size_type target_size)
Reserves space for a minimum number of objects in the pool.
Definition ObjectPool.hpp:153
RAII wrapper for managing leased ObjectPool objects.
Definition ObjectPool.hpp:257
~PoolLease()
Destructor for the PoolLease class.
Definition ObjectPool.hpp:284
const auto & get() const noexcept
Returns a constant reference to the managed object.
Definition ObjectPool.hpp:306
value_type release() noexcept
Releases ownership of the managed object.
Definition ObjectPool.hpp:323
value_type * operator->() noexcept
Provides pointer-like access to the underlying object.
Definition ObjectPool.hpp:300
PoolLease(Pool &p)
Creates a PoolLease and acquires an object from the given pool.
Definition ObjectPool.hpp:265
PoolLease(PoolLease &&o) noexcept
Move constructor for PoolLease. Transfers ownership and deactivates the source to prevent double rele...
Definition ObjectPool.hpp:273
auto & get() noexcept
Returns a reference to the internal object.
Definition ObjectPool.hpp:294
const value_type * operator->() const noexcept
Provides pointer-like access to the underlying object.
Definition ObjectPool.hpp:312
Concept to check if a type supports the acquire hook. Type T must implement Policy::on_acquire(T&),...
Definition ObjectPool.hpp:20
Concept to check if a type supports the release hook. Type T must implement Policy::on_release(T&),...
Definition ObjectPool.hpp:30
A no-operation pool policy for resource management.
Definition ObjectPool.hpp:44