MxEngine
VectorPool.h
1 // Copyright(c) 2019 - 2020, #Momo
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met :
6 //
7 // 1. Redistributions of source code must retain the above copyright notice, this
8 // list of conditions and the following disclaimer.
9 //
10 // 2. Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and /or other materials provided with the distribution.
13 //
14 // 3. Neither the name of the copyright holder nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #pragma once
30 
31 #include "Utilities/STL/MxVector.h"
32 #include "Utilities/Memory/PoolAllocator.h"
33 
34 namespace MxEngine
35 {
41  template<typename T, template<typename> typename Container = MxVector>
42  class VectorPool
43  {
44  public:
50  {
54  size_t index = 0;
58  VectorPool<T, Container>& poolRef;
59  public:
60  size_t GetBase() const
61  {
62  return index;
63  }
64 
65  VectorPool<T, Container>& GetPoolRef()
66  {
67  return poolRef;
68  }
69 
76  : index(index), poolRef(ref)
77  {
78  while (this->index < this->poolRef.Capacity() && !poolRef.IsAllocated(this->index))
79  {
80  this->index++; // 0 element may not exists, so we should skip it until find any allocated
81  }
82  }
83 
89  {
90  PoolIterator copy = *this;
91  ++(*this);
92  return copy;
93  }
94 
100  {
101  do { index++; } while (index < poolRef.Capacity() && !poolRef.IsAllocated(index));
102  return *this;
103  }
104 
110  {
111  PoolIterator copy = *this;
112  --(*this);
113  return copy;
114  }
115 
121  {
122  do { index--; } while (index < poolRef.Capacity() && !poolRef.IsAllocated(index));
123  return *this;
124  }
125 
131  {
132  return &poolRef[index];
133  }
134 
139  const T* operator->() const
140  {
141  return &poolRef[index];
142  }
143 
149  {
150  return poolRef[index];
151  }
152 
157  const T& operator*() const
158  {
159  return poolRef[index];
160  }
161 
166  bool operator==(const PoolIterator& it) const
167  {
168  return (index == it.index) && (&poolRef == &it.poolRef);
169  }
170 
175  bool operator!=(const PoolIterator& it) const
176  {
177  return !(*this == it);
178  }
179  };
180 
181  using Allocator = PoolAllocator<T>;
182  using Block = typename Allocator::Block;
183  private:
187  Container<uint8_t> memoryStorage;
191  Allocator allocator;
195  size_t allocated = 0;
196 
197  Block* GetBlockByIndex(size_t index)
198  {
199  size_t byteIndex = index * sizeof(Block);
200  MX_ASSERT(byteIndex < memoryStorage.size());
201  return (Block*)(memoryStorage.data() + byteIndex);
202  }
203 
204  const Block* GetBlockByIndex(size_t index) const
205  {
206  size_t byteIndex = index * sizeof(Block);
207  MX_ASSERT(byteIndex < memoryStorage.size());
208  return (Block*)(memoryStorage.data() + byteIndex);
209  }
210  public:
214  VectorPool() = default;
215 
220  VectorPool(size_t count)
221  {
222  this->Resize(count);
223  }
224 
229  void Resize(size_t count)
230  {
231  if (count <= this->Capacity()) return;
232 
233  Container<uint8_t> newMemory(count * sizeof(Block));
234  allocator.Transfer(newMemory.data(), newMemory.size());
235  memoryStorage = std::move(newMemory);
236  }
237 
242  size_t Allocated() const
243  {
244  return this->allocated;
245  }
246 
251  size_t Capacity() const
252  {
253  return memoryStorage.size() / sizeof(Block);
254  }
255 
260  T& operator[] (size_t index)
261  {
262  return GetBlockByIndex(index)->data;
263  }
264 
269  const T& operator[] (size_t index) const
270  {
271  return GetBlockByIndex(index)->data;
272  }
273 
277  void Clear()
278  {
279  allocator.~PoolAllocator();
280  memoryStorage.clear();
281  }
282 
288  bool IsAllocated(size_t index)
289  {
290  return !GetBlockByIndex(index)->IsFree();
291  }
292 
297  void Deallocate(size_t index)
298  {
299  if (IsAllocated(index))
300  {
301  T& ptr = GetBlockByIndex(index)->data;
302  allocator.Free(&ptr);
303  this->allocated--;
304  }
305  }
306 
307  void Deallocate(const PoolIterator& it)
308  {
309  this->Deallocate(it.GetBase());
310  }
311 
317  template<typename... Args>
318  size_t Allocate(Args&&... args)
319  {
320  if (this->allocated == this->Capacity())
321  {
322  size_t newSize = (this->allocated + 1) * 3 / 2;
323  this->Resize(newSize);
324  }
325 
326  T* obj = allocator.Alloc(std::forward<Args>(args)...);
327  this->allocated++;
328  return this->IndexOf(*obj);
329  }
330 
337  size_t IndexOf(const T& obj)
338  {
339  const uint8_t* ptr = (uint8_t*)&obj - offsetof(Block, data);
340  MX_ASSERT(memoryStorage.data() <= ptr && ptr < memoryStorage.data() + memoryStorage.size());
341  return (Block*)ptr - (Block*)memoryStorage.data();
342  }
343 
349  {
350  return PoolIterator{ 0, *this };
351  }
352 
357  const PoolIterator begin() const
358  {
359  return PoolIterator{ 0, *this };
360  }
361 
367  {
368  return PoolIterator{ this->Capacity(), *this };
369  }
370 
375  const PoolIterator end() const
376  {
377  return PoolIterator{ this->Capacity(), *this };
378  }
379  };
380 }
const PoolIterator begin() const
Definition: VectorPool.h:357
void Deallocate(size_t index)
Definition: VectorPool.h:297
Definition: VectorPool.h:49
bool operator!=(const PoolIterator &it) const
Definition: VectorPool.h:175
void Transfer(DataPointer newData, size_t newBytes)
Definition: PoolAllocator.h:114
void Clear()
Definition: VectorPool.h:277
PoolIterator(size_t index, VectorPool< T, Container > &ref)
Definition: VectorPool.h:75
~PoolAllocator()
Definition: PoolAllocator.h:154
bool IsAllocated(size_t index)
Definition: VectorPool.h:288
T * operator->()
Definition: VectorPool.h:130
const PoolIterator end() const
Definition: VectorPool.h:375
size_t Allocated() const
Definition: VectorPool.h:242
void Resize(size_t count)
Definition: VectorPool.h:229
Definition: PoolAllocator.h:25
bool operator==(const PoolIterator &it) const
Definition: VectorPool.h:166
PoolIterator begin()
Definition: VectorPool.h:348
Definition: VectorPool.h:42
PoolIterator operator--(int)
Definition: VectorPool.h:109
T & operator*()
Definition: VectorPool.h:148
Definition: PoolAllocator.h:19
size_t Allocate(Args &&... args)
Definition: VectorPool.h:318
PoolIterator operator--()
Definition: VectorPool.h:120
size_t IndexOf(const T &obj)
Definition: VectorPool.h:337
T * Alloc(Args &&... args)
Definition: PoolAllocator.h:188
VectorPool(size_t count)
Definition: VectorPool.h:220
PoolIterator operator++()
Definition: VectorPool.h:99
size_t Capacity() const
Definition: VectorPool.h:251
T & operator[](size_t index)
Definition: VectorPool.h:260
Definition: Application.cpp:49
void Free(T *object)
Definition: PoolAllocator.h:202
PoolIterator end()
Definition: VectorPool.h:366
PoolIterator operator++(int)
Definition: VectorPool.h:88