Gray C++ Libraries  0.0.2
A set of C++ libraries for MSVC, GNU on Windows, WinCE, Linux
cPool.h
Go to the documentation of this file.
1 //
7 //
8 
9 #ifndef _INC_cPool_H
10 #define _INC_cPool_H
11 #ifndef NO_PRAGMA_ONCE
12 #pragma once
13 #endif
14 
15 #include "../GrayLibBase.h"
22 
23 namespace GrayLib
24 {
26 
27 #ifdef _DEBUG
28 #define USE_POOL_FREESORT // look for weird bugs by sorting the free pool.
29 #endif
30 
31  template< class TYPE >
32  class cPoolBase
33  {
38 
39  protected:
43 
44  protected:
45  cPoolBase(ITERATE_t nBucketAllocQty = 128) noexcept
46  : m_nBucketAllocQty(nBucketAllocQty)
47  {
49  DEBUG_ASSERT(m_nBucketAllocQty > 0, "cPoolBase");
50  }
51 
52  public:
53  ITERATE_t get_BucketAllocQty() const noexcept
54  {
56  return m_nBucketAllocQty ;
57  }
58  ITERATE_t get_AllocQty() const noexcept
59  {
62  return m_aBuckets.GetSize() * m_nBucketAllocQty;
63  }
64 
65  bool isInPool(const void* pObj) const
66  {
69  for (ITERATE_t i = 0; i < m_aBuckets.GetSize(); i++)
70  {
71  INT_PTR j = GET_INDEX_IN(m_aBuckets[i].GetData(), (const TYPE*)pObj);
73  return true;
74  }
75  return false;
76  }
77 
79  {
81  if (m_nBucketAllocQty <= 0)
82  return nullptr;
83  ITERATE_t nSize = m_aBuckets.GetSize() + 1;
84  m_aBuckets.SetSize(nSize);
85  if (m_aBuckets.GetSize() != nSize)
86  return nullptr;
87  cPoolBucket& bucket = m_aBuckets.Tail();
88  bucket.SetSize(m_nBucketAllocQty);
89  if (bucket.GetSize() != m_nBucketAllocQty) // ASSERT ?
90  return nullptr;
91  return &bucket;
92  }
93  void FreeBuckets()
94  {
96  m_aBuckets.RemoveAll();
97  }
98  };
99 
100  //*******************************************************************
101 
102  template< class TYPE >
104  {
108 
109  private:
110  union
111  {
114  BYTE m_Used[sizeof(TYPE)];
115  } m_u;
116  bool m_bIsFreeNode;
117 
118  public:
119  cPoolNodeFreeT() noexcept
120  : m_bIsFreeNode(true)
121  {
122  m_u.m_pFreeNext = nullptr; // start off free.
123  }
124  ~cPoolNodeFreeT() noexcept
125  {
126  m_bIsFreeNode = false; // destructed when m_Used state
127  }
128  bool isPoolNodeFree() const noexcept
129  {
132  return m_bIsFreeNode;
133  }
134  TYPE* get_Used() const
135  {
137  return (TYPE*)m_u.m_Used;
138  }
140  {
142  return m_u.m_pFreeNext;
143  }
144  void put_FreeNext(THIS_t* pFreeNext)
145  {
146  m_u.m_pFreeNext = pFreeNext;
147  }
148  };
149 
150  MIDL_INTERFACE("0C3E2E71-B93C-11d2-AAD0-006007654564") IPoolNode
151  {
155  virtual bool isPoolNodeValid(UINT_PTR uCheckVal = 0) const = 0; // for debug purposes.
156  };
157 
158  template< class TYPE >
159  class cPool : public cPoolBase< cPoolNodeFreeT< TYPE > >
160  {
164 
167 
168  private:
169  mutable cThreadLockCount m_Lock;
170  ITERATE_t m_iFreeCount;
171  cPoolNodeFree_t* m_pFreeListHead;
172 #ifdef USE_POOL_FREESORT
173  cArraySorted< const cPoolNodeFree_t*, const cPoolNodeFree_t*, const cPoolNodeFree_t* > m_FreeQ; // sorted array of free objects. so i can't add it twice!
174 #endif
175 
176  private:
177  bool IsInFreeList(const cPoolNodeFree_t* pFreeNode) const
178  {
179  ASSERT(pFreeNode != nullptr);
180  ASSERT(this->isInPool(pFreeNode));
181 #ifdef USE_POOL_FREESORT
182  // fast search through sorted free list.
183  return(m_FreeQ.FindIFor(pFreeNode) >= 0);
184 #else
185  // brute force find the item in the list.
186  cPoolNodeFree_t* pFree = m_pFreeListHead;
187  for (; pFree != nullptr; pFree = pFree->get_FreeNext())
188  {
189  ASSERT(pFree->isPoolNodeFree());
190  // ASSERT( isInPool(pFree));
191  if (pFree == pFreeNode)
192  return true;
193  }
194  return false;
195 #endif
196  }
197  void AddFreeNode(cPoolNodeFree_t* pFreeNode)
198  {
200  ASSERT(pFreeNode != nullptr);
201 #ifdef USE_POOL_FREESORT
202  m_FreeQ.Add(pFreeNode);
203 #endif
204  pFreeNode->put_FreeNext(m_pFreeListHead);
205  m_pFreeListHead = pFreeNode;
206  m_iFreeCount++;
207  }
208  cPoolNodeFree_t* AddBucket()
209  {
212  if (pBucket == nullptr)
213  return nullptr;
215  ITERATE_t i = 0;
217  for (; i < iSizeN; i++)
218  {
219  AddFreeNode(&(pBucket->ElementAt(i)));
220  }
221  return &(pBucket->ElementAt(i));
222  }
223 
224  public:
225  cPool(ITERATE_t nBucketAllocQty = 128) noexcept
226  : cPoolBase< cPoolNodeFree_t >(nBucketAllocQty)
227  , m_iFreeCount(0)
228  , m_pFreeListHead(nullptr)
229  {
230  cAppState::isInCInit(); // Must call this to ensure proper static init/destruction order for cAppState.
231 #ifdef _WIN32
232  // STATIC_ASSERT( offsetof(cPoolNodeFree_t,m_u.m_Free) == 0 );
233 #endif
234  }
236  {
238  if (!cAppState::isInCExit())
239  {
240  // m_FreeList.DisposeAll();
241  FreePool();
242  }
243  }
244 
245  bool isPoolUsed() const
246  {
247  // has Anything been used ?
248  ITERATE_t iAllocQty = SUPER_t::get_AllocQty();
249  ASSERT(iAllocQty >= m_iFreeCount);
250 #ifdef USE_POOL_FREESORT
251  ASSERT(m_iFreeCount == m_FreeQ.GetSize());
252 #endif
253  if (m_iFreeCount == iAllocQty)
254  return false;
255  return true;
256  }
257 
258  bool put_BucketAllocQty(ITERATE_t nBucketAllocQty)
259  {
261  if (SUPER_t::m_nBucketAllocQty != 0) // can only set this once !!
262  {
263  // shouldn't ever really happen!? don't allow this to change if used.
264  if (isPoolUsed())
265  return false;
266  FreePool();
267  }
268  SUPER_t::m_nBucketAllocQty = nBucketAllocQty;
269  return true;
270  }
271  void FreePool()
272  {
274  cThreadGuard guard(m_Lock);
275  ASSERT(m_iFreeCount == this->get_AllocQty()); // full free list!
276 #ifdef USE_POOL_FREESORT
277  m_FreeQ.RemoveAll();
278 #endif
280  }
282  {
284  cThreadGuard guard(m_Lock);
285  cPoolNodeFree_t* pFreeNode;
286  if (m_pFreeListHead != nullptr)
287  {
288  // use existing object.
289  pFreeNode = m_pFreeListHead;
290  m_pFreeListHead = m_pFreeListHead->get_FreeNext();
291  m_iFreeCount--;
292 #ifdef USE_POOL_FREESORT
293  bool bRet = m_FreeQ.RemoveKey(pFreeNode);
294  ASSERT(bRet);
295 #endif
296  }
297  else
298  {
299  // add more buckets.
300  pFreeNode = AddBucket();
301  if (pFreeNode == nullptr)
302  {
303  return nullptr;
304  }
305  }
306  ASSERT(this->isInPool(pFreeNode));
307  ASSERT(pFreeNode->isPoolNodeFree());
308  // destruct cPoolNodeFree_t
309  pFreeNode->~cPoolNodeFree_t();
310  ASSERT(!pFreeNode->isPoolNodeFree());
311  // ASSUME TYPE construct will be called.
312  return reinterpret_cast<TYPE*>(pFreeNode);
313  }
314  void FreePoolObjectND(TYPE* pUsed)
315  {
318  cThreadGuard guard(m_Lock);
319  ASSERT(pUsed != nullptr);
320  ASSERT(this->isInPool(pUsed));
321  cPoolNodeFree_t* pFreeNode = reinterpret_cast<cPoolNodeFree_t*>(pUsed);
322 #ifdef USE_POOL_FREESORT
323  ASSERT(!IsInFreeList(pFreeNode));
324 #endif
325  ASSERT(!pFreeNode->isPoolNodeFree());
326  // construct cPoolNodeFree_t in place.
327  ::new((void*)pFreeNode) cPoolNodeFree_t;
328  ASSERT(pFreeNode->isPoolNodeFree());
329  AddFreeNode(pFreeNode);
330  }
331 
333  {
337  TYPE* pUsed = this->AllocPoolObjectNC();
338  ASSERT(pUsed != nullptr);
339  // construct TYPE in place.
340  ::new((void*)pUsed) TYPE;
341  return pUsed;
342  }
343  void FreePoolObject(TYPE* pUsed)
344  {
348  ASSERT(pUsed != nullptr);
349  pUsed->~TYPE();
350  // now put back in free list.
351  this->FreePoolObjectND(pUsed);
352  }
353 
354  bool CheckValidPool(UINT_PTR uCheckVal = 0) const
355  {
357  cThreadGuard guard(m_Lock);
358 
359  // Validate that all objects isPoolNodeFree() state is accurate.
360  cPoolNodeFree_t* pFreeNode = m_pFreeListHead;
361  for (; pFreeNode != nullptr; pFreeNode = pFreeNode->get_FreeNext())
362  {
363  ASSERT(pFreeNode->isPoolNodeFree());
364  ASSERT(this->isInPool(pFreeNode));
365 #ifdef USE_POOL_FREESORT
366  ASSERT(m_FreeQ.FindIForKey(pFreeNode) >= 0);
367 #endif
368  }
369  // Validate the all objects are in either free or alloc state. not both.
370  for (ITERATE_t i = 0; i < SUPER_t::m_aBuckets.GetSize(); i++)
371  {
373  for (ITERATE_t j = 0; j < SUPER_t::m_nBucketAllocQty; j++)
374  {
375  const cPoolNodeFree_t* pNode = SUPER_t::m_aBuckets[i].GetData() + j;
376  if (pNode->isPoolNodeFree())
377  {
378  // in the free list?
379  ASSERT(IsInFreeList(pNode));
380  }
381  else
382  {
383  // NOT in the free list?
384  ASSERT(!IsInFreeList(pNode));
385  pNode->get_Used()->isPoolNodeValid(uCheckVal); // IPoolNode
386  }
387  }
388  }
389  return true;
390  }
391 
392  bool IsInFreeState(const TYPE* pUsedNode) const
393  {
394  ASSERT(pUsedNode != nullptr);
395  const cPoolNodeFree_t* pFreeNode = reinterpret_cast<const cPoolNodeFree_t*>(pUsedNode);
396  return pFreeNode->isPoolNodeFree();
397  }
398  bool IsInFreeList(const TYPE* pUsedNode) const
399  {
401  ASSERT(pUsedNode != nullptr);
402  const cPoolNodeFree_t* pFreeNode = reinterpret_cast<const cPoolNodeFree_t*>(pUsedNode);
403  return this->IsInFreeList(pFreeNode);
404  }
405 
407  };
408 
409  template< class TYPE >
410  class cPoolClass : public cSingleton< cPoolClass<TYPE> >, public cPool< TYPE >
411  {
416 
417  friend class cSingleton< cPoolClass<TYPE> >;
419 
420  protected:
421  cPoolClass(ITERATE_t nBucketAllocQty = 128) noexcept
422  : cPool<TYPE>(nBucketAllocQty)
423  {
424  }
426  {
427  }
428  };
429 
430  // overload the new and delete operators for a class.
431 #define POOL_CLASS_IMPL(TYPE) \
432  void * operator new (size_t size) { ASSERT( size == sizeof(TYPE)); return cPoolClass<TYPE>::I().AllocPoolObjectNC(); } \
433  void operator delete(void * dead, size_t size) { ASSERT( size == sizeof(TYPE)); cPoolClass<TYPE>::I().FreePoolObjectND( (TYPE*) dead); }
434 }
435 #endif // _INC_cPool_H
#define IGNORE_WARN_INTERFACE(c)
Definition: GrayCore.h:79
#define IS_INDEX_GOOD(i, q)
cast the (likely) int to unsigned to check for negatives.
Definition: Index.h:35
#define TYPE
Definition: StrT.cpp:38
#define ASSERT(exp)
Definition: cDebugAssert.h:87
#define DEBUG_ASSERT(exp, sDesc)
Definition: cDebugAssert.h:93
#define CHEAPOBJECT_IMPL
Definition: cHeapObject.h:32
Definition: cPool.h:33
cPoolBucket * AddBucketNew()
Definition: cPool.h:78
ITERATE_t m_nBucketAllocQty
how many new objects per bucket.
Definition: cPool.h:42
cArrayStruct< cPoolBucket > m_aBuckets
all allocated space. free and used objects.
Definition: cPool.h:41
cPoolBase(ITERATE_t nBucketAllocQty=128) noexcept
Definition: cPool.h:45
ITERATE_t get_BucketAllocQty() const noexcept
Definition: cPool.h:53
cArrayStruct< TYPE > cPoolBucket
Definition: cPool.h:40
ITERATE_t get_AllocQty() const noexcept
Definition: cPool.h:58
void FreeBuckets()
Definition: cPool.h:93
bool isInPool(const void *pObj) const
Definition: cPool.h:65
Definition: cPool.h:411
cPoolClass(ITERATE_t nBucketAllocQty=128) noexcept
Definition: cPool.h:421
~cPoolClass()
Definition: cPool.h:425
Definition: cPool.h:104
THIS_t * m_pFreeNext
union the object in 'free' or 'used' state.
Definition: cPool.h:113
bool isPoolNodeFree() const noexcept
Definition: cPool.h:128
TYPE * get_Used() const
Definition: cPool.h:134
THIS_t * get_FreeNext() const
Definition: cPool.h:139
cPoolNodeFreeT() noexcept
Definition: cPool.h:119
BYTE m_Used[sizeof(TYPE)]
the TYPE object in 'used' state. assume IPoolNode based.
Definition: cPool.h:114
~cPoolNodeFreeT() noexcept
Definition: cPool.h:124
void put_FreeNext(THIS_t *pFreeNext)
Definition: cPool.h:144
Definition: cPool.h:160
bool IsInFreeList(const TYPE *pUsedNode) const
Definition: cPool.h:398
bool IsInFreeState(const TYPE *pUsedNode) const
Definition: cPool.h:392
TYPE * AllocPoolObject()
Definition: cPool.h:332
void FreePool()
Definition: cPool.h:271
~cPool()
Definition: cPool.h:235
void FreePoolObjectND(TYPE *pUsed)
Definition: cPool.h:314
TYPE * AllocPoolObjectNC()
Definition: cPool.h:281
cPool(ITERATE_t nBucketAllocQty=128) noexcept
Definition: cPool.h:225
void FreePoolObject(TYPE *pUsed)
Definition: cPool.h:343
bool isPoolUsed() const
Definition: cPool.h:245
UNITTEST_FRIEND(cPool)
bool put_BucketAllocQty(ITERATE_t nBucketAllocQty)
Definition: cPool.h:258
bool CheckValidPool(UINT_PTR uCheckVal=0) const
Definition: cPool.h:354
void RemoveAll()
Clean up.
Definition: cArray.h:230
TYPE & ElementAt(ITERATE_t nIndex)
Definition: cArray.h:167
ITERATE_t GetSize() const noexcept
Definition: cArray.h:137
void SetSize(ITERATE_t nNewSize)
Definition: cArray.h:248
static bool __stdcall isInCInit()
Definition: cAppState.cpp:280
static bool __stdcall isInCExit()
Definition: cAppState.cpp:310
Definition: cArraySort.h:24
ITERATE_t FindIForKey(KEY_t key) const
Definition: cArraySort.h:68
bool RemoveKey(TYPE_KEY key)
Definition: cArraySort.h:124
ITERATE_t Add(TYPE_ARG pNew)
Definition: cArraySort.h:186
Definition: cArray.h:932
ITERATE_t FindIFor(ARG_TYPE arg) const
Definition: cArray.h:614
Definition: cLocker.h:72
Definition: cSingleton.h:127
Definition: cThreadLock.h:498
Definition: cPool.h:150
Definition: cMesh.h:22
UNITTEST2_PREDEF(cQuadtree)
MIDL_INTERFACE("0C3E2E71-B93C-11d2-AAD0-006007654304") IScriptableObj
int ITERATE_t
like size_t but signed
Definition: Index.h:28