109class ObjectPool :
public std::enable_shared_from_this<ObjectPool<T>> {
204 [[nodiscard]] std::unique_ptr<T, typename ObjectPool<T>::PoolDeleter>
get();
218 [[nodiscard]] std::shared_ptr<T>
get_shared();
234 [[nodiscard]] T*
borrow();
263 [[nodiscard]]
size_t size()
const;
270 [[nodiscard]]
size_t borrowed()
const;
288 [[nodiscard]]
size_t max_size()
const;
293 std::unique_ptr<T> acquire();
295 void release(std::unique_ptr<T> obj)
noexcept;
297 void safe_dec_borrowed_and_live() noexcept;
299 bool should_reset_on_acquire() const noexcept;
301 bool should_reset_on_release() const noexcept;
303 [[nodiscard]]
std::runtime_error exhausted_error_locked() const;
310 mutable std::mutex mutex_;
311 std::vector<std::unique_ptr<T>> pool_;
314 size_t live_count_{0};
315 size_t total_created_{0};
327 : factory_callback_(
std::move(factory_callback)),
328 reset_callback_(
std::move(reset_callback)),
331 if VUNLIKELY (max_size_ > 0 && initial_size > max_size_) {
332 throw std::invalid_argument(
"initial_size exceeds max_size");
335 pool_.reserve(initial_size);
336 for (
size_t i = 0; i < initial_size; ++i) {
337 auto obj = factory_callback_();
340 throw std::runtime_error(
"FactoryCallback returned nullptr during pre-fill");
343 if (should_reset_on_release() && reset_callback_) {
344 reset_callback_(*obj);
347 pool_.emplace_back(std::move(obj));
350 total_created_ = initial_size;
351 live_count_ = initial_size;
356 std::unique_ptr<T> obj = acquire();
359 if (should_reset_on_acquire() && reset_callback_) {
360 reset_callback_(*obj);
363 release(std::move(obj));
367 return {obj.release(),
PoolDeleter{this->weak_from_this()}};
372 std::unique_ptr<T> obj = acquire();
375 if (should_reset_on_acquire() && reset_callback_) {
376 reset_callback_(*obj);
379 release(std::move(obj));
383 return {obj.release(),
PoolDeleter{this->weak_from_this()}};
388 std::unique_ptr<T> obj = acquire();
391 if (should_reset_on_acquire() && reset_callback_) {
392 reset_callback_(*obj);
395 release(std::move(obj));
399 return obj.release();
408 std::unique_ptr<T> u(ptr);
409 release(std::move(u));
414 std::lock_guard<std::mutex> lock(mutex_);
415 return {pool_.size(), borrowed_, total_created_, max_size_};
420 std::lock_guard<std::mutex> lock(mutex_);
426 std::lock_guard<std::mutex> lock(mutex_);
432 std::lock_guard<std::mutex> lock(mutex_);
433 return total_created_;
443 return [] {
return std::make_unique<T>(); };
447inline std::unique_ptr<T> ObjectPool<T>::acquire() {
448 std::unique_lock<std::mutex> lock(mutex_);
450 if (!pool_.empty()) {
451 std::unique_ptr<T> obj = std::move(pool_.back());
457 if VUNLIKELY (max_size_ > 0 && live_count_ >= max_size_) {
458 throw exhausted_error_locked();
467 std::unique_ptr<T> new_obj;
469 new_obj = factory_callback_();
472 throw std::runtime_error(
"FactoryCallback returned nullptr");
486inline void ObjectPool<T>::release(std::unique_ptr<T> obj)
noexcept {
491 if (should_reset_on_release() && reset_callback_) {
493 reset_callback_(*obj);
495 safe_dec_borrowed_and_live();
501 std::lock_guard<std::mutex> lock(mutex_);
507 pool_.emplace_back(std::move(obj));
512inline void ObjectPool<T>::safe_dec_borrowed_and_live() noexcept {
513 std::lock_guard<std::mutex> lock(mutex_);
519 if (live_count_ > 0) {
525inline bool ObjectPool<T>::should_reset_on_acquire() const noexcept {
526 return policy_ == kPolicyAcquire || policy_ == kPolicyBoth;
530inline bool ObjectPool<T>::should_reset_on_release() const noexcept {
531 return policy_ == kPolicyRelease || policy_ == kPolicyBoth;
535inline std::runtime_error ObjectPool<T>::exhausted_error_locked()
const {
536 std::ostringstream oss;
538 oss <<
"ObjectPool exhausted: max_size=" << max_size_ <<
" live_count=" << live_count_
539 <<
" total_created=" << total_created_ <<
" borrowed=" << borrowed_ <<
" pool_size=" << pool_.size();
541 return std::runtime_error(oss.str());
551 std::unique_ptr<T> u(ptr);
552 sp->release(std::move(u));
std::shared_ptr< T > get_shared()
Acquires an object and returns it as a shared_ptr with automatic pool return.
Definition object_pool.h:371
T * borrow()
Acquires an object and returns a raw pointer; caller is responsible for returning it.
Definition object_pool.h:387
size_t borrowed() const
Returns the number of objects currently held by callers.
Definition object_pool.h:425
std::function< void(T &)> ResetCallback
Callback type for resetting an object before acquisition or after release.
Definition object_pool.h:127
size_t max_size() const
Returns the maximum total object count allowed by this pool.
Definition object_pool.h:437
ObjectPool(FactoryCallback factory_callback=get_default_factory(), size_t initial_size=0, size_t max_size=0, ResetCallback reset_callback=nullptr, Policy policy=kPolicyRelease)
Constructs the pool and optionally pre-populates it with objects.
Definition object_pool.h:325
void give_back(T *ptr)
Returns a raw-pointer object previously obtained via borrow() to the pool.
Definition object_pool.h:403
size_t size() const
Returns the number of idle objects currently in the pool.
Definition object_pool.h:419
Stats stats() const
Returns a snapshot of all pool statistics (thread-safe).
Definition object_pool.h:413
std::unique_ptr< T, typename ObjectPool< T >::PoolDeleter > get()
Acquires an object and returns it as a unique_ptr with automatic pool return.
Definition object_pool.h:355
Policy
Controls when the ResetCallback is invoked relative to acquire and release.
Definition object_pool.h:132
@ kPolicyRelease
Invoke reset callback when object is returned to the pool.
Definition object_pool.h:134
@ kPolicyNone
Never invoke reset callback.
Definition object_pool.h:133
@ kPolicyBoth
Invoke reset callback on both acquire and release.
Definition object_pool.h:136
@ kPolicyAcquire
Invoke reset callback when object is acquired from the pool.
Definition object_pool.h:135
size_t total_created() const
Returns the total number of objects ever created by this pool.
Definition object_pool.h:431
std::function< std::unique_ptr< T >()> FactoryCallback
Callback type for creating a new instance of T.
Definition object_pool.h:118
Platform-independent macro definitions for the VLink library.
#define VUNLIKELY(...)
Shorthand alias for VLINK_UNLIKELY. Hints that the expression is unlikely true.
Definition macros.h:302
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition macros.h:184
Custom deleter for RAII handles returned by get() and get_shared().
Definition object_pool.h:159
std::weak_ptr< ObjectPool< T > > weak_pool
Non-owning reference to the parent pool.
Definition object_pool.h:166
void operator()(T *ptr) const noexcept
Returns ptr to the pool, or deletes it if the pool is gone.
Definition object_pool.h:545
Snapshot of pool statistics at a point in time.
Definition object_pool.h:142
size_t pool_size
Number of objects currently idle in the pool.
Definition object_pool.h:143
size_t total_created
Total objects ever created (pool_size + borrowed + destroyed).
Definition object_pool.h:145
size_t borrowed
Number of objects currently held by callers.
Definition object_pool.h:144
size_t max_size
Maximum allowed total objects. 0 means unlimited.
Definition object_pool.h:146