gobj: add alignment support and move semantics to SimpleAllocator

This commit is contained in:
rdb 2018-07-02 12:55:18 +02:00
parent 68e7f681f4
commit f2976b03ec
3 changed files with 96 additions and 14 deletions

View File

@ -32,9 +32,9 @@ SimpleAllocator(size_t max_size, Mutex &lock) :
* pointer.
*/
SimpleAllocatorBlock *SimpleAllocator::
alloc(size_t size) {
alloc(size_t size, size_t alignment) {
MutexHolder holder(_lock);
return do_alloc(size);
return do_alloc(size, alignment);
}
/**
@ -148,6 +148,24 @@ SimpleAllocatorBlock(SimpleAllocator *alloc,
{
}
/**
* 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.
*/
@ -156,6 +174,28 @@ INLINE 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.
*/

View File

@ -13,6 +13,37 @@
#include "simpleAllocator.h"
/**
* Move constructor.
*/
SimpleAllocator::
SimpleAllocator(SimpleAllocator &&from) noexcept :
LinkedListNode(std::move(from)),
_total_size(from._total_size),
_max_size(from._max_size),
_contiguous(from._contiguous),
_lock(from._lock)
{
MutexHolder holder(_lock);
from._total_size = 0;
from._max_size = 0;
from._contiguous = 0;
// We still need to leave the list in a valid state.
from._prev = &from;
from._next = &from;
// Change all the blocks to point to the new allocator.
LinkedListNode *next = _next;
while (next != this) {
SimpleAllocatorBlock *block = (SimpleAllocatorBlock *)next;
nassertv(block->_allocator == &from);
block->_allocator = this;
next = block->_next;
}
}
/**
*
*/
@ -66,7 +97,7 @@ write(std::ostream &out) const {
* Assumes the lock is already held.
*/
SimpleAllocatorBlock *SimpleAllocator::
do_alloc(size_t size) {
do_alloc(size_t size, size_t alignment) {
if (size > _contiguous) {
// Don't even bother.
return nullptr;
@ -86,9 +117,9 @@ do_alloc(size_t size) {
// Scan until we have reached the last allocated block.
while (block->_next != this) {
SimpleAllocatorBlock *next = (SimpleAllocatorBlock *)block->_next;
size_t free_size = next->_start - end;
if (size <= free_size) {
SimpleAllocatorBlock *new_block = make_block(end, size);
size_t start = end + ((alignment - end) % alignment);
if (start + size <= next->_start) {
SimpleAllocatorBlock *new_block = make_block(start, size);
nassertr(new_block->get_allocator() == this, nullptr);
new_block->insert_before(next);
@ -103,6 +134,7 @@ do_alloc(size_t size) {
}
return new_block;
}
size_t free_size = next->_start - end;
if (free_size > best) {
best = free_size;
}
@ -113,9 +145,9 @@ do_alloc(size_t size) {
}
// No free blocks; check for room at the end.
size_t free_size = _max_size - end;
if (size <= free_size) {
SimpleAllocatorBlock *new_block = make_block(end, size);
size_t start = end + ((alignment - end) % alignment);
if (start + size <= _max_size) {
SimpleAllocatorBlock *new_block = make_block(start, size);
nassertr(new_block->get_allocator() == this, nullptr);
new_block->insert_before(this);
@ -131,6 +163,7 @@ do_alloc(size_t size) {
return new_block;
}
size_t free_size = _max_size - end;
if (free_size > best) {
best = free_size;
}

View File

@ -29,9 +29,10 @@ class SimpleAllocatorBlock;
class EXPCL_PANDA_GOBJ SimpleAllocator : public LinkedListNode {
PUBLISHED:
INLINE explicit SimpleAllocator(size_t max_size, Mutex &lock);
SimpleAllocator(SimpleAllocator &&from) noexcept;
virtual ~SimpleAllocator();
INLINE SimpleAllocatorBlock *alloc(size_t size);
INLINE SimpleAllocatorBlock *alloc(size_t size, size_t alignment=1);
INLINE bool is_empty() const;
INLINE size_t get_total_size() const;
@ -45,7 +46,7 @@ PUBLISHED:
void write(std::ostream &out) const;
protected:
SimpleAllocatorBlock *do_alloc(size_t size);
SimpleAllocatorBlock *do_alloc(size_t size, size_t alignment=1);
INLINE bool do_is_empty() const;
virtual SimpleAllocatorBlock *make_block(size_t start, size_t size);
@ -91,6 +92,14 @@ protected:
INLINE SimpleAllocatorBlock(SimpleAllocator *alloc,
size_t start, size_t size);
public:
SimpleAllocatorBlock() = default;
SimpleAllocatorBlock(const SimpleAllocatorBlock &copy) = delete;
INLINE SimpleAllocatorBlock(SimpleAllocatorBlock &&from);
SimpleAllocatorBlock &operator = (const SimpleAllocatorBlock &copy) = delete;
INLINE SimpleAllocatorBlock &operator = (SimpleAllocatorBlock &&from);
PUBLISHED:
INLINE ~SimpleAllocatorBlock();
INLINE void free();
@ -114,9 +123,9 @@ protected:
INLINE bool do_realloc(size_t size);
private:
SimpleAllocator *_allocator;
size_t _start;
size_t _size;
SimpleAllocator *_allocator = nullptr;
size_t _start = 0;
size_t _size = 0;
friend class SimpleAllocator;
};