Browse Source

gobj: add alignment support and move semantics to SimpleAllocator

rdb 7 years ago
parent
commit
f2976b03ec

+ 42 - 2
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.
  */

+ 40 - 7
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;
   }

+ 14 - 5
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 &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;
 };