LiquidFun
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
b2SlabAllocator.h
1 /*
2 * Copyright (c) 2014 Google, Inc.
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 * Permission is granted to anyone to use this software for any purpose,
8 * including commercial applications, and to alter it and redistribute it
9 * freely, subject to the following restrictions:
10 * 1. The origin of this software must not be misrepresented; you must not
11 * claim that you wrote the original software. If you use this software
12 * in a product, an acknowledgment in the product documentation would be
13 * appreciated but is not required.
14 * 2. Altered source versions must be plainly marked as such, and must not be
15 * misrepresented as being the original software.
16 * 3. This notice may not be removed or altered from any source distribution.
17 */
18 #ifndef B2_SLAB_ALLOCATOR_H
19 #define B2_SLAB_ALLOCATOR_H
20 
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <new>
24 #include <Box2D/Common/b2IntrusiveList.h>
25 #include <Box2D/Common/b2FreeList.h>
27 #include <Box2D/Common/b2TrackedBlock.h>
28 
35 template<typename T>
37 {
38 private:
39  // Information about a slab.
40  class Slab
41  {
42  public:
44  Slab(uint32 numberOfItems) :
45  m_numberOfItems(numberOfItems)
46  {
47  B2_NOT_USED(m_padding);
48  // This assumes that this class is packed on at least a 4-byte
49  // boundary with no padding. Verify the assumption.
50  b2Assert(sizeof(*this) == b2_mallocAlignment);
51  }
52 
54  ~Slab() { }
55 
57  uint32 GetNumberOfItems() const { return m_numberOfItems; }
58 
60  T* GetFirstItem() const
61  {
62  return (T*)((uint8*)(this + 1));
63  }
64 
68  T* GetItemEnd() const { return GetFirstItem() + GetNumberOfItems(); }
69 
70  private:
72  uint32 m_numberOfItems;
74  uint8 m_padding[b2_mallocAlignment - sizeof(uint32)];
75  };
76 
77 public:
80  b2SlabAllocator(const uint32 itemsPerSlab) :
81  m_itemsPerSlab(itemsPerSlab)
82  {
83  }
84 
87  {
88  FreeAllSlabs();
89  }
90 
93  void SetItemsPerSlab(uint32 itemsPerSlab)
94  {
95  m_itemsPerSlab = itemsPerSlab;
96  }
97 
98  // Get the size of the next allocated slab.
99  uint32 GetItemsPerSlab() const
100  {
101  return m_itemsPerSlab;
102  }
103 
105  T* Allocate()
106  {
107  // Allocate a slab if needed here.
108  if (m_freeList.GetFreeList()->GetFreeList().IsEmpty() &&
109  !AllocateSlab())
110  return NULL;
111  return m_freeList.Allocate();
112  }
113 
115  void Free(T *object)
116  {
117  m_freeList.Free(object);
118  }
119 
123  {
124  if (!m_itemsPerSlab) return false;
125  const uint32 slabSize = sizeof(Slab) + (sizeof(T) * m_itemsPerSlab);
126  void* const memory = m_slabs.Allocate(slabSize);
127  if (!memory) return false;
128 
129  Slab* const slab = new (BlockGetSlab(memory)) Slab(m_itemsPerSlab);
130  T* item = slab->GetFirstItem();
131  for (uint32 i = 0; i < m_itemsPerSlab; ++i, ++item)
132  {
133  m_freeList.AddToFreeList(new (item) T);
134  }
135  return true;
136  }
137 
140  {
142  m_slabs.GetList();
143  while (!slabList.IsEmpty())
144  {
145  FreeSlab(BlockGetSlab(slabList.GetNext()->GetMemory()));
146  }
147  }
148 
153  {
154  const b2IntrusiveListNode& freeItemList =
155  m_freeList.GetFreeList()->GetFreeList();
156  const b2IntrusiveListNode* freeItemListTerminator =
157  freeItemList.GetTerminator();
159  m_slabs.GetList();
160  const b2TypedIntrusiveListNode<b2TrackedBlock>* slabListTerminator =
161  slabList.GetTerminator();
162  b2TrackedBlock* block = slabList.GetNext();
163  while (block != slabListTerminator)
164  {
165  // Get the Slab from the memory associated with the block.
166  Slab* const slab = BlockGetSlab(block->GetMemory());
167  block = block->GetNext();
168 
169  // Determine the range of memory the Slab owns.
170  const uint8* const slabItemStart = (uint8*)slab->GetFirstItem();
171  const uint8* const slabItemEnd = (uint8*)slab->GetItemEnd();
172 
173  // Count all free items that are owned by the current slab.
174  uint8 freeItems = 0;
175  bool empty = false;
176  for (b2IntrusiveListNode* itemNode = freeItemList.GetNext();
177  itemNode != freeItemListTerminator;
178  itemNode = itemNode->GetNext())
179  {
180  const uint8* itemNodeAddress = (uint8*)itemNode;
181  if (itemNodeAddress >= slabItemStart &&
182  itemNodeAddress <= slabItemEnd)
183  {
184  ++freeItems;
185  if (slab->GetNumberOfItems() == freeItems)
186  {
187  empty = true;
188  break;
189  }
190  }
191  }
192  // If a slab is empty, free it.
193  if (empty)
194  {
195  FreeSlab(slab);
196  }
197  }
198  }
199 
202  {
203  return m_freeList;
204  }
205 
206 private:
208  void FreeSlab(Slab * const slab)
209  {
210  b2Assert(slab);
211  const uint32 numberOfItems = slab->GetNumberOfItems();
212  T* item = slab->GetFirstItem();
213  for (uint32 i = 0; i < numberOfItems; ++i, ++item)
214  {
215  item->~T();
216  }
217  slab->~Slab();
218  m_slabs.Free(slab);
219  }
220 
222  Slab* BlockGetSlab(void *memory)
223  {
224  return (Slab*)memory;
225  }
226 
229  T* SlabGetFirstItem(Slab* slab)
230  {
231  return (T*)(slab + 1);
232  }
233 
234 private:
237  b2TrackedBlockAllocator m_slabs;
239  uint32 m_itemsPerSlab;
241  b2TypedFreeList<T> m_freeList;
242 };
243 
244 #endif // B2_SLAB_ALLOCATOR_H
void * Allocate(uint32 size)
Allocate a block of size bytes using b2TrackedBlock::Allocate().
Definition: b2TrackedBlock.cpp:91
const b2TypedFreeList< T > & GetFreeList() const
Get the item allocator freelist.
Definition: b2SlabAllocator.h:201
Definition: b2SlabAllocator.h:36
~b2SlabAllocator()
Free all allocated slabs.
Definition: b2SlabAllocator.h:86
Definition: b2IntrusiveList.h:64
T * GetNext() const
Definition: b2IntrusiveList.h:294
void * GetMemory() const
Get the allocated memory associated with this block.
Definition: b2TrackedBlock.cpp:33
void SetItemsPerSlab(uint32 itemsPerSlab)
Definition: b2SlabAllocator.h:93
T * Allocate()
Allocate a item from the slab.
Definition: b2SlabAllocator.h:105
Definition: b2FreeList.h:76
b2IntrusiveListNode * GetNext() const
Get the next node in the list.
Definition: b2IntrusiveList.h:146
void Free(T *object)
Free an item from the slab.
Definition: b2SlabAllocator.h:115
void FreeEmptySlabs()
Definition: b2SlabAllocator.h:152
Allocated block of memory that can be tracked in a b2IntrusiveList.
Definition: b2TrackedBlock.h:28
const b2IntrusiveListNode * GetTerminator() const
Get the terminator of the list.
Definition: b2IntrusiveList.h:106
void FreeAllSlabs()
Free all slabs.
Definition: b2SlabAllocator.h:139
bool AllocateSlab()
Definition: b2SlabAllocator.h:122
T * GetTerminator() const
Definition: b2IntrusiveList.h:309
b2SlabAllocator(const uint32 itemsPerSlab)
Definition: b2SlabAllocator.h:80
Allocator of blocks which are tracked in a list.
Definition: b2TrackedBlock.h:62
void Free(void *memory)
Free a block returned by Allocate().
Definition: b2TrackedBlock.cpp:99