From f2976b03ecdde973d1fcfaa671246565e4138a90 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 2 Jul 2018 12:55:18 +0200 Subject: [PATCH] gobj: add alignment support and move semantics to SimpleAllocator --- panda/src/gobj/simpleAllocator.I | 44 ++++++++++++++++++++++++++-- panda/src/gobj/simpleAllocator.cxx | 47 +++++++++++++++++++++++++----- panda/src/gobj/simpleAllocator.h | 19 ++++++++---- 3 files changed, 96 insertions(+), 14 deletions(-) diff --git a/panda/src/gobj/simpleAllocator.I b/panda/src/gobj/simpleAllocator.I index 2129ba6681..1f8bf4e01c 100644 --- a/panda/src/gobj/simpleAllocator.I +++ b/panda/src/gobj/simpleAllocator.I @@ -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. */ diff --git a/panda/src/gobj/simpleAllocator.cxx b/panda/src/gobj/simpleAllocator.cxx index 0cc087e2d7..fa6b20d1a3 100644 --- a/panda/src/gobj/simpleAllocator.cxx +++ b/panda/src/gobj/simpleAllocator.cxx @@ -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; } diff --git a/panda/src/gobj/simpleAllocator.h b/panda/src/gobj/simpleAllocator.h index 9e4cb7661b..5a9ca7b616 100644 --- a/panda/src/gobj/simpleAllocator.h +++ b/panda/src/gobj/simpleAllocator.h @@ -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 ©) = delete; + INLINE SimpleAllocatorBlock(SimpleAllocatorBlock &&from); + + SimpleAllocatorBlock &operator = (const SimpleAllocatorBlock ©) = 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; };