Leviathan  0.8.0.0
Leviathan game engine
ObjectPool.h
Go to the documentation of this file.
1 // Leviathan Game Engine
2 // Copyright (c) 2012-2018 Henri Hyyryläinen
3 #pragma once
4 #include "Include.h"
5 // ------------------------------------ //
6 
7 #include "Exceptions.h"
8 
9 #include <functional>
10 #include <tuple>
11 #include <type_traits>
12 #include <unordered_map>
13 #include <vector>
14 
15 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
16 //#include "boost/pool/object_pool.hpp"
17 #include "boost/pool/pool.hpp"
18 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
19 
20 namespace Leviathan {
21 
23 template<class ElementType>
24 class BasicPool {
25 public:
27 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
28  :
29  Elements(sizeof(ElementType), 16)
30 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
31  {}
32 
34 
35 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
36 
39  template<typename... Args>
40  ElementType* ConstructNew(Args&&... args)
41  {
42  // Get memory to hold the object //
43  void* memoryForObject = Elements.malloc();
44 
45  if(!memoryForObject)
46  throw Exception("Out of memory for element");
47 
48  // Construct the object //
49  ElementType* created;
50  try {
51  created = new(memoryForObject) ElementType(std::forward<Args>(args)...);
52  } catch(...) {
53 
54  Elements.free(memoryForObject);
55  throw;
56  }
57 
58  return created;
59  }
60 
62  void Destroy(ElementType* element)
63  {
64 
65  element->~ElementType();
66  Elements.free(element);
67  }
68 #else
69  template<typename... Args>
70  ElementType* ConstructNew(Args&&... args)
71  {
72  return new ElementType(std::forward<Args>(args)...);
73  }
74 
75  void Destroy(ElementType* element)
76  {
77  delete element;
78  }
79 
80 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
81 
82 protected:
83 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
84  boost::pool<> Elements;
86 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
87 };
88 
92 template<class ElementType, typename KeyType, bool AutoCleanupObjects = true>
93 class ObjectPool {
94 public:
95 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
96  ObjectPool() : Elements(sizeof(ElementType), 16) {}
98 #else
99  ObjectPool() {}
100 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
101 
103  {
104  if(!AutoCleanupObjects)
105  return;
106 
107  Clear();
108  }
109 
112  template<typename... Args>
113  ElementType* ConstructNew(KeyType forentity, Args&&... args)
114  {
115  if(Find(forentity))
116  throw Exception("Entity with ID already has object in pool of this type");
117 
118 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
119  // Get memory to hold the object //
120  void* memoryForObject = Elements.malloc();
121 
122  if(!memoryForObject)
123  throw Exception("Out of memory for element");
124 
125  // Construct the object //
126  ElementType* created;
127  try {
128  created = new(memoryForObject) ElementType(std::forward<Args>(args)...);
129  } catch(...) {
130 
131  Elements.free(memoryForObject);
132  throw;
133  }
134 #else
135  // Construct the object //
136  ElementType* created = new ElementType(std::forward<Args>(args)...);
137 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
138 
139  // Add to index for finding later //
140  Index.insert(std::make_pair(forentity, created));
141  return created;
142  }
143 
145  template<typename... Args>
146  void Release(KeyType entity, Args&&... args)
147  {
148  auto* object = Find(entity);
149 
150  if(!object)
151  throw NotFound("entity not in pool");
152 
153  object->Release(std::forward<Args>(args)...);
154 
155 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
156  object->~ElementType();
157  Elements.free(object);
158 #else
159  delete object;
160 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
161 
162  RemoveFromIndex(entity);
163  RemoveFromAdded(entity);
164  }
165 
167  ElementType* Find(KeyType id) const
168  {
169  auto iter = Index.find(id);
170 
171  if(iter == Index.end())
172  return nullptr;
173 
174  return iter->second;
175  }
176 
178  void Destroy(KeyType id)
179  {
180  auto object = Find(id);
181 
182  if(!object)
183  throw InvalidArgument("ID is not in index");
184 
185 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
186  object->~ElementType();
187  Elements.free(object);
188 #else
189  delete object;
190 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
191 
192  RemoveFromIndex(id);
193  RemoveFromAdded(id);
194  }
195 
197  template<typename Any>
198  void RemoveBasedOnKeyTupleList(const std::vector<std::tuple<Any, KeyType>>& values)
199  {
200  for(auto iter = values.begin(); iter != values.end(); ++iter) {
201 
202  auto todelete = Index.find(std::get<1>(*iter));
203 
204  if(todelete == Index.end())
205  continue;
206 
207 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
208  todelete->second->~ElementType();
209  Elements.free(todelete->second);
210 #else
211  delete todelete->second;
212 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
213 
214  Index.erase(todelete);
215  }
216  }
217 
218 
225  void Call(std::function<bool(ElementType&, KeyType)> function)
226  {
227  for(auto iter = Index.begin(); iter != Index.end();) {
228 
229  if(function(*iter->second, iter->first)) {
230 
231 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
232  iter->second->~ElementType();
233  Elements.free(iter->second);
234 #else
235  delete iter->second;
236 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
237 
238  iter = Index.erase(iter);
239 
240  } else {
241 
242  ++iter;
243  }
244  }
245  }
246 
249  void Clear()
250  {
251  for(auto iter = Index.begin(); iter != Index.end(); ++iter) {
252 
253 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
254  iter->second->~ElementType();
255  Elements.free(iter->second);
256 #else
257  delete iter->second;
258 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
259  }
260 
261  Index.clear();
262  }
263 
264  auto GetObjectCount() const
265  {
266  return Index.size();
267  }
268 
272  inline std::unordered_map<KeyType, ElementType*>& GetIndex()
273  {
274  return Index;
275  }
276 
277 protected:
280  bool RemoveFromIndex(KeyType id)
281  {
282  auto end = Index.end();
283  for(auto iter = Index.begin(); iter != end; ++iter) {
284 
285  if(iter->first == id) {
286 
287  Index.erase(iter);
288  return true;
289  }
290  }
291 
292  return false;
293  }
294 
295 protected:
297  std::unordered_map<KeyType, ElementType*> Index;
298 
299 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
300  boost::pool<> Elements;
302 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
303 };
304 
305 // ------------------------------------ //
311 template<class ElementType, typename KeyType, bool AutoCleanupObjects = true>
313 public:
315 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
316  :
317  Elements(sizeof(ElementType), 16)
318 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
319  {}
320 
322  {
323  if(!AutoCleanupObjects)
324  return;
325 
326  Clear();
327  }
328 
331  template<typename... Args>
332  ElementType* ConstructNew(KeyType forentity, Args&&... args)
333  {
334  if(Find(forentity))
335  throw Exception("Entity with ID already has object in pool of this type");
336 
337 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
338  // Get memory to hold the object //
339  void* memoryForObject = Elements.malloc();
340 
341  if(!memoryForObject)
342  throw Exception("Out of memory for element");
343 
344  // Construct the object //
345  ElementType* created;
346  try {
347  created = new(memoryForObject) ElementType(std::forward<Args>(args)...);
348  } catch(...) {
349 
350  Elements.free(memoryForObject);
351  throw;
352  }
353 #else
354  // Construct the object //
355  ElementType* created = new ElementType(std::forward<Args>(args)...);
356 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
357 
358  // Add to index for finding later //
359  Index.insert(std::make_pair(forentity, created));
360 
361  Added.push_back(std::make_tuple(created, forentity));
362 
363  return created;
364  }
365 
367  bool HasElementsInRemoved() const
368  {
369  return !Removed.empty();
370  }
371 
373  bool HasElementsInAdded() const
374  {
375  return !Added.empty();
376  }
377 
379  bool HasElementsInQueued() const
380  {
381  return !Queued.empty();
382  }
383 
386  template<typename... Args>
387  void ReleaseQueued(Args&&... args)
388  {
389  for(auto iter = Queued.begin(); iter != Queued.end(); ++iter) {
390 
391  auto object = std::get<0>(*iter);
392  const auto id = std::get<1>(*iter);
393 
394  object->Release(std::forward<Args>(args)...);
395 
396 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
397  object->~ElementType();
398  Elements.free(object);
399 #else
400  delete object;
401 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
402  Removed.push_back(std::make_tuple(object, id));
403  RemoveFromIndex(id);
404  }
405 
406  Queued.clear();
407  }
408 
410  template<typename... Args>
411  void Release(KeyType id, bool addtoremoved, Args&&... args)
412  {
413  auto* object = Find(id);
414 
415  if(!object)
416  throw NotFound("id not in pool");
417 
418  _ReleaseCommon(object, id, addtoremoved, std::forward<Args>(args)...);
419  }
420 
423  template<typename... Args>
424  bool ReleaseIfExists(KeyType id, bool addtoremoved, Args&&... args)
425  {
426  auto* object = Find(id);
427 
428  if(!object)
429  return false;
430 
431  _ReleaseCommon(object, id, addtoremoved, std::forward<Args>(args)...);
432  return true;
433  }
434 
437  void ClearQueued()
438  {
439  for(auto iter = Queued.begin(); iter != Queued.end(); ++iter) {
440 
441  auto object = std::get<0>(*iter);
442  const auto id = std::get<1>(*iter);
443 
444 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
445  object->~ElementType();
446  Elements.free(object);
447 #else
448  delete object;
449 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
450 
451  Removed.push_back(std::make_tuple(object, id));
452  RemoveFromIndex(id);
453  }
454 
455  Queued.clear();
456  }
457 
459  const auto& GetRemoved() const
460  {
461  return Removed;
462  }
463 
465  auto& GetAdded()
466  {
467  return Added;
468  }
469 
471  void ClearAdded()
472  {
473  Added.clear();
474  }
475 
478  {
479  Removed.clear();
480  }
481 
485  template<typename Any>
487  const std::vector<std::tuple<Any, KeyType>>& values, bool addtoremoved = false)
488  {
489  for(auto iter = values.begin(); iter != values.end(); ++iter) {
490 
491  auto todelete = Index.find(std::get<1>(*iter));
492 
493  if(todelete == Index.end())
494  continue;
495 
496 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
497  todelete->second->~ElementType();
498  Elements.free(todelete->second);
499 #else
500  delete todelete->second;
501 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
502 
503  if(addtoremoved)
504  Removed.push_back(std::make_tuple(todelete->second, todelete->first));
505 
506  RemoveFromAdded(todelete->first);
507 
508  Index.erase(todelete);
509  }
510  }
511 
513  template<typename... Args>
514  void ReleaseAllAndClear(Args&&... args)
515  {
516  for(auto iter = Index.begin(); iter != Index.end(); ++iter) {
517 
518  auto object = iter->second;
519 
520  object->Release(std::forward<Args>(args)...);
521 
522 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
523  object->~ElementType();
524  Elements.free(object);
525 #else
526  delete object;
527 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
528  }
529 
530  // Skip double free
531  Index.clear();
532 
533  // And then clear the rest of things
534  Clear();
535  }
536 
542  void RemoveFromAdded(KeyType id)
543  {
544  for(auto iter = Added.begin(); iter != Added.end(); ++iter) {
545 
546  if(std::get<1>(*iter) == id) {
547 
548  Added.erase(iter);
549  return;
550  }
551  }
552  }
553 
555  ElementType* Find(KeyType id) const
556  {
557  auto iter = Index.find(id);
558 
559  if(iter == Index.end())
560  return nullptr;
561 
562  return iter->second;
563  }
564 
566  void Destroy(KeyType id, bool addtoremoved = true)
567  {
568  auto object = Find(id);
569 
570  if(!object)
571  throw InvalidArgument("ID is not in index");
572 
573  _DestroyCommon(object, id, addtoremoved);
574  }
575 
577  bool DestroyIfExists(KeyType id, bool addtoremoved = true)
578  {
579  auto object = Find(id);
580 
581  if(!object)
582  return false;
583 
584  _DestroyCommon(object, id, addtoremoved);
585  return true;
586  }
587 
591  void QueueDestroy(KeyType id)
592  {
593  auto end = Index.end();
594  for(auto iter = Index.begin(); iter != end; ++iter) {
595 
596  if(iter->first == id) {
597 
598  Queued.push_back(std::make_tuple(iter->second, id));
599 
600  RemoveFromAdded(id);
601 
602  return;
603  }
604  }
605 
606  throw InvalidArgument("ID is not in index");
607  }
608 
615  void Call(std::function<bool(ElementType&, KeyType)> function)
616  {
617  for(auto iter = Index.begin(); iter != Index.end();) {
618 
619  if(function(*iter->second, iter->first)) {
620 
621 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
622  iter->second->~ElementType();
623  Elements.free(iter->second);
624 #else
625  delete iter->second;
626 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
627 
628  iter = Index.erase(iter);
629 
630  } else {
631 
632  ++iter;
633  }
634  }
635  }
636 
639  void Clear()
640  {
641  for(auto iter = Index.begin(); iter != Index.end(); ++iter) {
642 
643 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
644  iter->second->~ElementType();
645  Elements.free(iter->second);
646 #else
647  delete iter->second;
648 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
649  }
650 
651  Index.clear();
652  Removed.clear();
653  Queued.clear();
654  Added.clear();
655  }
656 
657  auto GetObjectCount() const
658  {
659  return Index.size();
660  }
661 
665  inline std::unordered_map<KeyType, ElementType*>& GetIndex()
666  {
667  return Index;
668  }
669 
670  inline auto GetIndexSize() const
671  {
672  return Index.size();
673  }
674 
680  inline ElementType* GetAtIndex(size_t index)
681  {
682  if(index >= Index.size())
683  throw InvalidArgument("index out of range");
684 
685  auto iter = Index.begin();
686 
687  for(size_t i = 0; i < index; ++i)
688  ++iter;
689  return iter->second;
690  }
691 
692 protected:
695  bool RemoveFromIndex(KeyType id)
696  {
697  auto end = Index.end();
698  for(auto iter = Index.begin(); iter != end; ++iter) {
699 
700  if(iter->first == id) {
701 
702  Index.erase(iter);
703  return true;
704  }
705  }
706 
707  return false;
708  }
709 
710  template<typename... Args>
711  void _ReleaseCommon(ElementType* object, KeyType id, bool addtoremoved, Args&&... args)
712  {
713  object->Release(std::forward<Args>(args)...);
714 
715 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
716  object->~ElementType();
717  Elements.free(object);
718 #else
719  delete object;
720 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
721 
722 
723 
724  if(addtoremoved)
725  Removed.push_back(std::make_tuple(object, id));
726 
727  RemoveFromIndex(id);
728  RemoveFromAdded(id);
729  }
730 
731  void _DestroyCommon(ElementType* object, KeyType id, bool addtoremoved)
732  {
733 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
734  object->~ElementType();
735  Elements.free(object);
736 #else
737  delete object;
738 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
739 
740  if(addtoremoved)
741  Removed.push_back(std::make_tuple(object, id));
742 
743  RemoveFromIndex(id);
744  RemoveFromAdded(id);
745  }
746 
747 protected:
749  std::unordered_map<KeyType, ElementType*> Index;
750 
754  std::vector<std::tuple<ElementType*, KeyType>> Removed;
755 
759  std::vector<std::tuple<ElementType*, KeyType>> Queued;
760 
762  std::vector<std::tuple<ElementType*, KeyType>> Added;
763 
764 #ifdef LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
765  boost::pool<> Elements;
767 #endif // LEVIATHAN_USE_ACTUAL_OBJECT_POOLS
768 };
769 
770 
771 
772 } // namespace Leviathan
auto & GetAdded()
Returns a reference to the vector of added elements.
Definition: ObjectPool.h:465
ElementType * ConstructNew(KeyType forentity, Args &&... args)
Constructs a new component of the held type for entity.
Definition: ObjectPool.h:113
ElementType * ConstructNew(KeyType forentity, Args &&... args)
Constructs a new component of the held type for entity.
Definition: ObjectPool.h:332
void Clear()
Clears the index and replaces the pool with a new one.
Definition: ObjectPool.h:249
void ClearAdded()
Clears the added list.
Definition: ObjectPool.h:471
const auto & GetRemoved() const
Returns a reference to the vector of removed elements.
Definition: ObjectPool.h:459
void ReleaseAllAndClear(Args &&... args)
Calls release on all objects and clears everything.
Definition: ObjectPool.h:514
void Destroy(KeyType id)
Destroys a component based on id.
Definition: ObjectPool.h:178
void Clear()
Clears the index and replaces the pool with a new one.
Definition: ObjectPool.h:639
std::unordered_map< KeyType, ElementType * > Index
Used for looking up element belonging to id.
Definition: ObjectPool.h:297
A tiny wrapper around boost pool.
Definition: ObjectPool.h:24
void Release(KeyType entity, Args &&... args)
Calls Release on an object and then removes it from the pool.
Definition: ObjectPool.h:146
bool RemoveFromIndex(KeyType id)
Removes an component from the index but doesn&#39;t destruct it.
Definition: ObjectPool.h:695
void RemoveFromAdded(KeyType id)
Removes a specific id from the added list.
Definition: ObjectPool.h:542
void Call(std::function< bool(ElementType &, KeyType)> function)
Calls an function on all the objects in the pool.
Definition: ObjectPool.h:225
std::unordered_map< KeyType, ElementType * > & GetIndex()
Returns a direct access to Index.
Definition: ObjectPool.h:272
void RemoveBasedOnKeyTupleList(const std::vector< std::tuple< Any, KeyType >> &values, bool addtoremoved=false)
Destroys without releasing elements based on ids in vector.
Definition: ObjectPool.h:486
Base class for all exceptions thrown by Leviathan.
Definition: Exceptions.h:10
bool HasElementsInQueued() const
Returns true if there are objects in Queued.
Definition: ObjectPool.h:379
void ReleaseQueued(Args &&... args)
Calls Release with the specified arguments on elements that are queued for destruction.
Definition: ObjectPool.h:387
boost::pool Elements
Pool for objects.
Definition: ObjectPool.h:85
void Destroy(ElementType *element)
Destroys a created element.
Definition: ObjectPool.h:62
std::unordered_map< KeyType, ElementType * > Index
Used for looking up element belonging to id.
Definition: ObjectPool.h:749
Creates objects in a shared memory region.
Definition: ObjectPool.h:312
ElementType * Find(KeyType id) const
Definition: ObjectPool.h:167
auto GetObjectCount() const
Definition: ObjectPool.h:264
bool ReleaseIfExists(KeyType id, bool addtoremoved, Args &&... args)
Calls Release on an object if it is in this pool and then removes it from the pool.
Definition: ObjectPool.h:424
void _DestroyCommon(ElementType *object, KeyType id, bool addtoremoved)
Definition: ObjectPool.h:731
void Release(KeyType id, bool addtoremoved, Args &&... args)
Calls Release on an object and then removes it from the pool.
Definition: ObjectPool.h:411
bool RemoveFromIndex(KeyType id)
Removes an component from the index but doesn&#39;t destruct it.
Definition: ObjectPool.h:280
void ClearRemoved()
Clears the removed list.
Definition: ObjectPool.h:477
void Call(std::function< bool(ElementType &, KeyType)> function)
Calls an function on all the objects in the pool.
Definition: ObjectPool.h:615
bool HasElementsInAdded() const
Returns true if there are objects in Added.
Definition: ObjectPool.h:373
void ClearQueued()
Removes elements that are queued for destruction without calling release.
Definition: ObjectPool.h:437
std::vector< std::tuple< ElementType *, KeyType > > Queued
Definition: ObjectPool.h:759
void RemoveBasedOnKeyTupleList(const std::vector< std::tuple< Any, KeyType >> &values)
Destroys without releasing elements based on ids in vector.
Definition: ObjectPool.h:198
boost::pool Elements
Pool for objects.
Definition: ObjectPool.h:766
std::vector< std::tuple< ElementType *, KeyType > > Removed
Definition: ObjectPool.h:754
ElementType * GetAtIndex(size_t index)
Returns a created object by index.
Definition: ObjectPool.h:680
ElementType * Find(KeyType id) const
Definition: ObjectPool.h:555
std::unordered_map< KeyType, ElementType * > & GetIndex()
Returns a direct access to Index.
Definition: ObjectPool.h:665
void _ReleaseCommon(ElementType *object, KeyType id, bool addtoremoved, Args &&... args)
Definition: ObjectPool.h:711
boost::pool Elements
Pool for objects.
Definition: ObjectPool.h:301
bool HasElementsInRemoved() const
Returns true if there are objects in Removed.
Definition: ObjectPool.h:367
ElementType * ConstructNew(Args &&... args)
Constructs a new component of the held type for entity.
Definition: ObjectPool.h:40
std::vector< std::tuple< ElementType *, KeyType > > Added
Used for detecting created elements.
Definition: ObjectPool.h:762
bool DestroyIfExists(KeyType id, bool addtoremoved=true)
Destroys a component based on id if exists.
Definition: ObjectPool.h:577
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
void Destroy(KeyType id, bool addtoremoved=true)
Destroys a component based on id.
Definition: ObjectPool.h:566
void QueueDestroy(KeyType id)
Queues destruction of an element.
Definition: ObjectPool.h:591
Creates objects in a shared memory region.
Definition: ObjectPool.h:93