historical/toontown-classic.git/panda/include/simpleAllocator.I
2024-01-16 11:20:27 -06:00

337 lines
7.7 KiB
Text

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file simpleAllocator.I
* @author drose
* @date 2007-05-12
*/
/**
*
*/
INLINE SimpleAllocator::
SimpleAllocator(size_t max_size, Mutex &lock) :
LinkedListNode(true),
_total_size(0),
_max_size(max_size),
_contiguous(max_size),
_lock(lock)
{
}
/**
* Allocates a new block. Returns NULL if a block of the requested size
* cannot be allocated.
*
* To free the allocated block, call block->free(), or simply delete the block
* pointer.
*/
SimpleAllocatorBlock *SimpleAllocator::
alloc(size_t size, size_t alignment) {
MutexHolder holder(_lock);
return do_alloc(size, alignment);
}
/**
* Returns true if there are no blocks allocated on this page, or false if
* there is at least one.
*/
INLINE bool SimpleAllocator::
is_empty() const {
MutexHolder holder(_lock);
return do_is_empty();
}
/**
* Returns the total size of allocated objects.
*/
INLINE size_t SimpleAllocator::
get_total_size() const {
MutexHolder holder(_lock);
return _total_size;
}
/**
* Returns the available space for allocated objects.
*/
INLINE size_t SimpleAllocator::
get_max_size() const {
MutexHolder holder(_lock);
return _max_size;
}
/**
* Changes the available space for allocated objects. This will not affect
* any already-allocated objects, but will have an effect on future calls to
* alloc().
*/
INLINE void SimpleAllocator::
set_max_size(size_t max_size) {
MutexHolder holder(_lock);
_max_size = max_size;
}
/**
* Returns an upper-bound estimate of the size of the largest contiguous block
* that may be allocated. It is guaranteed that an attempt to allocate a
* block larger than this will fail, though it is not guaranteed that an
* attempt to allocate a block this size or smaller will succeed.
*/
INLINE size_t SimpleAllocator::
get_contiguous() const {
MutexHolder holder(_lock);
return _contiguous;
}
/**
* Returns a pointer to the first allocated block, or NULL if there are no
* allocated blocks.
*/
INLINE SimpleAllocatorBlock *SimpleAllocator::
get_first_block() const {
MutexHolder holder(_lock);
return (_next == this) ? nullptr : (SimpleAllocatorBlock *)_next;
}
/**
* Returns true if there are no blocks allocated on this page, or false if
* there is at least one.
*
* Assumes the lock is already held.
*/
INLINE bool SimpleAllocator::
do_is_empty() const {
return (_next == this);
}
/**
* Some space has been made available following the indicated block. Increase
* the contiguous space accordingly.
*
* Assumes the lock is already held.
*/
INLINE void SimpleAllocator::
mark_contiguous(const LinkedListNode *block) {
size_t space;
if (block == this) {
// This is the beginning of the list.
if (_next == this) {
// And the list is empty.
space = _max_size;
} else {
space = ((SimpleAllocatorBlock *)_next)->get_start();
}
} else {
space = ((SimpleAllocatorBlock *)block)->do_get_max_size() - ((SimpleAllocatorBlock *)block)->get_size();
}
if (space > _contiguous) {
_contiguous = space;
changed_contiguous();
}
}
/**
* A SimpleAllocatorBlock must be constructed via the SimpleAllocator::alloc()
* call.
*/
INLINE SimpleAllocatorBlock::
SimpleAllocatorBlock(SimpleAllocator *alloc,
size_t start, size_t size) :
_allocator(alloc),
_start(start),
_size(size)
{
}
/**
* Transfers ownership from the given SimpleAllocatorBlock to this one.
*/
INLINE SimpleAllocatorBlock::
SimpleAllocatorBlock(SimpleAllocatorBlock &&from) :
_allocator(from._allocator)
{
if (_allocator == nullptr) {
return;
}
MutexHolder holder(_allocator->_lock);
_start = from._start;
_size = from._size;
LinkedListNode::operator = (std::move(from));
from._allocator = nullptr;
}
/**
* The block automatically frees itself when it destructs.
*/
INLINE SimpleAllocatorBlock::
~SimpleAllocatorBlock() {
free();
}
/**
* Frees this block and instead takes ownership of the given other block.
*/
INLINE SimpleAllocatorBlock &SimpleAllocatorBlock::
operator = (SimpleAllocatorBlock &&from) {
free();
_allocator = from._allocator;
if (_allocator == nullptr) {
_start = 0;
_size = 0;
return *this;
}
MutexHolder holder(_allocator->_lock);
_start = from._start;
_size = from._size;
LinkedListNode::operator = (std::move(from));
from._allocator = nullptr;
return *this;
}
/**
* Releases the allocated space.
*/
INLINE void SimpleAllocatorBlock::
free() {
if (_allocator != nullptr) {
MutexHolder holder(_allocator->_lock);
do_free();
}
}
/**
* Returns the SimpleAllocator object that owns this block. Returns NULL if
* the block has been freed.
*/
INLINE SimpleAllocator *SimpleAllocatorBlock::
get_allocator() const {
return _allocator;
}
/**
* Returns the starting point of this block. It is an error to call this if
* the block has been freed.
*/
INLINE size_t SimpleAllocatorBlock::
get_start() const {
nassertr(_allocator != nullptr, 0);
return _start;
}
/**
* Returns the size of this block. It is an error to call this if the block
* has been freed.
*/
INLINE size_t SimpleAllocatorBlock::
get_size() const {
nassertr(_allocator != nullptr, 0);
return _size;
}
/**
* Returns true if the block has been freed, false if it is still valid.
*/
INLINE bool SimpleAllocatorBlock::
is_free() const {
return (_allocator != nullptr);
}
/**
* Returns the maximum size this block can be reallocated to, as limited by
* the following block.
*/
INLINE size_t SimpleAllocatorBlock::
get_max_size() const {
nassertr(_allocator != nullptr, 0);
MutexHolder holder(_allocator->_lock);
return do_get_max_size();
}
/**
* Changes the size of this block to the specified size. Returns true if the
* change is accepted, false if there was not enough room.
*/
INLINE bool SimpleAllocatorBlock::
realloc(size_t size) {
nassertr(_allocator != nullptr, false);
MutexHolder holder(_allocator->_lock);
return do_realloc(size);
}
/**
* Returns a pointer to the next allocated block in the chain, or NULL if
* there are no more allocated blocks.
*/
INLINE SimpleAllocatorBlock *SimpleAllocatorBlock::
get_next_block() const {
nassertr(_allocator != nullptr, nullptr);
MutexHolder holder(_allocator->_lock);
return (_next == _allocator) ? nullptr : (SimpleAllocatorBlock *)_next;
}
/**
* Releases the allocated space.
*
* Assumes the lock is already held.
*/
INLINE void SimpleAllocatorBlock::
do_free() {
nassertv(_allocator != nullptr);
_allocator->_total_size -= _size;
LinkedListNode *prev = _prev;
remove_from_list();
_allocator->mark_contiguous(prev);
_allocator = nullptr;
}
/**
* Returns the maximum size this block can be reallocated to, as limited by
* the following block.
*
* Assumes the lock is already held.
*/
INLINE size_t SimpleAllocatorBlock::
do_get_max_size() const {
size_t end;
if (_next == _allocator) {
end = _allocator->_max_size;
} else {
end = ((SimpleAllocatorBlock *)_next)->_start;
}
return end - _start;
}
/**
* Changes the size of this block to the specified size. Returns true if the
* change is accepted, false if there was not enough room.
*
* Assumes the lock is already held.
*/
INLINE bool SimpleAllocatorBlock::
do_realloc(size_t size) {
if (size > do_get_max_size()) {
return false;
}
_allocator->_total_size -= _size;
_allocator->_total_size += size;
if (size < _size) {
// We're decreasing the block size.
_size = size;
_allocator->mark_contiguous(this);
} else {
// We're increasing the block size.
_size = size;
}
return true;
}