open_toontown_panda3d/panda/src/gobj/simpleAllocator.I

353 lines
12 KiB
Plaintext

// Filename: simpleAllocator.I
// Created by: drose (12May07)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SimpleAllocator::
SimpleAllocator(size_t max_size, Mutex &lock) :
LinkedListNode(true),
_total_size(0),
_max_size(max_size),
_contiguous(max_size),
_lock(lock)
{
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::alloc
// Access: Published
// Description: 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) {
MutexHolder holder(_lock);
return do_alloc(size);
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::is_empty
// Access: Published
// Description: 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();
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::get_total_size
// Access: Published
// Description: Returns the total size of allocated objects.
////////////////////////////////////////////////////////////////////
INLINE size_t SimpleAllocator::
get_total_size() const {
MutexHolder holder(_lock);
return _total_size;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::get_max_size
// Access: Published
// Description: Returns the available space for allocated objects.
////////////////////////////////////////////////////////////////////
INLINE size_t SimpleAllocator::
get_max_size() const {
MutexHolder holder(_lock);
return _max_size;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::set_max_size
// Access: Published
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::get_contiguous
// Access: Published
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::get_first_block
// Access: Published
// Description: 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) ? (SimpleAllocatorBlock *)NULL : (SimpleAllocatorBlock *)_next;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::do_is_empty
// Access: Protected
// Description: 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);
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::mark_contiguous
// Access: Protected
// Description: 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();
}
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::Constructor
// Access: Private
// Description: 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)
{
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::Destructor
// Access: Published
// Description: The block automatically frees itself when it
// destructs.
////////////////////////////////////////////////////////////////////
INLINE SimpleAllocatorBlock::
~SimpleAllocatorBlock() {
free();
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::free
// Access: Published
// Description: Releases the allocated space.
////////////////////////////////////////////////////////////////////
INLINE void SimpleAllocatorBlock::
free() {
if (_allocator != (SimpleAllocator *)NULL) {
MutexHolder holder(_allocator->_lock);
do_free();
}
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::get_allocator
// Access: Published
// Description: Returns the SimpleAllocator object that owns this
// block. Returns NULL if the block has been freed.
////////////////////////////////////////////////////////////////////
INLINE SimpleAllocator *SimpleAllocatorBlock::
get_allocator() const {
return _allocator;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::get_start
// Access: Published
// Description: 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 != (SimpleAllocator *)NULL, 0);
return _start;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::get_size
// Access: Published
// Description: 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 != (SimpleAllocator *)NULL, 0);
return _size;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::is_free
// Access: Published
// Description: Returns true if the block has been freed, false if it
// is still valid.
////////////////////////////////////////////////////////////////////
INLINE bool SimpleAllocatorBlock::
is_free() const {
return (_allocator != (SimpleAllocator *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::get_max_size
// Access: Published
// Description: 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 != (SimpleAllocator *)NULL, 0);
MutexHolder holder(_allocator->_lock);
return do_get_max_size();
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::realloc
// Access: Published
// Description: 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 != (SimpleAllocator *)NULL, false);
MutexHolder holder(_allocator->_lock);
return do_realloc(size);
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::get_next_block
// Access: Published
// Description: 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 != (SimpleAllocator *)NULL, NULL);
MutexHolder holder(_allocator->_lock);
return (_next == _allocator) ? (SimpleAllocatorBlock *)NULL : (SimpleAllocatorBlock *)_next;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::do_free
// Access: Protected
// Description: Releases the allocated space.
//
// Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
INLINE void SimpleAllocatorBlock::
do_free() {
nassertv(_allocator != (SimpleAllocator *)NULL);
_allocator->_total_size -= _size;
LinkedListNode *prev = _prev;
remove_from_list();
_allocator->mark_contiguous(prev);
_allocator = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::do_get_max_size
// Access: Protected
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::do_realloc
// Access: Protected
// Description: 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;
}