127 uint8_t m_capacity {InitCapacity};
130 std::atomic_uint16_t m_resources_checkedout {0};
134 std::atomic_uint16_t m_invalidated_resources {0};
138 std::atomic_uint64_t m_counter_checkout {0};
141 std::atomic_uint64_t m_counter_ondemand_adds {0};
144 std::atomic_uint64_t m_counter_checkin {0};
147 std::atomic_uint64_t m_counter_auto_returned {0};
151 std::deque<T> m_pool {};
153#if defined(arrp_USE_RECURSIVE_MUTEX) || defined(ARRP_USE_RECURSIVE_MUTEX)
159 mutable std::recursive_mutex m_pool_lock {};
161 #warning "You're using std::recursive_mutex which is more expensive"
166 mutable std::mutex m_pool_lock {};
173 std::function<SRT(resource_pool&)> m_callback_to_add_new_raw_resource_to_pool {};
187 throw std::runtime_error(
"No items in the pool; add something first.");
225 if (new_resource_callback) {
226 m_callback_to_add_new_raw_resource_to_pool = std::move(new_resource_callback);
239 if (add_policy == auto_add_policy::NoGrow) {
242 else if (add_policy == auto_add_policy::AutoGrow) {
246 m_callback_to_add_new_raw_resource_to_pool = [
this](resource_pool& pool) -> SRT {
249 return SRT {T {}, [
this](T&& src) {
250 this->m_counter_auto_returned++;
251 this->checkin(std::forward<T&&>(src));
305 void clear() noexcept
307 std::scoped_lock l(m_pool_lock);
334 [[nodiscard]]
size_t size() const noexcept
336 std::scoped_lock l(m_pool_lock);
337 return m_pool.size();
377 [[nodiscard]]
auto checkout() -> SRT
381 auto checkout_guard = [
this]() {
382 if (m_resources_checkedout > 0) {
383 m_resources_checkedout--;
390 std::unique_lock l(m_pool_lock);
392 if (!m_pool.empty()) {
395 RunOnEnd pop_guard([&]() { m_pool.pop_front(); });
397 m_resources_checkedout++;
398 ++m_counter_checkout;
403 return SRT {std::move(m_pool.front()), [
this](T&& src) {
404 this->m_counter_auto_returned++;
405 this->checkin(std::forward<T&&>(src));
412 else if ((m_capacity > m_pool.size() + m_resources_checkedout) && m_callback_to_add_new_raw_resource_to_pool) {
417 m_resources_checkedout++;
421 ++m_counter_checkout;
423 ++m_counter_ondemand_adds;
427 return m_callback_to_add_new_raw_resource_to_pool(*
this);
429 else if (m_capacity > m_pool.size() + m_resources_checkedout) {
431 std::cerr << std::format(
"We're under-capacity.. but no dynamic resource provider\n");
434 catch (std::exception& ex) {
436 std::cerr << std::format(
"Error in checkout: {}\n", ex.what());
441 std::cerr << std::format(
"UNKNOWN Error in checkout\n");
445 auto msg = std::format(
446 "Pool Size:{} checkedout:{} capacity:{}", m_pool.size(), m_resources_checkedout.load(), m_capacity);
447 throw std::runtime_error(msg);
486 void checkin(T&& raw_resource)
490 std::scoped_lock l(m_pool_lock);
492 m_pool.push_back(std::move(raw_resource));
493 if (m_resources_checkedout > 0) m_resources_checkedout--;
497#if defined(NLOHMANN_JSON_VERSION_MAJOR)
545 nlohmann::json to_json()
const
547 auto myPoolSize = this->size();
549 return {{
"_typver",
"siddiqsoft.arrp.resource_pool/0.0.0"},
550 {
"capacity", m_capacity},
551 {
"size", myPoolSize},
552 {
"load", myPoolSize + m_resources_checkedout.load()},
553 {
"invalidated", m_invalidated_resources.load()},
554 {
"checkedout", m_resources_checkedout.load()},
556 {{
"autoreturns", m_counter_auto_returned.load()},
557 {
"newitems", m_counter_ondemand_adds.load()},
558 {
"return", m_counter_checkin.load()},
559 {
"borrow", m_counter_checkout.load()}}}};
592 static void to_json(nlohmann::json& dest,
const siddiqsoft::arrp::resource_pool<T, SRT, InitCapacity>& src)