diff --git a/include/blt/std/memory.h b/include/blt/std/memory.h index c3fb4e8..9ae3f37 100755 --- a/include/blt/std/memory.h +++ b/include/blt/std/memory.h @@ -12,6 +12,7 @@ #include #include "queue.h" #include +#include #include #include #include @@ -506,7 +507,7 @@ namespace blt } }; - template + template class area_allocator { public: @@ -522,72 +523,94 @@ namespace blt size_t n; }; - void expand() + struct block_storage { - size_t new_size = m_size * 2; - T* data = static_cast(malloc(sizeof(T) * new_size)); - if constexpr (std::is_trivially_copyable_v) - std::memcpy(data, m_data, m_size); - else if constexpr (std::is_move_assignable_v || std::is_move_constructible_v) - { - for (size_t i = 0; i < m_size; i++) - data[i] = std::move(m_data[i]); - } else if constexpr (std::is_copy_assignable_v || std::is_copy_constructible_v) - { - for (size_t i = 0; i < m_size; i++) - data[i] = m_data[i]; - } else - { - static_assert("Unable to use this type with this allocator!"); - } - free(m_data); - m_data = data; - m_size = new_size; - } + pointer data; + size_t used = 0; + // TODO: b-tree? + std::vector unallocated_blocks; + }; - void realign() + void allocate_block() { - + BLT_INFO("Allocating a new block of size %d", BLOCK_SIZE); + block_storage blk; + blk.data = static_cast(malloc(sizeof(T) * BLOCK_SIZE)); + blocks.push_back(blk); } public: area_allocator() { - m_data = new T[m_size]; + allocate_block(); } - [[nodiscard]] pointer* allocate(size_t n) + [[nodiscard]] pointer allocate(size_t n) { - if (m_last + n > m_size) - expand(); - pointer loc = &m_data[m_last]; - m_last += n; - return loc; + if (n > BLOCK_SIZE) + { + // handle cases where they want to allocate one large huge block + // in this case we do not care about it since the allocator is meant for small object allocations + throw std::runtime_error("Requested allocation is too large!"); + } + // TODO: something better + if (blocks.back().used + n > BLOCK_SIZE) + { + BLT_TRACE("Moving to a new block"); + allocate_block(); + } + auto& current_block = blocks.back(); + + auto* ptr = &blocks.back().data[current_block.used]; + if constexpr (std::is_default_constructible_v && !std::is_trivially_default_constructible_v) + { + for (size_t i = 0; i < n; i++) + new(&ptr[i]) T(); + } + current_block.used += n; + return ptr; } - void deallocate(pointer* p, size_t n) noexcept + void deallocate(pointer p, size_t n) noexcept { - deallocated_blocks.push({p, n}); - m_deallocated += n; - // TODO: magic number - if (static_cast(m_deallocated) / static_cast(m_last) > 0.25) - realign(); + for (size_t i = 0; i < n; i++) + p[i].~T(); + for (auto& blk : blocks) + { + if (p >= blk.data && p <= (blk.data + BLOCK_SIZE)) + { + blk.unallocated_blocks.push_back({p, n}); + break; + } + } } ~area_allocator() { - delete[] m_data; + for (auto& blk : blocks) + { +// for (size_t i = 0; i < blk.used; i++) +// { +// bool alreadyDeallocated = false; +// for (const auto& dealoc : blk.unallocated_blocks) +// { +// auto pos = (blk.data + i); +// if (pos >= dealoc.p && pos <= (dealoc.p + dealoc.n)) +// { +// alreadyDeallocated = true; +// break; +// } +// } +// if (!alreadyDeallocated) +// blk.data[i].~T(); +// } + // it is UB to not deallocate allocated memory. Get fucked. + free(blk.data); + } } private: - // current size of the data - size_t m_size = 1; - // last allocated location - size_t m_last = 0; - // how many values have been deallocated - size_t m_deallocated = 0; - T* m_data = nullptr; - blt::flat_queue deallocated_blocks; + std::vector blocks; }; } diff --git a/tests/include/memory_test.h b/tests/include/memory_test.h index 4b6141e..9feeb2a 100644 --- a/tests/include/memory_test.h +++ b/tests/include/memory_test.h @@ -28,12 +28,15 @@ namespace blt::test::memory void static_vector_test(); + void test(); + static inline void run() { copy(); move(); access(); static_vector_test(); + test(); } } diff --git a/tests/src/datastructure_tests.cpp b/tests/src/datastructure_tests.cpp index 3640222..1f40ce3 100644 --- a/tests/src/datastructure_tests.cpp +++ b/tests/src/datastructure_tests.cpp @@ -69,6 +69,12 @@ namespace blt blt_linked_stack.push(random_data[i]); BLT_END_INTERVAL(insertProfile, "blt::linked_stack"); + std::vector vector_stack; + BLT_START_INTERVAL(insertProfile, "std::vector"); + for (size_t i = 0; i < size; i++) + vector_stack.push_back(random_data[i]); + BLT_END_INTERVAL(insertProfile, "std::vector"); + BLT_START_INTERVAL(readProfile, "std::stack"); for (size_t i = 0; i < size; i++) { @@ -93,6 +99,14 @@ namespace blt } BLT_END_INTERVAL(readProfile, "blt::linked_stack"); + BLT_START_INTERVAL(readProfile, "std::vector"); + for (size_t i = 0; i < size; i++) + { + blt::black_box(vector_stack.back()); + vector_stack.pop_back(); + } + BLT_END_INTERVAL(readProfile, "std::vector"); + BLT_PRINT_PROFILE(insertProfile); BLT_PRINT_PROFILE(readProfile); } diff --git a/tests/src/memory_test.cpp b/tests/src/memory_test.cpp index 85e8900..403dcd3 100644 --- a/tests/src/memory_test.cpp +++ b/tests/src/memory_test.cpp @@ -21,6 +21,7 @@ #include #include #include +#include "blt/std/utility.h" template blt::scoped_buffer create_scoped_buffer(size_t size) @@ -134,3 +135,68 @@ void blt::test::memory::static_vector_test() BLT_DEBUG_STREAM << v << ' '; BLT_DEBUG_STREAM << '\n'; } + +struct fucked_type1 +{ + private: + int T = 0; + public: + fucked_type1() = default; +}; + +struct fucked_type2 +{ + public: + int T = 0; + public: + fucked_type2() + { + T = 50; + BLT_DEBUG("I HAVE BEEN CONSTRUCTED"); + } + + ~fucked_type2() + { + BLT_DEBUG("I HAVE BEEN DESTRUCTED!"); + } +}; + +void blt::test::memory::test() +{ + area_allocator int_test{}; + //auto arr = int_test.allocate(10); + auto arr2 = int_test.allocate(15); + blt::black_box(int_test.allocate(1)); + blt::black_box(int_test.allocate(1)); + blt::black_box(int_test.allocate(1)); + blt::black_box(int_test.allocate(1)); + blt::black_box(int_test.allocate(1)); + + blt::black_box(int_test.allocate(1)); + blt::black_box(int_test.allocate(1)); + blt::black_box(int_test.allocate(1)); + blt::black_box(int_test.allocate(1)); + blt::black_box(int_test.allocate(1)); + //blt::black_box(arr4); + BLT_INFO("CUM"); +// arr3 = int_test.allocate(2); +// blt::black_box(arr3); +// arr3 = int_test.allocate(5); +// blt::black_box(arr3); +// arr3 = int_test.allocate(10); +// blt::black_box(arr3); + //auto arr3 = int_test.allocate(20); + + //std::memset(arr, 0, 10); + //std::memset(arr2, 0, 15); + //std::memset(arr3, 0, 20); + + for (int i = 0; i < 15; i++) + { + BLT_TRACE_STREAM << arr2[i].T << ' '; + } + BLT_TRACE_STREAM << "\n"; + + int_test.deallocate(arr2, 15); + BLT_INFO("-----------------"); +}