diff --git a/.travis.yml b/.travis.yml index d5c02969..9955fb8c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,13 +15,12 @@ addons: - g++-4.9 - g++-5 install: - - cmake --version - - wget http://www.cmake.org/files/v3.3/cmake-3.3.1-Linux-x86_64.tar.gz + - wget --no-check-certificate https://www.cmake.org/files/v3.3/cmake-3.3.1-Linux-x86_64.tar.gz - tar -xzf cmake-3.3.1-Linux-x86_64.tar.gz - export CC='gcc-4.8' - export CXX=$compiler script: - mkdir $CXX && cd $CXX - - ../cmake-3.3.1-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=$build_type ../ + - ../cmake-3.3.1-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=$build_type -DCMAKE_CXX_FLAGS="-Wall -Wextra -pedantic -Wno-parentheses" ../ - ../cmake-3.3.1-Linux-x86_64/bin/cmake --build . - ./test/foonathan_memory_test \ No newline at end of file diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 2298d9d2..136a8c25 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,3 +1,16 @@ +0.5 +--- +* improved CMake build system, now supports cmake installation and `find_package()` +* improved low-level allocators and added `malloc_allocator` +* add virtual memory interface and allocators +* add allocators using a fixed-sized storage block +* introduced `BlockAllocator` concept and various implementations +* new class template `memory_arena` that is used inside the higher level allocators, allows more control over the internal allocations +* add wrappers/adapters for the polymorphic memory resource TS +* improved tracking classes +* other improvements like concept checks and more exception classes +* internal changes + 0.4 --- * polished up the interface, many breaking changes in the form of renaming and new header files diff --git a/CMakeLists.txt b/CMakeLists.txt index 82f35aed..36ce7e30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2015 Jonathan Müller +# Copyright (C) 2015-2016 Jonathan Müller # This file is subject to the license terms in the LICENSE file # found in the top-level directory of this distribution. @@ -7,75 +7,13 @@ cmake_minimum_required(VERSION 3.1) project(FOONATHAN_MEMORY) -# compatibility options -include(cmake/compatibility.cmake) - -# debug options -if(${CMAKE_BUILD_TYPE} MATCHES "Debug") - set(debug_asserts ON) - set(debug_checks ON) - set(debug_fence 8) -elseif(${CMAKE_BUILD_TYPE} MATCHES "RelWithDebInfo") - set(debug_asserts OFF) - set(debug_checks ON) - set(debug_fence 0) -else() - set(debug_asserts OFF) - set(debug_checks OFF) - set(debug_fence 0) -endif() - -option(FOONATHAN_MEMORY_DEBUG_ASSERT - "whether or not internal assertions (like the macro assert) are enabled" ${debug_asserts}) -option(FOONATHAN_MEMORY_DEBUG_FILL - "whether or not the (de-)allocated memory will be pre-filled" ${debug_checks}) -set(FOONATHAN_MEMORY_DEBUG_FENCE ${debug_fence} CACHE STRING - "the amount of memory used as fence to help catching overflow errors" ) -option(FOONATHAN_MEMORY_DEBUG_LEAK_CHECK - "whether or not leak checking is active" ${debug_checks}) -option(FOONATHAN_MEMORY_DEBUG_POINTER_CHECK - "whether or not pointer checking on deallocation is active" ${debug_checks}) -option(FOONATHAN_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK - "whether or not the (sometimes expensive) check for double deallocation is active" ${debug_asserts}) - -# other options -set(FOONATHAN_MEMORY_DEFAULT_ALLOCATOR heap_allocator CACHE STRING - "the default implementation allocator for higher-level ones") -option(FOONATHAN_MEMORY_THREAD_SAFE_REFERENCE - "whether or not allocator_reference is thread safe by default" ON) - -# calculates default values for build_* options -if(COMP_HAS_HOSTED_IMPLEMENTATION AND (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)) - # examples/tests if toplevel directory (i.e. direct build, not as subdirectory) and hosted - set(build_examples_tests 1) -else() - set(build_examples_tests 0) -endif() - -if(COMP_HAS_HOSTED_IMPLEMENTATION) - set(build_tools 1) -else() - set(build_tools 0) -endif() - -option(FOONATHAN_MEMORY_BUILD_EXAMPLES "whether or not to build the examples" ${build_examples_tests}) -option(FOONATHAN_MEMORY_BUILD_TESTS "whether or not to build the tests" ${build_examples_tests}) -option(FOONATHAN_MEMORY_BUILD_TOOLS "whether or not to build the tools" ${build_tools}) - -option(FOONATHAN_MEMORY_INCLUDE_PREFIX "whether or not you have to use " OFF) -option(FOONATHAN_MEMORY_NAMESPACE_PREFIX "whether or not everything is in namespace foonathan::memory" OFF) - -# variables to use library in other projects -if(FOONATHAN_MEMORY_INCLUDE_PREFIX) - set(FOONATHAN_MEMORY_INCLUDE_DIR ${FOONATHAN_MEMORY_SOURCE_DIR}/include/ CACHE PATH - "include directory for library") -else() - set(FOONATHAN_MEMORY_INCLUDE_DIR ${FOONATHAN_MEMORY_SOURCE_DIR}/include/foonathan CACHE PATH - "include directory for library") -endif() - set(FOONATHAN_MEMORY_VERSION_MAJOR 0 CACHE STRING "major version of memory" FORCE) -set(FOONATHAN_MEMORY_VERSION_MINOR 4 CACHE STRING "minor version of memory" FORCE) +set(FOONATHAN_MEMORY_VERSION_MINOR 5 CACHE STRING "minor version of memory" FORCE) +set(FOONATHAN_MEMORY_VERSION "${FOONATHAN_MEMORY_VERSION_MAJOR}.${FOONATHAN_MEMORY_VERSION_MINOR}" + CACHE STRING "version of memory" FORCE) + +include(cmake/compatibility.cmake) +include(cmake/configuration.cmake) # subdirectories add_subdirectory(src) @@ -88,3 +26,11 @@ endif() if(FOONATHAN_MEMORY_BUILD_TOOLS) add_subdirectory(tool) endif() + +# exporting +configure_file(cmake/foonathan_memory-config-version.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/foonathan_memory-config-version.cmake + @ONLY) + +install(FILES cmake/foonathan_memory-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/foonathan_memory-config-version.cmake DESTINATION ${main_lib_dest}) +install(EXPORT foonathan_memory DESTINATION ${lib_dest}) diff --git a/LICENSE b/LICENSE index 6280e506..5f7c8202 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2015 Jonathan Müller +Copyright (C) 2015-2016 Jonathan Müller This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held diff --git a/README.md b/README.md index c8c540e2..e3b391f1 100644 --- a/README.md +++ b/README.md @@ -7,49 +7,112 @@ Over the course of the years many solutions have been proposed. for example [EAS ## Features -* new `RawAllocator` concept that is similar to an `Allocator` but easier to use and write -* implementations of it like memory pools, and other allocator classes +New allocator concepts: + +* a `RawAllocator` that is similar to an `Allocator` but easier to use and write +* a `BlockAllocator` that is an allocator for huge memory blocks + +Several implementations: + +* `heap_/malloc_/new_allocator` +* virtual memory allocators +* allocator using a static memory block located on the stack +* memory stack +* different memory pools * a portable, improved `alloca()` in the form of `temporary_allocator` -* various adapter classes, e.g. for memory tracking or type-erased references -* std_allocator class that converts a RawAllocator to an Allocator, so they can be used everywhere an Allocator is accepted -* allocator_deleter clases to have deleters that use a RawAllocator + +Adapters, wrappers and storage classes: + +* incredible powerful `allocator_traits` allowing `Allocator`s as `RawAllocator`s +* `std_allocator` to make a `RawAllocator` an `Allocator` again +* adapters for the memory resource TS +* `allocator_deleter` classes for smart pointers +* (optionally type-erased) `allocator_reference` and other storage classes +* memory tracking wrapper + +In addition: + * container node size debuggers that obtain information about the node size of an STL container at compile-time to specify node sizes for pools -* customizable error handling routines that can work with exceptions disabled * debugging options for leak checking, double-free checks or buffer overflows -* most parts can work on a freestanding implementation +* customizable error handling routines that can work with exceptions disabled +* everything except the STL adapters works on a freestanding environment ## Basic example ```cpp -#include +include #include #include -#include -#include -#include -#include +#include // vector, list, list_node_size +#include // memory_pool +#include // allocate_unique +#include // static_allocator_storage, static_block_allocator +#include // temporary_allocator + +// alias namespace foonathan::memory as memory for easier access +#include template void merge_sort(BiIter begin, BiIter end); int main() { + // a memory pool RawAllocator + // allocates a memory block - initially 4KiB - and splits it into chunks of list_node_size::value big + // list_node_size::value is the size of each node of a std::list memory::memory_pool<> pool(memory::list_node_size::value, 4096u); - // alias for std::list> + // just an alias for std::list> + // a std::list using a memory_pool + // std_allocator stores a reference to a RawAllocator and provides the Allocator interface memory::list> list(pool); list.push_back(3); list.push_back(2); list.push_back(1); + for (auto e : list) + std::cout << e << ' '; + std::cout << '\n'; + merge_sort(list.begin(), list.end()); - // a unique_ptr using the pool + for (auto e : list) + std::cout << e << ' '; + std::cout << '\n'; + + // allocate a std::unique_ptr using the pool + // memory::allocate_shared is also available auto ptr = memory::allocate_unique(pool, *list.begin()); std::cout << *ptr << '\n'; + + // static storage of size 4KiB + memory::static_allocator_storage<4096u> storage; + + // a memory pool again but this time with a BlockAllocator + // this controls the internal allocations of the pool itself + // we need to specify the first template parameter giving the type of the pool as well + // (node_pool is the default) + // we use a static_block_allocator that uses the static storage above + // all allocations will use a memory block on the stack + using static_pool_t = memory::memory_pool; + static_pool_t static_pool(memory::unordered_set_node_size::value, 4096u, storage); + + // again, just an alias for std::unordered_set, std::equal_to, memory::std_allocator + // see why I wrote these? :D + // now we have a hash set that lives on the stack! + memory::unordered_set set(static_pool); + + set.insert(3); + set.insert(2); + set.insert(3); // running out of stack memory is properly handled, of course + + for (auto e : set) + std::cout << e << ' '; + std::cout << '\n'; } +// naive implementation of merge_sort using temporary memory allocator template void merge_sort(BiIter begin, BiIter end) { @@ -62,9 +125,14 @@ void merge_sort(BiIter begin, BiIter end) auto mid = begin; std::advance(mid, distance / 2); + // an allocator for temporary memory + // is similar to alloca() but uses its own stack + // this stack is thread_local and created on the first call to this function + // as soon as the allocator object goes out of scope, everything allocated through it, will be freed auto alloc = memory::make_temporary_allocator(); // alias for std::vector> + // a std::vector using a temporary_allocator memory::vector first(begin, mid, alloc), second(mid, end, alloc); @@ -78,7 +146,7 @@ See `example/` for more. ## Installation -This library is designed to work as [CMake] subdirectory. +This library can be used as [CMake] subdirectory. It is tested on GCC 4.7-4.9, Clang 3.4-3.5 and Visual Studio 2013. Newer versions should work too. 1. Fetch it, e.g. using [git submodules] `git submodule add https://github.com/foonathan/memory ext/memory` and `git submodule update --init --recursive`. @@ -94,6 +162,20 @@ not on the newest version, run `git submodule update --recursive --remote` to force the compatiblity submodule of memory to update to the latest version.* +You can also install the library: + +1. Run `cmake -DCMAKE_BUILD_TYPE="buildtype" -DFOONATHAN_MEMORY_BUILD_EXAMPLES=OFF -DFOONATHAN_MEMORY_BUILD_TESTS=OFF .` inside the library sources. + +2. Run `cmake --build . -- install` to install the library under `${CMAKE_INSTALL_PREFIX}`. + +3. Repeat 1 and 2 for each build type/configuration you want to have (like `Debug`, `RelWithDebInfo` and `Release` or custom names). + +The use an installed library: + +4. Call `find_package(foonathan_memory major.minor REQUIRED)` to find the library. + +5. Call `target_link_libraries(your_target PUBLIC foonathan_memory)` and activate C++11 to link to the library. + See http://foonathan.github.io/doc/memory/md_doc_installation.html for a detailed guide. ## Documentation diff --git a/cmake/comp b/cmake/comp index 92c65148..065396b1 160000 --- a/cmake/comp +++ b/cmake/comp @@ -1 +1 @@ -Subproject commit 92c65148d2eac1c6142951fc820dc2390e55f07e +Subproject commit 065396b124f901abdf59f98a573035e9b57e7bcf diff --git a/cmake/compatibility.cmake b/cmake/compatibility.cmake index ce26e72f..470617bb 100644 --- a/cmake/compatibility.cmake +++ b/cmake/compatibility.cmake @@ -1,4 +1,4 @@ -# Copyright (C) 2015 Jonathan Müller +# Copyright (C) 2015-2016 Jonathan Müller # This file is subject to the license terms in the LICENSE file # found in the top-level directory of this distribution. @@ -7,21 +7,22 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/comp/comp_base.cmake) -# download in source for convenience -set(_foonathan_comp_dest_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/comp) - # dummy library running the required tests -add_library(_foonathan_comp_runner INTERFACE) -comp_target_features(_foonathan_comp_runner INTERFACE - cpp11_lang/alignof cpp11_lang/constexpr cpp11_lang/noexcept cpp11_lang/thread_local - cpp11_lib/max_align_t cpp11_lib/get_new_handler - env/exception_support env/hosted_implementation env/threading_support - PREFIX "FOONATHAN_" NAMESPACE "foonathan_memory_comp" - CMAKE_PATH "${_foonathan_comp_dest_dir}" +add_library(_foonathan_memory_comp_runner INTERFACE) +set(_foonathan_memory_comp_include_path "${CMAKE_CURRENT_BINARY_DIR}") +comp_target_features(_foonathan_memory_comp_runner INTERFACE + cpp11_lang/alignas cpp11_lang/alignof cpp11_lang/constexpr cpp11_lang/noexcept cpp11_lang/thread_local + cpp11_lib/get_new_handler cpp11_lib/max_align_t cpp11_lib/mutex + ts/pmr + env/exception_support env/hosted_implementation + ext/clz + PREFIX "FOONATHAN_" NAMESPACE "foonathan_comp" + INCLUDE_PATH ${_foonathan_memory_comp_include_path} NOFLAGS) +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/foonathan DESTINATION include/comp) function(_foonathan_use_comp target) - # just activate C++11 comp_target_features(${target} PRIVATE CPP11) - target_link_libraries(${target} PUBLIC _foonathan_comp_runner) + target_include_directories(${target} PUBLIC $ + $) endfunction() diff --git a/cmake/configuration.cmake b/cmake/configuration.cmake new file mode 100644 index 00000000..0364fc8c --- /dev/null +++ b/cmake/configuration.cmake @@ -0,0 +1,80 @@ +# Copyright (C) 2015-2016 Jonathan Müller +# This file is subject to the license terms in the LICENSE file +# found in the top-level directory of this distribution. + +# defines configuration options +# note: only include it in memory's top-level CMakeLists.txt, after compatibility.cmake + +# installation destinations +set(tool_dest "bin") # for the nodesize_dbg, just ignore version and the like +set(include_dest "include/foonathan_memory-${FOONATHAN_MEMORY_VERSION}") # header files +set(main_lib_dest "lib/foonathan_memory-${FOONATHAN_MEMORY_VERSION}") # library config file +set(lib_dest "${main_lib_dest}/${CMAKE_BUILD_TYPE}") # build type dependend files (config_impl.hpp/library file) + +# what to build +# examples/tests if toplevel directory (i.e. direct build, not as subdirectory) and hosted +# tools if hosted +if(COMP_HAS_HOSTED_IMPLEMENTATION) + if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(build_examples_tests 1) + else() + set(build_examples_test 0) + endif() + set(build_tools 1) +else() + set(build_examples_tests 0) + set(build_tools 0) +endif() + +option(FOONATHAN_MEMORY_BUILD_EXAMPLES "whether or not to build the examples" ${build_examples_tests}) +option(FOONATHAN_MEMORY_BUILD_TESTS "whether or not to build the tests" ${build_examples_tests}) +option(FOONATHAN_MEMORY_BUILD_TOOLS "whether or not to build the tools" ${build_tools}) + +# debug options, pre-set by build type +if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set(FOONATHAN_MEMORY_DEBUG_ASSERT ON CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_FILL ON CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_FENCE 8 CACHE STRING "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_LEAK_CHECK ON CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_POINTER_CHECK ON CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK ON CACHE BOOL "" FORCE) +elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") + set(FOONATHAN_MEMORY_DEBUG_ASSERT OFF CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_FILL ON CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_FENCE 0 CACHE STRING "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_LEAK_CHECK ON CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_POINTER_CHECK ON CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK OFF CACHE BOOL "" FORCE) +elseif("${CMAKE_BUILD_TYPE}" STREQUAL "Release") + set(FOONATHAN_MEMORY_DEBUG_ASSERT OFF CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_FILL OFF CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_FENCE 0 CACHE STRING "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_LEAK_CHECK OFF CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_POINTER_CHECK OFF CACHE BOOL "" FORCE) + set(FOONATHAN_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK OFF CACHE BOOL "" FORCE) +else() + option(FOONATHAN_MEMORY_DEBUG_ASSERT + "whether or not internal assertions (like the macro assert) are enabled" OFF) + option(FOONATHAN_MEMORY_DEBUG_FILL + "whether or not the (de-)allocated memory will be pre-filled" OFF) + set(FOONATHAN_MEMORY_DEBUG_FENCE 0 CACHE STRING + "the amount of memory used as fence to help catching overflow errors" ) + option(FOONATHAN_MEMORY_DEBUG_LEAK_CHECK + "whether or not leak checking is active" OFF) + option(FOONATHAN_MEMORY_DEBUG_POINTER_CHECK + "whether or not pointer checking on deallocation is active" OFF) + option(FOONATHAN_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK + "whether or not the (sometimes expensive) check for double deallocation is active" OFF) +endif() + +# other options +set(FOONATHAN_MEMORY_DEFAULT_ALLOCATOR heap_allocator CACHE STRING + "the default implementation allocator for higher-level ones") +option(FOONATHAN_MEMORY_THREAD_SAFE_REFERENCE + "whether or not allocator_reference is thread safe by default" ON) +set(FOONATHAN_MEMORY_MEMORY_RESOURCE_HEADER "" CACHE STRING + "the header of the memory_resource class used") +set(FOONATHAN_MEMORY_MEMORY_RESOURCE foonathan_comp::memory_resource CACHE STRING + "the memory_resource class used") +option(FOONATHAN_MEMORY_EXTERN_TEMPLATE + "whether or not common template instantiations are already provided by the library" ON) diff --git a/cmake/foonathan_memory-config-version.cmake.in b/cmake/foonathan_memory-config-version.cmake.in new file mode 100644 index 00000000..027a3a44 --- /dev/null +++ b/cmake/foonathan_memory-config-version.cmake.in @@ -0,0 +1,20 @@ +# Copyright (C) 2015-2016 Jonathan Müller +# This file is subject to the license terms in the LICENSE file +# found in the top-level directory of this distribution. + +# checks version: major must match, minor must be less than or equal + +set(PACKAGE_VERSION @FOONATHAN_MEMORY_VERSION@) + +if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@FOONATHAN_MEMORY_VERSION_MAJOR@") + if ("${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@FOONATHAN_MEMORY_VERSION_MINOR@") + set(PACKAGE_VERSION_EXACT TRUE) + elseif(NOT ("@FOONATHAN_MEMORY_VERSION_MAJOR@" EQUAL 0) + AND "${PACKAGE_FIND_VERSION_MINOR}" LESS "@FOONATHAN_MEMORY_VERSION_MINOR@") + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_UNSUITABLE TRUE) + endif() +else() + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/cmake/foonathan_memory-config.cmake b/cmake/foonathan_memory-config.cmake new file mode 100644 index 00000000..4dc00ded --- /dev/null +++ b/cmake/foonathan_memory-config.cmake @@ -0,0 +1,8 @@ +# Copyright (C) 2015-2016 Jonathan Müller +# This file is subject to the license terms in the LICENSE file +# found in the top-level directory of this distribution. + +# package configuration file + +get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +include(${SELF_DIR}/${CMAKE_BUILD_TYPE}/foonathan_memory.cmake) diff --git a/doc/adapters_storage.md b/doc/adapters_storage.md index 5b31559e..3f18cabf 100644 --- a/doc/adapters_storage.md +++ b/doc/adapters_storage.md @@ -29,15 +29,17 @@ A little bit more semantics provides the alias [thread_safe_allocator] it synchr The [StoragePolicy] [reference_storage] stores a pointer to an allocator object. Although it stores a pointer, it always references an object, i.e. it is never `null`. -It provides two slightly different semantics depending on whether or not the allocator is stateful: +It provides three slightly different semantics depending on whether or not the allocator is stateful: * For stateful allocator, it takes a reference to it. Then it will store a pointer to the given allocator. It does not take ownership, i.e. the passed allocator object must live longer than the reference to it! -* For stateless allocators, it does not actually store anything. They are default-constructed as needed by `get_allocator()`. -This means that they don't actually depend on the lifetime of the given allocator and also can take temporaries. +* For stateless allocators, it uses a `static` object in order to return a reference in `get_allocator()`. +But this means that they don't actually depend on the lifetime of the given allocator and also can take temporaries. -In either case, the class is nothrow copyable and never actually moves the allocator, just copies the pointer. +* For special allocators that already provide reference semantics (determinted through traits specialization), it behaves like a [direct_storage] policy. + +In either case, the class is nothrow copyable and never actually moves the referred allocator, just copies the pointer. A copy of a [reference_storage] references the same allocator as the origin. The alias [allocator_reference] uses this storage policy with the [default_mutex]. diff --git a/doc/concepts.md b/doc/concepts.md index 9b81b1cd..1ab413bc 100644 --- a/doc/concepts.md +++ b/doc/concepts.md @@ -77,14 +77,6 @@ Most of the time stateless allocators are also empty types, although this is not (*note:* it does not make much sense for them to be not-empty, since the values of the member variables is not required to be the same.) An additional requirement for stateless allocator is that they have a default constructor. -Some allocator types manage huge memory block and return part of it in their allocation functions, i.e. memory arenas. -The used memory block is managed by an allocator itself. -Such an allocator is called an *implementation allocator*. -It is simply a normal `RawAllocator` but embedded inside another one and primarily used in it. -They are often low-level allocators that are specialized for huge allocations. -The allocator using the implementation allocator often only needs a memory block of given size. -It is recommended to use the array version there, i.e. to call `allocate_array(size, 1, alignment)`. - Access to a `RawAllocator` is only done via the class [allocator_traits]. It can be specialized for own `RawAllocator` types. The requirements for such a specialization are shown in the following table, @@ -134,13 +126,17 @@ Expression|RawAllocator|Fallback `traits::max_array_size(calloc)` | `calloc.max_array_size()` | `traits::max_node_size(calloc)` `traits::max_alignment(calloc)` | `calloc.max_alignment()` | `alignof(std::max_align_t)` -To allow usage of types modelling the `Allocator` concept, there is an additional behavior when selecting the fallback. +To allow rebinding required for traditional `Allocator`s, there is an additional behavior when selecting the fallback. If the parameter of the `allocator_traits` contains a typedef `value_type`, `traits::allocator_type` will rebind the type to `char`. This is done in the same way `std::allocator_traits` does it, i.e. first try to access the `rebind` member struct, then a type `alloc` will be rebound to `alloc`. If the parameter does not provide a member function `allocate_node`, it will try and call the allocation function required by the `Allocator` concept, i.e. `static_cast(alloc.allocate(size)`, likewise for `deallocate_node` which will call forward to the deallocation function `alloc.deallocate(static_cast(node), size)`. + This enables the usage of any type modelling the `Allocator` concept where a `RawAllocator` is expected. +It is only enabled, however, if the `Allocator` does not provide custom `construct()`/`destroy()` function since they would never be called. +The checking can be overriden by specializing the traits class [allocator_is_raw_allocator](\ref foonathan::memory::allocator_is_raw_allocator). +Note that it does *not* use the `std::allocator_traits` but calls the functions directly enabling only the `Allocator` classes that do not have specialized the traits template. For exposition, this is the minimum required interface for a `RawAllocator` without an appropriate specialization: @@ -160,6 +156,53 @@ struct min_raw_allocator i.e. allocate memory through the traits and deallocate through the member function or vice-versa. It is completely allowed that those functions do completely different things. +## BlockAllocator + +Some allocator types manage huge memory blocks and returns part of them in their allocation functions. +Such huge memory blocks are managed by a memory arena, implemented in the class [memory_arena]. + +The size and the allocation of the memory blocks is controlled by a `BlockAllocator`. +It is responsible to allocate and deallocate those blocks. It must be nothrow moveable and a valid base class, i.e. not `final`. In addition, it must provide the following: + +Expression|Semantics +----------|--------- +`BlockAllocator(block_size, args)`|Creates a `BlockAllocator` by giving it a non-zero initial block size and optionally multiple further arguments. +`alloc.allocate_block()`|Returns a new [memory_block] object that is the next memory block. +`alloc.deallocate_block(block)`|Deallocates a `memory_block`. Deallocation will be done in reverse order. +`calloc.next_block_size()`|Returns the size of the `memory_block` in the next allocation. + +The alignments of the allocated memory blocks must be the maximum alignment. + +This is a sample `BlockAllocator` that uses `new` for the allocation: + +```cpp +class block_allocator +{ +public: + block_allocator(std::size_t block_size) + : block_size_(block_size) {} + + memory_block allocate_block() + { + auto mem = ::operator new(block_size_); + return {mem, block_size_}; + } + + void deallocate_block(memory_block b) + { + ::operator delete(b.memory); + } + + std::size_t next_block_size() const + { + return block_size_; + } + +private: + std::size_t block_size_; +}; +``` + ## StoragePolicy A `StoragePolicy` stores a [RawAllocator](#concept_rawallocator) and is used with the class template [allocator_storage]. @@ -173,7 +216,7 @@ Expression|Semantics ----------|--------- `StoragePolicy::allocator_type` | The type of the allocator being stored as determinted through the [allocator_traits]. For a type-erased storage, it can be the type-erased base class. `StoragePolicy(args)` | Creates the `StoragePolicy`. `args` can be anything. It is used to create the allocator. -`policy.get_allocator()` | Returns a reference to the `allocator_type`. Must not throw. Returns a `const` reference, if `policy` is `const`. Can return a default constructed allocator as a temporary if stateless allocator types are stored. +`policy.get_allocator()` | Returns a reference to the `allocator_type`. Must not throw. May return a `const` reference, if `policy` is `const`. For exposition, this is a sample `StoragePolicy`. Note that it is not required to be a template, although it does not make much sense otherwise. @@ -219,16 +262,14 @@ Expression|Semantics `tracker.on_array_allocation(array, count, size, alignment)` | Same as the [node](#concept_node) version, but for [arrays](#concept_array). `tracker.on_array_deallocation(array, count, size, alignment)` | Same the [node](#concept_node) version, but for [arrays](#concept_array). -A *deep tracker* also tracks an implementation allocator of another allocator +A *deep tracker* also tracks a [BlockAllocator](#concept_block_allocator) of another allocator and thus allows monitoring the often more expensive big allocations done by it. Such a `Tracker` must provide the following additional functions: Expression|Semantics ----------|--------- -`tracker.on_allocator_growth(memory, size)` | Gets called after the implementation allocator has allocated the passed memory block of given size. -`tracker.on_allocator_shrinkage(memory, size)` | Gets called before a given memory block of the implementation allocator will be deallocated. - -The above functions do not distinguish between [nodes](#concept_node) or [arrays](#concept_array). +`tracker.on_allocator_growth(memory, size)` | Gets called after the block allocator has allocated the passed memory block of given size. +`tracker.on_allocator_shrinkage(memory, size)` | Gets called before a given memory block of the block allocator will be deallocated. For exposition, this is a sample `Tracker`: @@ -261,4 +302,6 @@ struct tracker [allocator_storage]: \ref foonathan::memory::allocator_storage [allocator_traits]: \ref foonathan::memory::allocator_traits +[memory_arena]: \ref foonathan::memory::memory_arena +[memory_block]: \ref foonathan::memory::memory_block [tracked_allocator]: \ref foonathan::memory::tracked_allocator diff --git a/doc/index.md b/doc/index.md index 7b4fed75..8ce72087 100644 --- a/doc/index.md +++ b/doc/index.md @@ -3,60 +3,178 @@ This is the documentation of `foonathan/memory`. For a quick start, read the [Tutorial] or skim the examples at the [Github page]. The concepts of this library are defined are [here](md_doc_concepts.html). -## Short example - -This is a short example using a some allocators. - -~~~{.cpp} -#include -#include -#include - -#include -#include -#include -#include - -template -void merge_sort(BiIter begin, BiIter end) -{ - using value_type = typename std::iterator_traits::value_type; - - auto distance = std::distance(begin, end); - if (distance <= 1) - return; - - auto mid = begin; - std::advance(mid, distance / 2); - - auto alloc = memory::make_temporary_allocator(); - - // alias for std::vector> - memory::vector first(begin, mid, alloc), - second(mid, end, alloc); - - merge_sort(first.begin(), first.end()); - merge_sort(second.begin(), second.end()); - std::merge(first.begin(), first.end(), second.begin(), second.end(), begin); -} - -int main() -{ - memory::memory_pool<> pool(memory::list_node_size::value, 4096u); - - // alias for std::list> - memory::list> list(pool); - list.push_back(3); - list.push_back(2); - list.push_back(1); - - merge_sort(list.begin(), list.end()); - - // a unique_ptr using the pool - auto ptr = memory::allocate_unique(pool, *list.begin()); - std::cout << *ptr << '\n'; -} -~~~ +## Features + + New allocator concepts: + + * a `RawAllocator` that is similar to an `Allocator` but easier to use and write + * a `BlockAllocator` that is an allocator for huge memory blocks + + Several implementations: + + * `heap_/malloc_/new_allocator` + * virtual memory allocators + * allocator using a static memory block located on the stack + * memory stack + * different memory pools + * a portable, improved `alloca()` in the form of `temporary_allocator` + + Adapters, wrappers and storage classes: + + * incredible powerful `allocator_traits` allowing `Allocator`s as `RawAllocator`s + * `std_allocator` to make a `RawAllocator` an `Allocator` again + * adapters for the memory resource TS + * `allocator_deleter` classes for smart pointers + * (optionally type-erased) `allocator_reference` and other storage classes + * memory tracking wrapper + + In addition: + + * container node size debuggers that obtain information about the node size of an STL container at compile-time to specify node sizes for pools + * debugging options for leak checking, double-free checks or buffer overflows + * customizable error handling routines that can work with exceptions disabled + * everything except the STL adapters works on a freestanding environment + + ## Basic example + + ```cpp + include + #include + #include + + #include // vector, list, list_node_size + #include // memory_pool + #include // allocate_unique + #include // static_allocator_storage, static_block_allocator + #include // temporary_allocator + + // alias namespace foonathan::memory as memory for easier access + #include + + template + void merge_sort(BiIter begin, BiIter end); + + int main() + { + // a memory pool RawAllocator + // allocates a memory block - initially 4KiB - and splits it into chunks of list_node_size::value big + // list_node_size::value is the size of each node of a std::list + memory::memory_pool<> pool(memory::list_node_size::value, 4096u); + + // just an alias for std::list> + // a std::list using a memory_pool + // std_allocator stores a reference to a RawAllocator and provides the Allocator interface + memory::list> list(pool); + list.push_back(3); + list.push_back(2); + list.push_back(1); + + for (auto e : list) + std::cout << e << ' '; + std::cout << '\n'; + + merge_sort(list.begin(), list.end()); + + for (auto e : list) + std::cout << e << ' '; + std::cout << '\n'; + + // allocate a std::unique_ptr using the pool + // memory::allocate_shared is also available + auto ptr = memory::allocate_unique(pool, *list.begin()); + std::cout << *ptr << '\n'; + + // static storage of size 4KiB + memory::static_allocator_storage<4096u> storage; + + // a memory pool again but this time with a BlockAllocator + // this controls the internal allocations of the pool itself + // we need to specify the first template parameter giving the type of the pool as well + // (node_pool is the default) + // we use a static_block_allocator that uses the static storage above + // all allocations will use a memory block on the stack + using static_pool_t = memory::memory_pool; + static_pool_t static_pool(memory::unordered_set_node_size::value, 4096u, storage); + + // again, just an alias for std::unordered_set, std::equal_to, memory::std_allocator + // see why I wrote these? :D + // now we have a hash set that lives on the stack! + memory::unordered_set set(static_pool); + + set.insert(3); + set.insert(2); + set.insert(3); // running out of stack memory is properly handled, of course + + for (auto e : set) + std::cout << e << ' '; + std::cout << '\n'; + } + + // naive implementation of merge_sort using temporary memory allocator + template + void merge_sort(BiIter begin, BiIter end) + { + using value_type = typename std::iterator_traits::value_type; + + auto distance = std::distance(begin, end); + if (distance <= 1) + return; + + auto mid = begin; + std::advance(mid, distance / 2); + + // an allocator for temporary memory + // is similar to alloca() but uses its own stack + // this stack is thread_local and created on the first call to this function + // as soon as the allocator object goes out of scope, everything allocated through it, will be freed + auto alloc = memory::make_temporary_allocator(); + + // alias for std::vector> + // a std::vector using a temporary_allocator + memory::vector first(begin, mid, alloc), + second(mid, end, alloc); + + merge_sort(first.begin(), first.end()); + merge_sort(second.begin(), second.end()); + std::merge(first.begin(), first.end(), second.begin(), second.end(), begin); + } + ``` + + See `example/` for more. + +## Installation + +This library can be used as [CMake] subdirectory. +It is tested on GCC 4.7-4.9, Clang 3.4-3.5 and Visual Studio 2013. Newer versions should work too. + +1. Fetch it, e.g. using [git submodules] `git submodule add https://github.com/foonathan/memory ext/memory` and `git submodule update --init --recursive`. + +2. Call `add_subdirectory(ext/memory)` or whatever your local path is to make it available in CMake. + +3. Simply call `target_link_libraries(your_target PUBLIC foonathan_memory)` to link this library and setups the include search path. + +4. You need to activate C++11 at your target, if not already done, you can use [foonathan/compatibility] already available through `add_subdirectory()` and call `comp_target_features(your_target PUBLIC CPP11)`. + +*Note: If during CMake you see an error message that compatibility is +not on the newest version, run `git submodule update +--recursive --remote` to force the compatiblity submodule of memory to +update to the latest version.* + +You can also install the library: + +1. Run `cmake -DCMAKE_BUILD_TYPE="buildtype" -DFOONATHAN_MEMORY_BUILD_EXAMPLES=OFF -DFOONATHAN_MEMORY_BUILD_TESTS=OFF .` inside the library sources. + +2. Run `cmake --build . -- install` to install the library under `${CMAKE_INSTALL_PREFIX}`. + +3. Repeat 1 and 2 for each build type/configuration you want to have (like `Debug`, `RelWithDebInfo` and `Release` or custom names). + +The use an installed library: + +4. Call `find_package(foonathan_memory major.minor REQUIRED)` to find the library. + +5. Call `target_link_libraries(your_target PUBLIC foonathan_memory)` and activate C++11 to link to the library. + +See http://foonathan.github.io/doc/memory/md_doc_installation.html for a detailed guide. ## About this documentation diff --git a/doc/installation.md b/doc/installation.md index 5e98b942..110d32f7 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -1,15 +1,16 @@ # Installation -This library is designed to be used with [CMake]'s `add_subdirectory()` command. +This library can either be used [CMake]'s `add_subdirectory()` command or installed globally. -## 0. Requirements +## Requirements * git * CMake version 3.1 or higher * GCC 4.7 or higher, or clang 3.4 or higher or Visual Studio 12 or higher -* the project that wants to use it already uses CMake -## 1. Fetching +## As subdirectory of your project + +### 1. Fetching It is recommended to setup a [git submodule] inside your project. Simply run: @@ -23,7 +24,7 @@ If you later want to update your local copy to the latest version, simply run: ` telling you that a newer version of compatibility is required. This will update the compatibility submodule to its newest version.* -## 2. CMake Setup +### 2. CMake Setup I am assuming that there is a local copy of the library source files under the path `ext/memory`. @@ -40,11 +41,55 @@ It provides an advanced `target_compile_features()` functionality with automated but also a simple way to activate C++11. Just call `comp_target_features(target PUBLIC CPP11)`. This function is already available through the call to `add_subdirectory()` since `memory` is using it, too. -## 3. Code Usage +### 3. Code Usage In your code you simply need to include the appropriate headers and you are good to got. -By default, everything is under the subdirectory `memory/`, so write `#include ` to use the [heap_allocator]. -Also by default a namespace alias `memory` is available which allows access, i.e. write `memory::heap_allocator`. +Everything is under the subdirectory `foonathan/memory` so write `#include ` to use the [heap_allocator]. + +## Installing the library + +Download or clone the source for the library version you want to install. +Run `git submodule update --init --recursive` to fetch the libary's submodules. +You can build the library inside the source directory, it will not be needed after the installation. + +For each build type, run `cmake -DCMAKE_BUILD_TYPE="buildtype" -DFOONATHAN_MEMORY_BUILD_EXAMPLES=OFF -DFOONATHAN_MEMORY_BUILD_TESTS=OFF .` with possible other [options] to configure, then simply `cmake --build . -- install` to build and install the library. +This will install the header files under `${CMAKE_INSTALL_PREFIX}/include/foonathan_memory-${major}.${minor}`, the tools under `${CMAKE_INSTALL_PREFIX}/bin` and the build artifacts under `${CMAKE_INSTALL_PREFIX}/lib/foonathan_memory-${major}.${minor}`. +By default, `${CMAKE_INSTALL_PREFIX}` is `/usr/local` under UNIX and `C:/Program Files` under Windows, +installation may require `sudo`/administrative privileges. + +It is recommended that you install the library for the `Debug`, `RelWithDebInfo` and `Release` build types. +Each build type allows different CMake configurations and compiler flags, you can also create your own. + +## Using an installed library (CMake) + +After you've installed the library, all you need to call is `find_package(foonathan_memory major.minor REQUIRED)` to find it. +This will look for a library installation of a compatible version and the same build type as your project, +i.e. if you compile under build type `Debug`, it will also match the `Debug` library. +This *should* work without your help, otherwise it will tell you what to do. + +A `0.x` version requires an exact match in the call to `find_package()`, otherwise a library with same major version and a higher minor version is also compatible. +If you want only exact version matches add the `EXACT` flag to `find_package()`. + +If a right library version/configuration cannot be found, this is an error due to the `REQUIRED`. +If this is not what you want, leave it out and do conditionals based on the CMake variable `foonathan_memory_FOUND`. +In the source code, all targets linking to the library have the macro `FOONATHAN_MEMORY` defined automatically, +as `FOONATHAN_MEMORY_VERSION_MAJOR/MINOR`. +Use conditional compilation with them. + +After that you can link to the library by calling `target_link_libraries(your_target PUBLIC foonathan_memory)`. +This only requires that `your_target` has C++11 or higher activated. + +*Note: unlike in the `add_subdirectory()` version, my [compatibility library] is not exposed. +You need to add it manually, if you want to use it to activate C++11.* + +Then simply include the headers, everything is under the subdirectory `foonathan/memory` so write `#include ` to use the [heap_allocator]. + +## Using an installed library (other buildsystems) + +To use the library with other build-systems, add `${CMAKE_INSTALL_PREFIX}/include/foonathan_memory-${major}.${minor}` and `${CMAKE_INSTALL_PREFIX}/lib/foonathan_memory-${major}.${minor}/${CMAKE_BUILD_TYPE}` to your include directories path. +Activate C++11 and link to the library file in `${CMAKE_INSTALL_PREFIX}/lib/foonathan_memory-${major}.${minor}/${CMAKE_BUILD_TYPE}`. + +You should also gobally define the `FOONATHAN_MEMORY` macro as `1` and the `FOONATHAN_MEMORY_VERSION_MAJOR/MINOR` macros as the corresponding values. [CMake]: www.cmake.org [git submodule]: http://git-scm.com/docs/git-submodule diff --git a/doc/options.md b/doc/options.md index 8179e9e4..21889cbc 100644 --- a/doc/options.md +++ b/doc/options.md @@ -1,18 +1,30 @@ # CMake options for configuring the library +When installing the library, each build type (`-DCMAKE_BUILD_TYPE=XXX`) allows a separate configuration. +The configuration doesn't affect your targets, you can link to any configuration (your compiler might complain though, if you link your debug target to a library compiled in release mode or vice-versa). + +The build types `Debug`, `RelWithDebInfo` and `Release` provide pre-defined values for the debugging options, +those cannot be overridden. + +You can create as many build types as you want. + ## Options There are the following variables available to configure it: -* `FOONATHAN_MEMORY_DEFAULT_ALLOCATOR`: The default allocator used by the higher level allocator classes. Either `heap_allocator` or `new_allocator`. Default is `heap_allocator`. -* `FOONATHAN_MEMORY_THREAD_SAFE_REFERENCE`: Whether or not the `allocator_reference` is thread safe by default. Default is `ON`. -* `FOONATHAN_MEMORY_DEBUG_*`: specifies debugging options such as pointer check in `deallocate()` or filling newly allocated memory with values. All of them are enabled in `Debug` builds by default, the faster ones in `RelWithDebInfo` and none in `Release`. See [debugging](md_doc_debug_error.html#debugging) for a detailed description. - * `FOONATHAN_HAS_*`: specifies compatibility options, that is, whether a certain C++ feature is available under your compiler. They are automatically detected by CMake, so there is usually no need to change them. -* `FOONATHAN_MEMORY_BUILD_*`: whether or not to build examples or tests. If this is `OFF` their CMake scripts are not even included. It is `ON` for standalone builds and `OFF` if used in `add_subdirectory()`. + +* `FOONATHAN_MEMORY_BUILD_EXAMPLES/_TESTS`: whether or not to build examples or tests. If this is `OFF` their CMake scripts are not even included. It is `ON` for standalone builds and `OFF` if used in `add_subdirectory()`. * `FOONATHAN_MEMORY_BUILD_TOOLS`: whether or not build the tools. Unlike the other two options, this is always `ON`. -* `FOONATHAN_MEMORY_NAMESPACE_PREFIX`: If `ON`, everything is in namespace `foonathan::memory`. If `OFF`, you can use namespace `memory` directly (the default). -* `FOONATHAN_MEMORY_INCLUDE_PREFIX`: Similar to the namespace prefix, if `ON`, include directory is ``, if `OFF`include directory is `` directly (the default). + + +* `FOONATHAN_MEMORY_EXTERN_TEMPLATE`: If active the library provides already the definition of common instantiations of its class templates. This can speed up compilation time of user code since the compiler does not need to generate the definition each time the class instantiation is used (this compilation time is done when compiling the library and the size of the library binary increases). Default is `ON`. + +* `FOONATHAN_MEMORY_DEFAULT_ALLOCATOR`: The default allocator used by the higher level allocator classes. One of the low level allocators (see \ref foonathan::memory::default_allocator). Default is `heap_allocator`. +* `FOONATHAN_MEMORY_THREAD_SAFE_REFERENCE`: Whether or not the `allocator_reference` is thread safe by default. Default is `ON`. +* `FOONATHAN_MEMORY_MEMORY_RESOURCE` and `FOONATHAN_MEMORY_MEMORY_RESOURCE_HEADER`: Specifye th memory resource class used. The first one is the full name including namespace, the second one the header (including `"..."` or `<...>` that needs to be included for it. Default is `foonathan_comp::memory_resource` and `"foonathan/memory_resource.hpp"` to use the version of foonathan/compatibility. + +* `FOONATHAN_MEMORY_DEBUG_*`: Specifies debugging options such as pointer check in `deallocate()` or filling newly allocated memory with values. They are set automatically for certain build types and cannot be overriden: All of them are enabled in `Debug` builds, the faster ones in `RelWithDebInfo` and none in `Release`. See [debugging](md_doc_debug_error.html#debugging) for a detailed description. A list of all options with description is generated by calling `cmake -LH`. @@ -21,7 +33,7 @@ A list of all options with description is generated by calling `cmake -LH`. The following variables or targets are available if used with `add_subdirectory()`: * `FOONATHAN_MEMORY_INCLUDE_DIR` (variable): The include directory for the header files. -* `FOONATHAN_MEMORY_VERSION_MAJOR/MINOR` (variable): Major and minor version of the library. +* `FOONATHAN_MEMORY_VERSION[_MAJOR/MINOR]` (variable): Major and minor version of the library. * `foonathan_memory` (target): The target of the library you can link to. * `foonathan_memory_example_*` (target): The targets for the examples. Only available if `FOONATHAN_MEMORY_BUILD_EXAMPLES` is `ON`. * `foonathan_memory_test` (target): The test target. Only available if `FOONATHAN_MEMORY_BUILD_TESTS` is `ON`. diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 70c40f49..7f761b24 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2015 Jonathan Müller +# Copyright (C) 2015-2016 Jonathan Müller # This file is subject to the license terms in the LICENSE file # found in the top-level directory of this distribution. @@ -7,8 +7,6 @@ macro(_foonathan_add_example name) add_executable(foonathan_memory_example_${name} ${name}.cpp) target_link_libraries(foonathan_memory_example_${name} PRIVATE foonathan_memory) - target_include_directories(foonathan_memory_example_${name} PRIVATE - ${FOONATHAN_MEMORY_SOURCE_DIR}/include/foonathan/) comp_target_features(foonathan_memory_example_${name} PUBLIC CPP11) endmacro() diff --git a/example/allocator_storage.cpp b/example/allocator_storage.cpp index f5ff916b..0f6c37dd 100644 --- a/example/allocator_storage.cpp +++ b/example/allocator_storage.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jonathan Müller +// Copyright (C) 2015-2016 Jonathan Müller // This file is subject to the license terms in the LICENSE file // found in the top-level directory of this distribution. @@ -8,14 +8,12 @@ #include #include -#include // allocator_reference, any_allocator_reference -#include // heap_allocator -#include // memory_stack +#include // allocator_reference, any_allocator_reference +#include // heap_allocator +#include // memory_stack -// namespace alias for easier access -// if the CMake option FOONATHAN_MEMORY_NAMESPACE_PREFIX is OFF (the default), -// it is already provided in each header file, so unznecessary in real application code -namespace memory = foonathan::memory; +// alias namespace foonathan::memory as memory for easier access +#include template void do_sth(memory::allocator_reference ref); diff --git a/example/taking_allocators.cpp b/example/taking_allocators.cpp index 82b38db1..3515fe9d 100644 --- a/example/taking_allocators.cpp +++ b/example/taking_allocators.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jonathan Müller +// Copyright (C) 2015-2016 Jonathan Müller // This file is subject to the license terms in the LICENSE file // found in the top-level directory of this distribution. @@ -11,13 +11,11 @@ #include #include -#include // allocator_reference -#include // default_allocator +#include // allocator_reference +#include // default_allocator -// namespace alias for easier access -// if the CMake option FOONATHAN_MEMORY_NAMESPACE_PREFIX is OFF (the default), -// it is already provided in each header file, so unecessary in real application code -namespace memory = foonathan::memory; +// alias namespace foonathan::memory as memory for easier access +#include namespace using_std_allocator { diff --git a/example/tracking.cpp b/example/tracking.cpp index 6df8c36d..c6d62f8f 100644 --- a/example/tracking.cpp +++ b/example/tracking.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jonathan Müller +// Copyright (C) 2015-2016 Jonathan Müller // This file is subject to the license terms in the LICENSE file // found in the top-level directory of this distribution. @@ -7,14 +7,12 @@ #include -#include // set, set_node_size -#include // memory_pool -#include // make_tracked_allocator +#include // set, set_node_size +#include // memory_pool +#include // make_tracked_allocator -// namespace alias for easier access -// if the CMake option FOONATHAN_MEMORY_NAMESPACE_PREFIX is OFF (the default), -// it is already provided in each header file, so unnecessary in real application code -namespace memory = foonathan::memory; +// alias namespace foonathan::memory as memory for easier access +#include int main() { diff --git a/example/using_allocators.cpp b/example/using_allocators.cpp index 629c1255..5eca3074 100644 --- a/example/using_allocators.cpp +++ b/example/using_allocators.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jonathan Müller +// Copyright (C) 2015-2016 Jonathan Müller // This file is subject to the license terms in the LICENSE file // found in the top-level directory of this distribution. @@ -9,15 +9,14 @@ #include #include -#include // vector, list, list_node_size -#include // memory_pool -#include // allocate_unique -#include // temporary_allocator +#include // vector, list, list_node_size,... +#include // memory_pool +#include // allocate_unique +#include // static_allocator_storage, static_block_allocator +#include // temporary_allocator -// namespace alias for easier access -// if the CMake option FOONATHAN_MEMORY_NAMESPACE_PREFIX is OFF (the default), -// it is already provided in each header file, so unnecessary in real application code -namespace memory = foonathan::memory; +// alias namespace foonathan::memory as memory for easier access +#include template void merge_sort(BiIter begin, BiIter end); @@ -29,7 +28,7 @@ int main() // list_node_size::value is the size of each node of a std::list memory::memory_pool<> pool(memory::list_node_size::value, 4096u); - // alias for std::list> + // just an alias for std::list> // a std::list using a memory_pool // std_allocator stores a reference to a RawAllocator and provides the Allocator interface memory::list> list(pool); @@ -37,12 +36,45 @@ int main() list.push_back(2); list.push_back(1); + for (auto e : list) + std::cout << e << ' '; + std::cout << '\n'; + merge_sort(list.begin(), list.end()); + for (auto e : list) + std::cout << e << ' '; + std::cout << '\n'; + // allocate a std::unique_ptr using the pool // memory::allocate_shared is also available auto ptr = memory::allocate_unique(pool, *list.begin()); std::cout << *ptr << '\n'; + + // static storage of size 4KiB + memory::static_allocator_storage<4096u> storage; + + // a memory pool again but this time with a BlockAllocator + // this controls the internal allocations of the pool itself + // we need to specify the first template parameter giving the type of the pool as well + // (node_pool is the default) + // we use a static_block_allocator that uses the static storage above + // all allocations will use a memory block on the stack + using static_pool_t = memory::memory_pool; + static_pool_t static_pool(memory::unordered_set_node_size::value, 4096u, storage); + + // again, just an alias for std::unordered_set, std::equal_to, memory::std_allocator + // see why I wrote these? :D + // now we have a hash set that lives on the stack! + memory::unordered_set set(13, std::hash{}, std::equal_to{}, static_pool); // GCC 4.7 is missing the allocator-only ctor, breaks travis :( + + set.insert(3); + set.insert(2); + set.insert(3); // running out of stack memory is properly handled, of course + + for (auto e : set) + std::cout << e << ' '; + std::cout << '\n'; } // naive implementation of merge_sort using temporary memory allocator diff --git a/include/foonathan/memory/aligned_allocator.hpp b/include/foonathan/memory/aligned_allocator.hpp index 9c031f00..97b9daa5 100644 --- a/include/foonathan/memory/aligned_allocator.hpp +++ b/include/foonathan/memory/aligned_allocator.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jonathan Müller +// Copyright (C) 2015-2016 Jonathan Müller // This file is subject to the license terms in the LICENSE file // found in the top-level directory of this distribution. @@ -8,16 +8,18 @@ /// \file /// Class \ref foonathan::memory::aligned_allocator and related functions. +#include + +#include "detail/assert.hpp" #include "detail/utility.hpp" #include "allocator_traits.hpp" #include "config.hpp" -#include "error.hpp" namespace foonathan { namespace memory { /// A \concept{concept_rawallocator,RawAllocator} adapter that ensures a minimum alignment. /// It adjusts the alignment value so that it is always larger than the minimum and forwards to the specified allocator. - /// \ingroup memory + /// \ingroup memory adapter template class aligned_allocator : FOONATHAN_EBO(allocator_traits::allocator_type) diff --git a/include/foonathan/memory/allocator_storage.hpp b/include/foonathan/memory/allocator_storage.hpp index a2003322..3ce01fbb 100644 --- a/include/foonathan/memory/allocator_storage.hpp +++ b/include/foonathan/memory/allocator_storage.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jonathan Müller +// Copyright (C) 2015-2016 Jonathan Müller // This file is subject to the license terms in the LICENSE file // found in the top-level directory of this distribution. @@ -25,13 +25,6 @@ namespace foonathan { namespace memory namespace detail { - // whether or not a type is an instantiation of a template - template