diff --git a/include/blt/std/allocator.h b/include/blt/std/allocator.h index e52c92e..b5536bc 100644 --- a/include/blt/std/allocator.h +++ b/include/blt/std/allocator.h @@ -23,6 +23,7 @@ #include #include #include +#include "logging.h" namespace blt { @@ -304,7 +305,8 @@ namespace blt {} template - explicit bump_allocator(blt::size_t size, Args&& ... defaults): buffer_(static_cast(malloc(size * sizeof(type)))), offset_(0), size_(size) + explicit bump_allocator(blt::size_t size, Args&& ... defaults): + buffer_(static_cast(malloc(size * sizeof(type)))), offset_(0), size_(size) { for (blt::size_t i = 0; i < size_; i++) ::new(&buffer_[i]) T(std::forward(defaults)...); @@ -350,19 +352,22 @@ namespace blt } }; - class multi_type_area_allocator + template + class multi_type_area_allocator; + + template<> + class multi_type_area_allocator { private: - struct pointer_view - { - blt::u8* p; - size_t n; - }; - blt::u8* buffer_; blt::u8* offset_; blt::size_t size_; public: + explicit multi_type_area_allocator(blt::size_t size): buffer_(static_cast(malloc(size))), offset_(buffer_), size_(size) + {} + + explicit multi_type_area_allocator(blt::u8* buffer, blt::size_t size): buffer_(buffer), offset_(buffer), size_(size) + {} template [[nodiscard]] T* allocate() @@ -398,7 +403,118 @@ namespace blt ~multi_type_area_allocator() { - delete[] buffer_; + free(buffer_); + } + }; + + template<> + class multi_type_area_allocator + { + private: + struct block + { + blt::u8* buffer; + blt::size_t offset; + blt::size_t allocated_objects = 0; + blt::size_t deallocated_objects = 0; + }; + std::vector blocks; + blt::size_t size_; + + void expand() + { + BLT_INFO("I have expanded!"); + blocks.push_back({static_cast(malloc(size_)), 0}); + } + + template + T* allocate_back() + { + auto& back = blocks.back(); + size_t remaining_bytes = size_ - back.offset; + auto void_ptr = reinterpret_cast(&back.buffer[back.offset]); + auto new_ptr = static_cast(std::align(alignof(T), sizeof(T), void_ptr, remaining_bytes)); + if (new_ptr == nullptr) + expand(); + else + { + back.offset += (back.buffer - new_ptr + sizeof(T)); + back.allocated_objects++; + } + return static_cast(new_ptr); + } + + public: + explicit multi_type_area_allocator(blt::size_t size): size_(size) + { + expand(); + } + + template + [[nodiscard]] T* allocate() + { + if (blocks.back().offset + sizeof(T) > size_) + expand(); + if (auto ptr = allocate_back(); ptr == nullptr) + { + BLT_INFO("Not enough space for me"); + expand(); + } else + return ptr; + if (auto ptr = allocate_back(); ptr == nullptr) + throw std::bad_alloc(); + else + return ptr; + } + + template + void deallocate(T* p) + { + auto* ptr = static_cast(p); + blt::i64 remove_index = -1; + for (auto e : blt::enumerate(blocks)) + { + auto& block = e.second; + if (ptr >= block.buffer && ptr <= &block.buffer[block.offset]) + { + block.deallocated_objects++; + if (block.deallocated_objects == block.allocated_objects) + remove_index = static_cast(e.first); + break; + } + } + if (remove_index < 0) + return; + std::iter_swap(blocks.begin() + remove_index, blocks.end() - 1); + free(blocks.back().buffer); + BLT_DEBUG("I have freed a block!"); + blocks.pop_back(); + } + + template + [[nodiscard]] T* emplace(Args&& ... args) + { + const auto allocated_memory = allocate(); + return new(allocated_memory) T{std::forward(args)...}; + } + + template + inline void construct(U* p, Args&& ... args) + { + ::new((void*) p) U(std::forward(args)...); + } + + template + inline void destroy(U* p) + { + if (p != nullptr) + p->~U(); + } + + ~multi_type_area_allocator() + { + for (auto& v : blocks) + free(v.buffer); } }; }