From 03d8347d7141b5af9e197ced6e36a8c50ca4041c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Sun, 29 Mar 2015 22:07:52 +0200 Subject: [PATCH] + added copyright information and licensce file + added example + added README.md file * fixed bug in free_memory_list::allocate(n), allows n to be 1 now * improved memory_pool allocation for arrays if multiple elements can fit into one node --- LICENSE | 21 ++++++++ README.md | 43 +++++++++++++++ allocator_adapter.hpp | 4 ++ allocator_traits.hpp | 6 ++- biicode.conf | 1 + detail/free_list.cpp | 11 ++-- example/main.cpp | 120 +++++++++++++++++++++++++++++++++++++++-- heap_allocator.cpp | 4 ++ heap_allocator.hpp | 4 ++ new_allocator.cpp | 4 ++ new_allocator.hpp | 4 ++ pool_allocator.hpp | 19 +++++-- pool_collection.cpp | 4 ++ pool_collection.hpp | 4 ++ pool_type.hpp | 4 ++ raw_allocator_base.hpp | 4 ++ smart_ptr.hpp | 6 ++- stack_allocator.hpp | 4 ++ std_allocator_base.hpp | 4 ++ tracking.hpp | 4 ++ 20 files changed, 262 insertions(+), 13 deletions(-) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..6280e506 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +Copyright (C) 2015 Jonathan Müller + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but + is not required. + +2. Altered source versions must be plainly marked as such, + and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any + source distribution. diff --git a/README.md b/README.md new file mode 100644 index 00000000..9da03549 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +memory +====== +This library provides various memory allocators for high-performance allocation and deallocation. These allocators are provided in the form of a new allocator concept: RawAllocator. A RawAllocator is an improved version over the classical STL-Allocator. There are various wrapper classes and traits to convert between the two types. Each RawAllocator has the following interface or an appropriate specialization of the raw_allocator_traits: + + // A raw allocator, only supports raw memory allocation. + // Similar to ::operator new/malloc. This avoids the need to be templated and to use one allocator for multiple types. + // The raw_allocator_traits can be specialized to adopt to another interface. + class raw_allocator + { + public: + // Whether or not the allocator is stateful. + // Non-stateful allocators don't need to be stored and can be default constructed on the fly. + using is_stateful = std::true_type/std::false_type; + + // The allocator is required to be moveable + raw_allocator(raw_allocator&&); + raw_allocator& operator=(raw_allocator&&); + + // Allocates memory for a node. A node is a single object of given size and alignment. + // Precondition: size <= max_node_size() && alignment <= max_alignment() + // Throws an exception derived from std::bad_alloc in case of failure. + void* allocate_node(std::size_t size, std::size_t alignment); + + // Allocates memory for an array of multiple nodes. + // Precondition: count * size <= max_array_size() && alignment <= max_alignment() + // Throws an exception derived from std::bad_alloc in case of failure. + void* allocate_array(std::size_t count, std::size_t size, std::size_t alignment); + + // Deallocates memory for a node. Must not throw. + void deallocate_node(void *node, std::size_t size, std::size_t alignment) noexcept; + + // Deallocates memory for an array of nodes. Must not throw. + void deallocate_array(void *array, std::size_t count, std::size_t size, std::size_t alignment) noexcept; + + // Returns the maximum size of a node, inclusive. Should not throw. + std::size_t max_node_size() const; + + // Returns the maximum size for an array (total size, no_elements * object_size), inclusive. Should not throw. + std::size_t max_array_size() const; + + // Returns the maximum supported alignment, inclusive. Should not throw. + std::size_t max_alignment() const; + }; diff --git a/allocator_adapter.hpp b/allocator_adapter.hpp index 5a6926d2..ed2be3f0 100644 --- a/allocator_adapter.hpp +++ b/allocator_adapter.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_ALLOCATOR_ADAPTER_HPP_INCLUDED #define FOONATHAN_MEMORY_ALLOCATOR_ADAPTER_HPP_INCLUDED diff --git a/allocator_traits.hpp b/allocator_traits.hpp index b4ab02c6..9e62299b 100644 --- a/allocator_traits.hpp +++ b/allocator_traits.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED #define FOONATHAN_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED @@ -141,4 +145,4 @@ namespace foonathan { namespace memory {}; }} // namespace foonathan::memory -#endif // FOONATHAN_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED \ No newline at end of file +#endif // FOONATHAN_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED diff --git a/biicode.conf b/biicode.conf index 487107a1..86488e76 100644 --- a/biicode.conf +++ b/biicode.conf @@ -8,6 +8,7 @@ # user/block # No version number means not published yet # You can change it to publish to a different track, and change version, e.g. # user/block(track): 7 + foonathan/memory: 0 [paths] # Local directories to look for headers (within block) diff --git a/detail/free_list.cpp b/detail/free_list.cpp index ce1232ca..b1849bc5 100644 --- a/detail/free_list.cpp +++ b/detail/free_list.cpp @@ -50,6 +50,8 @@ namespace bool check_n(char* &cur, std::size_t n, std::size_t el_size) noexcept { --n; // we already have one (cur) + if (n == 0u) + return true; for (; cur; cur += el_size) { if (next(cur) == cur + el_size) @@ -66,11 +68,12 @@ namespace } } +constexpr std::size_t free_memory_list::min_element_size; +constexpr std::size_t free_memory_list::min_element_alignment; + free_memory_list::free_memory_list(std::size_t el_size) noexcept -: first_(nullptr), el_size_(el_size), capacity_(0u) -{ - assert(el_size >= min_element_size && "element size too small"); -} +: first_(nullptr), el_size_(std::max(min_element_size, el_size)), capacity_(0u) +{} free_memory_list::free_memory_list(std::size_t el_size, void *mem, std::size_t size) noexcept diff --git a/example/main.cpp b/example/main.cpp index 8f7c4a86..564f9473 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -1,9 +1,121 @@ -#include "../pool.hpp" +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. -using namespace foonathan::memory; +#include +#include +#include -int main() +#include "../allocator_adapter.hpp" // for raw_allocator_allocator +#include "../pool_allocator.hpp" // for memory_pool +#include "../tracking.hpp" // for make_tracked_allocator + +using namespace foonathan; + +// uses a RawAllocator or a class that has specialized the raw_allocator_traits +template +void use_allocator(RawAllocator &alloc) +{ + // raw_allocator_allocator is the bridge between RawAllocators and STL-Allocator + using std_allocator = memory::raw_allocator_allocator; + + // create a vector that uses the pool + // it is passed via reference to the vector + std::vector a(alloc); + // add some elements + std::clog << "vector creation\n"; + for (auto i = 0u; i != 10u; ++i) + a.push_back(i); + + // remove the third one + std::clog << "vector erase\n"; + a.erase(a.begin() + 2); + + // make a copy of the vector + // they share the same allocator + std::clog << "vector copy\n"; + auto b = a; + // insert an element into the copy + std::clog << "vector insert\n"; + b.push_back(4); + + // move b into a new vector + // the allocator is transferred two to make it fast + std::clog << "vector move\n"; + auto c = std::move(b); + + // swap a and c, this also swaps the allocator + std::clog << "vector swap\n"; + swap(a, c); + + // create a set that uses the allocator + std::clog << "create set\n"; + std::unordered_set, std::equal_to, std_allocator> + set(5, {}, {}, alloc); // set bucket counter to trigger rehash + + // insert and erase values + std::clog << "insert/erase set\n"; + for (auto i = 0u; i != 10u; ++i) + set.insert(i); + set.erase(2); + set.erase(10); +} +int main() { - memory_pool<> pool(16, 1024); + std::clog << std::unitbuf; + // a memory pool that supports arrays, each node is 32 bytes big, initially 4KB long + memory::memory_pool pool(32, 4096); + { + // allocate one such node + auto mem = pool.allocate_node(); + std::clog << "Allocated a node from pool " << mem << '\n'; + + // deallocate it + pool.deallocate_node(mem); + + // allocate an array, that is, multiple nodes one after the other + mem = pool.allocate_array(16); + std::clog << "Allocated array from pool " << mem << '\n'; + // deallocate it + pool.deallocate_array(mem, 16); + } + // use the allocator inside STL containers + std::clog << "\npool test\n\n"; + use_allocator(pool); + + // tracker class that logs internal behavior of the allocator + struct tracker + { + void on_node_allocation(void *mem, std::size_t size, std::size_t) noexcept + { + std::clog << this << " node allocated: "; + std::clog << mem << " (" << size << ") " << '\n'; + } + + void on_array_allocation(void *mem, std::size_t count, std::size_t size, std::size_t) noexcept + { + std::clog << this << " array allocated: "; + std::clog << mem << " (" << count << " * " << size << ") " << '\n'; + } + + void on_node_deallocation(void *ptr, std::size_t, std::size_t) noexcept + { + std::clog << this << " node deallocated: " << ptr << " \n"; + } + + void on_array_deallocation(void *ptr, std::size_t, std::size_t, std::size_t) noexcept + { + std::clog << this << " array deallocated: " << ptr << " \n"; + } + }; + + // create a tracked memory_pool to see what kind of allocations are made + // necessary to move the pool into the new allocator, since it can't be copied + auto tracked_pool = memory::make_tracked_allocator(tracker{}, std::move(pool)); + // tracked_pool does not provide the pool specific interface anymore, only the general one + + // use it + std::clog << "\ntracked pool test\n\n"; + use_allocator(tracked_pool); } diff --git a/heap_allocator.cpp b/heap_allocator.cpp index de13645c..8f0d08df 100644 --- a/heap_allocator.cpp +++ b/heap_allocator.cpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #include "heap_allocator.hpp" #include diff --git a/heap_allocator.hpp b/heap_allocator.hpp index a3a5a2b2..205bab1f 100644 --- a/heap_allocator.hpp +++ b/heap_allocator.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_HEAP_ALLOCATOR_HPP_INCLUDED #define FOONATHAN_MEMORY_HEAP_ALLOCATOR_HPP_INCLUDED diff --git a/new_allocator.cpp b/new_allocator.cpp index b719b438..159831be 100644 --- a/new_allocator.cpp +++ b/new_allocator.cpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #include "new_allocator.hpp" using namespace foonathan::memory; diff --git a/new_allocator.hpp b/new_allocator.hpp index 11b34acc..df65aa5e 100644 --- a/new_allocator.hpp +++ b/new_allocator.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_NEW_ALLOCATOR_HPP_INCLUDED #define FOONATHAN_MEMORY_NEW_ALLOCATOR_HPP_INCLUDED diff --git a/pool_allocator.hpp b/pool_allocator.hpp index 72eb1ca1..1c00e5a6 100644 --- a/pool_allocator.hpp +++ b/pool_allocator.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_POOL_ALLOCATOR_HPP_INCLUDED #define FOONATHAN_MEMORY_POOL_ALLOCATOR_HPP_INCLUDED @@ -178,7 +182,10 @@ namespace foonathan { namespace memory assert(size <= max_node_size(state) && "invalid node size"); assert(alignment <= max_alignment(state) && "invalid alignment"); assert(count * size <= max_array_size(state) && "invalid array size"); - return state.allocate_array(count); + if (size == max_node_size(state)) + return state.allocate_array(count); + auto ratio = max_node_size(state) / size; + return state.allocate_array(count / ratio + 1); } /// @} @@ -191,9 +198,15 @@ namespace foonathan { namespace memory } static void deallocate_array(allocator_type &state, - void *array, std::size_t count, std::size_t, std::size_t) noexcept + void *array, std::size_t count, std::size_t size, std::size_t) noexcept { - state.deallocate_array(array, count); + if (size == max_node_size(state)) + state.deallocate_array(array, count); + else + { + auto ratio = max_node_size(state) / size; + state.deallocate_array(array, count / ratio + 1); + } } /// @} diff --git a/pool_collection.cpp b/pool_collection.cpp index fc5d1fa5..36087aba 100644 --- a/pool_collection.cpp +++ b/pool_collection.cpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #include "pool_collection.hpp" #include diff --git a/pool_collection.hpp b/pool_collection.hpp index 122be719..03859e8b 100644 --- a/pool_collection.hpp +++ b/pool_collection.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_POOL_COLLECTION_HPP_INCLUDED #define FOONATHAN_MEMORY_POOL_COLLECTION_HPP_INCLUDED diff --git a/pool_type.hpp b/pool_type.hpp index e3b31f17..ea4b0f61 100644 --- a/pool_type.hpp +++ b/pool_type.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_POOL_TYPE_HPP_INCLUDED #define FOONATHAN_MEMORY_POOL_TYPE_HPP_INCLUDED diff --git a/raw_allocator_base.hpp b/raw_allocator_base.hpp index 79e03661..bfbaf0bc 100644 --- a/raw_allocator_base.hpp +++ b/raw_allocator_base.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_RAW_ALLOCATOR_BASE #define FOONATHAN_MEMORY_RAW_ALLOCATOR_BASE diff --git a/smart_ptr.hpp b/smart_ptr.hpp index 2ac83e6f..8f1395cc 100644 --- a/smart_ptr.hpp +++ b/smart_ptr.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_SMART_PTR_HPP_INCLUDED #define FOONATHAN_MEMORY_SMART_PTR_HPP_INCLUDED @@ -243,4 +247,4 @@ namespace foonathan { namespace memory } }} // namespace foonathan::memory -#endif // FOONATHAN_MEMORY_SMART_PTR_HPP_INCLUDED \ No newline at end of file +#endif // FOONATHAN_MEMORY_SMART_PTR_HPP_INCLUDED diff --git a/stack_allocator.hpp b/stack_allocator.hpp index a7ea114b..d0796012 100644 --- a/stack_allocator.hpp +++ b/stack_allocator.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_STACK_ALLOCATOR_HPP_INCLUDED #define FOONATHAN_MEMORY_STACK_ALLOCATOR_HPP_INCLUDED diff --git a/std_allocator_base.hpp b/std_allocator_base.hpp index 8368b116..5882bc52 100644 --- a/std_allocator_base.hpp +++ b/std_allocator_base.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_STD_ALLOCATOR_BASE_HPP_INCLUDED #define FOONATHAN_MEMORY_STD_ALLOCATOR_BASE_HPP_INCLUDED diff --git a/tracking.hpp b/tracking.hpp index db2aa372..a0347a4b 100644 --- a/tracking.hpp +++ b/tracking.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2015 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + #ifndef FOONATHAN_MEMORY_TRACKING_HPP_INCLUDED #define FOONATHAN_MEMORY_TRACKING_HPP_INCLUDED