Chris@102: ////////////////////////////////////////////////////////////////////////////// Chris@102: // Chris@102: // (C) Copyright Ion Gaztanaga 2008-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_POOLED_NODE_ALLOCATOR_HPP Chris@102: #define BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_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: Chris@102: #include Chris@102: #include Chris@102: #include 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 node_allocator with equal sizeof(T). Chris@102: //! Chris@102: //!NodesPerBlock is the number of nodes allocated at once when the allocator Chris@102: //!runs out of nodes Chris@102: #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: template Chris@102: < class T Chris@102: , std::size_t NodesPerBlock = NodeAlloc_nodes_per_block> Chris@102: #else Chris@102: template Chris@102: < class T Chris@102: , std::size_t NodesPerBlock Chris@102: , std::size_t Version> Chris@102: #endif Chris@102: class node_allocator Chris@102: { Chris@102: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED 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 node_allocator self_t; Chris@102: Chris@102: static const std::size_t nodes_per_block = NodesPerBlock; Chris@102: Chris@102: BOOST_STATIC_ASSERT((Version <=2)); Chris@102: #endif 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 node_allocator from Chris@102: //!node_allocator Chris@102: template Chris@102: struct rebind Chris@102: { Chris@102: typedef node_allocator< T2, NodesPerBlock Chris@102: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: , Version Chris@102: #endif Chris@102: > other; Chris@102: }; Chris@102: Chris@102: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: private: Chris@102: //!Not assignable from related node_allocator Chris@102: template Chris@102: node_allocator& operator= Chris@102: (const node_allocator&); Chris@102: Chris@102: //!Not assignable from other node_allocator Chris@102: node_allocator& operator=(const node_allocator&); Chris@102: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: Chris@102: public: Chris@102: Chris@102: //!Default constructor Chris@102: node_allocator() BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Copy constructor from other node_allocator. Chris@102: node_allocator(const node_allocator &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Copy constructor from related node_allocator. Chris@102: template Chris@102: node_allocator Chris@102: (const node_allocator &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Destructor Chris@102: ~node_allocator() 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 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 container_detail::shared_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: void *ret = boost_cont_malloc(count*sizeof(T)); Chris@102: if(BOOST_UNLIKELY(!ret)) Chris@102: boost::container::throw_bad_alloc(); Chris@102: return static_cast(ret); 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_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: //!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_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: pointer allocation_command Chris@102: (allocation_type command, size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 )); 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: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: return boost_cont_size(p); Chris@102: } 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: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: typedef container_detail::shared_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: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: typedef container_detail::shared_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; Chris@102: singleton_t::instance().allocate_nodes(num_elements, ch); Chris@102: chain.incorporate_after(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: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: typedef container_detail::shared_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: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: typedef container_detail::shared_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: } 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_LASTMEM(&ch) Chris@102: , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) Chris@102: , BOOST_CONTAINER_MEMCHAIN_SIZE(&ch)); 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_cont_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch); Chris@102: if(BOOST_UNLIKELY(BOOST_CONTAINER_MEMCHAIN_EMPTY(&ch))){ Chris@102: boost::container::throw_bad_alloc(); Chris@102: } Chris@102: chain.incorporate_after( chain.before_begin() Chris@102: , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) Chris@102: , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) Chris@102: , BOOST_CONTAINER_MEMCHAIN_SIZE(&ch)); Chris@102: } Chris@102: Chris@102: void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: void *first = &*chain.begin(); Chris@102: void *last = &*chain.last(); Chris@102: size_t num = chain.size(); Chris@102: boost_cont_memchain ch; Chris@102: BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, first, last, num); Chris@102: boost_cont_multidealloc(&ch); 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(self_t &, self_t &) 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 node_allocator &, const node_allocator &) 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 node_allocator &, const node_allocator &) 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 Chris@102: ,pointer &reuse) 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((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; Chris@102: ret = boost_cont_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); Chris@102: reuse = static_cast(reuse_ptr_void); 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_POOLED_NODE_ALLOCATOR_HPP