From a555ddfd1dbb9449bffdcad7e3e8b50abc14973e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Sat, 16 Apr 2016 20:44:56 +0200 Subject: [PATCH] Improve array allocations in memory_pool_collection Now it uses the shared stack directly and supports free lists that do not support array allocations natively. Also change internal requirements for those free lists. --- .../memory/detail/small_free_list.hpp | 9 +++-- .../memory/memory_pool_collection.hpp | 38 ++++++++++++------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/include/foonathan/memory/detail/small_free_list.hpp b/include/foonathan/memory/detail/small_free_list.hpp index e3057a27..cce655d3 100644 --- a/include/foonathan/memory/detail/small_free_list.hpp +++ b/include/foonathan/memory/detail/small_free_list.hpp @@ -77,7 +77,7 @@ namespace foonathan { namespace memory // pre: !empty() void* allocate() FOONATHAN_NOEXCEPT; - // must not be called + // always returns nullptr, because array allocations are not supported void* allocate(std::size_t) FOONATHAN_NOEXCEPT { return nullptr; @@ -86,8 +86,11 @@ namespace foonathan { namespace memory // deallocates the node previously allocated via allocate() void deallocate(void *node) FOONATHAN_NOEXCEPT; - // must not be called - void deallocate(void *, std::size_t) FOONATHAN_NOEXCEPT {} + // forwards to insert() + void deallocate(void *mem, std::size_t size) FOONATHAN_NOEXCEPT + { + insert(mem, size); + } // hint for allocate() to be prepared to allocate n nodes // it searches for a chunk that has n nodes free diff --git a/include/foonathan/memory/memory_pool_collection.hpp b/include/foonathan/memory/memory_pool_collection.hpp index 78fc5ae8..7eb58930 100644 --- a/include/foonathan/memory/memory_pool_collection.hpp +++ b/include/foonathan/memory/memory_pool_collection.hpp @@ -123,8 +123,14 @@ namespace foonathan { namespace memory detail::check_allocation_size(node_size, [&]{return max_node_size();}, info()); auto& pool = pools_.get(node_size); if (pool.empty()) - reserve_impl(pool, def_capacity()); - return pool.allocate(); + { + auto block = reserve_memory(pool, def_capacity()); + pool.insert(block.memory, block.size); + } + + auto mem = pool.allocate(); + FOONATHAN_MEMORY_ASSERT(mem); + return mem; } /// \effects Allocates an \concept{concept_array,array} of nodes by searching for \c n continuous nodes on the appropriate free list and removing them. @@ -141,16 +147,20 @@ namespace foonathan { namespace memory detail::check_allocation_size(node_size, [&]{return max_node_size();}, info()); auto& pool = pools_.get(node_size); - if (pool.empty()) - reserve_impl(pool, def_capacity()); - auto mem = pool.allocate(count * node_size); + + // try allocating if not empty + // for pools without array allocation support, allocate() will always return nullptr + auto mem = pool.empty() ? nullptr : pool.allocate(count * node_size); if (!mem) { - reserve_impl(pool, count * node_size); - mem = pool.allocate(count * node_size); - if (!mem) - FOONATHAN_THROW(bad_array_size(info(), count * node_size, next_capacity())); + // use stack for allocation + detail::check_allocation_size(count * node_size, + [&]{return next_capacity() - pool.alignment() + 1;}, + info()); + mem = reserve_memory(pool, count * node_size).memory; + FOONATHAN_MEMORY_ASSERT(mem); } + return mem; } @@ -167,8 +177,9 @@ namespace foonathan { namespace memory /// i.e. either this allocator object or a new object created by moving this to it. void deallocate_array(void *ptr, std::size_t count, std::size_t node_size) FOONATHAN_NOEXCEPT { - FOONATHAN_MEMORY_ASSERT_MSG(PoolType::value, "array allocations not supported"); auto& pool = pools_.get(node_size); + // deallocate array + // for pools without array allocation support, this will simply forward to insert() pool.deallocate(ptr, count * node_size); } @@ -183,7 +194,7 @@ namespace foonathan { namespace memory { FOONATHAN_MEMORY_ASSERT_MSG(node_size <= max_node_size(), "node_size too big"); auto& pool = pools_.get(node_size); - reserve_impl(pool, capacity); + reserve_memory(pool, capacity); } /// \returns The maximum node size for which is a free list. @@ -249,7 +260,7 @@ namespace foonathan { namespace memory return static_cast(block.memory) + block.size; } - void reserve_impl(typename pool_type::type &pool, std::size_t capacity) + memory_block reserve_memory(typename pool_type::type &pool, std::size_t capacity) { auto mem = stack_.allocate(block_end(), capacity, detail::max_alignment); if (!mem) @@ -272,8 +283,7 @@ namespace foonathan { namespace memory mem = stack_.allocate(block_end(), capacity, detail::max_alignment); FOONATHAN_MEMORY_ASSERT(mem); } - // insert new - pool.insert(mem, capacity); + return {mem, capacity}; } memory_arena arena_;