git subrepo pull (merge) --force deps/libchdr
[pcsx_rearmed.git] / deps / libchdr / deps / zstd-1.5.5 / contrib / pzstd / utils / ResourcePool.h
CommitLineData
648db22b 1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
8 */
9#pragma once
10
11#include <cassert>
12#include <functional>
13#include <memory>
14#include <mutex>
15#include <vector>
16
17namespace pzstd {
18
19/**
20 * An unbounded pool of resources.
21 * A `ResourcePool<T>` requires a factory function that takes allocates `T*` and
22 * a free function that frees a `T*`.
23 * Calling `ResourcePool::get()` will give you a new `ResourcePool::UniquePtr`
24 * to a `T`, and when it goes out of scope the resource will be returned to the
25 * pool.
26 * The `ResourcePool<T>` *must* survive longer than any resources it hands out.
27 * Remember that `ResourcePool<T>` hands out mutable `T`s, so make sure to clean
28 * up the resource before or after every use.
29 */
30template <typename T>
31class ResourcePool {
32 public:
33 class Deleter;
34 using Factory = std::function<T*()>;
35 using Free = std::function<void(T*)>;
36 using UniquePtr = std::unique_ptr<T, Deleter>;
37
38 private:
39 std::mutex mutex_;
40 Factory factory_;
41 Free free_;
42 std::vector<T*> resources_;
43 unsigned inUse_;
44
45 public:
46 /**
47 * Creates a `ResourcePool`.
48 *
49 * @param factory The function to use to create new resources.
50 * @param free The function to use to free resources created by `factory`.
51 */
52 ResourcePool(Factory factory, Free free)
53 : factory_(std::move(factory)), free_(std::move(free)), inUse_(0) {}
54
55 /**
56 * @returns A unique pointer to a resource. The resource is null iff
57 * there are no available resources and `factory()` returns null.
58 */
59 UniquePtr get() {
60 std::lock_guard<std::mutex> lock(mutex_);
61 if (!resources_.empty()) {
62 UniquePtr resource{resources_.back(), Deleter{*this}};
63 resources_.pop_back();
64 ++inUse_;
65 return resource;
66 }
67 UniquePtr resource{factory_(), Deleter{*this}};
68 ++inUse_;
69 return resource;
70 }
71
72 ~ResourcePool() noexcept {
73 assert(inUse_ == 0);
74 for (const auto resource : resources_) {
75 free_(resource);
76 }
77 }
78
79 class Deleter {
80 ResourcePool *pool_;
81 public:
82 explicit Deleter(ResourcePool &pool) : pool_(&pool) {}
83
84 void operator() (T *resource) {
85 std::lock_guard<std::mutex> lock(pool_->mutex_);
86 // Make sure we don't put null resources into the pool
87 if (resource) {
88 pool_->resources_.push_back(resource);
89 }
90 assert(pool_->inUse_ > 0);
91 --pool_->inUse_;
92 }
93 };
94};
95
96}