Chris@102: ////////////////////////////////////////////////////////////////////////////// Chris@102: // Chris@102: // (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost Chris@102: // Software License, Version 1.0. (See accompanying file Chris@102: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@102: // Chris@102: // See http://www.boost.org/libs/container for documentation. Chris@102: // Chris@102: ////////////////////////////////////////////////////////////////////////////// Chris@102: Chris@102: #ifndef BOOST_CONTAINER_ADAPTIVE_POOL_HPP Chris@102: #define BOOST_CONTAINER_ADAPTIVE_POOL_HPP Chris@102: Chris@102: #ifndef BOOST_CONFIG_HPP Chris@102: # include Chris@102: #endif Chris@102: Chris@102: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@102: # pragma once Chris@102: #endif Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: Chris@102: namespace boost { Chris@102: namespace container { Chris@102: Chris@102: //!An STL node allocator that uses a modified DLMalloc as memory Chris@102: //!source. Chris@102: //! Chris@102: //!This node allocator shares a segregated storage between all instances Chris@102: //!of adaptive_pool with equal sizeof(T). Chris@102: //! Chris@102: //!NodesPerBlock is the number of nodes allocated at once when the allocator Chris@102: //!needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks Chris@102: //!that the adaptive node pool will hold. The rest of the totally free blocks will be Chris@102: //!deallocated to the memory manager. Chris@102: //! Chris@102: //!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator: Chris@102: //!(memory usable for nodes / total memory allocated from the memory allocator) Chris@102: template < class T Chris@102: , std::size_t NodesPerBlock BOOST_CONTAINER_DOCONLY(= ADP_nodes_per_block) Chris@102: , std::size_t MaxFreeBlocks BOOST_CONTAINER_DOCONLY(= ADP_max_free_blocks) Chris@102: , std::size_t OverheadPercent BOOST_CONTAINER_DOCONLY(= ADP_overhead_percent) Chris@102: BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I unsigned Version) Chris@102: > Chris@102: class adaptive_pool Chris@102: { Chris@102: //!If Version is 1, the allocator is a STL conforming allocator. If Version is 2, Chris@102: //!the allocator offers advanced expand in place and burst allocation capabilities. Chris@102: public: Chris@102: typedef unsigned int allocation_type; Chris@102: typedef adaptive_pool Chris@102: self_t; Chris@102: Chris@102: static const std::size_t nodes_per_block = NodesPerBlock; Chris@102: static const std::size_t max_free_blocks = MaxFreeBlocks; Chris@102: static const std::size_t overhead_percent = OverheadPercent; Chris@102: static const std::size_t real_nodes_per_block = NodesPerBlock; Chris@102: Chris@102: BOOST_CONTAINER_DOCIGN(BOOST_STATIC_ASSERT((Version <=2))); Chris@102: Chris@102: public: Chris@102: //------- Chris@102: typedef T value_type; Chris@102: typedef T * pointer; Chris@102: typedef const T * const_pointer; Chris@102: typedef typename ::boost::container:: Chris@102: container_detail::unvoid::type & reference; Chris@102: typedef const typename ::boost::container:: Chris@102: container_detail::unvoid::type & const_reference; Chris@102: typedef std::size_t size_type; Chris@102: typedef std::ptrdiff_t difference_type; Chris@102: Chris@102: typedef boost::container::container_detail:: Chris@102: version_type version; Chris@102: Chris@102: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: typedef boost::container::container_detail:: Chris@102: basic_multiallocation_chain multiallocation_chain_void; Chris@102: typedef boost::container::container_detail:: Chris@102: transform_multiallocation_chain Chris@102: multiallocation_chain; Chris@102: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: Chris@102: //!Obtains adaptive_pool from Chris@102: //!adaptive_pool Chris@102: template Chris@102: struct rebind Chris@102: { Chris@102: typedef adaptive_pool Chris@102: < T2 Chris@102: , NodesPerBlock Chris@102: , MaxFreeBlocks Chris@102: , OverheadPercent Chris@102: BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version) Chris@102: > other; Chris@102: }; Chris@102: Chris@102: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: private: Chris@102: //!Not assignable from related adaptive_pool Chris@102: template Chris@102: adaptive_pool& operator= Chris@102: (const adaptive_pool&); Chris@102: Chris@102: //!Not assignable from other adaptive_pool Chris@102: adaptive_pool& operator=(const adaptive_pool&); Chris@102: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: Chris@102: public: Chris@102: //!Default constructor Chris@102: adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Copy constructor from other adaptive_pool. Chris@102: adaptive_pool(const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Copy constructor from related adaptive_pool. Chris@102: template Chris@102: adaptive_pool Chris@102: (const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Destructor Chris@102: ~adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Returns the number of elements that could be allocated. Chris@102: //!Never throws Chris@102: size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { return size_type(-1)/sizeof(T); } Chris@102: Chris@102: //!Allocate memory for an array of count elements. Chris@102: //!Throws std::bad_alloc if there is no enough memory Chris@102: pointer allocate(size_type count, const void * = 0) Chris@102: { Chris@102: if(BOOST_UNLIKELY(count > this->max_size())) Chris@102: boost::container::throw_bad_alloc(); Chris@102: Chris@102: if(Version == 1 && count == 1){ Chris@102: typedef typename container_detail::shared_adaptive_node_pool Chris@102: shared_pool_t; Chris@102: typedef container_detail::singleton_default singleton_t; Chris@102: return pointer(static_cast(singleton_t::instance().allocate_node())); Chris@102: } Chris@102: else{ Chris@102: return static_cast(boost_cont_malloc(count*sizeof(T))); Chris@102: } Chris@102: } Chris@102: Chris@102: //!Deallocate allocated memory. Chris@102: //!Never throws Chris@102: void deallocate(const pointer &ptr, size_type count) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: (void)count; Chris@102: if(Version == 1 && count == 1){ Chris@102: typedef container_detail::shared_adaptive_node_pool Chris@102: shared_pool_t; Chris@102: typedef container_detail::singleton_default singleton_t; Chris@102: singleton_t::instance().deallocate_node(ptr); Chris@102: } Chris@102: else{ Chris@102: boost_cont_free(ptr); Chris@102: } Chris@102: } Chris@102: Chris@102: pointer allocation_command(allocation_type command, Chris@102: size_type limit_size, Chris@102: size_type &prefer_in_recvd_out_size, Chris@102: pointer &reuse) Chris@102: { Chris@102: pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); Chris@102: if(BOOST_UNLIKELY(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION))) Chris@102: boost::container::throw_bad_alloc(); Chris@102: return ret; Chris@102: } Chris@102: Chris@102: //!Returns maximum the number of objects the previously allocated memory Chris@102: //!pointed by p can hold. Chris@102: size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { return boost_cont_size(p); } Chris@102: Chris@102: //!Allocates just one object. Memory allocated with this function Chris@102: //!must be deallocated only with deallocate_one(). Chris@102: //!Throws bad_alloc if there is no enough memory Chris@102: pointer allocate_one() Chris@102: { Chris@102: typedef container_detail::shared_adaptive_node_pool Chris@102: shared_pool_t; Chris@102: typedef container_detail::singleton_default singleton_t; Chris@102: return (pointer)singleton_t::instance().allocate_node(); Chris@102: } Chris@102: Chris@102: //!Allocates many elements of size == 1. Chris@102: //!Elements must be individually deallocated with deallocate_one() Chris@102: void allocate_individual(std::size_t num_elements, multiallocation_chain &chain) Chris@102: { Chris@102: typedef container_detail::shared_adaptive_node_pool Chris@102: shared_pool_t; Chris@102: typedef container_detail::singleton_default singleton_t; Chris@102: singleton_t::instance().allocate_nodes(num_elements, static_cast(chain)); Chris@102: //typename shared_pool_t::multiallocation_chain ch; Chris@102: //singleton_t::instance().allocate_nodes(num_elements, ch); Chris@102: //chain.incorporate_after Chris@102: //(chain.before_begin(), (T*)&*ch.begin(), (T*)&*ch.last(), ch.size()); Chris@102: } Chris@102: Chris@102: //!Deallocates memory previously allocated with allocate_one(). Chris@102: //!You should never use deallocate_one to deallocate memory allocated Chris@102: //!with other functions different from allocate_one(). Never throws Chris@102: void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: typedef container_detail::shared_adaptive_node_pool Chris@102: shared_pool_t; Chris@102: typedef container_detail::singleton_default singleton_t; Chris@102: singleton_t::instance().deallocate_node(p); Chris@102: } Chris@102: Chris@102: void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: typedef container_detail::shared_adaptive_node_pool Chris@102: shared_pool_t; Chris@102: typedef container_detail::singleton_default singleton_t; Chris@102: //typename shared_pool_t::multiallocation_chain ch(&*chain.begin(), &*chain.last(), chain.size()); Chris@102: //singleton_t::instance().deallocate_nodes(ch); Chris@102: singleton_t::instance().deallocate_nodes(chain); Chris@102: } Chris@102: Chris@102: //!Allocates many elements of size elem_size. Chris@102: //!Elements must be individually deallocated with deallocate() Chris@102: void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 ));/* Chris@102: boost_cont_memchain ch; Chris@102: BOOST_CONTAINER_MEMCHAIN_INIT(&ch); Chris@102: if(BOOST_UNLIKELY(!boost_cont_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ Chris@102: boost::container::throw_bad_alloc(); Chris@102: } Chris@102: chain.incorporate_after(chain.before_begin() Chris@102: ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) Chris@102: ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) Chris@102: ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ Chris@102: if(BOOST_UNLIKELY(!boost_cont_multialloc_nodes Chris@102: (n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ Chris@102: boost::container::throw_bad_alloc(); Chris@102: } Chris@102: } Chris@102: Chris@102: //!Allocates n_elements elements, each one of size elem_sizes[i] Chris@102: //!Elements must be individually deallocated with deallocate() Chris@102: void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 ));/* Chris@102: boost_cont_memchain ch; Chris@102: BOOST_CONTAINER_MEMCHAIN_INIT(&ch); Chris@102: if(BOOST_UNLIKELY(!boost_cont_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ Chris@102: boost::container::throw_bad_alloc(); Chris@102: } Chris@102: chain.incorporate_after(chain.before_begin() Chris@102: ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) Chris@102: ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) Chris@102: ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ Chris@102: if(BOOST_UNLIKELY(!boost_cont_multialloc_arrays Chris@102: (n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ Chris@102: boost::container::throw_bad_alloc(); Chris@102: } Chris@102: } Chris@102: Chris@102: void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {/* Chris@102: boost_cont_memchain ch; Chris@102: void *beg(&*chain.begin()), *last(&*chain.last()); Chris@102: size_t size(chain.size()); Chris@102: BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size); Chris@102: boost_cont_multidealloc(&ch);*/ Chris@102: boost_cont_multidealloc(reinterpret_cast(&chain)); Chris@102: } Chris@102: Chris@102: //!Deallocates all free blocks of the pool Chris@102: static void deallocate_free_blocks() BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: typedef container_detail::shared_adaptive_node_pool Chris@102: shared_pool_t; Chris@102: typedef container_detail::singleton_default singleton_t; Chris@102: singleton_t::instance().deallocate_free_blocks(); Chris@102: } Chris@102: Chris@102: //!Swaps allocators. Does not throw. If each allocator is placed in a Chris@102: //!different memory segment, the result is undefined. Chris@102: friend void swap(adaptive_pool &, adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!An allocator always compares to true, as memory allocated with one Chris@102: //!instance can be deallocated by another instance Chris@102: friend bool operator==(const adaptive_pool &, const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { return true; } Chris@102: Chris@102: //!An allocator always compares to false, as memory allocated with one Chris@102: //!instance can be deallocated by another instance Chris@102: friend bool operator!=(const adaptive_pool &, const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { return false; } Chris@102: Chris@102: private: Chris@102: pointer priv_allocation_command Chris@102: (allocation_type command, std::size_t limit_size Chris@102: ,size_type &prefer_in_recvd_out_size, pointer &reuse_ptr) Chris@102: { Chris@102: std::size_t const preferred_size = prefer_in_recvd_out_size; Chris@102: boost_cont_command_ret_t ret = {0 , 0}; Chris@102: if(BOOST_UNLIKELY(limit_size > this->max_size() || preferred_size > this->max_size())){ Chris@102: return pointer(); Chris@102: } Chris@102: std::size_t l_size = limit_size*sizeof(T); Chris@102: std::size_t p_size = preferred_size*sizeof(T); Chris@102: std::size_t r_size; Chris@102: { Chris@102: void* reuse_ptr_void = reuse_ptr; Chris@102: ret = boost_cont_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); Chris@102: reuse_ptr = ret.second ? static_cast(reuse_ptr_void) : 0; Chris@102: } Chris@102: prefer_in_recvd_out_size = r_size/sizeof(T); Chris@102: return (pointer)ret.first; Chris@102: } Chris@102: }; Chris@102: Chris@102: } //namespace container { Chris@102: } //namespace boost { Chris@102: Chris@102: #include Chris@102: Chris@102: #endif //#ifndef BOOST_CONTAINER_ADAPTIVE_POOL_HPP