1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#pragma once
#include <map>
#include <memory>
#include <stack>
#include <mutex>
namespace DB
{
/** Pool for objects that cannot be used from different threads simultaneously.
* Allows to create an object for each thread.
* Pool has unbounded size and objects are not destroyed before destruction of pool.
*
* Use it in cases when thread local storage is not appropriate
* (when maximum number of simultaneously used objects is less
* than number of running/sleeping threads, that has ever used object,
* and creation/destruction of objects is expensive).
*/
template <typename T>
class SimpleObjectPool
{
protected:
/// Hold all available objects in stack.
std::mutex mutex;
std::stack<std::unique_ptr<T>> stack;
/// Specialized deleter for std::unique_ptr.
/// Returns underlying pointer back to stack thus reclaiming its ownership.
struct Deleter
{
SimpleObjectPool<T> * parent;
Deleter(SimpleObjectPool<T> * parent_ = nullptr) : parent{parent_} {} /// NOLINT
void operator()(T * owning_ptr) const
{
std::lock_guard lock{parent->mutex};
parent->stack.emplace(owning_ptr);
}
};
public:
using Pointer = std::unique_ptr<T, Deleter>;
/// Extracts and returns a pointer from the stack if it's not empty,
/// creates a new one by calling provided f() otherwise.
template <typename Factory>
Pointer get(Factory && f)
{
std::unique_lock lock(mutex);
if (stack.empty())
{
lock.unlock();
return { f(), this };
}
auto object = stack.top().release();
stack.pop();
return { object, this };
}
/// Like get(), but creates object using default constructor.
Pointer getDefault()
{
return get([] { return new T; });
}
};
/// Like SimpleObjectPool, but additionally allows store different kind of objects that are identified by Key
template <typename T, typename Key>
class ObjectPoolMap
{
private:
using Object = SimpleObjectPool<T>;
/// Key -> objects
using Container = std::map<Key, std::unique_ptr<Object>>;
Container container;
std::mutex mutex;
public:
using Pointer = typename Object::Pointer;
template <typename Factory>
Pointer get(const Key & key, Factory && f)
{
std::lock_guard lock(mutex);
auto it = container.find(key);
if (container.end() == it)
it = container.emplace(key, std::make_unique<Object>()).first;
return it->second->get(std::forward<Factory>(f));
}
};
}
|