Vowpal Wabbit
object_pool.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <set>
4 #include <queue>
5 #include <stack>
6 
7 // Mutex and CV cannot be used in managed C++, tell the compiler that this is unmanaged even if included in a managed
8 // project.
9 #ifdef _M_CEE
10 #pragma managed(push, off)
11 #undef _M_CEE
12 #include <mutex>
13 #include <condition_variable>
14 #define _M_CEE 001
15 #pragma managed(pop)
16 #else
17 #include <mutex>
18 #include <condition_variable>
19 #endif
20 
21 namespace VW
22 {
23 template <typename T>
25 {
26  void operator()(T*) {}
27 };
28 
29 template <typename T, typename TInitializer, typename TCleanup = default_cleanup<T>>
31 {
32  no_lock_object_pool() = default;
33  no_lock_object_pool(size_t initial_chunk_size, TInitializer initializer = {}, size_t chunk_size = 8)
34  : m_initializer(initializer), m_initial_chunk_size(initial_chunk_size), m_chunk_size(chunk_size)
35  {
36  new_chunk(initial_chunk_size);
37  }
38 
40  {
41  while (!m_pool.empty())
42  {
43  auto front = m_pool.front();
44  m_cleanup(front);
45  m_pool.pop();
46  }
47  }
48 
49  void return_object(T* obj)
50  {
51  assert(is_from_pool(obj));
52  m_pool.push(obj);
53  }
54 
56  {
57  if (m_pool.empty())
58  {
59  new_chunk(m_chunk_size);
60  }
61 
62  auto obj = m_pool.front();
63  m_pool.pop();
64  return obj;
65  }
66 
67  bool empty() const { return m_pool.empty(); }
68 
69  size_t size() const
70  {
71  size_t size = 0;
72  auto num_chunks = m_chunk_bounds.size();
73 
74  if (m_chunk_bounds.size() > 0 && m_initial_chunk_size > 0)
75  {
76  size += m_initial_chunk_size;
77  num_chunks--;
78  }
79 
80  size += num_chunks * m_chunk_size;
81  return size;
82  }
83 
84  bool is_from_pool(T* obj) const
85  {
86  for (auto& bound : m_chunk_bounds)
87  {
88  if (obj >= bound.first && obj <= bound.second)
89  {
90  return true;
91  }
92  }
93 
94  return false;
95  }
96 
97  private:
98  void new_chunk(size_t size)
99  {
100  if (size == 0)
101  {
102  return;
103  }
104 
105  m_chunks.push_back(std::unique_ptr<T[]>(new T[size]));
106  auto& chunk = m_chunks.back();
107  m_chunk_bounds.push_back({&chunk[0], &chunk[size - 1]});
108 
109  for (size_t i = 0; i < size; i++)
110  {
111  memset(&chunk[i], 0, sizeof(T));
112  new (&chunk[i]) T{};
113  m_pool.push(m_initializer(&chunk[i]));
114  }
115  }
116 
117  std::queue<T*> m_pool;
118  std::vector<std::pair<T*, T*>> m_chunk_bounds;
119  std::vector<std::unique_ptr<T[]>> m_chunks;
120  TInitializer m_initializer;
121  TCleanup m_cleanup;
122  size_t m_initial_chunk_size = 0;
123  size_t m_chunk_size = 8;
124 };
125 
126 template <typename T, typename TAllocator, typename TDeleter>
128 {
129  value_object_pool() = default;
130 
132  {
133  while (!m_pool.empty())
134  {
135  auto& item = m_pool.top();
136  m_deleter(item);
137  m_pool.pop();
138  }
139  }
140 
141  void return_object(T obj) { m_pool.push(obj); }
142 
144  {
145  if (m_pool.empty())
146  {
147  return m_allocator();
148  }
149 
150  auto obj = m_pool.top();
151  m_pool.pop();
152  return obj;
153  }
154 
155  bool empty() const { return m_pool.empty(); }
156 
157  size_t size() const { return m_pool.size(); }
158 
159  private:
160  std::stack<T> m_pool;
161  TAllocator m_allocator;
162  TDeleter m_deleter;
163 };
164 
165 template <typename T, typename TInitializer, typename TCleanup = default_cleanup<T>>
167 {
168  object_pool() = default;
169  object_pool(size_t initial_chunk_size, TInitializer initializer = {}, size_t chunk_size = 8)
170  : inner_pool(initial_chunk_size, initializer, chunk_size)
171  {
172  }
173 
174  void return_object(T* obj)
175  {
176  std::unique_lock<std::mutex> lock(m_lock);
177  inner_pool.return_object(obj);
178  }
179 
181  {
182  std::unique_lock<std::mutex> lock(m_lock);
183  return inner_pool.get_object();
184  }
185 
186  bool empty() const { return inner_pool.empty(); }
187 
188  size_t size() const { return inner_pool.size(); }
189 
190  bool is_from_pool(T* obj) const { return inner_pool.is_from_pool(obj); }
191 
192  std::mutex m_lock;
194 };
195 } // namespace VW
object_pool(size_t initial_chunk_size, TInitializer initializer={}, size_t chunk_size=8)
Definition: object_pool.h:169
bool empty() const
Definition: object_pool.h:155
no_lock_object_pool< T, TInitializer, TCleanup > inner_pool
Definition: object_pool.h:193
TInitializer m_initializer
Definition: object_pool.h:120
std::vector< std::unique_ptr< T[]> > m_chunks
Definition: object_pool.h:119
void new_chunk(size_t size)
Definition: object_pool.h:98
size_t size() const
Definition: object_pool.h:69
void return_object(T obj)
Definition: object_pool.h:141
bool is_from_pool(T *obj) const
Definition: object_pool.h:190
size_t size() const
Definition: object_pool.h:157
std::mutex m_lock
Definition: object_pool.h:192
void return_object(T *obj)
Definition: object_pool.h:49
TAllocator m_allocator
Definition: object_pool.h:161
std::queue< T * > m_pool
Definition: object_pool.h:117
void operator()(T *)
Definition: object_pool.h:26
Definition: autolink.cc:11
std::vector< std::pair< T *, T * > > m_chunk_bounds
Definition: object_pool.h:118
no_lock_object_pool(size_t initial_chunk_size, TInitializer initializer={}, size_t chunk_size=8)
Definition: object_pool.h:33
size_t size() const
Definition: object_pool.h:188
void return_object(T *obj)
Definition: object_pool.h:174
bool is_from_pool(T *obj) const
Definition: object_pool.h:84
std::stack< T > m_pool
Definition: object_pool.h:160
bool empty() const
Definition: object_pool.h:186