Kaynağa Gözat

change(allocator): make all functions constexpr

greatbridf 1 yıl önce
ebeveyn
işleme
0746c681e2
1 değiştirilmiş dosya ile 63 ekleme ve 47 silme
  1. 63 47
      include/types/allocator.hpp

+ 63 - 47
include/types/allocator.hpp

@@ -2,7 +2,7 @@
 #include <new>
 #include <utility>
 #include <type_traits>
-#include <assert.h>
+#include <bit>
 #include <stdint.h>
 #include <types/cplusplus.hpp>
 #include <types/types.h>
@@ -26,7 +26,7 @@ namespace __allocator {
             size_t size;
             struct mem_blk_flags flags;
             // the first byte of the memory space
-            // the minimal allocated space is 4 bytes
+            // the minimal allocated space is 8 bytes
             byte data[];
         };
 
@@ -35,60 +35,67 @@ namespace __allocator {
         byte* p_break;
         byte* p_limit;
 
-        brk_memory_allocator(void) = delete;
+        brk_memory_allocator() = delete;
         brk_memory_allocator(const brk_memory_allocator&) = delete;
         brk_memory_allocator(brk_memory_allocator&&) = delete;
 
-        constexpr int brk(byte* addr)
+        constexpr byte* brk(byte* addr)
         {
             if (unlikely(addr >= p_limit))
-                return GB_FAILED;
-            p_break = addr;
-            return GB_OK;
-        }
-
-        // sets errno
-        inline byte* sbrk(size_type increment)
-        {
-            if (unlikely(brk(p_break + increment) != GB_OK))
                 return nullptr;
-            else
-                return p_break;
+            return p_break = addr;
         }
 
-        inline mem_blk* _find_next_mem_blk(mem_blk* blk, size_type blk_size)
+        constexpr byte* sbrk(size_type increment)
+        { return brk(p_break + increment); }
+
+        constexpr mem_blk* _next(mem_blk* blk, size_type blk_size)
         {
-            byte* p = (byte*)blk;
+            auto* p = std::bit_cast<byte*>(blk);
             p += sizeof(mem_blk);
             p += blk_size;
-            return (mem_blk*)p;
+            return std::bit_cast<mem_blk*>(p);
+        }
+
+        // blk MUST be free
+        constexpr void unite_afterwards(mem_blk* blk)
+        {
+            while (blk->flags.has_next) {
+                auto* blk_next = _next(blk, blk->size);
+                if (!blk_next->flags.is_free)
+                    break;
+                blk->size += sizeof(mem_blk) + blk_next->size;
+                blk->flags.has_next = blk_next->flags.has_next;
+            }
         }
 
-        // sets errno
         // @param start_pos position where to start finding
         // @param size the size of the block we're looking for
         // @return found block if suitable block exists, if not, the last block
-        inline mem_blk* find_blk(mem_blk* start_pos, size_type size)
+        constexpr mem_blk* find_blk(mem_blk* start_pos, size_type size)
         {
-            while (1) {
-                if (start_pos->flags.is_free && start_pos->size >= size) {
-                    return start_pos;
-                } else {
-                    if (unlikely(!start_pos->flags.has_next))
-                        return start_pos;
-
-                    start_pos = _find_next_mem_blk(start_pos, start_pos->size);
+            while (true) {
+                if (start_pos->flags.is_free) {
+                    unite_afterwards(start_pos);
+
+                    if (start_pos->size >= size)
+                        break;
                 }
+
+                if (!start_pos->flags.has_next)
+                    break;
+                start_pos = _next(start_pos, start_pos->size);
             }
+            return start_pos;
         }
 
-        inline mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
+        constexpr mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
         {
             auto ret = sbrk(sizeof(mem_blk) + size);
             if (!ret)
                 return nullptr;
 
-            mem_blk* blk = _find_next_mem_blk(blk_before, blk_before->size);
+            mem_blk* blk = _next(blk_before, blk_before->size);
 
             blk_before->flags.has_next = 1;
 
@@ -99,14 +106,15 @@ namespace __allocator {
             return blk;
         }
 
-        inline void split_block(mem_blk* blk, size_type this_size)
+        constexpr void split_block(mem_blk* blk, size_type this_size)
         {
             // block is too small to get split
-            if (blk->size < sizeof(mem_blk) + this_size) {
+            // that is, the block to be split should have enough room
+            // for "this_size" bytes and also could contain a new block
+            if (blk->size < this_size + sizeof(mem_blk) + 8)
                 return;
-            }
 
-            mem_blk* blk_next = _find_next_mem_blk(blk, this_size);
+            mem_blk* blk_next = _next(blk, this_size);
 
             blk_next->size = blk->size
                 - this_size
@@ -120,26 +128,23 @@ namespace __allocator {
         }
 
     public:
-        inline brk_memory_allocator(byte* start, size_type limit)
+        constexpr brk_memory_allocator(byte* start, size_type limit)
             : p_start(start)
-            , p_limit(p_start + limit)
+            , p_limit(start + limit)
         {
             brk(p_start);
-            mem_blk* p_blk = (mem_blk*)sbrk(0);
+            auto* p_blk = std::bit_cast<mem_blk*>(sbrk(0));
             p_blk->size = 8;
             p_blk->flags.has_next = 0;
             p_blk->flags.is_free = 1;
         }
 
-        // sets errno
-        inline void* alloc(size_type size)
+        constexpr void* alloc(size_type size)
         {
-            struct mem_blk* block_allocated;
-
-            if (size < 8)
-                size = 8;
+            // align to 8 bytes boundary
+            size = (size + 7) & ~7;
 
-            block_allocated = find_blk((mem_blk*)p_start, size);
+            auto* block_allocated = find_blk(std::bit_cast<mem_blk*>(p_start), size);
             if (!block_allocated->flags.has_next
                 && (!block_allocated->flags.is_free || block_allocated->size < size)) {
                 // 'block_allocated' in the argument list is the pointer
@@ -152,14 +157,25 @@ namespace __allocator {
             }
 
             block_allocated->flags.is_free = 0;
+
+            auto* blkpos = std::bit_cast<byte*>(block_allocated);
+            if (blkpos > p_start)
+                p_start = blkpos;
             return block_allocated->data;
         }
 
-        inline void free(void* ptr)
+        constexpr void free(void* ptr)
         {
-            mem_blk* blk = (mem_blk*)((byte*)ptr - (sizeof(mem_blk_flags) + sizeof(size_t)));
+            auto* blk = std::bit_cast<mem_blk*>(
+                std::bit_cast<byte*>(ptr) - sizeof(mem_blk));
+
             blk->flags.is_free = 1;
-            // TODO: fusion free blocks nearby
+
+            if (std::bit_cast<byte*>(blk) < p_start)
+                p_start = std::bit_cast<byte*>(blk);
+
+            // unite free blocks nearby
+            unite_afterwards(blk);
         }
     };
 }; // namespace __allocator