mirror of
				https://github.com/facebook/zstd.git
				synced 2025-10-30 10:25:39 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			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 the BSD-style license found in the
 | |
|  * LICENSE file in the root directory of this source tree. An additional grant
 | |
|  * of patent rights can be found in the PATENTS file in the same directory.
 | |
|  */
 | |
| #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 avaiable 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_;
 | |
|     }
 | |
|   };
 | |
| };
 | |
| 
 | |
| }
 |