Chris@102: ////////////////////////////////////////////////////////////////////////////// Chris@102: // Chris@102: // (C) Copyright Ion Gaztanaga 2007-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_ALLOCATOR_HPP Chris@102: #define BOOST_CONTAINER_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: #include Chris@102: Chris@102: namespace boost { Chris@102: namespace container { Chris@102: Chris@102: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: Chris@102: template Chris@102: class allocator Chris@102: { Chris@102: typedef allocator self_t; Chris@102: public: Chris@102: typedef void value_type; Chris@102: typedef void * pointer; Chris@102: typedef const void* const_pointer; Chris@102: typedef int & reference; Chris@102: typedef const int & const_reference; Chris@102: typedef std::size_t size_type; Chris@102: typedef std::ptrdiff_t difference_type; 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; Chris@102: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: Chris@102: //!Obtains an allocator that allocates Chris@102: //!objects of type T2 Chris@102: template Chris@102: struct rebind Chris@102: { Chris@102: typedef allocator< T2 Chris@102: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: , Version, AllocationDisableMask Chris@102: #endif Chris@102: > other; Chris@102: }; Chris@102: Chris@102: //!Default constructor Chris@102: //!Never throws Chris@102: allocator() Chris@102: {} Chris@102: Chris@102: //!Constructor from other allocator. Chris@102: //!Never throws Chris@102: allocator(const allocator &) Chris@102: {} Chris@102: Chris@102: //!Constructor from related allocator. Chris@102: //!Never throws Chris@102: template Chris@102: allocator(const allocator &) Chris@102: {} Chris@102: }; Chris@102: Chris@102: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: Chris@102: //!\file Chris@102: //! This class is an extended STL-compatible that offers advanced allocation mechanism Chris@102: //!(in-place expansion, shrinking, burst-allocation...) Chris@102: //! Chris@102: //! This allocator is a wrapper around a modified DLmalloc. Chris@102: #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: template Chris@102: #else 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: // Chris@102: //! AllocationDisableMask works only if Version is 2 and it can be an inclusive OR Chris@102: //! of allocation types the user wants to disable. Chris@102: template Chris@102: #endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: class allocator Chris@102: { Chris@102: typedef unsigned int allocation_type; Chris@102: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: private: Chris@102: Chris@102: //Self type Chris@102: typedef allocator self_t; Chris@102: Chris@102: //Not assignable from related allocator Chris@102: template Chris@102: allocator& operator=(const allocator&); Chris@102: Chris@102: //Not assignable from other allocator Chris@102: allocator& operator=(const allocator&); Chris@102: Chris@102: static const unsigned int ForbiddenMask = Chris@102: BOOST_CONTAINER_ALLOCATE_NEW | BOOST_CONTAINER_EXPAND_BWD | BOOST_CONTAINER_EXPAND_FWD ; Chris@102: Chris@102: //The mask can't disable all the allocation types Chris@102: BOOST_STATIC_ASSERT(( (AllocationDisableMask & ForbiddenMask) != ForbiddenMask )); Chris@102: Chris@102: //The mask is only valid for version 2 allocators Chris@102: BOOST_STATIC_ASSERT(( Version != 1 || (AllocationDisableMask == 0) )); Chris@102: Chris@102: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@102: Chris@102: public: Chris@102: typedef T value_type; Chris@102: typedef T * pointer; Chris@102: typedef const T * const_pointer; Chris@102: typedef T & reference; Chris@102: typedef const T & 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 void_multiallocation_chain; Chris@102: 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 an allocator that allocates Chris@102: //!objects of type T2 Chris@102: template Chris@102: struct rebind Chris@102: { Chris@102: typedef allocator other; Chris@102: }; Chris@102: Chris@102: //!Default constructor Chris@102: //!Never throws Chris@102: allocator() BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Constructor from other allocator. Chris@102: //!Never throws Chris@102: allocator(const allocator &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Constructor from related allocator. Chris@102: //!Never throws Chris@102: template Chris@102: allocator(const allocator &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: {} Chris@102: Chris@102: //!Allocates memory for an array of count elements. Chris@102: //!Throws std::bad_alloc if there is no enough memory Chris@102: //!If Version is 2, this allocated memory can only be deallocated Chris@102: //!with deallocate() or (for Version == 2) deallocate_many() Chris@102: pointer allocate(size_type count, const void * hint= 0) Chris@102: { Chris@102: (void)hint; Chris@102: if(count > this->max_size()) Chris@102: boost::container::throw_bad_alloc(); Chris@102: void *ret = boost_cont_malloc(count*sizeof(T)); Chris@102: if(!ret) Chris@102: boost::container::throw_bad_alloc(); Chris@102: return static_cast(ret); Chris@102: } Chris@102: Chris@102: //!Deallocates previously allocated memory. Chris@102: //!Never throws Chris@102: void deallocate(pointer ptr, size_type) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { boost_cont_free(ptr); } Chris@102: Chris@102: //!Returns the maximum 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: //!Swaps two allocators, does nothing Chris@102: //!because this allocator is stateless 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 allocator &, const 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 allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { return false; } Chris@102: Chris@102: //!An advanced function that offers in-place expansion shrink to fit and new allocation Chris@102: //!capabilities. Memory allocated with this function can only be deallocated with deallocate() Chris@102: //!or deallocate_many(). Chris@102: //!This function is available only with Version == 2 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: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: const allocation_type mask(AllocationDisableMask); Chris@102: command &= ~mask; Chris@102: pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); Chris@102: if(!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: //!Memory must not have been allocated with Chris@102: //!allocate_one or allocate_individual. Chris@102: //!This function is available only with Version == 2 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: //!This function is available only with Version == 2 Chris@102: pointer allocate_one() Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: return this->allocate(1); Chris@102: } Chris@102: Chris@102: //!Allocates many elements of size == 1. Chris@102: //!Elements must be individually deallocated with deallocate_one() Chris@102: //!This function is available only with Version == 2 Chris@102: void allocate_individual(std::size_t num_elements, multiallocation_chain &chain) Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: this->allocate_many(1, num_elements, chain); 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() or allocate_individual. Chris@102: //Never throws Chris@102: void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: return this->deallocate(p, 1); Chris@102: } Chris@102: Chris@102: //!Deallocates memory allocated with allocate_one() or allocate_individual(). Chris@102: //!This function is available only with Version == 2 Chris@102: void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 )); Chris@102: return this->deallocate_many(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: //!This function is available only with Version == 2 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_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_cont_multialloc_nodes(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: //!This function is available only with Version == 2 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_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: /* Chris@102: if(!boost_cont_multialloc_arrays(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: //!Deallocates several elements allocated by Chris@102: //!allocate_many(), allocate(), or allocation_command(). Chris@102: //!This function is available only with Version == 2 Chris@102: void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: BOOST_STATIC_ASSERT(( Version > 1 )); 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: private: Chris@102: 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_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((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 //BOOST_CONTAINER_ALLOCATOR_HPP Chris@102: