/
mempool.h
212 lines (166 loc) · 5.08 KB
/
mempool.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
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// mempool.h -- Quick but stupid memory allocator
//
// Copyright (C) 2007, 2008, 2010, 2011 Miles Bader <miles@gnu.org>
//
// This source code is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3, or (at
// your option) any later version. See the file COPYING for more details.
//
// Written by Miles Bader <miles@gnu.org>
//
#ifndef SNOGRAY_MEMPOOL_H
#define SNOGRAY_MEMPOOL_H
#include <new>
namespace snogray {
// A mempool is a quick-but-stupid "allocate-only" memory allocator.
// Allocating from it is _extremely_ fast, but memory can only be freed
// in "bulk".
//
class Mempool
{
public:
// The default maximum allocation size we support.
//
static const size_t DEFAULT_BLOCK_SIZE = 16384;
static const size_t DEFAULT_LARGE_SIZE = 8192;
Mempool (size_t _block_size = DEFAULT_BLOCK_SIZE,
size_t _large_size = DEFAULT_LARGE_SIZE)
: beg (0), end (0), blocks (0), avail (0), large_blocks (0),
block_size (_block_size), large_size (_large_size)
{ }
~Mempool () { clear (); }
// Allocate a block of memory from this pool.
//
// If alignment of the returned memory is relevant, it is up to the
// user to make sure he only requests sizes which are multiples of the
// desired minimum alignment. Memory in the pool initially starts out
// with typical system allocator alignment guarantees, but if the user
// request a block with a size that is not a multiple of that
// alignment, that may affect the alignment of subsequent blocks.
//
void *get (size_t size)
{
if (beg + size > end)
return _get (size);
else
{
void *block = beg;
beg += size;
return block;
}
}
// Return all memory allocate from this pool to the pool. This is the
// only way to reclaim memory allocated with Mempool::get.
//
void reset ();
// Return all allocated and available memory to the system.
//
void clear ();
private:
// A chunk of memory allocated from the OS.
//
struct Block
{
Block (char *_mem, Block *_next) : mem (_mem), next (_next) { }
char *mem;
Block *next;
};
// Allocate a block of memory from this pool. Unlike the Mempool::get
// method, this method knows how to allocate large blocks or refill the
// small-allocation arena. If this is a small allocation it is assumed
// that there is no more room in the small-allocation arena, so it is
// refilled with a new block; this is because the easy case of allocating
// small allocations form the arena is handled by Mempool::get.
//
void *_get (size_t size);
// Return all blocks in BLOCK_LIST to the system, and set BLOCK_LIST to
// zero.
//
void free_blocks (Block *&block_list);
// The beginning and end of the current region of memory available for
// allocation. There are (END - BEG) bytes available for allocation.
//
char *beg, *end;
// The actual (large) chunks of memory we allocated from the OS.
//
Block *blocks;
// Blocks which are still available for allocation. AVAIL is a tail
// of the BLOCKS list.
//
Block *avail;
// Blocks too large to be allocated using the default mechanism, each
// dedicated to a single user allocation. These are returned the system
// when reseting.
//
Block *large_blocks;
// The size of the blocks used for normal allocations.
//
size_t block_size;
// Allocations this size or larger are allocated individually from the
// LARGE_BLOCKS list.
//
size_t large_size;
};
extern Mempool &anon_mempool_alloc_barf ();
// An STL allocator for allocating from an Intersect object.
//
template<typename T>
class MempoolAlloc
{
public:
MempoolAlloc (Mempool &_mempool) : mempool (_mempool) { }
// STL constructors need this, though using it would certainly be
// incorrect.
//
MempoolAlloc () : mempool (anon_mempool_alloc_barf ()) { }
typedef T value_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
template<typename T2>
struct rebind
{
typedef MempoolAlloc<T2> other;
};
T *allocate (size_t n)
{
return static_cast<T *> (mempool.get (n * sizeof (T)));
}
void deallocate (void *, size_t)
{
// Nothing -- mempools cannot free data
}
void construct (T *obj, const T &from)
{
new (static_cast<void *> (obj)) T (from);
}
void destroy (T *obj)
{
obj->~T ();
}
size_t max_size() const
{
return size_t (-1) / sizeof (T);
}
Mempool &mempool;
};
}
// The user can use this via placement new: "new (MEMPOOL) T (...)".
// The resulting object cannot be deleted using delete, but should be
// destructed (if necessary) explicitly: "OBJ->~T()".
//
inline void *operator new (size_t size, snogray::Mempool &pool)
{
return pool.get (size);
}
// There's no syntax for user to use this, but the compiler may call it
// during exception handling.
//
inline void operator delete (void *, snogray::Mempool &)
{
// Nothing can be done
}
#endif // SNOGRAY_MEMPOOL_H
// arch-tag: ce37e99d-810f-498b-ad0b-d98ccb5cdf2f