1
+ #include < functional>
2
+ #include < iostream>
3
+ #include < memory>
4
+ #include < stack>
5
+ #include < tuple>
6
+
7
+ using namespace std ;
8
+
9
+ class IPoolableObject
10
+ {
11
+ public:
12
+ virtual ~IPoolableObject () = default ;
13
+ virtual void reset () = 0;
14
+
15
+ protected:
16
+ IPoolableObject () = default ;
17
+ };
18
+
19
+ class UsedObject : public IPoolableObject
20
+ {
21
+ public:
22
+ UsedObject (int init_num = 0 ) : _num{init_num}, _init_num{init_num} {};
23
+ void increment () { ++_num; }
24
+
25
+ void print () { std::cout << " My number is: " << _num << std::endl; }
26
+ void reset () override { _num = _init_num; }
27
+
28
+ private:
29
+ int _num;
30
+ int _init_num;
31
+ };
32
+
33
+ // parameter pack , can accept any number of arguments
34
+ // Variadic templates
35
+ template <typename T, typename ... Args>
36
+ class ObjectPool
37
+ {
38
+ public:
39
+ template <typename P>
40
+ using pointer_type = std::unique_ptr<P, std::function<void (P *)>>;
41
+
42
+ ObjectPool (std::size_t init_size = 0 , std::size_t max_size = 10 , Args &&... args)
43
+ : _max_size{max_size}, _available{max_size}, _size{0 }, _args{args...} // store pack parameter into tuples for later use
44
+ {
45
+ static_assert (std::is_base_of<IPoolableObject, T>::value, " Must be poolable object" );
46
+ initialize (init_size);
47
+ }
48
+
49
+ pointer_type<T> get ()
50
+ {
51
+ if (_pool.empty ())
52
+ {
53
+ if (_available == 0 )
54
+ {
55
+ return nullptr ;
56
+ }
57
+ add ();
58
+ }
59
+ --_available;
60
+ auto inst = std::move (_pool.top ());
61
+ _pool.pop ();
62
+ return std::move (inst);
63
+ }
64
+
65
+ std::size_t free () { return _available; }
66
+ std::size_t max_size () { return _max_size; }
67
+ std::size_t size () { return _size; }
68
+ bool empty () { return _pool.empty (); }
69
+
70
+ private:
71
+ // Adds a new object to the pool
72
+ void add (T *ptr = nullptr )
73
+ {
74
+ if (ptr == nullptr )
75
+ {
76
+ ptr = create_with_params (std::index_sequence_for<Args...>());
77
+ ++_size;
78
+ }
79
+ else
80
+ {
81
+ ptr->reset ();
82
+ ++_available;
83
+ }
84
+
85
+ pointer_type<T> inst (ptr, [this ](T *ptr) {
86
+ // This is the custom deleter of the unique_ptr.
87
+ // When the object is deleted in the callers context, it will be
88
+ // returned back to the pool by utilizing the add function
89
+ add (ptr);
90
+ });
91
+
92
+ _pool.push (std::move (inst));
93
+ }
94
+
95
+ template <std::size_t ... Is>
96
+ T *create_with_params (const std::index_sequence<Is...> &)
97
+ {
98
+ return new T (std::get<Is>(_args)...);
99
+ }
100
+
101
+ // Initializes the pool
102
+ void initialize (std::size_t init_size)
103
+ {
104
+ for (std::size_t i = 0 ; i < init_size; ++i)
105
+ {
106
+ add ();
107
+ }
108
+ }
109
+
110
+ std::size_t _max_size;
111
+ std::size_t _available;
112
+ std::size_t _size;
113
+ std::stack<pointer_type<T>> _pool;
114
+ std::tuple<Args...> _args;
115
+ };
0 commit comments