a880ca239b
* spelling: accidentally * spelling: across * spelling: additionally * spelling: addresses * spelling: appropriate * spelling: assumed * spelling: available * spelling: builder * spelling: capacity * spelling: compiler * spelling: compressibility * spelling: compressor * spelling: compression * spelling: contract * spelling: convenience * spelling: decompress * spelling: description * spelling: deflate * spelling: deterministically * spelling: dictionary * spelling: display * spelling: eliminate * spelling: preemptively * spelling: exclude * spelling: failure * spelling: independence * spelling: independent * spelling: intentionally * spelling: matching * spelling: maximum * spelling: meaning * spelling: mishandled * spelling: memory * spelling: occasionally * spelling: occurrence * spelling: official * spelling: offsets * spelling: original * spelling: output * spelling: overflow * spelling: overridden * spelling: parameter * spelling: performance * spelling: probability * spelling: receives * spelling: redundant * spelling: recompression * spelling: resources * spelling: sanity * spelling: segment * spelling: series * spelling: specified * spelling: specify * spelling: subtracted * spelling: successful * spelling: return * spelling: translation * spelling: update * spelling: unrelated * spelling: useless * spelling: variables * spelling: variety * spelling: verbatim * spelling: verification * spelling: visited * spelling: warming * spelling: workers * spelling: with
97 lines
2.6 KiB
C++
97 lines
2.6 KiB
C++
/*
|
|
* 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_;
|
|
}
|
|
};
|
|
};
|
|
|
|
}
|