Panda3D
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  */
17 INLINE SimpleAllocator::
18 SimpleAllocator(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  */
35 alloc(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  */
44 INLINE bool SimpleAllocator::
45 is_empty() const {
46  MutexHolder holder(_lock);
47  return do_is_empty();
48 }
49 
50 /**
51  * Returns the total size of allocated objects.
52  */
53 INLINE size_t SimpleAllocator::
54 get_total_size() const {
55  MutexHolder holder(_lock);
56  return _total_size;
57 }
58 
59 /**
60  * Returns the available space for allocated objects.
61  */
62 INLINE size_t SimpleAllocator::
63 get_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  */
73 INLINE void SimpleAllocator::
74 set_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  */
85 INLINE size_t SimpleAllocator::
86 get_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  */
96 get_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  */
107 INLINE bool SimpleAllocator::
108 do_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  */
118 INLINE void SimpleAllocator::
119 mark_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  */
142 INLINE SimpleAllocatorBlock::
143 SimpleAllocatorBlock(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  */
154 INLINE SimpleAllocatorBlock::
155 SimpleAllocatorBlock(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  */
174  free();
175 }
176 
177 /**
178  * Frees this block and instead takes ownership of the given other block.
179  */
180 INLINE SimpleAllocatorBlock &SimpleAllocatorBlock::
181 operator = (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  */
202 INLINE void SimpleAllocatorBlock::
203 free() {
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  */
215 get_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  */
223 INLINE size_t SimpleAllocatorBlock::
224 get_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  */
233 INLINE size_t SimpleAllocatorBlock::
234 get_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  */
242 INLINE bool SimpleAllocatorBlock::
243 is_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  */
251 INLINE size_t SimpleAllocatorBlock::
252 get_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  */
262 INLINE bool SimpleAllocatorBlock::
263 realloc(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  */
274 get_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  */
285 INLINE void SimpleAllocatorBlock::
286 do_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  */
302 INLINE size_t SimpleAllocatorBlock::
303 do_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  */
319 INLINE bool SimpleAllocatorBlock::
320 do_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 }
~SimpleAllocatorBlock()
The block automatically frees itself when it destructs.
An implementation of a very simple block allocator.
bool is_empty() const
Returns true if there are no blocks allocated on this page, or false if there is at least one.
A standard mutex, or mutual exclusion lock.
Definition: pmutex.h:38
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:25
bool realloc(size_t size)
Changes the size of this block to the specified size.
SimpleAllocatorBlock * alloc(size_t size, size_t alignment=1)
Allocates a new block.
bool is_free() const
Returns true if the block has been freed, false if it is still valid.
This just stores the pointers to implement a doubly-linked list of some kind of object.
A single block as returned from SimpleAllocator::alloc().
size_t get_contiguous() const
Returns an upper-bound estimate of the size of the largest contiguous block that may be allocated.
size_t get_max_size() const
Returns the available space for allocated objects.
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...
SimpleAllocatorBlock * get_first_block() const
Returns a pointer to the first allocated block, or NULL if there are no allocated blocks.
void free()
Releases the allocated space.
size_t get_total_size() const
Returns the total size of allocated objects.
size_t get_start() const
Returns the starting point of this block.
SimpleAllocator * get_allocator() const
Returns the SimpleAllocator object that owns this block.
size_t get_max_size() const
Returns the maximum size this block can be reallocated to, as limited by the following block.
void set_max_size(size_t max_size)
Changes the available space for allocated objects.
size_t get_size() const
Returns the size of this block.