1// tPool.cpp 
2// 
3// Memory management pools. These are significantly faster than standard memory allocators. All pool implementations 
4// found here must not call new or delete. The reason for this is to allow a user of the pool to overload operator new. 
5// We would get into an infinite loop if we called new from inside the pool implementation. 
6// 
7// Copyright (c) 2004-2006, 2017, 2020 Tristan Grimmer. 
8// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
9// granted, provided that the above copyright notice and this permission notice appear in all copies. 
10// 
11// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
12// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
13// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
14// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
15// PERFORMANCE OF THIS SOFTWARE. 
16 
17#include "Foundation/tPool.h" 
18#include "Foundation/tMemory.h" 
19 
20 
21void tMem::tFastPool::SlotBlock::Init(int slotSizeInBytes, int numSlots
22
23 SlotSize = slotSizeInBytes
24 NumSlots = numSlots
25 
26 tAssert((!(SlotSize % 4)) && (SlotSize >= 8)); 
27 Slots = (uint8*)tMalloc(SlotSize * NumSlots); 
28 
29 // Next we need to initialize all the slots so they all "point" to the next one. 
30 uint8* currSlot = Slots
31 for (int i = 0; i < NumSlots; i++) 
32
33 uint8** currPointerPointer = (uint8**)currSlot
34 
35 if (i < (NumSlots-1)) 
36
37 uint8* next = currSlot+SlotSize
38 *currPointerPointer = next
39
40 else 
41
42 *currPointerPointer = 0
43
44 
45 currSlot += SlotSize
46
47
48 
49 
50tMem::tFastPool::tFastPool(int maxItemSizeInBytes, int initialSlotsInBlock, int slotsPerExpansionBlock, bool threadSafe) : 
51 Blocks(tListMode::UserOwns), 
52 FreeSlot(nullptr), 
53 SlotSize(maxItemSizeInBytes), 
54 SlotsInitialBlock(initialSlotsInBlock), 
55 SlotsPerExpansionBlock(slotsPerExpansionBlock), 
56 ThreadSafe(threadSafe), 
57 PoolMutex(
58
59 // OK, the slot size must be big enough to hold a pointer. We currently support up to 8 byte pointers. Also, the slot 
60 // size must be a multiple of 4 for alignment purposes. 
61 if (SlotSize < 8
62
63 SlotSize = 8
64
65 else 
66
67 int mod = SlotSize % 4
68 if (mod > 0
69 SlotSize += 4 - mod
70
71 
72 tAssert(!(SlotSize % 4)); 
73 SlotBlock* initialBlock = (SlotBlock*)tMalloc(sizeof(SlotBlock)); 
74 initialBlock->Init(SlotSize, initialSlotsInBlock); 
75 Blocks.Append(initialBlock); 
76 
77 FreeSlot = initialBlock->Slots
78
79 
80 
81tMem::tFastPool::~tFastPool() 
82
83 // Statically allocated pools can't assume NumAllocations is 0 even if there are no leaks. 
84 if (NumAllocations == 0
85
86 while (SlotBlock* block = Blocks.Remove()) 
87
88 block->Shutdown(); 
89 tFree(block); 
90
91
92
93 
94 
95void tMem::tFastPool::GrowPool() 
96
97 // You're only allowed to grow if there is currently no free slot. 
98 tAssert(!FreeSlot); 
99 
100 SlotBlock* expansionBlock = (SlotBlock*)tMalloc(sizeof(SlotBlock)); 
101 expansionBlock->Init(SlotSize, SlotsPerExpansionBlock); 
102 
103 Blocks.Append(expansionBlock); 
104 FreeSlot = expansionBlock->Slots
105
106 
107 
108#ifdef MEMORY_ALLOCATOR_CHECK 
109void tMem::tFastPool::SanityCheckSlotValid(void* slot) 
110
111 uint64 slotValue = uint64(slot); 
112 
113 bool found = false
114 SlotBlock* block = Blocks.Head(); 
115 while (block) 
116
117 uint64 memStart = uint64(block->Slots); 
118 uint64 memSize = block->SlotSize * block->NumSlots; 
119 uint64 position = slotValue - memStart; 
120 
121 if ((position >= 0) && (position < memSize)) 
122
123 found = true
124 tAssert((position % block->SlotSize) == 0); 
125 break
126
127 
128 block = block->Next(); 
129
130 
131 tAssert(found); 
132
133 
134 
135void tMem::tFastPool::SanityCheckSlotFreeable(void* slot) 
136
137 SanityCheckSlotValid(slot); 
138 
139 // This check is really slow since it goes through all the allocated slots. We verify that the 
140 // slot is not in the free list. 
141 #ifdef MEMORY_ALLOCATOR__DEEP_CHECK 
142 uint8* freeSlot = FreeSlot; 
143 while (freeSlot) 
144
145 tAssert(freeSlot != (uint8*)slot); 
146 freeSlot = *((uint8**)freeSlot); 
147
148 #endif 
149
150#endif 
151