Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #pragma once 11 : 12 : // System Includes 13 : #include <stack> 14 : #include <memory> 15 : 16 : namespace MooseUtils 17 : { 18 : 19 : template <class T, typename... Args> 20 : auto 21 2 : reset(int, T & obj, Args... args) -> decltype(obj.reset(args...), void()) 22 : { 23 2 : obj.reset(std::forward<Args>(args)...); 24 2 : } 25 : 26 : template <class T, typename... Args> 27 : void 28 2 : reset(double, T & /*obj*/, Args... /*args*/) 29 : { 30 2 : } 31 : 32 : /** 33 : * 34 : * Originally From https://stackoverflow.com/a/27837534/2042320 35 : * 36 : * friedmud added variadic templated perfect forwarding to acquire() 37 : * 38 : * For an object to be resetable it needs to define a reset() function 39 : * that takes the same arguments as its constructor. 40 : */ 41 : template <class T> 42 : class SharedPool 43 : { 44 : private: 45 : struct ExternalDeleter 46 : { 47 10 : explicit ExternalDeleter(std::weak_ptr<SharedPool<T> *> pool) : _pool(pool) {} 48 : 49 10 : void operator()(T * ptr) 50 : { 51 20 : if (auto _poolptr = _pool.lock()) 52 : { 53 : try 54 : { 55 10 : (*_poolptr.get())->add(std::unique_ptr<T>{ptr}); 56 10 : return; 57 : } 58 0 : catch (...) 59 : { 60 : } 61 : } 62 0 : std::default_delete<T>{}(ptr); 63 : } 64 : 65 : private: 66 : std::weak_ptr<SharedPool<T> *> _pool; 67 : }; 68 : 69 : public: 70 : typedef typename std::unique_ptr<T, ExternalDeleter> PtrType; 71 : 72 2 : SharedPool() : _this_ptr(new SharedPool<T> *(this)) {} 73 2 : virtual ~SharedPool() {} 74 : 75 10 : void add(std::unique_ptr<T> t) { _pool.push(std::move(t)); } 76 : 77 : template <typename... Args> 78 10 : PtrType acquire(Args &&... args) 79 : { 80 : // if the pool is empty - create one 81 10 : if (_pool.empty()) 82 : { 83 6 : _num_created++; 84 17 : return PtrType(new T(std::forward<Args>(args)...), 85 17 : ExternalDeleter{std::weak_ptr<SharedPool<T> *>{_this_ptr}}); 86 : } 87 : else 88 : { 89 4 : PtrType tmp(_pool.top().release(), 90 4 : ExternalDeleter{std::weak_ptr<SharedPool<T> *>{_this_ptr}}); 91 4 : _pool.pop(); 92 : 93 4 : reset(1, *tmp, std::forward<Args>(args)...); 94 : 95 4 : return tmp; 96 4 : } 97 : } 98 : 99 : bool empty() const { return _pool.empty(); } 100 : 101 4 : size_t size() const { return _pool.size(); } 102 : 103 4 : size_t num_created() const { return _num_created; } 104 : 105 : private: 106 : std::shared_ptr<SharedPool<T> *> _this_ptr; 107 : std::stack<std::unique_ptr<T>> _pool; 108 : 109 : size_t _num_created = 0; 110 : }; 111 : }