diff --git a/include/DataFrame/Utils/FixedSizeAllocator.h b/include/DataFrame/Utils/FixedSizeAllocator.h deleted file mode 100644 index 07b96dde..00000000 --- a/include/DataFrame/Utils/FixedSizeAllocator.h +++ /dev/null @@ -1,590 +0,0 @@ -// Hossein Moein -// June 26 2023 -/* -Copyright (c) 2019-2026, Hossein Moein -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -* Neither the name of Hossein Moein and/or the DataFrame nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL Hossein Moein BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// ---------------------------------------------------------------------------- - -namespace hmdf -{ - -template -struct StaticStorage { - - using value_type = T; - using size_type = std::size_t; - - inline static constexpr size_type max_size = - MAX_SIZE * sizeof(value_type); - inline static constexpr bool is_static = true; - - StaticStorage() = default; - StaticStorage(const StaticStorage &) = delete; - StaticStorage(StaticStorage &&) = delete; - ~StaticStorage() = default; - - StaticStorage &operator =(const StaticStorage &) = delete; - StaticStorage &operator =(StaticStorage &&) = delete; - - // Main allocation space - // - alignas(value_type[]) - inline static unsigned char buffer_[max_size]; -}; - -// ---------------------------------------------------------------------------- - -template -struct StackStorage { - - using value_type = T; - using size_type = std::size_t; - - inline static constexpr size_type max_size = - MAX_SIZE * sizeof(value_type); - inline static constexpr bool is_static = false; - - StackStorage() = default; - StackStorage(const StackStorage &) = delete; - StackStorage(StackStorage &&) = delete; - ~StackStorage() = default; - - StackStorage &operator =(const StackStorage &) = delete; - StackStorage &operator =(StackStorage &&) = delete; - - // Main allocation space - // - alignas(value_type[]) - unsigned char buffer_[max_size]; -}; - -// ---------------------------------------------------------------------------- - -struct BestFitMemoryBlock { - - using value_type = unsigned char *; - using size_type = std::size_t; - - value_type address { nullptr }; - size_type size { 0 }; - - inline value_type - get_end() const { return (address + size); } - inline value_type - get_start() const { return (address - size); } - - // Hash function - // - inline size_type - operator() (const BestFitMemoryBlock &mb) const { - - return (std::hash{ }(mb.address)); - } - - inline friend bool - operator < (const BestFitMemoryBlock &lhs, - const BestFitMemoryBlock &rhs) { - - return (lhs.size < rhs.size); - } - inline friend bool - operator > (const BestFitMemoryBlock &lhs, - const BestFitMemoryBlock &rhs) { - - return (lhs.size > rhs.size); - } - inline friend bool - operator == (const BestFitMemoryBlock &lhs, - const BestFitMemoryBlock &rhs) { - - return (lhs.address == rhs.address); - } -}; - -// ---------------------------------------------------------------------------- - -template // Storage class -struct BestFitAlgo : public S { - - using Base = S; - using size_type = Base::size_type; - using pointer = unsigned char *; - - BestFitAlgo() : Base() { - - free_blocks_start_.insert({ Base::buffer_, Base::max_size }); - free_blocks_assist_.insert( - std::make_pair(Base::buffer_, free_blocks_start_.begin())); - free_blocks_end_.insert(std::make_pair(Base::buffer_ + Base::max_size, - Base::max_size)); - } - ~BestFitAlgo() = default; - - // Like malloc - // - [[nodiscard]] pointer - get_space (size_type requested_size) { - - auto free_iter = - free_blocks_start_.lower_bound({ nullptr, requested_size }); - - if (free_iter != free_blocks_start_.end()) { - auto found_end = free_iter->get_end(); - - if (free_iter->size > requested_size) { - auto remaining = free_iter->size - requested_size; - auto new_address = free_iter->address + requested_size; - const auto insert_ret = - free_blocks_start_.insert({ new_address, remaining }); - - free_blocks_assist_.insert( - std::make_pair(new_address, insert_ret)); - free_blocks_end_[found_end] = remaining; - } - else // Exact size match - free_blocks_end_.erase(found_end); - - auto ret = free_iter->address; - - free_blocks_assist_.erase(free_iter->address); - free_blocks_start_.erase(free_iter); - used_blocks_.insert({ ret, requested_size }); - return (ret); - } - throw std::bad_alloc(); - } - - // Like free - // - void - put_space (pointer to_be_freed, size_type) { - - auto used_iter = used_blocks_.find({ to_be_freed, 0 }); - - if (used_iter != used_blocks_.end()) { - const pointer tail_ptr = to_be_freed + used_iter->size; - bool found_tail = false; - const auto tail_block = free_blocks_assist_.find(tail_ptr); - - // Try to find a free block that starts where to_be_freed block - // ends. If there is such a free block, join it with to_be_freed - // block - // - if (tail_block != free_blocks_assist_.end()) { - const size_type new_len = - used_iter->size + tail_block->second->size; - const BestFitMemoryBlock to_insert { to_be_freed, new_len }; - - free_blocks_start_.erase(tail_block->second); - free_blocks_assist_.erase(tail_block); - - const auto insert_ret = free_blocks_start_.insert(to_insert); - - free_blocks_assist_.insert( - std::make_pair(to_be_freed, insert_ret)); - free_blocks_end_[to_insert.get_end()] = new_len; - found_tail = true; - } - - // Try to find a free block that ends where to_be_freed block - // starts. If there is such a free block, join it with to_be_freed - // block - // - const auto end_iter = free_blocks_end_.find(to_be_freed); - bool found_head = false; - - if (end_iter != free_blocks_end_.end()) { - const pointer head_ptr = - end_iter->first - end_iter->second; - const auto head_block = free_blocks_assist_.find(head_ptr); - - if (head_block != free_blocks_assist_.end()) { - const size_type new_len = - used_iter->size + head_block->second->size; - const auto new_head = head_block->second->address; - const auto new_end = - end_iter->first + used_iter->size; - - free_blocks_start_.erase(head_block->second); - free_blocks_assist_.erase(head_block); - - const auto insert_ret = - free_blocks_start_.insert({ new_head, new_len }); - - free_blocks_assist_.insert( - std::make_pair(new_head, insert_ret)); - free_blocks_end_.erase(end_iter); - free_blocks_end_[new_end] = new_len; - found_head = true; - } - } - - // If we could not join with any other adjacent free blocks, - // process it as a stand alone - // - if (! (found_tail || found_head)) { - const pointer end_address = - used_iter->address + used_iter->size; - const auto insert_ret = - free_blocks_start_.insert( - { used_iter->address, used_iter->size }); - - free_blocks_assist_.insert( - std::make_pair(used_iter->address, insert_ret)); - free_blocks_end_[end_address] = used_iter->size; - } - - // Finally remove the block from used blocks map - // - used_blocks_.erase(used_iter); - } - // else // This is undefined behavior in delete operator - // throw std::invalid_argument("BestFitAlgo::put_space()"); - } - -private: - - // It is based on size, so it must be multi-set - // - using blk_set = std::multiset; - using blk_uoset = - std::unordered_set; - using blk_uomap = std::unordered_map; - using blk_assist = std::unordered_map; - - // Set of free blocks, keyed by size of the block. There could be multiple - // blocks with the same size. - // - blk_set free_blocks_start_ { }; - - // Map of free blocks to size, keyed by the pointer to the end of the block. - // - blk_uomap free_blocks_end_ { }; - - // Hash set of used blocks, keyed by the pointer to the beginning of - // the block. - // - blk_uoset used_blocks_ { }; - - // Map of free blocks to iterators of free_blocks_start_, keyed pointers - // to the beginning of free blocks - // - blk_assist free_blocks_assist_ { }; -}; - -// ---------------------------------------------------------------------------- - -template -struct FirstFitStaticBase : public StaticStorage { - - using Base = StaticStorage; - using value_type = Base::value_type; - using size_type = Base::size_type; - - inline static constexpr unsigned char FREE_ { 0 }; - inline static constexpr unsigned char USED_ { 1 }; - inline static constexpr std::size_t max_size = MAX_SIZE; - - // The bitmap to indicate which slots are in use. - // - alignas(value_type[]) - inline static unsigned char in_use_[MAX_SIZE]; - - // Pointer to the first free slot. - // - alignas(value_type *) - inline static unsigned char *first_free_ptr_ { in_use_ }; - - FirstFitStaticBase() : Base() { - - // This is guaranteed to execute only once even in multithreading - // - [[maybe_unused]] static auto slug = std::invoke([]() -> int { - std::memset(in_use_, FREE_, MAX_SIZE); - return (0); - }); - } -}; - -// ---------------------------------------------------------------------------- - -template -struct FirstFitStackBase : public StackStorage { - - using Base = StackStorage; - using value_type = Base::value_type; - using size_type = Base::size_type; - - inline static constexpr unsigned char FREE_ { 0 }; - inline static constexpr unsigned char USED_ { 1 }; - inline static constexpr std::size_t max_size = MAX_SIZE; - - // The bitmap to indicate which slots are in use. - // - alignas(value_type[]) - unsigned char in_use_[MAX_SIZE]; - - // Pointer to the first free slot. - // - alignas(value_type *) - unsigned char *first_free_ptr_ { in_use_ }; - - FirstFitStackBase() : Base() { std::memset(in_use_, FREE_, MAX_SIZE); } -}; - -// ---------------------------------------------------------------------------- - -template // Storage class -struct FirstFitAlgo : public S { - - using Base = S; - using value_type = Base::value_type; - using size_type = Base::size_type; - using pointer = unsigned char *; - - FirstFitAlgo() : Base() { } - ~FirstFitAlgo() = default; - - // Like malloc - // - [[nodiscard]] pointer - get_space (size_type requested_size) { - - // Pointers to the "in use" bitmap. - // - unsigned char *first_ptr = Base::first_free_ptr_; - unsigned char *const end_ptr = &(Base::in_use_[Base::max_size]); - const size_type n_items = requested_size / sizeof(value_type); - - // Find first fit allocation algorithm, starting from the first - // free slot. - // Search for a big enough range of free slots. - // - first_ptr = std::search_n(first_ptr, end_ptr, n_items, Base::FREE_); - - // Not enough space found? - // - if (first_ptr == end_ptr) - throw std::bad_alloc(); - - // Mark the range as used - // - std::memset(first_ptr, Base::USED_, n_items); - - // Update the "first free" pointer if necessary. - // - if (first_ptr == Base::first_free_ptr_) // Find the next free slot - Base::first_free_ptr_ = - std::find(first_ptr + n_items, end_ptr, Base::FREE_); - - // Return the memory allocation. - // - const size_type offset = - std::distance(Base::in_use_, first_ptr) * sizeof(value_type); - - return (&(Base::buffer_[offset])); - } - - // Like free - // - void - put_space (pointer to_be_freed, size_type space_size) { - - // Find the start of the range. - // - const size_type index = // Find the start of the range. - std::distance(Base::buffer_, to_be_freed) / sizeof(value_type); - unsigned char *first_ptr = &(Base::in_use_[index]); - - // Mark the range as free. - // - std::memset(first_ptr, Base::FREE_, space_size / sizeof(value_type)); - - // Update the "first free" pointer if necessary. - // - if (first_ptr < Base::first_free_ptr_) - Base::first_free_ptr_ = first_ptr; - } -}; - -// ---------------------------------------------------------------------------- - -template typename STORAGE, - template typename ALGO> -class FixedSizeAllocator : ALGO> { - - using AlgoBase = ALGO>; - -public: - - // std::allocator_traits stuff - // - using value_type = T; - using pointer = T *; - using const_pointer = const T *; - using void_pointer = void *; - using const_void_pointer = const void *; - using reference = T &; - using const_reference = const T &; - using size_type = AlgoBase::size_type; - using difference_type = ptrdiff_t; - using propagate_on_container_copy_assignment = std::false_type; - using propagate_on_container_move_assignment = std::false_type; - using propagate_on_container_swap = std::false_type; - using is_always_equal = std::true_type; - - // This is only necessary because allocator has a second and third template - // arguments for the alignment that will make the default - // std::allocator_traits implementation fail during compilation. - // - template - struct rebind { - using other = FixedSizeAllocator; - }; - - [[nodiscard]] pointer - address(reference r) const { return (std::addressof(r)); } - [[nodiscard]] const_pointer - address(const_reference cr) const { return (std::addressof(cr)); } - - [[nodiscard]] constexpr size_type - max_size() const { return (MAX_SIZE); } - -public: - - FixedSizeAllocator() : AlgoBase() { } - FixedSizeAllocator(const FixedSizeAllocator &that) = delete; - FixedSizeAllocator(FixedSizeAllocator &&) = delete; - ~FixedSizeAllocator() = default; - - FixedSizeAllocator & - operator =(FixedSizeAllocator &&) = delete; - FixedSizeAllocator & - operator =(const FixedSizeAllocator &) = delete; - - template - FixedSizeAllocator(const FixedSizeAllocator &) { - } - - // Always return true for stateless allocators. - // - [[nodiscard]] inline bool - operator == (const FixedSizeAllocator &) const { return (true); } - [[nodiscard]] inline bool - operator != (const FixedSizeAllocator &) const { return (false); } - -public: - - inline void - construct(pointer p, const_reference val) const { - - new (static_cast(p)) value_type(val); - } - inline void - construct(pointer p) const { new (static_cast(p)) value_type(); } - - template - inline void - construct(U *p, As && ... args) const { - - new (static_cast(p)) U(std::forward(args) ...); - } - - inline void - destroy(pointer p) const { p->~value_type(); } - - template - inline void - destroy(U *p) const { p->~U(); } - - [[nodiscard]] inline pointer - allocate(size_type n_items, [[maybe_unused]] const_pointer cp) { - - auto memory_ptr = this->get_space(n_items * sizeof(value_type)); - - return (reinterpret_cast(memory_ptr)); - } - - [[nodiscard]] inline pointer - allocate(size_type n_items) { return (allocate(n_items, nullptr)); } - - void - deallocate(pointer p, size_type n_items) { - - this->put_space(reinterpret_cast(p), - n_items * sizeof(value_type)); - } -}; - -// ---------------------------------------------------------------------------- - -// This is slower than first-fit, but it causes a lot less fragmentations. -// -template -using StaticBestFitAllocator = - FixedSizeAllocator; - -// This is slower than first-fit, but it causes a lot less fragmentations. -// -template -using StackBestFitAllocator = - FixedSizeAllocator; - -// This is faster than best-fit, but it causes more fragmentations. -// -template -using StaticFirstFitAllocator = - FixedSizeAllocator; - -// This is faster than best-fit, but it causes more fragmentations. -// -template -using StackFirstFitAllocator = - FixedSizeAllocator; - -} // namespace std - -// ---------------------------------------------------------------------------- - -// Local Variables: -// mode:C++ -// tab-width:4 -// c-basic-offset:4 -// End: diff --git a/src/CommonMakefile.mk b/src/CommonMakefile.mk index cb258fa6..86b7e699 100644 --- a/src/CommonMakefile.mk +++ b/src/CommonMakefile.mk @@ -68,8 +68,7 @@ HEADERS = $(LOCAL_INCLUDE_DIR)/DataFrame/Vectors/HeteroVector.h \ $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/Concepts.h \ $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/FixedSizeString.h \ $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/FixedSizePriorityQueue.h \ - $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/AlignedAllocator.h \ - $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/FixedSizeAllocator.h + $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/AlignedAllocator.h LIB_NAME = DataFrame TARGET_LIB = $(LOCAL_LIB_DIR)/lib$(LIB_NAME).a diff --git a/test/allocator_tester.cc b/test/allocator_tester.cc index 70f2e9b2..52329dc6 100644 --- a/test/allocator_tester.cc +++ b/test/allocator_tester.cc @@ -26,7 +26,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include -#include #include #include @@ -166,403 +165,9 @@ static void test_aligned_allocator() { // ----------------------------------------------------------------------------- -static void test_first_fit_static_allocator() { - - std::cout << "\nTesting StaticFirstFitAllocator ..." << std::endl; - - std::vector> vec1; - - vec1.reserve(100000); - for (std::size_t i = 0; i < 100000; ++i) - vec1.push_back(int(i)); - for (std::size_t i = 0; i < 100000; ++i) - assert(vec1[i] == int(i)); - - std::vector> vec2; - - for (std::size_t i = 0; i < 10000; ++i) - vec2.push_back(int(i)); - for (std::size_t i = 0; i < 10000; ++i) - assert(vec2[i] == int(i)); - - { - std::vector> vec3; - - for (std::size_t i = 0; i < 10000; ++i) - vec3.push_back(double(i)); - for (std::size_t i = 0; i < 10000; ++i) - assert(vec3[i] == double(i)); - } - - std::vector> vec4; - - for (std::size_t i = 0; i < 10000; ++i) - vec4.push_back(double(i)); - for (std::size_t i = 0; i < 10000; ++i) - assert(vec4[i] == double(i)); - - using MyString = std::basic_string, - StaticFirstFitAllocator>; - - { - MyString str1 = - "This is the first strig xo xo xo xo xo xo xo xo xo xo xo xo xo xo"; - - str1 += ". Adding more stuff xo xo xo xo xo xo xo xo xo xo"; - - { - MyString str2 = - "This is the second strig"; - - str2 += ". Again, adding more stuff wd wd wd wd wd wd wd wd wd wd"; - - std::cout << str2 << std::endl; - } - std::cout << str1 << std::endl; - } - - MyString str3 = "This is the third strig"; - - str3 += ". Adding more stuff"; - std::cout << str3 << std::endl; - - std::vector> vec5; - - vec5.reserve(1); - for (std::size_t i = 0; i < 2; ++i) - vec5.push_back(double(i)); - for (std::size_t i = 0; i < 2; ++i) - assert(vec5[i] == double(i)); - - using map_t = - std::map, - StaticFirstFitAllocator, 1000>>; - - map_t my_map; - - for (int i = 0; i < 1000; ++i) - my_map.insert({ i, i * 10 }); - for (int i = 0; i < 1000; ++i) - assert((my_map.find(i)->second == i * 10)); - - // Test how badly it fragments the memory - // - FirstFitAlgo> allocator; - std::vector> ptr_vec; - std::mt19937 gen { 98 }; - - std::srand(98); - for (std::size_t i = 0; i < 1000; ++i) { - for (std::size_t j = 0; j < 10; ++j) { - const std::size_t size = (std::rand() % 100) * sizeof(int); - const auto ptr = allocator.get_space(size); - - ptr_vec.push_back(std::make_pair(ptr, size)); - } - - std::shuffle(ptr_vec.begin(), ptr_vec.end(), gen); - - if ((i % 10) == 0) { - for (std::size_t w = 0; w < (ptr_vec.size() / 3); ++w) - allocator.put_space(ptr_vec[w].first, ptr_vec[w].second); - ptr_vec.erase(ptr_vec.begin(), - ptr_vec.begin() + (ptr_vec.size() / 3)); - } - else { - for (std::size_t w = 0; w < (ptr_vec.size() / 2); ++w) - allocator.put_space(ptr_vec[w].first, ptr_vec[w].second); - ptr_vec.erase(ptr_vec.begin(), - ptr_vec.begin() + (ptr_vec.size() / 2)); - } - } -} - -// ----------------------------------------------------------------------------- - -static void test_first_fit_stack_allocator() { - - std::cout << "\nTesting StackFirstFitAllocator ..." << std::endl; - - std::vector> vec1; - - vec1.reserve(1000); - for (std::size_t i = 0; i < 1000; ++i) - vec1.push_back(int(i)); - for (std::size_t i = 0; i < 1000; ++i) - assert(vec1[i] == int(i)); - - std::vector> vec2; - - for (std::size_t i = 0; i < 100; ++i) - vec2.push_back(int(i)); - for (std::size_t i = 0; i < 100; ++i) - assert(vec2[i] == int(i)); - - { - std::vector> vec3; - - for (std::size_t i = 0; i < 100; ++i) - vec3.push_back(double(i)); - for (std::size_t i = 0; i < 100; ++i) - assert(vec3[i] == double(i)); - } - - std::vector> vec4; - - for (std::size_t i = 0; i < 100; ++i) - vec4.push_back(double(i)); - for (std::size_t i = 0; i < 100; ++i) - assert(vec4[i] == double(i)); - - using MyString = std::basic_string, - StackFirstFitAllocator>; - - { - MyString str1 = - "This is the first strig xo xo xo xo xo xo xo xo xo xo xo xo xo xo"; - - str1 += ". Adding more stuff xo xo xo xo xo xo xo xo xo xo"; - - { - MyString str2 = - "This is the second strig"; - - str2 += ". Again, adding more stuff wd wd wd wd wd wd wd wd wd wd"; - - std::cout << str2 << std::endl; - } - std::cout << str1 << std::endl; - } - - MyString str3 = "This is the third strig"; - - str3 += ". Adding more stuff"; - std::cout << str3 << std::endl; - - std::vector> vec5; - - vec5.reserve(1); - for (std::size_t i = 0; i < 2; ++i) - vec5.push_back(double(i)); - for (std::size_t i = 0; i < 2; ++i) - assert(vec5[i] == double(i)); - - using map_t = - std::map, - StackFirstFitAllocator, 1000>>; - - map_t my_map; - - for (int i = 0; i < 1000; ++i) - my_map.insert({ i, i * 10 }); - for (int i = 0; i < 1000; ++i) - assert((my_map.find(i)->second == i * 10)); -} - -// ----------------------------------------------------------------------------- - -static void test_best_fit_static_allocator() { - - std::cout << "\nTesting StaticBestFitAllocator ..." << std::endl; - - std::vector> vec1; - - vec1.reserve(100000); - for (std::size_t i = 0; i < 100000; ++i) - vec1.push_back(int(i)); - for (std::size_t i = 0; i < 100000; ++i) - assert(vec1[i] == int(i)); - - std::vector> vec2; - - for (std::size_t i = 0; i < 10000; ++i) - vec2.push_back(int(i)); - for (std::size_t i = 0; i < 10000; ++i) - assert(vec2[i] == int(i)); - - { - std::vector> vec3; - - for (std::size_t i = 0; i < 10000; ++i) - vec3.push_back(double(i)); - for (std::size_t i = 0; i < 10000; ++i) - assert(vec3[i] == double(i)); - } - - std::vector> vec4; - - for (std::size_t i = 0; i < 10000; ++i) - vec4.push_back(double(i)); - for (std::size_t i = 0; i < 10000; ++i) - assert(vec4[i] == double(i)); - - using MyString = std::basic_string, - StaticBestFitAllocator>; - - { - MyString str1 = - "This is the first strig xo xo xo xo xo xo xo xo xo xo xo xo xo xo"; - - str1 += ". Adding more stuff xo xo xo xo xo xo xo xo xo xo"; - - { - MyString str2 = - "This is the second strig"; - - str2 += ". Again, adding more stuff wd wd wd wd wd wd wd wd wd wd"; - - std::cout << str2 << std::endl; - } - std::cout << str1 << std::endl; - } - - MyString str3 = "This is the third strig"; - - str3 += ". Adding more stuff"; - std::cout << str3 << std::endl; - - std::vector> vec5; - - vec5.reserve(1); - for (std::size_t i = 0; i < 2; ++i) - vec5.push_back(double(i)); - for (std::size_t i = 0; i < 2; ++i) - assert(vec5[i] == double(i)); - - using map_t = - std::map, - StaticBestFitAllocator, 1000>>; - - map_t my_map; - - for (int i = 0; i < 1000; ++i) - my_map.insert({ i, i * 10 }); - for (int i = 0; i < 1000; ++i) - assert((my_map.find(i)->second == i * 10)); - - // Test how badly it fragments the memory - // - BestFitAlgo> allocator; - std::vector> ptr_vec; - std::mt19937 gen { 98 }; - - std::srand(98); - for (std::size_t i = 0; i < 10000; ++i) { - for (std::size_t j = 0; j < 100; ++j) { - const std::size_t size = (std::rand() % 100) * sizeof(int); - const auto ptr = allocator.get_space(size); - - ptr_vec.push_back(std::make_pair(ptr, size)); - } - - std::shuffle(ptr_vec.begin(), ptr_vec.end(), gen); - - if ((i % 10) == 0) { - for (std::size_t w = 0; w < (ptr_vec.size() / 3); ++w) - allocator.put_space(ptr_vec[w].first, ptr_vec[w].second); - ptr_vec.erase(ptr_vec.begin(), - ptr_vec.begin() + (ptr_vec.size() / 3)); - } - else { - for (std::size_t w = 0; w < (ptr_vec.size() / 2); ++w) - allocator.put_space(ptr_vec[w].first, ptr_vec[w].second); - ptr_vec.erase(ptr_vec.begin(), - ptr_vec.begin() + (ptr_vec.size() / 2)); - } - } -} - -// ----------------------------------------------------------------------------- - -static void test_best_fit_stack_allocator() { - - std::cout << "\nTesting StackBestFitAllocator ..." << std::endl; - - std::vector> vec1; - - vec1.reserve(1000); - for (std::size_t i = 0; i < 1000; ++i) - vec1.push_back(int(i)); - for (std::size_t i = 0; i < 1000; ++i) - assert(vec1[i] == int(i)); - - std::vector> vec2; - - for (std::size_t i = 0; i < 100; ++i) - vec2.push_back(int(i)); - for (std::size_t i = 0; i < 100; ++i) - assert(vec2[i] == int(i)); - - { - std::vector> vec3; - - for (std::size_t i = 0; i < 100; ++i) - vec3.push_back(double(i)); - for (std::size_t i = 0; i < 100; ++i) - assert(vec3[i] == double(i)); - } - - std::vector> vec4; - - for (std::size_t i = 0; i < 100; ++i) - vec4.push_back(double(i)); - for (std::size_t i = 0; i < 100; ++i) - assert(vec4[i] == double(i)); - - using MyString = std::basic_string, - StackBestFitAllocator>; - - { - MyString str1 = - "This is the first strig xo xo xo xo xo xo xo xo xo xo xo xo xo xo"; - - str1 += ". Adding more stuff xo xo xo xo xo xo xo xo xo xo"; - - { - MyString str2 = - "This is the second strig"; - - str2 += ". Again, adding more stuff wd wd wd wd wd wd wd wd wd wd"; - - std::cout << str2 << std::endl; - } - std::cout << str1 << std::endl; - } - - MyString str3 = "This is the third strig"; - - str3 += ". Adding more stuff"; - std::cout << str3 << std::endl; - - std::vector> vec5; - - vec5.reserve(1); - for (std::size_t i = 0; i < 2; ++i) - vec5.push_back(double(i)); - for (std::size_t i = 0; i < 2; ++i) - assert(vec5[i] == double(i)); - - using map_t = - std::map, - StackBestFitAllocator, 1000>>; - - map_t my_map; - - for (int i = 0; i < 1000; ++i) - my_map.insert({ i, i * 10 }); - for (int i = 0; i < 1000; ++i) - assert((my_map.find(i)->second == i * 10)); -} - -// ----------------------------------------------------------------------------- - int main(int, char *[]) { test_aligned_allocator(); - test_first_fit_static_allocator(); - test_first_fit_stack_allocator(); - test_best_fit_static_allocator(); - test_best_fit_stack_allocator(); return (0); }