Panda3D
Loading...
Searching...
No Matches
simpleAllocator.I
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file simpleAllocator.I
10 * @author drose
11 * @date 2007-05-12
12 */
13
14/**
15 *
16 */
17INLINE SimpleAllocator::
18SimpleAllocator(size_t max_size, Mutex &lock) :
19 LinkedListNode(true),
20 _total_size(0),
21 _max_size(max_size),
22 _contiguous(max_size),
23 _lock(lock)
24{
25}
26
27/**
28 * Allocates a new block. Returns NULL if a block of the requested size
29 * cannot be allocated.
30 *
31 * To free the allocated block, call block->free(), or simply delete the block
32 * pointer.
33 */
35alloc(size_t size, size_t alignment) {
36 MutexHolder holder(_lock);
37 return do_alloc(size, alignment);
38}
39
40/**
41 * Returns true if there are no blocks allocated on this page, or false if
42 * there is at least one.
43 */
45is_empty() const {
46 MutexHolder holder(_lock);
47 return do_is_empty();
48}
49
50/**
51 * Returns the total size of allocated objects.
52 */
53INLINE size_t SimpleAllocator::
54get_total_size() const {
55 MutexHolder holder(_lock);
56 return _total_size;
57}
58
59/**
60 * Returns the available space for allocated objects.
61 */
62INLINE size_t SimpleAllocator::
63get_max_size() const {
64 MutexHolder holder(_lock);
65 return _max_size;
66}
67
68/**
69 * Changes the available space for allocated objects. This will not affect
70 * any already-allocated objects, but will have an effect on future calls to
71 * alloc().
72 */
74set_max_size(size_t max_size) {
75 MutexHolder holder(_lock);
76 _max_size = max_size;
77}
78
79/**
80 * Returns an upper-bound estimate of the size of the largest contiguous block
81 * that may be allocated. It is guaranteed that an attempt to allocate a
82 * block larger than this will fail, though it is not guaranteed that an
83 * attempt to allocate a block this size or smaller will succeed.
84 */
85INLINE size_t SimpleAllocator::
86get_contiguous() const {
87 MutexHolder holder(_lock);
88 return _contiguous;
89}
90
91/**
92 * Returns a pointer to the first allocated block, or NULL if there are no
93 * allocated blocks.
94 */
96get_first_block() const {
97 MutexHolder holder(_lock);
98 return (_next == this) ? nullptr : (SimpleAllocatorBlock *)_next;
99}
100
101/**
102 * Returns true if there are no blocks allocated on this page, or false if
103 * there is at least one.
104 *
105 * Assumes the lock is already held.
106 */
107INLINE bool SimpleAllocator::
108do_is_empty() const {
109 return (_next == this);
110}
111
112/**
113 * Some space has been made available following the indicated block. Increase
114 * the contiguous space accordingly.
115 *
116 * Assumes the lock is already held.
117 */
118INLINE void SimpleAllocator::
119mark_contiguous(const LinkedListNode *block) {
120 size_t space;
121 if (block == this) {
122 // This is the beginning of the list.
123 if (_next == this) {
124 // And the list is empty.
125 space = _max_size;
126 } else {
127 space = ((SimpleAllocatorBlock *)_next)->get_start();
128 }
129 } else {
130 space = ((SimpleAllocatorBlock *)block)->do_get_max_size() - ((SimpleAllocatorBlock *)block)->get_size();
131 }
132 if (space > _contiguous) {
133 _contiguous = space;
134 changed_contiguous();
135 }
136}
137
138/**
139 * A SimpleAllocatorBlock must be constructed via the SimpleAllocator::alloc()
140 * call.
141 */
142INLINE SimpleAllocatorBlock::
143SimpleAllocatorBlock(SimpleAllocator *alloc,
144 size_t start, size_t size) :
145 _allocator(alloc),
146 _start(start),
147 _size(size)
148{
149}
150
151/**
152 * Transfers ownership from the given SimpleAllocatorBlock to this one.
153 */
154INLINE SimpleAllocatorBlock::
155SimpleAllocatorBlock(SimpleAllocatorBlock &&from) :
156 _allocator(from._allocator)
157{
158 if (_allocator == nullptr) {
159 return;
160 }
161
162 MutexHolder holder(_allocator->_lock);
163 _start = from._start;
164 _size = from._size;
165 LinkedListNode::operator = (std::move(from));
166 from._allocator = nullptr;
167}
168
169/**
170 * The block automatically frees itself when it destructs.
171 */
176
177/**
178 * Frees this block and instead takes ownership of the given other block.
179 */
180INLINE SimpleAllocatorBlock &SimpleAllocatorBlock::
181operator = (SimpleAllocatorBlock &&from) {
182 free();
183
184 _allocator = from._allocator;
185 if (_allocator == nullptr) {
186 _start = 0;
187 _size = 0;
188 return *this;
189 }
190
191 MutexHolder holder(_allocator->_lock);
192 _start = from._start;
193 _size = from._size;
194 LinkedListNode::operator = (std::move(from));
195 from._allocator = nullptr;
196 return *this;
197}
198
199/**
200 * Releases the allocated space.
201 */
203free() {
204 if (_allocator != nullptr) {
205 MutexHolder holder(_allocator->_lock);
206 do_free();
207 }
208}
209
210/**
211 * Returns the SimpleAllocator object that owns this block. Returns NULL if
212 * the block has been freed.
213 */
215get_allocator() const {
216 return _allocator;
217}
218
219/**
220 * Returns the starting point of this block. It is an error to call this if
221 * the block has been freed.
222 */
224get_start() const {
225 nassertr(_allocator != nullptr, 0);
226 return _start;
227}
228
229/**
230 * Returns the size of this block. It is an error to call this if the block
231 * has been freed.
232 */
234get_size() const {
235 nassertr(_allocator != nullptr, 0);
236 return _size;
237}
238
239/**
240 * Returns true if the block has been freed, false if it is still valid.
241 */
243is_free() const {
244 return (_allocator != nullptr);
245}
246
247/**
248 * Returns the maximum size this block can be reallocated to, as limited by
249 * the following block.
250 */
252get_max_size() const {
253 nassertr(_allocator != nullptr, 0);
254 MutexHolder holder(_allocator->_lock);
255 return do_get_max_size();
256}
257
258/**
259 * Changes the size of this block to the specified size. Returns true if the
260 * change is accepted, false if there was not enough room.
261 */
263realloc(size_t size) {
264 nassertr(_allocator != nullptr, false);
265 MutexHolder holder(_allocator->_lock);
266 return do_realloc(size);
267}
268
269/**
270 * Returns a pointer to the next allocated block in the chain, or NULL if
271 * there are no more allocated blocks.
272 */
274get_next_block() const {
275 nassertr(_allocator != nullptr, nullptr);
276 MutexHolder holder(_allocator->_lock);
277 return (_next == _allocator) ? nullptr : (SimpleAllocatorBlock *)_next;
278}
279
280/**
281 * Releases the allocated space.
282 *
283 * Assumes the lock is already held.
284 */
285INLINE void SimpleAllocatorBlock::
286do_free() {
287 nassertv(_allocator != nullptr);
288
289 _allocator->_total_size -= _size;
290 LinkedListNode *prev = _prev;
291 remove_from_list();
292 _allocator->mark_contiguous(prev);
293 _allocator = nullptr;
294}
295
296/**
297 * Returns the maximum size this block can be reallocated to, as limited by
298 * the following block.
299 *
300 * Assumes the lock is already held.
301 */
302INLINE size_t SimpleAllocatorBlock::
303do_get_max_size() const {
304 size_t end;
305 if (_next == _allocator) {
306 end = _allocator->_max_size;
307 } else {
308 end = ((SimpleAllocatorBlock *)_next)->_start;
309 }
310 return end - _start;
311}
312
313/**
314 * Changes the size of this block to the specified size. Returns true if the
315 * change is accepted, false if there was not enough room.
316 *
317 * Assumes the lock is already held.
318 */
319INLINE bool SimpleAllocatorBlock::
320do_realloc(size_t size) {
321 if (size > do_get_max_size()) {
322 return false;
323 }
324
325 _allocator->_total_size -= _size;
326 _allocator->_total_size += size;
327
328 if (size < _size) {
329 // We're decreasing the block size.
330 _size = size;
331 _allocator->mark_contiguous(this);
332 } else {
333 // We're increasing the block size.
334 _size = size;
335 }
336 return true;
337}
This just stores the pointers to implement a doubly-linked list of some kind of object.
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition mutexHolder.h:25
A standard mutex, or mutual exclusion lock.
Definition pmutex.h:40
A single block as returned from SimpleAllocator::alloc().
bool realloc(size_t size)
Changes the size of this block to the specified size.
SimpleAllocator * get_allocator() const
Returns the SimpleAllocator object that owns this block.
bool is_free() const
Returns true if the block has been freed, false if it is still valid.
SimpleAllocatorBlock * get_next_block() const
Returns a pointer to the next allocated block in the chain, or NULL if there are no more allocated bl...
size_t get_size() const
Returns the size of this block.
size_t get_max_size() const
Returns the maximum size this block can be reallocated to, as limited by the following block.
~SimpleAllocatorBlock()
The block automatically frees itself when it destructs.
size_t get_start() const
Returns the starting point of this block.
void free()
Releases the allocated space.
An implementation of a very simple block allocator.
size_t get_total_size() const
Returns the total size of allocated objects.
size_t get_max_size() const
Returns the available space for allocated objects.
size_t get_contiguous() const
Returns an upper-bound estimate of the size of the largest contiguous block that may be allocated.
SimpleAllocatorBlock * get_first_block() const
Returns a pointer to the first allocated block, or NULL if there are no allocated blocks.
void set_max_size(size_t max_size)
Changes the available space for allocated objects.
bool is_empty() const
Returns true if there are no blocks allocated on this page, or false if there is at least one.
SimpleAllocatorBlock * alloc(size_t size, size_t alignment=1)
Allocates a new block.