Chris@16: // Copyright (C) 2000, 2001 Stephen Cleary
Chris@16: // Copyright (C) 2010 Paul A. Bristow added Doxygen comments.
Chris@16: //
Chris@16: // Distributed under the Boost Software License, Version 1.0. (See
Chris@16: // accompanying file LICENSE_1_0.txt or copy at
Chris@16: // http://www.boost.org/LICENSE_1_0.txt)
Chris@16: //
Chris@16: // See http://www.boost.org for updates, documentation, and revision history.
Chris@16:
Chris@16: #ifndef BOOST_POOL_ALLOC_HPP
Chris@16: #define BOOST_POOL_ALLOC_HPP
Chris@16:
Chris@16: /*!
Chris@16: \file
Chris@16: \brief C++ Standard Library compatible pool-based allocators.
Chris@16: \details This header provides two template types -
Chris@16: \ref pool_allocator and \ref fast_pool_allocator -
Chris@16: that can be used for fast and efficient memory allocation
Chris@16: in conjunction with the C++ Standard Library containers.
Chris@16:
Chris@16: These types both satisfy the Standard Allocator requirements [20.1.5]
Chris@16: and the additional requirements in [20.1.5/4],
Chris@16: so they can be used with either Standard or user-supplied containers.
Chris@16:
Chris@16: In addition, the fast_pool_allocator also provides an additional allocation
Chris@16: and an additional deallocation function:
Chris@16:
Chris@16:
Chris@16: Expression | Return Type | Semantic Equivalence | |
Chris@16: PoolAlloc::allocate() | T * | PoolAlloc::allocate(1) |
Chris@16: PoolAlloc::deallocate(p) | void | PoolAlloc::deallocate(p, 1) |
Chris@16:
Chris@16:
Chris@16: The typedef user_allocator publishes the value of the UserAllocator template parameter.
Chris@16:
Chris@16: Notes
Chris@16:
Chris@16: If the allocation functions run out of memory, they will throw std::bad_alloc.
Chris@16:
Chris@16: The underlying Pool type used by the allocators is accessible through the Singleton Pool Interface.
Chris@16: The identifying tag used for pool_allocator is pool_allocator_tag,
Chris@16: and the tag used for fast_pool_allocator is fast_pool_allocator_tag.
Chris@16: All template parameters of the allocators (including implementation-specific ones)
Chris@16: determine the type of the underlying Pool,
Chris@16: with the exception of the first parameter T, whose size is used instead.
Chris@16:
Chris@16: Since the size of T is used to determine the type of the underlying Pool,
Chris@16: each allocator for different types of the same size will share the same underlying pool.
Chris@16: The tag class prevents pools from being shared between pool_allocator and fast_pool_allocator.
Chris@16: For example, on a system where
Chris@16: sizeof(int) == sizeof(void *), pool_allocator and pool_allocator
Chris@16: will both allocate/deallocate from/to the same pool.
Chris@16:
Chris@16: If there is only one thread running before main() starts and after main() ends,
Chris@16: then both allocators are completely thread-safe.
Chris@16:
Chris@16: Compiler and STL Notes
Chris@16:
Chris@16: A number of common STL libraries contain bugs in their using of allocators.
Chris@16: Specifically, they pass null pointers to the deallocate function,
Chris@16: which is explicitly forbidden by the Standard [20.1.5 Table 32].
Chris@16: PoolAlloc will work around these libraries if it detects them;
Chris@16: currently, workarounds are in place for:
Chris@16: Borland C++ (Builder and command-line compiler)
Chris@16: with default (RogueWave) library, ver. 5 and earlier,
Chris@16: STLport (with any compiler), ver. 4.0 and earlier.
Chris@16: */
Chris@16:
Chris@16: // std::numeric_limits
Chris@16: #include
Chris@16: // new, std::bad_alloc
Chris@16: #include
Chris@16:
Chris@16: #include
Chris@16: #include
Chris@16:
Chris@16: // boost::singleton_pool
Chris@16: #include
Chris@16:
Chris@16: #include
Chris@16:
Chris@16: #ifdef BOOST_POOL_INSTRUMENT
Chris@16: #include
Chris@16: #include
Chris@16: #endif
Chris@16:
Chris@16: // The following code will be put into Boost.Config in a later revision
Chris@16: #if defined(_RWSTD_VER) || defined(__SGI_STL_PORT) || \
Chris@16: BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
Chris@16: #define BOOST_NO_PROPER_STL_DEALLOCATE
Chris@16: #endif
Chris@16:
Chris@16: namespace boost {
Chris@16:
Chris@16: #ifdef BOOST_POOL_INSTRUMENT
Chris@16:
Chris@16: template
Chris@16: struct debug_info
Chris@16: {
Chris@16: static unsigned allocated;
Chris@16: };
Chris@16:
Chris@16: template
Chris@16: unsigned debug_info::allocated = 0;
Chris@16:
Chris@16: #endif
Chris@16:
Chris@16: //! Simple tag type used by pool_allocator as an argument to the
Chris@16: //! underlying singleton_pool.
Chris@16: struct pool_allocator_tag
Chris@16: {
Chris@16: };
Chris@16:
Chris@16: /*! \brief A C++ Standard Library conforming allocator, based on an underlying pool.
Chris@16:
Chris@16: Template parameters for pool_allocator are defined as follows:
Chris@16:
Chris@16: T Type of object to allocate/deallocate.
Chris@16:
Chris@16: UserAllocator. Defines the method that the underlying Pool will use to allocate memory from the system. See
Chris@16: User Allocators for details.
Chris@16:
Chris@16: Mutex Allows the user to determine the type of synchronization to be used on the underlying singleton_pool.
Chris@16:
Chris@16: NextSize The value of this parameter is passed to the underlying singleton_pool when it is created.
Chris@16:
Chris@16: MaxSize Limit on the maximum size used.
Chris@16:
Chris@16: \attention
Chris@16: The underlying singleton_pool used by the this allocator
Chris@16: constructs a pool instance that
Chris@16: is never freed. This means that memory allocated
Chris@16: by the allocator can be still used after main() has
Chris@16: completed, but may mean that some memory checking programs
Chris@16: will complain about leaks.
Chris@16:
Chris@16:
Chris@16: */
Chris@16: template
Chris@16: class pool_allocator
Chris@16: {
Chris@16: public:
Chris@16: typedef T value_type; //!< value_type of template parameter T.
Chris@16: typedef UserAllocator user_allocator; //!< allocator that defines the method that the underlying Pool will use to allocate memory from the system.
Chris@16: typedef Mutex mutex; //!< typedef mutex publishes the value of the template parameter Mutex.
Chris@16: BOOST_STATIC_CONSTANT(unsigned, next_size = NextSize); //!< next_size publishes the values of the template parameter NextSize.
Chris@16:
Chris@16: typedef value_type * pointer; //!<
Chris@16: typedef const value_type * const_pointer;
Chris@16: typedef value_type & reference;
Chris@16: typedef const value_type & const_reference;
Chris@16: typedef typename pool::size_type size_type;
Chris@16: typedef typename pool::difference_type difference_type;
Chris@16:
Chris@16: //! \brief Nested class rebind allows for transformation from
Chris@16: //! pool_allocator to pool_allocator.
Chris@16: //!
Chris@16: //! Nested class rebind allows for transformation from
Chris@16: //! pool_allocator to pool_allocator via the member
Chris@16: //! typedef other.
Chris@16: template
Chris@16: struct rebind
Chris@16: { //
Chris@16: typedef pool_allocator other;
Chris@16: };
Chris@16:
Chris@16: public:
Chris@16: pool_allocator()
Chris@16: { /*! Results in default construction of the underlying singleton_pool IFF an
Chris@16: instance of this allocator is constructed during global initialization (
Chris@16: required to ensure construction of singleton_pool IFF an
Chris@16: instance of this allocator is constructed during global
Chris@16: initialization. See ticket #2359 for a complete explanation at
Chris@16: http://svn.boost.org/trac/boost/ticket/2359) .
Chris@16: */
Chris@16: singleton_pool::is_from(0);
Chris@16: }
Chris@16:
Chris@16: // default copy constructor.
Chris@16:
Chris@16: // default assignment operator.
Chris@16:
Chris@16: // not explicit, mimicking std::allocator [20.4.1]
Chris@16: template
Chris@16: pool_allocator(const pool_allocator &)
Chris@16: { /*! Results in the default construction of the underlying singleton_pool, this
Chris@16: is required to ensure construction of singleton_pool IFF an
Chris@16: instance of this allocator is constructed during global
Chris@16: initialization. See ticket #2359 for a complete explanation
Chris@16: at http://svn.boost.org/trac/boost/ticket/2359 .
Chris@16: */
Chris@16: singleton_pool::is_from(0);
Chris@16: }
Chris@16:
Chris@16: // default destructor
Chris@16:
Chris@16: static pointer address(reference r)
Chris@16: { return &r; }
Chris@16: static const_pointer address(const_reference s)
Chris@16: { return &s; }
Chris@16: static size_type max_size()
Chris@16: { return (std::numeric_limits::max)(); }
Chris@16: static void construct(const pointer ptr, const value_type & t)
Chris@16: { new (ptr) T(t); }
Chris@16: static void destroy(const pointer ptr)
Chris@16: {
Chris@16: ptr->~T();
Chris@16: (void) ptr; // avoid unused variable warning.
Chris@16: }
Chris@16:
Chris@16: bool operator==(const pool_allocator &) const
Chris@16: { return true; }
Chris@16: bool operator!=(const pool_allocator &) const
Chris@16: { return false; }
Chris@16:
Chris@16: static pointer allocate(const size_type n)
Chris@16: {
Chris@16: #ifdef BOOST_POOL_INSTRUMENT
Chris@16: debug_info::allocated += n * sizeof(T);
Chris@16: std::cout << "Allocating " << n << " * " << sizeof(T) << " bytes...\n"
Chris@16: "Total allocated is now " << debug_info::allocated << std::endl;
Chris@16: #endif
Chris@16: const pointer ret = static_cast(
Chris@16: singleton_pool::ordered_malloc(n) );
Chris@16: if ((ret == 0) && n)
Chris@16: boost::throw_exception(std::bad_alloc());
Chris@16: return ret;
Chris@16: }
Chris@16: static pointer allocate(const size_type n, const void * const)
Chris@16: { //! allocate n bytes
Chris@16: //! \param n bytes to allocate.
Chris@16: //! \param unused.
Chris@16: return allocate(n);
Chris@16: }
Chris@16: static void deallocate(const pointer ptr, const size_type n)
Chris@16: { //! Deallocate n bytes from ptr
Chris@16: //! \param ptr location to deallocate from.
Chris@16: //! \param n number of bytes to deallocate.
Chris@16: #ifdef BOOST_POOL_INSTRUMENT
Chris@16: debug_info::allocated -= n * sizeof(T);
Chris@16: std::cout << "Deallocating " << n << " * " << sizeof(T) << " bytes...\n"
Chris@16: "Total allocated is now " << debug_info::allocated << std::endl;
Chris@16: #endif
Chris@16: #ifdef BOOST_NO_PROPER_STL_DEALLOCATE
Chris@16: if (ptr == 0 || n == 0)
Chris@16: return;
Chris@16: #endif
Chris@16: singleton_pool::ordered_free(ptr, n);
Chris@16: }
Chris@16: };
Chris@16:
Chris@16: /*! \brief Specialization of pool_allocator.
Chris@16:
Chris@16: Specialization of pool_allocator for type void: required by the standard to make this a conforming allocator type.
Chris@16: */
Chris@16: template<
Chris@16: typename UserAllocator,
Chris@16: typename Mutex,
Chris@16: unsigned NextSize,
Chris@16: unsigned MaxSize>
Chris@16: class pool_allocator
Chris@16: {
Chris@16: public:
Chris@16: typedef void* pointer;
Chris@16: typedef const void* const_pointer;
Chris@16: typedef void value_type;
Chris@16: //! \brief Nested class rebind allows for transformation from
Chris@16: //! pool_allocator to pool_allocator.
Chris@16: //!
Chris@16: //! Nested class rebind allows for transformation from
Chris@16: //! pool_allocator to pool_allocator via the member
Chris@16: //! typedef other.
Chris@16: template
Chris@16: struct rebind
Chris@16: {
Chris@16: typedef pool_allocator other;
Chris@16: };
Chris@16: };
Chris@16:
Chris@16: //! Simple tag type used by fast_pool_allocator as a template parameter to the underlying singleton_pool.
Chris@16: struct fast_pool_allocator_tag
Chris@16: {
Chris@16: };
Chris@16:
Chris@16: /*! \brief A C++ Standard Library conforming allocator geared towards allocating single chunks.
Chris@16:
Chris@16: While class template pool_allocator is a more general-purpose solution geared towards
Chris@16: efficiently servicing requests for any number of contiguous chunks,
Chris@16: fast_pool_allocator is also a general-purpose solution,
Chris@16: but is geared towards efficiently servicing requests for one chunk at a time;
Chris@16: it will work for contiguous chunks, but not as well as pool_allocator.
Chris@16:
Chris@16: If you are seriously concerned about performance,
Chris@16: use fast_pool_allocator when dealing with containers such as std::list,
Chris@16: and use pool_allocator when dealing with containers such as std::vector.
Chris@16:
Chris@16: The template parameters are defined as follows:
Chris@16:
Chris@16: T Type of object to allocate/deallocate.
Chris@16:
Chris@16: UserAllocator. Defines the method that the underlying Pool will use to allocate memory from the system.
Chris@16: See User Allocators for details.
Chris@16:
Chris@16: Mutex Allows the user to determine the type of synchronization to be used on the underlying singleton_pool.
Chris@16:
Chris@16: NextSize The value of this parameter is passed to the underlying Pool when it is created.
Chris@16:
Chris@16: MaxSize Limit on the maximum size used.
Chris@16:
Chris@16: \attention
Chris@16: The underlying singleton_pool used by the this allocator
Chris@16: constructs a pool instance that
Chris@16: is never freed. This means that memory allocated
Chris@16: by the allocator can be still used after main() has
Chris@16: completed, but may mean that some memory checking programs
Chris@16: will complain about leaks.
Chris@16:
Chris@16: */
Chris@16:
Chris@16: template
Chris@16: class fast_pool_allocator
Chris@16: {
Chris@16: public:
Chris@16: typedef T value_type;
Chris@16: typedef UserAllocator user_allocator;
Chris@16: typedef Mutex mutex;
Chris@16: BOOST_STATIC_CONSTANT(unsigned, next_size = NextSize);
Chris@16:
Chris@16: typedef value_type * pointer;
Chris@16: typedef const value_type * const_pointer;
Chris@16: typedef value_type & reference;
Chris@16: typedef const value_type & const_reference;
Chris@16: typedef typename pool::size_type size_type;
Chris@16: typedef typename pool::difference_type difference_type;
Chris@16:
Chris@16: //! \brief Nested class rebind allows for transformation from
Chris@16: //! fast_pool_allocator to fast_pool_allocator.
Chris@16: //!
Chris@16: //! Nested class rebind allows for transformation from
Chris@16: //! fast_pool_allocator to fast_pool_allocator via the member
Chris@16: //! typedef other.
Chris@16: template
Chris@16: struct rebind
Chris@16: {
Chris@16: typedef fast_pool_allocator other;
Chris@16: };
Chris@16:
Chris@16: public:
Chris@16: fast_pool_allocator()
Chris@16: {
Chris@16: //! Ensures construction of the underlying singleton_pool IFF an
Chris@16: //! instance of this allocator is constructed during global
Chris@16: //! initialization. See ticket #2359 for a complete explanation
Chris@16: //! at http://svn.boost.org/trac/boost/ticket/2359 .
Chris@16: singleton_pool::is_from(0);
Chris@16: }
Chris@16:
Chris@16: // Default copy constructor used.
Chris@16:
Chris@16: // Default assignment operator used.
Chris@16:
Chris@16: // Not explicit, mimicking std::allocator [20.4.1]
Chris@16: template
Chris@16: fast_pool_allocator(
Chris@16: const fast_pool_allocator &)
Chris@16: {
Chris@16: //! Ensures construction of the underlying singleton_pool IFF an
Chris@16: //! instance of this allocator is constructed during global
Chris@16: //! initialization. See ticket #2359 for a complete explanation
Chris@16: //! at http://svn.boost.org/trac/boost/ticket/2359 .
Chris@16: singleton_pool::is_from(0);
Chris@16: }
Chris@16:
Chris@16: // Default destructor used.
Chris@16:
Chris@16: static pointer address(reference r)
Chris@16: {
Chris@16: return &r;
Chris@16: }
Chris@16: static const_pointer address(const_reference s)
Chris@16: { return &s; }
Chris@16: static size_type max_size()
Chris@16: { return (std::numeric_limits::max)(); }
Chris@16: void construct(const pointer ptr, const value_type & t)
Chris@16: { new (ptr) T(t); }
Chris@16: void destroy(const pointer ptr)
Chris@16: { //! Destroy ptr using destructor.
Chris@16: ptr->~T();
Chris@16: (void) ptr; // Avoid unused variable warning.
Chris@16: }
Chris@16:
Chris@16: bool operator==(const fast_pool_allocator &) const
Chris@16: { return true; }
Chris@16: bool operator!=(const fast_pool_allocator &) const
Chris@16: { return false; }
Chris@16:
Chris@16: static pointer allocate(const size_type n)
Chris@16: {
Chris@16: const pointer ret = (n == 1) ?
Chris@16: static_cast(
Chris@16: (singleton_pool::malloc)() ) :
Chris@16: static_cast(
Chris@16: singleton_pool::ordered_malloc(n) );
Chris@16: if (ret == 0)
Chris@16: boost::throw_exception(std::bad_alloc());
Chris@16: return ret;
Chris@16: }
Chris@16: static pointer allocate(const size_type n, const void * const)
Chris@16: { //! Allocate memory .
Chris@16: return allocate(n);
Chris@16: }
Chris@16: static pointer allocate()
Chris@16: { //! Allocate memory.
Chris@16: const pointer ret = static_cast(
Chris@16: (singleton_pool::malloc)() );
Chris@16: if (ret == 0)
Chris@16: boost::throw_exception(std::bad_alloc());
Chris@16: return ret;
Chris@16: }
Chris@16: static void deallocate(const pointer ptr, const size_type n)
Chris@16: { //! Deallocate memory.
Chris@16:
Chris@16: #ifdef BOOST_NO_PROPER_STL_DEALLOCATE
Chris@16: if (ptr == 0 || n == 0)
Chris@16: return;
Chris@16: #endif
Chris@16: if (n == 1)
Chris@16: (singleton_pool::free)(ptr);
Chris@16: else
Chris@16: (singleton_pool::free)(ptr, n);
Chris@16: }
Chris@16: static void deallocate(const pointer ptr)
Chris@16: { //! deallocate/free
Chris@16: (singleton_pool::free)(ptr);
Chris@16: }
Chris@16: };
Chris@16:
Chris@16: /*! \brief Specialization of fast_pool_allocator.
Chris@16:
Chris@16: Specialization of fast_pool_allocator required to make the allocator standard-conforming.
Chris@16: */
Chris@16: template<
Chris@16: typename UserAllocator,
Chris@16: typename Mutex,
Chris@16: unsigned NextSize,
Chris@16: unsigned MaxSize >
Chris@16: class fast_pool_allocator
Chris@16: {
Chris@16: public:
Chris@16: typedef void* pointer;
Chris@16: typedef const void* const_pointer;
Chris@16: typedef void value_type;
Chris@16:
Chris@16: //! \brief Nested class rebind allows for transformation from
Chris@16: //! fast_pool_allocator to fast_pool_allocator.
Chris@16: //!
Chris@16: //! Nested class rebind allows for transformation from
Chris@16: //! fast_pool_allocator to fast_pool_allocator via the member
Chris@16: //! typedef other.
Chris@16: template struct rebind
Chris@16: {
Chris@16: typedef fast_pool_allocator other;
Chris@16: };
Chris@16: };
Chris@16:
Chris@16: } // namespace boost
Chris@16:
Chris@16: #endif