forked from toptensoftware/simplelib
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathplex.h
More file actions
167 lines (135 loc) · 3.72 KB
/
plex.h
File metadata and controls
167 lines (135 loc) · 3.72 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#ifndef __simplelib_plex_h__
#define __simplelib_plex_h__
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "semantics.h"
namespace SimpleLib
{
// Simple block allocator used by CMap
template <typename T>
class CPlex
{
public:
// Constructor
CPlex(int iBlockSize = -1)
{
if (iBlockSize == -1)
{
iBlockSize = (256 - sizeof(BLOCK)) / sizeof(T);
}
if (iBlockSize < 4)
iBlockSize = 4;
m_iBlockSize = iBlockSize;
m_pHead = nullptr;
m_pFreeList = nullptr;
m_iCount = 0;
}
// Destructor
~CPlex()
{
FreeAll();
}
// Allocate an item
T* Alloc()
{
// If no free list, create a new block
if (!m_pFreeList)
{
// Allocate a new block
BLOCK* pNewBlock = (BLOCK*)malloc(sizeof(BLOCK) + m_iBlockSize * sizeof(T));
// Add to list of blocks
pNewBlock->m_pNext = m_pHead;
m_pHead = pNewBlock;
// Setup free list chain
m_pFreeList = (FREEITEM*)&pNewBlock->m_bData[0];
FREEITEM* p = m_pFreeList;
for (int i = 0; i < m_iBlockSize - 1; i++)
{
p->m_pNext = reinterpret_cast<FREEITEM*>(reinterpret_cast<char*>(p) + sizeof(T));
p = p->m_pNext;
}
// nullptr terminate the list
p->m_pNext = nullptr;
}
// Remove top item from the free list
T* p = (T*)m_pFreeList;
m_pFreeList = m_pFreeList->m_pNext;
// Update count
m_iCount++;
new ((void*)p) T;
// Return pointer
return (T*)p;
}
// Free an item
void Free(T* p)
{
assert(m_iCount > 0);
Destructor(p);
if (m_iCount == 1)
{
// When freeing last item, free everything!
FreeAll();
}
else
{
// Add to list of free items
FREEITEM* pNewFreeItem = (FREEITEM*)p;
pNewFreeItem->m_pNext = m_pFreeList;
m_pFreeList = pNewFreeItem;
// Update count
m_iCount--;
}
}
// Free all items
void FreeAll()
{
// Release all blocks
BLOCK* pBlock = m_pHead;
while (pBlock)
{
// Save next
BLOCK* pNext = pBlock->m_pNext;
// Free it
free(pBlock);
// Move on
pBlock = pNext;
}
// Reset state
m_pHead = nullptr;
m_pFreeList = nullptr;
m_iCount = 0;
}
// Get the number of allocated items
int GetCount() const
{
return m_iCount;
}
void SetBlockSize(int iNewBlockSize)
{
assert(m_pHead == nullptr && "SetBlockSize only support when plex is empty");
m_iBlockSize = iNewBlockSize;
}
protected:
#ifdef _MSC_VER
#pragma warning(disable: 4200)
#endif
struct BLOCK
{
BLOCK* m_pNext;
char m_bData[0];
};
#ifdef _MSC_VER
#pragma warning(default: 4200)
#endif
struct FREEITEM
{
FREEITEM* m_pNext;
};
BLOCK* m_pHead;
FREEITEM* m_pFreeList;
int m_iCount;
int m_iBlockSize;
};
} // namespace
#endif // __simplelib_plex_h__