From 3ebbaf286fa3cb1de33ee219e7924d4cf8ed5546 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 23 Oct 2023 01:22:04 -0700 Subject: [PATCH 1/3] adding support to object construction with arguments. --- include/marl/pool.h | 123 +++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 70 deletions(-) diff --git a/include/marl/pool.h b/include/marl/pool.h index f03eec3..4c46f98 100644 --- a/include/marl/pool.h +++ b/include/marl/pool.h @@ -86,7 +86,10 @@ class Pool { MARL_NO_EXPORT inline T* get(); // construct() calls the constructor on the item's data. - MARL_NO_EXPORT inline void construct(); + template + MARL_NO_EXPORT inline void construct(Args&&... args) { + new (&data) T(std::forward(args)...); + } // destruct() calls the destructor on the item's data. MARL_NO_EXPORT inline void destruct(); @@ -110,11 +113,6 @@ T* Pool::Item::get() { return reinterpret_cast(&data); } -template -void Pool::Item::construct() { - new (&data) T; -} - template void Pool::Item::destruct() { get()->~T(); @@ -214,20 +212,57 @@ class BoundedPool : public Pool { // borrow() borrows a single item from the pool, blocking until an item is // returned if the pool is empty. - MARL_NO_EXPORT inline Loan borrow() const; + template + MARL_NO_EXPORT inline Loan borrow(Args&&... args) const { + marl::lock lock(storage->mutex); + storage->returned.wait(lock, [&] { return storage->free != nullptr; }); + auto item = storage->free; + storage->free = storage->free->next; + if constexpr (POLICY == PoolPolicy::Reconstruct) { + item->construct(std::forward(args)...); + } + return Loan(item, storage); + } - // borrow() borrows count items from the pool, blocking until there are at + // borrowList() borrows count items from the pool, blocking until there are at // least count items in the pool. The function f() is called with each // borrowed item. // F must be a function with the signature: void(T&&) - template - MARL_NO_EXPORT inline void borrow(size_t count, const F& f) const; + template + MARL_NO_EXPORT inline void borrowList(size_t count, const F& f, Args&&... args) const { + marl::lock lock(storage->mutex); + for (size_t i = 0; i < count; i++) { + storage->returned.wait(lock, [&] { return storage->free != nullptr; }); + auto item = storage->free; + storage->free = storage->free->next; + if constexpr (POLICY == PoolPolicy::Reconstruct) { + item->construct(std::forward(args)...); + } + f(std::move(Loan(item, storage))); + } + } // tryBorrow() attempts to borrow a single item from the pool without // blocking. // The boolean of the returned pair is true on success, or false if the pool // is empty. - MARL_NO_EXPORT inline std::pair tryBorrow() const; + template + MARL_NO_EXPORT inline std::pair tryBorrow(Args&&... args) const { + Item* item = nullptr; + { + marl::lock lock(storage->mutex); + if (storage->free == nullptr) { + return std::make_pair(Loan(), false); + } + item = storage->free; + storage->free = storage->free->next; + item->pool = this; + } + if constexpr (POLICY == PoolPolicy::Reconstruct) { + item->construct(std::forward(args)...); + } + return std::make_pair(Loan(item, storage), true); + } private: class Storage : public Pool::Storage { @@ -235,11 +270,6 @@ class BoundedPool : public Pool { MARL_NO_EXPORT inline Storage(Allocator* allocator); MARL_NO_EXPORT inline ~Storage(); MARL_NO_EXPORT inline void return_(Item*) override; - // We cannot copy this as the Item pointers would be shared and - // deleted at a wrong point. We cannot move this because we return - // pointers into items[N]. - MARL_NO_EXPORT inline Storage(const Storage&) = delete; - MARL_NO_EXPORT inline Storage& operator=(const Storage&) = delete; Item items[N]; marl::mutex mutex; @@ -253,7 +283,7 @@ template BoundedPool::Storage::Storage(Allocator* allocator) : returned(allocator) { for (int i = 0; i < N; i++) { - if (POLICY == PoolPolicy::Preserve) { + if constexpr (POLICY == PoolPolicy::Preserve) { items[i].construct(); } items[i].next = this->free; @@ -263,7 +293,7 @@ BoundedPool::Storage::Storage(Allocator* allocator) template BoundedPool::Storage::~Storage() { - if (POLICY == PoolPolicy::Preserve) { + if constexpr (POLICY == PoolPolicy::Preserve) { for (int i = 0; i < N; i++) { items[i].destruct(); } @@ -275,51 +305,9 @@ BoundedPool::BoundedPool( Allocator* allocator /* = Allocator::Default */) : storage(allocator->make_shared(allocator)) {} -template -typename BoundedPool::Loan BoundedPool::borrow() - const { - Loan out; - borrow(1, [&](Loan&& loan) { out = std::move(loan); }); - return out; -} - -template -template -void BoundedPool::borrow(size_t n, const F& f) const { - marl::lock lock(storage->mutex); - for (size_t i = 0; i < n; i++) { - storage->returned.wait(lock, [&] { return storage->free != nullptr; }); - auto item = storage->free; - storage->free = storage->free->next; - if (POLICY == PoolPolicy::Reconstruct) { - item->construct(); - } - f(std::move(Loan(item, storage))); - } -} - -template -std::pair::Loan, bool> -BoundedPool::tryBorrow() const { - Item* item = nullptr; - { - marl::lock lock(storage->mutex); - if (storage->free == nullptr) { - return std::make_pair(Loan(), false); - } - item = storage->free; - storage->free = storage->free->next; - item->pool = this; - } - if (POLICY == PoolPolicy::Reconstruct) { - item->construct(); - } - return std::make_pair(Loan(item, storage), true); -} - template void BoundedPool::Storage::return_(Item* item) { - if (POLICY == PoolPolicy::Reconstruct) { + if constexpr (POLICY == PoolPolicy::Reconstruct) { item->destruct(); } { @@ -366,11 +354,6 @@ class UnboundedPool : public Pool { MARL_NO_EXPORT inline Storage(Allocator* allocator); MARL_NO_EXPORT inline ~Storage(); MARL_NO_EXPORT inline void return_(Item*) override; - // We cannot copy this as the Item pointers would be shared and - // deleted at a wrong point. We could move this but would have to take - // extra care no Item pointers are left in the moved-out object. - MARL_NO_EXPORT inline Storage(const Storage&) = delete; - MARL_NO_EXPORT inline Storage& operator=(const Storage&) = delete; Allocator* allocator; marl::mutex mutex; @@ -389,7 +372,7 @@ UnboundedPool::Storage::Storage(Allocator* allocator) template UnboundedPool::Storage::~Storage() { for (auto item : items) { - if (POLICY == PoolPolicy::Preserve) { + if constexpr (POLICY == PoolPolicy::Preserve) { item->destruct(); } allocator->destroy(item); @@ -418,7 +401,7 @@ inline void UnboundedPool::borrow(size_t n, const F& f) const { auto count = std::max(storage->items.size(), 32); for (size_t j = 0; j < count; j++) { auto item = allocator->create(); - if (POLICY == PoolPolicy::Preserve) { + if constexpr (POLICY == PoolPolicy::Preserve) { item->construct(); } storage->items.push_back(item); @@ -429,7 +412,7 @@ inline void UnboundedPool::borrow(size_t n, const F& f) const { auto item = storage->free; storage->free = storage->free->next; - if (POLICY == PoolPolicy::Reconstruct) { + if constexpr (POLICY == PoolPolicy::Reconstruct) { item->construct(); } f(std::move(Loan(item, storage))); @@ -438,7 +421,7 @@ inline void UnboundedPool::borrow(size_t n, const F& f) const { template void UnboundedPool::Storage::return_(Item* item) { - if (POLICY == PoolPolicy::Reconstruct) { + if constexpr (POLICY == PoolPolicy::Reconstruct) { item->destruct(); } marl::lock lock(mutex); From a83f06e4fef5e765a070f41585228f1aad9723ce Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 24 Oct 2023 08:16:09 -0700 Subject: [PATCH 2/3] minor update --- include/marl/pool.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/marl/pool.h b/include/marl/pool.h index 4c46f98..f6b818d 100644 --- a/include/marl/pool.h +++ b/include/marl/pool.h @@ -214,6 +214,7 @@ class BoundedPool : public Pool { // returned if the pool is empty. template MARL_NO_EXPORT inline Loan borrow(Args&&... args) const { + static_assert((sizeof...(Args) == 0) || (POLICY != PoolPolicy::Preserve), "Arguments not supported with Preserve policy!"); marl::lock lock(storage->mutex); storage->returned.wait(lock, [&] { return storage->free != nullptr; }); auto item = storage->free; From f86a0ba127d1bcde027f9541765548dc77e5a28a Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 25 Oct 2023 23:49:28 -0700 Subject: [PATCH 3/3] fixed C++ 11 compatibility --- include/marl/pool.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/marl/pool.h b/include/marl/pool.h index f6b818d..df03f60 100644 --- a/include/marl/pool.h +++ b/include/marl/pool.h @@ -219,7 +219,7 @@ class BoundedPool : public Pool { storage->returned.wait(lock, [&] { return storage->free != nullptr; }); auto item = storage->free; storage->free = storage->free->next; - if constexpr (POLICY == PoolPolicy::Reconstruct) { + if (POLICY == PoolPolicy::Reconstruct) { item->construct(std::forward(args)...); } return Loan(item, storage); @@ -236,7 +236,7 @@ class BoundedPool : public Pool { storage->returned.wait(lock, [&] { return storage->free != nullptr; }); auto item = storage->free; storage->free = storage->free->next; - if constexpr (POLICY == PoolPolicy::Reconstruct) { + if (POLICY == PoolPolicy::Reconstruct) { item->construct(std::forward(args)...); } f(std::move(Loan(item, storage))); @@ -259,7 +259,7 @@ class BoundedPool : public Pool { storage->free = storage->free->next; item->pool = this; } - if constexpr (POLICY == PoolPolicy::Reconstruct) { + if (POLICY == PoolPolicy::Reconstruct) { item->construct(std::forward(args)...); } return std::make_pair(Loan(item, storage), true); @@ -284,7 +284,7 @@ template BoundedPool::Storage::Storage(Allocator* allocator) : returned(allocator) { for (int i = 0; i < N; i++) { - if constexpr (POLICY == PoolPolicy::Preserve) { + if (POLICY == PoolPolicy::Preserve) { items[i].construct(); } items[i].next = this->free; @@ -294,7 +294,7 @@ BoundedPool::Storage::Storage(Allocator* allocator) template BoundedPool::Storage::~Storage() { - if constexpr (POLICY == PoolPolicy::Preserve) { + if (POLICY == PoolPolicy::Preserve) { for (int i = 0; i < N; i++) { items[i].destruct(); } @@ -308,7 +308,7 @@ BoundedPool::BoundedPool( template void BoundedPool::Storage::return_(Item* item) { - if constexpr (POLICY == PoolPolicy::Reconstruct) { + if (POLICY == PoolPolicy::Reconstruct) { item->destruct(); } { @@ -373,7 +373,7 @@ UnboundedPool::Storage::Storage(Allocator* allocator) template UnboundedPool::Storage::~Storage() { for (auto item : items) { - if constexpr (POLICY == PoolPolicy::Preserve) { + if (POLICY == PoolPolicy::Preserve) { item->destruct(); } allocator->destroy(item); @@ -402,7 +402,7 @@ inline void UnboundedPool::borrow(size_t n, const F& f) const { auto count = std::max(storage->items.size(), 32); for (size_t j = 0; j < count; j++) { auto item = allocator->create(); - if constexpr (POLICY == PoolPolicy::Preserve) { + if (POLICY == PoolPolicy::Preserve) { item->construct(); } storage->items.push_back(item); @@ -413,7 +413,7 @@ inline void UnboundedPool::borrow(size_t n, const F& f) const { auto item = storage->free; storage->free = storage->free->next; - if constexpr (POLICY == PoolPolicy::Reconstruct) { + if (POLICY == PoolPolicy::Reconstruct) { item->construct(); } f(std::move(Loan(item, storage))); @@ -422,7 +422,7 @@ inline void UnboundedPool::borrow(size_t n, const F& f) const { template void UnboundedPool::Storage::return_(Item* item) { - if constexpr (POLICY == PoolPolicy::Reconstruct) { + if (POLICY == PoolPolicy::Reconstruct) { item->destruct(); } marl::lock lock(mutex);