-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBlockAllocator.cpp
More file actions
156 lines (130 loc) · 3.32 KB
/
BlockAllocator.cpp
File metadata and controls
156 lines (130 loc) · 3.32 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
// Copyright © 2009 CCP ehf.
/*
*************************************************************************
BlockAllocator.cpp
Project: EVE Server Database Access
Description:
A simple class to dole out stuff, with a single cleanup at the end.
Dependencies:
Python
*************************************************************************
*/
#include "stdafx.h"
#include "BlockAllocator.h"
//Block allocator members
SimplePoolAllocator::SimplePoolAllocator(size_t blockSize) : mBlockSize(blockSize)
{
mHead = mBigHead = 0;
mCurrent = 0;
mCurrentLeft = 0;
}
SimplePoolAllocator::~SimplePoolAllocator()
{
free();
}
void *SimplePoolAllocator::malloc(size_t s)
{
#ifdef _WIN64
return align(s, 16);
#else
return align(s, 8);
#endif
}
void *SimplePoolAllocator::align(size_t s, int a)
{
//use big blocks to reduce fragmentation
if (s > mBlockSize>>1)
return AddBigBlock(s, a);
//round the cursor to the alignment
char *p = RoundUp(mCurrent, a);
ptrdiff_t d = p-mCurrent;
if (s + d > mCurrentLeft) {
if (!AddBlock(s, a))
return 0;
//block is aligned now
d = 0;
}
void *result = mCurrent+d;
_ASSERT(RoundUp((char*)result, a) == (char*)result);
_ASSERT(mCurrentLeft >= s + d);
mCurrent += s + d;
mCurrentLeft -= s + d;
return result;
}
char *SimplePoolAllocator::RoundUp(char *p, int align)
{
return (char*)(((intptr_t)p+align-1) & (~(align-1)));
}
size_t SimplePoolAllocator::RoundUp(size_t s, int align)
{
return (s+align-1) & (~(align-1));
}
bool SimplePoolAllocator::AddBlock(size_t s, int a)
{
//Support only lower alignment than the defult currently
//(we get default alignment from the underying alloc
#ifdef _WIN64
_ASSERT(a <= 16);
#else
_ASSERT(a <= 8);
#endif
//how big should the block be?
const size_t hsize = RoundUp(sizeof(void*), a);
const size_t min_bsize = s + hsize;
size_t bsize = min_bsize;
if (bsize < mBlockSize)
bsize = mBlockSize;
//alloc it (here we should catch exceptions if we ever enable them)
char *block = (char*)CCP_MALLOC("SimplePoolAllocator", bsize);
if (!block) {
//ok, go for the minimum
bsize = min_bsize;
block = (char*)CCP_MALLOC("SimplePoolAllocator", bsize);
if (!block)
return false; //give up
}
//link it in
*reinterpret_cast<void**>(block) = mHead;
mHead = block;
//set allocation space past the link pointer
mCurrent = block + hsize;
mCurrentLeft = bsize - hsize;
_ASSERT(mCurrentLeft >= s);
_ASSERT(RoundUp(mCurrent, a) == mCurrent);
return true;
}
void *SimplePoolAllocator::AddBigBlock(size_t s, int a)
{
//Support only lower alignment than the defult currently
//(we get default alignment from the underying alloc
#ifdef _WIN64
_ASSERT(a <= 16);
#else
_ASSERT(a <= 8);
#endif
//how big should the block be?
const size_t hsize = RoundUp(sizeof(void*), a);
const size_t bsize = s + hsize;
//alloc it (here we should catch exceptions if we ever enable them)
char *block = (char*)CCP_MALLOC("SimplePoolAllocator", bsize);
if (!block)
return 0;
void *result = block+hsize;
//link it in
*reinterpret_cast<void**>(block) = mBigHead;
mBigHead = block;
return result;
}
void SimplePoolAllocator::free()
{
while (mHead) {
void *next = *reinterpret_cast<void**>(mHead);
CCP_FREE(mHead);
mHead = next;
}
while (mBigHead) {
void *next = *reinterpret_cast<void**>(mBigHead);
CCP_FREE(mBigHead);
mBigHead = next;
}
}