diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/zstd/contrib/pzstd/utils/ResourcePool.h | |
parent | Initial commit. (diff) | |
download | ceph-upstream/18.2.2.tar.xz ceph-upstream/18.2.2.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/zstd/contrib/pzstd/utils/ResourcePool.h')
-rw-r--r-- | src/zstd/contrib/pzstd/utils/ResourcePool.h | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/src/zstd/contrib/pzstd/utils/ResourcePool.h b/src/zstd/contrib/pzstd/utils/ResourcePool.h new file mode 100644 index 000000000..8dfcdd765 --- /dev/null +++ b/src/zstd/contrib/pzstd/utils/ResourcePool.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + */ +#pragma once + +#include <cassert> +#include <functional> +#include <memory> +#include <mutex> +#include <vector> + +namespace pzstd { + +/** + * An unbounded pool of resources. + * A `ResourcePool<T>` requires a factory function that takes allocates `T*` and + * a free function that frees a `T*`. + * Calling `ResourcePool::get()` will give you a new `ResourcePool::UniquePtr` + * to a `T`, and when it goes out of scope the resource will be returned to the + * pool. + * The `ResourcePool<T>` *must* survive longer than any resources it hands out. + * Remember that `ResourcePool<T>` hands out mutable `T`s, so make sure to clean + * up the resource before or after every use. + */ +template <typename T> +class ResourcePool { + public: + class Deleter; + using Factory = std::function<T*()>; + using Free = std::function<void(T*)>; + using UniquePtr = std::unique_ptr<T, Deleter>; + + private: + std::mutex mutex_; + Factory factory_; + Free free_; + std::vector<T*> resources_; + unsigned inUse_; + + public: + /** + * Creates a `ResourcePool`. + * + * @param factory The function to use to create new resources. + * @param free The function to use to free resources created by `factory`. + */ + ResourcePool(Factory factory, Free free) + : factory_(std::move(factory)), free_(std::move(free)), inUse_(0) {} + + /** + * @returns A unique pointer to a resource. The resource is null iff + * there are no available resources and `factory()` returns null. + */ + UniquePtr get() { + std::lock_guard<std::mutex> lock(mutex_); + if (!resources_.empty()) { + UniquePtr resource{resources_.back(), Deleter{*this}}; + resources_.pop_back(); + ++inUse_; + return resource; + } + UniquePtr resource{factory_(), Deleter{*this}}; + ++inUse_; + return resource; + } + + ~ResourcePool() noexcept { + assert(inUse_ == 0); + for (const auto resource : resources_) { + free_(resource); + } + } + + class Deleter { + ResourcePool *pool_; + public: + explicit Deleter(ResourcePool &pool) : pool_(&pool) {} + + void operator() (T *resource) { + std::lock_guard<std::mutex> lock(pool_->mutex_); + // Make sure we don't put null resources into the pool + if (resource) { + pool_->resources_.push_back(resource); + } + assert(pool_->inUse_ > 0); + --pool_->inUse_; + } + }; +}; + +} |