CORGI
An open source project by FPL.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Groups Pages
vector_pool.h
Go to the documentation of this file.
1 // Copyright 2015 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef VECTOR_POOL_H
16 #define VECTOR_POOL_H
17 
18 #include <assert.h>
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <vector>
23 
24 namespace corgi {
25 
26 /// @file
27 /// @addtogroup corgi_vector_pool
28 /// @{
29 ///
30 /// @enum AllocationLocation
31 ///
32 /// @brief `kAddToFront` allocates from the front of the pool. `kAddToBack`
33 /// allocates from the back of the pool.
34 enum AllocationLocation { kAddToFront, kAddToBack };
35 
36 /// @class VectorPool
37 ///
38 /// @brief A pool allocator, implemented as a vector-based pair of linked
39 /// lists.
40 ///
41 /// @tparam T The data type of the data stored by the VectorPool.
42 template <typename T>
43 class VectorPool {
44  template <bool>
45  friend class IteratorTemplate;
46  friend class VectorPoolReference;
47  typedef uint32_t UniqueIdType;
48 
49  public:
50  template <bool>
52 
53  /// @typedef Iterator
54  ///
55  /// @brief A non-const IteratorTemplate.
56  typedef IteratorTemplate<false> Iterator;
57 
58  /// @typedef ConstIterator
59  ///
60  /// @brief A const IteratorTemplate.
61  typedef IteratorTemplate<true> ConstIterator;
62 
63  /// @class VectorPoolReference
64  ///
65  /// @brief A reference object for pointing into the vector pool.
66  /// It acts as a pointer for vector pool elements and can be queried to
67  /// check if it has become invalid. (i.e. If the element it pointed
68  /// at has either been deallocated, or replaced with a new element).
69  ///
70  /// It also correctly handles situations where the underlying vector resizes,
71  /// moving the elements around in memory.
73  friend class VectorPool<T>;
74  template <bool>
75  friend class IteratorTemplate;
76 
77  public:
78  /// @brief Default constructor for a VectorPoolReference.
79  VectorPoolReference() : container_(nullptr), index_(0), unique_id_(0) {}
80 
81  /// @brief Constructor for a VectorPoolReference given a VectorPool.
82  ///
83  /// @param[in] container A VectorPool to be referenced.
84  /// @param[in] index The index into the VectorPool's underlying vector.
86  : container_(container), index_(index) {
87  unique_id_ = container->GetElement(index)->unique_id;
88  }
89 
90  /// @brief Standard equality operator for VectorPoolReferences.
91  ///
92  /// @param[in] other The other VectorPoolReference to compare equality to.
93  ///
94  /// @return Returns true if the two VectorPoolReferences point to the same
95  /// VectorPool with the same index. Otherwise, it returns false.
96  bool operator==(const VectorPoolReference& other) const {
97  return container_ == other.container_ && index_ == other.index_;
98  }
99 
100  /// @brief Standard inequality operator for VectorPoolReferences.
101  ///
102  /// @param[in] other The other VectorPoolReference to compare in-equality
103  /// to.
104  ///
105  /// @return Returns false if the two VectorPoolReferences point to the same
106  /// VectorPool with the same index. Otherwise, it returns true.
107  bool operator!=(const VectorPoolReference& other) const {
108  return !operator==(other);
109  }
110 
111  /// @brief Verifies that the reference is still valid.
112  ///
113  /// @return Will return false if the object pointed to has been freed,
114  /// even if the location was later filled with a new object.
115  bool IsValid() const {
116  return container_ != nullptr &&
117  (container_->GetElement(index_)->unique_id == unique_id_);
118  }
119 
120  /// @brief An alternate way to check to make sure the reference is still
121  /// valid.
122  ///
123  /// This is similar to most smart pointer types, which supply an
124  /// operator bool as syntactic sugar to check if they are nullptrs.
125  ///
126  /// @return Will return false if the object pointed to has been freed,
127  /// even if the location was later filled with a new object.
128  operator bool() const { return IsValid(); }
129 
130  /// @brief The member access operator.
131  ///
132  /// @warning Throws an assert if the VectorPoolReference is no longer valid.
133  /// (i.e. If something has deleted the thing we were pointing to.)
134  ///
135  /// @return Returns a pointer to the data that the VectorPoolReference
136  /// is referring to, allowing you to use VectorPoolReferences like
137  /// pointers, syntactically.
138  /// (e.g. myVectorPoolReference->MyDataMember = x;)
139  T* operator->() {
140  assert(IsValid());
141  VectorPoolElement* element = container_->GetElement(index_);
142  return &(element->data);
143  }
144 
145  /// @brief Const member access operator.
146  ///
147  /// @warning Throws an assert if the VectorPoolReference is no longer valid.
148  /// (i.e. If something has deleted the thing we were pointing to).
149  ///
150  /// @return Returns a pointer to the data that the VectorPoolReference
151  /// is referring to, allowing you to use VectorPoolReferences like
152  /// pointers, syntactically.
153  /// (e.g. x = myVectorPoolReference->MyDataMember;)
154  const T* operator->() const {
155  return const_cast<VectorPoolReference*>(this)->operator->();
156  }
157 
158  /// @brief The dereference operator.
159  ///
160  /// @warning Throws an assert if the VectorPoolReference is no longer valid.
161  /// (i.e. If something has deleted the thing we are pointing to).
162  ///
163  /// @return Returns a reference variable for the data the
164  /// VectorPoolReference points to, allowing you to use VectorPoolReference
165  /// like a pointer. (e.g. MyDataVariable = (*MyVectorPoolReference);)
166  T& operator*() {
167  assert(IsValid());
168  VectorPoolElement* element = container_->GetElement(index_);
169  return element->data;
170  }
171 
172  /// @brief The const dereference operator.
173  ///
174  /// @note Throws an assert if the VectorPoolReference is no longer valid.
175  /// (i.e. If something has deleted the thing we are pointing to).
176  ///
177  /// @return Returns a const reference variable for the data the
178  /// VectorPoolReference points to, allowing you to use VectorPoolReference
179  /// like a pointer. (e.g. MyDataVariable = (*MyVectorPoolReference);)
180  const T& operator*() const {
181  return const_cast<VectorPoolReference*>(this)->operator*();
182  }
183 
184  /// @brief Get a direct pointer to the element the VectorPoolReference
185  /// is referring to.
186  ///
187  /// @note This pointer is not guaranteed to remain valid, since the vector
188  /// may need to relocate the data in memory. It is recommended that when
189  /// working with data, it be left as a VectorPoolReference, and only
190  /// converted to a pointer when needed.
191  ///
192  /// @return Returns a pointer to the element that the VectorPoolReference
193  /// is referring to. If the VectorPoolReference is not referring to any
194  /// data, it returns a nullptr.
195  T* ToPointer() {
196  return IsValid() ? &(container_->GetElement(index_)->data) : nullptr;
197  }
198 
199  /// @brief Get a direct pointer to the element the
200  /// VectorPoolReference is referring to.
201  ///
202  /// @note This pointer is not guaranteed to remain valid, since the vector
203  /// may need to relocate the data in memory. It is recommended that when
204  /// working with data, it be left as a VectorPoolReference, and only
205  /// converted to a pointer when needed.
206  ///
207  /// @return Returns a const pointer to the element that the
208  /// VectorPoolReference is referring to. If the VectorPoolReference
209  /// is not referring to any data, it returns a nullptr.
210  const T* ToPointer() const {
211  return const_cast<VectorPoolReference*>(this)->ToPointer();
212  }
213 
214  /// @brief Get an iterator that points to the element referenced by
215  /// the VectorPoolReference.
216  ///
217  /// @return Returns an Iterator that points to the element referenced
218  /// by the VectorPoolReference.
219  Iterator ToIterator() const { return Iterator(container_, index_); }
220 
221  /// @brief Get the raw index into the underlying vector for this object.
222  ///
223  /// @return Returns a size_t corresponding to the index into the underlying
224  /// vector.
225  size_t index() const { return index_; }
226 
227  /// @brief Gets a pointer to the underlying vector for this object.
228  ///
229  /// @return Returns a VectorPool pointer to the underlying vector.
230  VectorPool<T>* container() const { return container_; }
231 
232  private:
233  VectorPool<T>* container_;
234  size_t index_;
235  UniqueIdType unique_id_;
236  };
237 
238  // ---------------------------
239  /// @class IteratorTemplate
240  ///
241  /// @brief An Iterator for the VectorPool.
242  ///
243  /// This has constant-time access, so it is a good choice for iterating
244  /// over the active elements that the pool owns.
245  ///
246  /// @tparam is_const A bool that determines if the IteratorTemplate should
247  /// be defined as const.
248  template <bool is_const>
249  class IteratorTemplate {
250  /// @typedef reference
251  ///
252  /// @brief A reference that may be const, depending on the templated
253  /// boolean provided to the IteratorTemplate<bool>.
254  typedef typename std::conditional<is_const, const T&, T&>::type reference;
255 
256  /// @typedef pointer
257  ///
258  /// @brief A pointer that may be const, depending on the templated
259  /// boolean provided to the IteratorTemplate<bool>.
260  typedef typename std::conditional<is_const, const T*, T*>::type pointer;
261 
262  friend class VectorPool<T>;
263 
264  public:
265  /// @brief Constructor for an IteratorTemplate to a given VectorPool
266  /// index.
267  ///
268  /// @param[in] container The VectorPool to point to.
269  /// @param[in] index The index into the VectorPool's underlying vector.
271  : container_(container), index_(index) {}
272 
273  /// @brief Destructor for an IteratorTemplate.
275 
276  /// @brief The standard equality operator to compare two
277  /// IteratorTemplates.
278  ///
279  /// @param[in] other The other IteratorTemplate to compare with
280  /// to check for equality.
281  ///
282  /// @return Returns true if the IteratorTemplate references the
283  /// same index into the same VectorPool. Otherwise, it returns
284  /// false.
285  bool operator==(const IteratorTemplate& other) const {
286  return container_ == other.container_ && index_ == other.index_;
287  }
288 
289  /// @brief The standard inequality operator to compare two
290  /// IteratorTemplates.
291  ///
292  /// @param[in] other The other IteratorTemplate to compare with
293  /// to check for inequality.
294  ///
295  /// @return Returns false if the IteratorTemplate references the
296  /// same index into the same VectorPool. Otherwise, it returns
297  /// true.
298  bool operator!=(const IteratorTemplate& other) const {
299  return !operator==(other);
300  }
301 
302  /// @brief The prefix increment operator to move the iterator
303  /// forward in the list.
304  ///
305  /// @return Returns a reference to the incremented iterator.
307  index_ = container_->elements_[index_].next;
308  return (*this);
309  }
310 
311  /// @brief The postfix increment operator to move the iterator
312  /// forward in the list.
313  ///
314  /// @return Returns a reference to the original, unincremented iterator.
316  IteratorTemplate temp = *this;
317  ++(*this);
318  return temp;
319  }
320 
321  /// @brief The prefix decrement operator to move the iterator
322  /// backward in the list.
323  ///
324  /// @return Returns a reference to the decremented iterator.
326  index_ = container_->elements_[index_].prev;
327  return (*this);
328  }
329 
330  /// @brief The postfix decrement operator to move the iterator
331  /// backward in the list.
332  ///
333  /// @return Returns a reference to the original, undecremented iterator.
335  IteratorTemplate temp = *this;
336  --(*this);
337  return temp;
338  }
339 
340  /// @brief The dereference operator.
341  ///
342  /// @return Returns a reference to the VectorPool data referenced by the
343  /// Iterator.
344  reference operator*() { return *(container_->GetElementData(index_)); }
345 
346  /// @brief Member access on the iterator.
347  ///
348  /// @return Returns a pointer to the VectorPool data referenced by the
349  /// Iterator.
350  pointer operator->() { return container_->GetElementData(index_); }
351 
352  /// @brief Converts the Iterator into a VectorPoolReference, which is
353  /// the preferred way for holding onto references into the VectorPool.
354  ///
355  /// @return Returns a VectorPoolReference pointing to the VectorPool
356  /// at the index that the Iterator referred to.
358  return VectorPoolReference(container_, index_);
359  }
360 
361  /// @brief Get the index into the VectorPool vector.
362  ///
363  /// @return Returns a size_t that represents the underlying index into the
364  /// VectorPool vector that the Iterator refers to.
365  size_t index() const { return index_; }
366 
367  private:
368  VectorPool<T>* container_;
369  size_t index_;
370  };
371 
372  // ---------------------------
373 
374  /// @var kOutOfBounds
375  ///
376  /// @brief A sentinel value that represents an out-of-bounds index.
377  static const size_t kOutOfBounds = static_cast<size_t>(-1);
378 
379  /// @var kInvalidId
380  ///
381  /// @brief A sentinel value that represents an invalid ID.
382  ///
383  /// @note Unique IDs start at 1.
384  static const UniqueIdType kInvalidId = 0;
385 
386  /// @struct VectorPoolElement
387  ///
388  /// @brief A struct representing an element inside of a VectorPool.
390  /// @brief The default constructor for an empty VectorPoolElement.
393 
394  /// @brief The standard operator to move a referenced
395  /// VectorPoolElement into this VectorPoolElement.
396  ///
397  /// @param[in] src A referenced VectorPoolElement to move
398  /// into this VectorPoolElement.
400  next = std::move(src.next);
401  prev = std::move(src.prev);
402  unique_id = std::move(src.unique_id);
403  data = std::move(src.data);
404  return *this;
405  }
406 
407  /// @brief A copy constructor to create a VectorPoolElement from an
408  /// existing VectorPoolElement.
409  ///
410  /// @param[in] src An existing VectorPoolElement to copy into
411  /// this VectorPoolElement.
413  next = std::move(src.next);
414  prev = std::move(src.prev);
415  unique_id = std::move(src.unique_id);
416  data = std::move(src.data);
417  }
418 
419  /// @var data
420  ///
421  /// @brief Holds the data within a VectorPoolElement.
422  T data;
423 
424  /// @var next
425  ///
426  /// @brief The index of the next element in the vector.
427  size_t next;
428 
429  /// @var prev
430  ///
431  /// @brief The index of the previous element in the vector.
432  size_t prev;
433 
434  /// @var unique_id
435  ///
436  /// @brief The unique ID of this VectorPoolElement.
437  UniqueIdType unique_id;
438 
439  private:
442  };
443 
444  /// @var kFirstUsed
445  ///
446  /// @brief Used to demarcate the first element of our used list.
447  ///
448  /// @note This is never given actual data. It is only used for list
449  /// demarcation.
450  static const size_t kFirstUsed = 0;
451 
452  /// @var kLastUsed
453  ///
454  /// @brief Used to demarcate the last element of our used list.
455  ///
456  /// @note This is never given actual data. It is only used for list
457  /// demarcation.
458  static const size_t kLastUsed = 1;
459 
460  /// @var kFirstFree
461  ///
462  /// @brief Used to demarcate the first element of our free list.
463  ///
464  /// @note This is never given actual data. It is only used for list
465  /// demarcation.
466  static const size_t kFirstFree = 2;
467 
468  /// @var kLastFree
469  ///
470  /// @brief Used to demarcate the last element of our free list.
471  ///
472  /// @note This is never given actual data. It is only used for list
473  /// demarcation.
474  static const size_t kLastFree = 3;
475 
476  /// @var kTotalReserved
477  ///
478  /// @brief Used to indicate the number of reserved elements.
479  /// (e.g. kFirstUsed, kLastUsed, kFirstFree, kLastFree).
480  static const size_t kTotalReserved = 4;
481 
482  /// @brief The default constructor for an empty VectorPool.
483  VectorPool() : active_count_(0), next_unique_id_(kInvalidId + 1) { Clear(); }
484 
485  /// @brief Get the data at the given element index.
486  ///
487  /// @note The pointer is not guaranteed to remain valid, if the vector
488  /// needs to relocate the data in memory. In general, if you need to hold
489  /// on to a reference to a data element, it is recommended that you use
490  /// a VectorPoolReference.
491  ///
492  /// @warning Asserts if the index is illegal (i.e. out of range for the
493  /// underlying vector).
494  ///
495  /// @param[in] index The index of the data element to return.
496  ///
497  /// @return Returns a pointer to the data.
498  T* GetElementData(size_t index) {
499  assert(index < elements_.size());
500  return (&elements_[index].data);
501  }
502 
503  /// @brief Get the data at the given element index.
504  ///
505  /// @note The pointer is not guaranteed to remain valid, if the vector
506  /// needs to relocate the data in memory. In general, if you need to hold
507  /// on to a reference to a data element, it is recommended that you use
508  /// a VectorPoolReference.
509  ///
510  /// @warning Asserts if the index is illegal (i.e. out of range for the
511  /// underlying vector).
512  ///
513  /// @param[in] index The index of the data element to return.
514  ///
515  /// @return Returns a const pointer to the data.
516  const T* GetElementData(size_t index) const {
517  assert(index < elements_.size());
518  return (&elements_[index].data);
519  }
520 
521  /// @brief Get a VectorPoolReference to a new element.
522  ///
523  /// @note This function grabs the first free element (if one exists).
524  /// Otherwise, it allocates a new one on the underlying vector.
525  ///
526  /// @param[in] alloc_location An AllocationLocation enum determining whether
527  /// to add to the front or back of the underlying vector.
528  ///
529  /// @return Returns a VectorPoolReference pointing to the new element.
530  VectorPoolReference GetNewElement(AllocationLocation alloc_location) {
531  size_t index;
532  if (elements_[kFirstFree].next != kLastFree) {
533  index = elements_[kFirstFree].next;
534  RemoveFromList(index); // remove it from the list of free elements.
535  } else {
536  index = elements_.size();
537  elements_.push_back(VectorPoolElement());
538  }
539  switch (alloc_location) {
540  case kAddToFront:
541  AddToListFront(index, kFirstUsed);
542  break;
543  case kAddToBack:
544  AddToListBack(index, kLastUsed);
545  break;
546  default:
547  assert(0);
548  }
549  active_count_++;
550  // Placement new, to make sure we always give back a cleanly constructed
551  // element:
552  elements_[index].data.~T();
553  new (&(elements_[index].data)) T;
554  elements_[index].unique_id = AllocateUniqueId();
555  return VectorPoolReference(this, index);
556  }
557 
558  /// @brief Frees an element at a given index.
559  ///
560  /// @note This removes the element from the list of active elements, and
561  /// adds it to the front of the inactive list (to be used later, when we
562  /// add elements to the VectorPool).
563  ///
564  /// @param[in] index The index corresponding to the element that should be
565  /// freed.
566  void FreeElement(size_t index) {
567  assert(elements_[index].unique_id != kInvalidId);
568  // Don't call the destructor directly - instead, assign over it.
569  // This ensures that data will always contain an object that is safe to
570  // destruct.
571  elements_[index].data.~T();
572  new (&(elements_[index].data)) T;
573  elements_[index].unique_id = kInvalidId;
574  RemoveFromList(index);
575  AddToListFront(index, kFirstFree);
576  active_count_--;
577  }
578 
579  /// @brief Frees a given element.
580  ///
581  /// @note This removes the element from the list of active elements, and
582  /// adds it to the front of the inactive list (to be used later, when we
583  /// add elements to the VectorPool).
584  ///
585  /// @param[in] element A VectorPoolReference to the element that should be
586  /// freed.
587  void FreeElement(VectorPoolReference element) {
588  if (element.IsValid()) {
589  FreeElement(element.index_);
590  }
591  }
592 
593  /// @ Frees an element that an Iterator points to.
594  ///
595  /// @note This removes the element from the list of active elements, and
596  /// adds it to the front of the inactive list (to be used later, when we
597  /// add elements to the VectorPool).
598  ///
599  /// @param[in] iter An Iterator that references an element that should be
600  /// freed.
601  ///
602  /// @return Returns an incremented Iterator that refers to the element
603  /// immediately after the freed element.
605  Iterator temp = iter++;
606  FreeElement(temp.index_);
607  return iter;
608  }
609 
610  /// @brief Get the total size of the vector pool.
611  ///
612  /// This is the total number of allocated elements (used AND free) by the
613  /// underlying vector.
614  ///
615  /// @return A size_t representing the total size of the VectorPool (both
616  /// used AND free elements).
617  size_t Size() const { return elements_.size(); }
618 
619  /// @brief Gets the total number of active elements.
620  ///
621  /// @return A size_t representing the total number of active elements in the
622  /// VectorPool.
623  size_t active_count() const { return active_count_; }
624 
625  /// @brief Clears out all of the elements in the VectorPool and resizes
626  /// the underlying vector to the minimum size.
627  void Clear() {
628  elements_.resize(kTotalReserved);
629  elements_[kFirstUsed].next = kLastUsed;
630  elements_[kLastUsed].prev = kFirstUsed;
631  elements_[kFirstFree].next = kLastFree;
632  elements_[kLastFree].prev = kFirstFree;
633  active_count_ = 0;
634  }
635 
636  /// @brief Get an Iterator to the first active element in the VectorPool.
637  ///
638  /// This is suitable for traversing all of the active elements in the
639  /// VectorPool.
640  ///
641  /// @return Returns an Iterator to the first active element in the VectorPool.
642  Iterator begin() { return Iterator(this, elements_[kFirstUsed].next); }
643 
644  /// @brief Gets an Iterator to the last active element in the VectorPool.
645  ///
646  /// This is suitable as an end condition when iterating over all active
647  /// elements in the VectorPool.
648  ///
649  /// @return Returns An Iterator to the last active element in the VectorPool.
650  Iterator end() { return Iterator(this, kLastUsed); }
651 
652  /// @brief Gets a ConstIterator to the first active element in the
653  /// VectorPool.
654  ///
655  /// This is suitable for traversing all of the active elements in the
656  /// VectorPool.
657  ///
658  /// @return Returns a ConstIterator to the first active element in the
659  /// VectorPool.
661  return ConstIterator(this, elements_[kFirstUsed].next);
662  }
663 
664  /// @brief Gets a ConstIterator to the last active element in the VectorPool.
665  ///
666  /// This is suitable as an end condition when iterating over all active
667  /// elements in the VectorPool.
668  ///
669  /// @return Returns a ConstIterator to the last active element in the
670  /// VectorPool.
672 
673  /// @brief Expands the vector until it is at least as large as new_size.
674  ///
675  /// @note: If the vector already contains at least new_size elements,
676  /// then there is no effect.
677  ///
678  /// @param[in] new_size A size_t indicating the new minimum size for the
679  /// underlying vector.
680  void Reserve(size_t new_size) {
681  size_t current_size = elements_.size();
682  if (current_size >= new_size) return;
683 
684  elements_.resize(new_size);
685  for (; current_size < new_size; current_size++) {
686  elements_[current_size].unique_id = kInvalidId;
687  AddToListFront(current_size, kFirstFree);
688  }
689  }
690 
691  private:
692  /// @brief A utility function for removing an element from whatever list
693  /// it is a part of.
694  ///
695  /// @note This should always be followed by AddToList, to reassign it, so we
696  /// don't lose track of the element.
697  ///
698  /// @param[in] index A size_t representing the index of the element to be
699  /// removed from whatever list it is a part of.
700  void RemoveFromList(size_t index) {
701  assert(index < elements_.size() && index >= kTotalReserved);
702  VectorPoolElement& element = elements_[index];
703  elements_[element.prev].next = element.next;
704  elements_[element.next].prev = element.prev;
705  }
706 
707  /// @brief A utility function to add an element to the front of a list.
708  ///
709  /// @note It adds it to whichever list is specified.
710  ///
711  /// @param[in] index A size_t representing the index of the element
712  /// to be added to the specified list.
713  /// @param[in] start_index The start of the list that the element
714  /// should be added to (usually either kFirstUsed or kFirstFree).
715  void AddToListFront(size_t index, size_t start_index) {
716  assert(index < elements_.size() && index >= kTotalReserved);
717  VectorPoolElement& list_start = elements_[start_index];
718  elements_[list_start.next].prev = index;
719  elements_[index].prev = start_index;
720  elements_[index].next = list_start.next;
721  list_start.next = index;
722  }
723 
724  /// @brief A utility function to add an element to the back of a list.
725  ///
726  /// @note It adds it to whichever list is specified.
727  ///
728  /// @param[in] index A size_t representing the index of the element
729  /// to be added to the specified list.
730  /// @param[in] end_index The end of the list that the element
731  /// should be added to (usually either kLastUsed or kLastFree).
732  void AddToListBack(size_t index, size_t end_index) {
733  assert(index < elements_.size() && index >= kTotalReserved);
734  VectorPoolElement& list_end = elements_[end_index];
735  elements_[list_end.prev].next = index;
736  elements_[index].next = end_index;
737  elements_[index].prev = list_end.prev;
738  list_end.prev = index;
739  }
740 
741  /// @brief Get an element at a given index.
742  ///
743  /// @note This is different from GetElementData, in that this function
744  /// returns a pointer to the full VectorPoolElement (as opposed to just
745  /// the user data).
746  ///
747  /// @param[in] index A size_t representing the index of the VectorPoolElement
748  /// to be returned.
749  ///
750  /// @return Returns a VectorPoolElement pointer to the element at the given
751  /// index.
752  VectorPoolElement* GetElement(size_t index) {
753  return index < elements_.size() ? &elements_[index] : nullptr;
754  }
755 
756  /// @brief Get an element at a given index.
757  ///
758  /// @note This is different from GetElementData, in that this function
759  /// returns a pointer to the full VectorPoolElement (as opposed to just
760  /// the user data).
761  ///
762  /// @param[in] index A size_t representing the index of the VectorPoolElement
763  /// to be returned.
764  ///
765  /// @return Returns a VectorPoolElement const pointer to the element at the
766  /// given index.
767  const VectorPoolElement* GetElement(size_t index) const {
768  return index < elements_.size() ? &elements_[index] : nullptr;
769  }
770 
771  /// @brief Allocates a unique ID.
772  ///
773  /// This is usually used when a new element is allocated.
774  ///
775  /// @warning Since the unique ID is done by simply allocating a counter, it
776  /// is theoretically possible that this function could wrap around
777  /// (especially if something has kept a constant reference for the duration
778  /// of the program). This would cause a lot of things to malfunction, so
779  /// ideally, do not use this class in situations where there are likely to
780  /// be over 4,294,967,295 allocations. (Or change the UniqueTypeID into an
781  /// uint_64 or something larger.)
782  ///
783  /// @return Returns a UniqueIdType representing the unique ID that
784  /// was generated.
785  UniqueIdType AllocateUniqueId() {
786  // untility function to make sure it rolls over correctly.
787  UniqueIdType result = next_unique_id_;
788  next_unique_id_++;
789  if (next_unique_id_ == kInvalidId) next_unique_id_++;
790  return result;
791  }
792 
793  std::vector<VectorPoolElement> elements_;
794  size_t active_count_;
795  UniqueIdType next_unique_id_;
796 };
797 /// @}
798 
799 } // corgi
800 
801 #endif // VECTOR_POOL_H
VectorPoolReference(VectorPool< T > *container, size_t index)
Constructor for a VectorPoolReference given a VectorPool.
Definition: vector_pool.h:85
const T * ToPointer() const
Get a direct pointer to the element the VectorPoolReference is referring to.
Definition: vector_pool.h:210
IteratorTemplate< false > Iterator
A non-const IteratorTemplate.
Definition: vector_pool.h:56
VectorPool< T > * container() const
Gets a pointer to the underlying vector for this object.
Definition: vector_pool.h:230
Iterator begin()
Get an Iterator to the first active element in the VectorPool.
Definition: vector_pool.h:642
size_t index() const
Get the raw index into the underlying vector for this object.
Definition: vector_pool.h:225
pointer operator->()
Member access on the iterator.
Definition: vector_pool.h:350
static const size_t kLastFree
Used to demarcate the last element of our free list.
Definition: vector_pool.h:474
VectorPoolReference ToReference() const
Converts the Iterator into a VectorPoolReference, which is the preferred way for holding onto referen...
Definition: vector_pool.h:357
IteratorTemplate & operator++()
The prefix increment operator to move the iterator forward in the list.
Definition: vector_pool.h:306
IteratorTemplate & operator--()
The prefix decrement operator to move the iterator backward in the list.
Definition: vector_pool.h:325
static const size_t kFirstFree
Used to demarcate the first element of our free list.
Definition: vector_pool.h:466
VectorPoolReference GetNewElement(AllocationLocation alloc_location)
Get a VectorPoolReference to a new element.
Definition: vector_pool.h:530
IteratorTemplate(VectorPool< T > *container, size_t index)
Constructor for an IteratorTemplate to a given VectorPool index.
Definition: vector_pool.h:270
ConstIterator cbegin()
Gets a ConstIterator to the first active element in the VectorPool.
Definition: vector_pool.h:660
size_t active_count() const
Gets the total number of active elements.
Definition: vector_pool.h:623
VectorPoolElement()
The default constructor for an empty VectorPoolElement.
Definition: vector_pool.h:391
IteratorTemplate< true > ConstIterator
A const IteratorTemplate.
Definition: vector_pool.h:61
VectorPool()
The default constructor for an empty VectorPool.
Definition: vector_pool.h:483
size_t next
The index of the next element in the vector.
Definition: vector_pool.h:427
size_t index() const
Get the index into the VectorPool vector.
Definition: vector_pool.h:365
static const size_t kLastUsed
Used to demarcate the last element of our used list.
Definition: vector_pool.h:458
const T * operator->() const
Const member access operator.
Definition: vector_pool.h:154
size_t Size() const
Get the total size of the vector pool.
Definition: vector_pool.h:617
VectorPoolReference()
Default constructor for a VectorPoolReference.
Definition: vector_pool.h:79
Iterator FreeElement(Iterator iter)
Definition: vector_pool.h:604
VectorPoolElement & operator=(VectorPoolElement &&src)
The standard operator to move a referenced VectorPoolElement into this VectorPoolElement.
Definition: vector_pool.h:399
static const size_t kFirstUsed
Used to demarcate the first element of our used list.
Definition: vector_pool.h:450
bool operator!=(const VectorPoolReference &other) const
Standard inequality operator for VectorPoolReferences.
Definition: vector_pool.h:107
ConstIterator cend()
Gets a ConstIterator to the last active element in the VectorPool.
Definition: vector_pool.h:671
static const size_t kOutOfBounds
A sentinel value that represents an out-of-bounds index.
Definition: vector_pool.h:377
void FreeElement(VectorPoolReference element)
Frees a given element.
Definition: vector_pool.h:587
IteratorTemplate operator++(int)
The postfix increment operator to move the iterator forward in the list.
Definition: vector_pool.h:315
AllocationLocation
kAddToFront allocates from the front of the pool. kAddToBack allocates from the back of the pool...
Definition: vector_pool.h:34
Iterator end()
Gets an Iterator to the last active element in the VectorPool.
Definition: vector_pool.h:650
A pool allocator, implemented as a vector-based pair of linked lists.
Definition: vector_pool.h:43
UniqueIdType unique_id
The unique ID of this VectorPoolElement.
Definition: vector_pool.h:437
T data
Holds the data within a VectorPoolElement.
Definition: vector_pool.h:422
Iterator ToIterator() const
Get an iterator that points to the element referenced by the VectorPoolReference. ...
Definition: vector_pool.h:219
bool operator!=(const IteratorTemplate &other) const
The standard inequality operator to compare two IteratorTemplates.
Definition: vector_pool.h:298
static const size_t kTotalReserved
Used to indicate the number of reserved elements. (e.g. kFirstUsed, kLastUsed, kFirstFree, kLastFree).
Definition: vector_pool.h:480
const T * GetElementData(size_t index) const
Get the data at the given element index.
Definition: vector_pool.h:516
VectorPoolElement(VectorPoolElement &&src)
A copy constructor to create a VectorPoolElement from an existing VectorPoolElement.
Definition: vector_pool.h:412
A reference object for pointing into the vector pool. It acts as a pointer for vector pool elements a...
Definition: vector_pool.h:72
T * ToPointer()
Get a direct pointer to the element the VectorPoolReference is referring to.
Definition: vector_pool.h:195
T * operator->()
The member access operator.
Definition: vector_pool.h:139
~IteratorTemplate()
Destructor for an IteratorTemplate.
Definition: vector_pool.h:274
IteratorTemplate operator--(int)
The postfix decrement operator to move the iterator backward in the list.
Definition: vector_pool.h:334
bool operator==(const VectorPoolReference &other) const
Standard equality operator for VectorPoolReferences.
Definition: vector_pool.h:96
bool operator==(const IteratorTemplate &other) const
The standard equality operator to compare two IteratorTemplates.
Definition: vector_pool.h:285
void FreeElement(size_t index)
Frees an element at a given index.
Definition: vector_pool.h:566
static const UniqueIdType kInvalidId
A sentinel value that represents an invalid ID.
Definition: vector_pool.h:384
size_t prev
The index of the previous element in the vector.
Definition: vector_pool.h:432
An Iterator for the VectorPool.
Definition: vector_pool.h:51
void Reserve(size_t new_size)
Expands the vector until it is at least as large as new_size.
Definition: vector_pool.h:680
A struct representing an element inside of a VectorPool.
Definition: vector_pool.h:389
bool IsValid() const
Verifies that the reference is still valid.
Definition: vector_pool.h:115
T & operator*()
The dereference operator.
Definition: vector_pool.h:166
const T & operator*() const
The const dereference operator.
Definition: vector_pool.h:180
T * GetElementData(size_t index)
Get the data at the given element index.
Definition: vector_pool.h:498
reference operator*()
The dereference operator.
Definition: vector_pool.h:344
void Clear()
Clears out all of the elements in the VectorPool and resizes the underlying vector to the minimum siz...
Definition: vector_pool.h:627