// // immer: immutable data structures for C++ // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente // // This software is distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt // #pragma once #include #include #include #include #include #include #include namespace immer { /*! * Heap policy that unconditionally uses its `Heap` argument. */ template struct heap_policy { using type = Heap; template struct optimized { using type = Heap; }; }; template struct enable_optimized_heap_policy { static void* operator new(std::size_t size) { using heap_type = typename HeapPolicy ::template optimized::type; return heap_type::allocate(size); } static void operator delete(void* data, std::size_t size) { using heap_type = typename HeapPolicy ::template optimized::type; heap_type::deallocate(size, data); } }; /*! * Heap policy that returns a heap with a free list of objects * of `max_size = max(Sizes...)` on top an underlying `Heap`. Note * these two properties of the resulting heap: * * - Allocating an object that is bigger than `max_size` may trigger * *undefined behavior*. * * - Allocating an object of size less than `max_size` still * returns an object of `max_size`. * * Basically, this heap will always return objects of `max_size`. * When an object is freed, it does not directly invoke `std::free`, * but it keeps the object in a global linked list instead. When a * new object is requested, it does not need to call `std::malloc` but * it can directly pop and return the other object from the global * list, a much faster operation. * * This actually creates a hierarchy with two free lists: * * - A `thread_local` free list is used first. It does not need any * kind of synchronization and is very fast. When the thread * finishes, its contents are returned to the next free list. * * - A global free list using lock-free access via atomics. * * @tparam Heap Heap to be used when the free list is empty. * * @rst * * .. tip:: For many applications that use immutable data structures * significantly, this is actually the best heap policy, and it * might become the default in the future. * * Note that most our data structures internally use trees with the * same big branching factors. This means that all *vectors*, * *maps*, etc. can just allocate elements from the same free-list * optimized heap. Not only does this lowers the allocation time, * but also makes up for more efficient *cache utilization*. When * a new node is needed, there are high chances the allocator will * return a node that was just accessed. When batches of immutable * updates are made, this can make a significant difference. * * @endrst */ template struct free_list_heap_policy { using type = debug_size_heap; template struct optimized { using type = split_heap>>>, debug_size_heap>; }; }; /*! * Similar to @ref free_list_heap_policy, but it assumes no * multi-threading, so a single global free list with no concurrency * checks is used. */ template struct unsafe_free_list_heap_policy { using type = Heap; template struct optimized { using type = split_heap< Size, with_free_list_node< unsafe_free_list_heap>>, debug_size_heap>; }; }; } // namespace immer