-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpool.h
129 lines (111 loc) · 4.25 KB
/
pool.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#pragma once
#include <cassert>
//http://www.codeproject.com/Articles/746630/O-Object-Pool-in-Cplusplus
// class that pools memory
// TODO: try redoing to be a little more like https://sites.google.com/site/initupdatedraw/home
// ie: add indices and bit shifting to calculate stuff rather than pointer arithmetic
// could also try making this pool resizable like in original link
template <class T>
class MemPool {
public:
struct Item {
T item;
bool free;
};
explicit MemPool(size_t max) :
maxCount(max),
nextFree(nullptr),
count(0) {
if (maxCount > 64000) { // cap at arbitrary 64K
maxCount = 64000;
}
// operator new to allocate a whole block of memory for this pool
memory = (char*)::operator new(maxCount * itemSize);
}
~MemPool() {
::operator delete(memory); // deallocate whole memory block
}
// constructs item and returns pointer to it
T* alloc() {
if (nextFree) { // if nextFree is not null
Item* ret = nextFree; // get pointer to item at nextFree
nextFree = *((Item**)nextFree); // assign nextFree to be whatever was in this free spot
new(ret) Item(); // placement new
return &ret->item;
}
// if there is no more room and nextFree is null then return nullptr
// later add ability to allocate new memory blocks like original article
if (count >= maxCount) {
std::cout << "WARNING::MEMPOOL::EMPTY: of " << typeid(T).name() << std::endl;
return nullptr;
}
// else increment count and allocate
Item* ret = new(memory + itemSize * count) Item();
++count;
return &ret->item;
}
// frees item at pointer address
void free(T* item) {
item->~T(); //call destructor on item
// cast item as a pointer to a pointer
// and store the current location of nextFree in its place
*((Item**)item) = nextFree;
nextFree = (Item*)item; // make nextFree point to this item
nextFree->free = true; // set the free bool so next() will skip it
}
// frees item at index
void free(int index) {
free((T*)(memory + index*itemSize));
}
// frees all allocated items in pool
void freeAll() {
// call destructors on all allocated items
for (T* t = nullptr; next(t);) {
t->~T();
}
// reset count and nextFree
count = 0;
nextFree = nullptr;
}
// this is pretty much an iterator
// call like so to iterate over all allocated elements:
// for(T* t = nullptr; pool.next(t);){}
bool next(T*& item) const { // reference to a pointer
char* address = (char*)item;
if (!item) { // if item is nullptr then start at one back from beginning
address = memory - itemSize;
}
do { // increment forward and check to make sure not past memory block
address += itemSize;
if (address >= memory + itemSize * count) {
item = nullptr;
return false;
}
} while (((Item*)(address))->free); // keep doing so while the item is free
// update the pointer reference with address of next allocated
item = (T*)address;
return true;
}
int getIndex(T* item) const { // get index from type pointer
return ((char*)item - memory) / itemSize;
}
int getIndex(char* ptr) const { // get index to current item from random point in memory block
return (int)(((char*)ptr - memory) / itemSize);
}
T* get(int index) const { // return item pointer by index
return (T*)(memory + index * itemSize);
}
size_t getCount() {
return count;
}
private:
char* memory; // block of memory for this pool
size_t maxCount; // max number of elements in pool
Item* nextFree; // pointer to next free element
size_t count; // signifies highest element index since reset
static const size_t itemSize;
};
// ensures itemSize is at least 8 bytes
// needs to be able to store the pointer for free list and the bool to signify free
template<class T>
const size_t MemPool<T>::itemSize = sizeof(Item) < 8 ? 8 : sizeof(Item);