GCS  0.2.3
gu_mem_pool.hpp
1 /* Copyright (C) 2013 Codership Oy <info@codership.com> */
13 #ifndef _GU_MEM_POOL_HPP_
14 #define _GU_MEM_POOL_HPP_
15 
16 #include "gu_lock.hpp"
17 #include "gu_macros.hpp"
18 
19 #include <assert.h>
20 
21 #include <vector>
22 #include <ostream>
23 //#include <new> // std::bad_alloc
24 
25 namespace gu
26 {
27  typedef std::vector<void*> MemPoolVector;
28 
29  /* Since we specialize this template iwth thread_safe=true parameter below,
30  * this makes it implicit thread_safe=false specialization. */
31  template <bool thread_safe>
32  class MemPool
33  {
34  public:
35 
36  explicit
37  MemPool(int buf_size, int reserve = 0, const char* name = "")
38  : pool_ (),
39  hits_ (0),
40  misses_ (0),
41  allocd_ (0),
42  name_ (name),
43  buf_size_ (buf_size),
44  reserve_ (reserve)
45  {
46  assert(buf_size > 0);
47  assert(reserve >= 0);
48  pool_.reserve(reserve_);
49  }
50 
51  ~MemPool()
52  {
53  /* all buffers must be returned to pool before destruction */
54  assert(pool_.size() == allocd_);
55 
56  for (size_t i(0); i < pool_.size(); ++i)
57  {
58  assert(pool_[i]);
59  free(pool_[i]);
60  }
61  }
62 
63  void* acquire()
64  {
65  void* ret(from_pool());
66 
67  if (!ret) ret = alloc();
68 
69  return ret;
70  }
71 
72  void recycle(void* buf)
73  {
74  if (!to_pool(buf)) free(buf);
75  }
76 
77  void print(std::ostream& os) const
78  {
79  double hr(hits_);
80 
81  if (hr > 0)
82  {
83  assert(misses_ > 0);
84  hr /= hits_ + misses_;
85  }
86 
87  os << "MemPool(" << name_
88  << "): hit ratio: " << hr
89  << ", misses: " << misses_
90  << ", in use: " << allocd_ - pool_.size()
91  << ", in pool: " << pool_.size();
92  }
93 
94  size_t buf_size() const { return buf_size_; }
95 
96  protected:
97 
98  /* from_pool() and to_pool() will need to be called under mutex
99  * in thread-safe version, so all object data are modified there.
100  * alloc() and free() then can be called outside critical section. */
101  void* from_pool()
102  {
103  void* ret(NULL);
104 
105  if (pool_.size() > 0)
106  {
107  ret = pool_.back();
108  assert(ret);
109  pool_.pop_back();
110  ++hits_;
111  }
112  else
113  {
114  ++allocd_;
115  ++misses_;
116  }
117 
118  return ret;
119  }
120 
121  // returns false if buffer can't be returned to pool
122  bool to_pool(void* buf)
123  {
124  assert(buf);
125 
126  bool const ret(reserve_ + allocd_/2 > pool_.size());
127 
128  if (ret)
129  {
130  pool_.push_back(buf);
131  }
132  else
133  {
134  assert(allocd_ > 0);
135  --allocd_;
136  }
137 
138  return ret;
139  }
140 
141  void* alloc()
142  {
143  return (operator new(buf_size_));
144  }
145 
146  void free(void* const buf)
147  {
148  assert(buf);
149  operator delete(buf);
150  }
151 
152  friend class MemPool<true>;
153 
154  private:
155 
156  MemPoolVector pool_;
157  size_t hits_;
158  size_t misses_;
159  size_t allocd_;
160  const char* const name_;
161  unsigned int const buf_size_;
162  unsigned int const reserve_;
163 
164  MemPool (const MemPool&);
165  MemPool operator= (const MemPool&);
166 
167  }; /* class MemPool<false>: thread-unsafe */
168 
169 
170  /* Thread-safe MemPool specialization.
171  * Even though MemPool<true> technically IS-A MemPool<false>, the need to
172  * overload nearly all public methods and practical uselessness of
173  * polymorphism in this case make inheritance undesirable. */
174  template <>
175  class MemPool<true>
176  {
177  public:
178 
179  explicit
180  MemPool(int buf_size, int reserve = 0, const char* name = "")
181  : base_(buf_size, reserve, name), mtx_ () {}
182 
183  ~MemPool() {}
184 
185  void* acquire()
186  {
187  void* ret;
188 
189  {
190  Lock lock(mtx_);
191  ret = base_.from_pool();
192  }
193 
194  if (!ret) ret = base_.alloc();
195 
196  return ret;
197  }
198 
199  void recycle(void* buf)
200  {
201  bool pooled;
202 
203  {
204  Lock lock(mtx_);
205  pooled = base_.to_pool(buf);
206  }
207 
208  if (!pooled) base_.free(buf);
209  }
210 
211  void print(std::ostream& os) const
212  {
213  Lock lock(mtx_);
214  base_.print(os);
215  }
216 
217  size_t buf_size() const { return base_.buf_size(); }
218 
219  private:
220 
221  MemPool<false> base_;
222  Mutex mtx_;
223 
224  }; /* class MemPool<true>: thread-safe */
225 
226  template <bool thread_safe>
227  std::ostream& operator << (std::ostream& os,
228  const MemPool<thread_safe>& mp)
229  {
230  mp.print(os); return os;
231  }
232 
233  typedef MemPool<false> MemPoolUnsafe;
234  typedef MemPool<true> MemPoolSafe;
235 
236 } /* namespace gu */
237 
238 
239 #endif /* _GU_MEM_POOL_HPP_ */
Definition: gu_lock.hpp:20
Definition: gu_mutex.hpp:19
Definition: gu_mem_pool.hpp:32