| // Copyright (C) 2000, 2001 Stephen Cleary |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See |
| // accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| // See http://www.boost.org for updates, documentation, and revision history. |
| |
| #ifndef BOOST_OBJECT_POOL_HPP |
| #define BOOST_OBJECT_POOL_HPP |
| /*! |
| \file |
| \brief Provides a template type boost::object_pool<T, UserAllocator> |
| that can be used for fast and efficient memory allocation of objects of type T. |
| It also provides automatic destruction of non-deallocated objects. |
| */ |
| |
| #include <boost/pool/poolfwd.hpp> |
| |
| // boost::pool |
| #include <boost/pool/pool.hpp> |
| |
| // The following code will be put into Boost.Config in a later revision |
| #if defined(BOOST_MSVC) || defined(__KCC) |
| # define BOOST_NO_TEMPLATE_CV_REF_OVERLOADS |
| #endif |
| |
| // The following code might be put into some Boost.Config header in a later revision |
| #ifdef __BORLANDC__ |
| # pragma option push -w-inl |
| #endif |
| |
| // There are a few places in this file where the expression "this->m" is used. |
| // This expression is used to force instantiation-time name lookup, which I am |
| // informed is required for strict Standard compliance. It's only necessary |
| // if "m" is a member of a base class that is dependent on a template |
| // parameter. |
| // Thanks to Jens Maurer for pointing this out! |
| |
| namespace boost { |
| |
| /*! \brief A template class |
| that can be used for fast and efficient memory allocation of objects. |
| It also provides automatic destruction of non-deallocated objects. |
| |
| \details |
| |
| <b>T</b> The type of object to allocate/deallocate. |
| T must have a non-throwing destructor. |
| |
| <b>UserAllocator</b> |
| Defines the allocator that the underlying Pool will use to allocate memory from the system. |
| See <a href="boost_pool/pool/pooling.html#boost_pool.pool.pooling.user_allocator">User Allocators</a> for details. |
| |
| Class object_pool is a template class |
| that can be used for fast and efficient memory allocation of objects. |
| It also provides automatic destruction of non-deallocated objects. |
| |
| When the object pool is destroyed, then the destructor for type T |
| is called for each allocated T that has not yet been deallocated. O(N). |
| |
| Whenever an object of type ObjectPool needs memory from the system, |
| it will request it from its UserAllocator template parameter. |
| The amount requested is determined using a doubling algorithm; |
| that is, each time more system memory is allocated, |
| the amount of system memory requested is doubled. |
| Users may control the doubling algorithm by the parameters passed |
| to the object_pool's constructor. |
| */ |
| |
| template <typename T, typename UserAllocator> |
| class object_pool: protected pool<UserAllocator> |
| { //! |
| public: |
| typedef T element_type; //!< ElementType |
| typedef UserAllocator user_allocator; //!< |
| typedef typename pool<UserAllocator>::size_type size_type; //!< pool<UserAllocator>::size_type |
| typedef typename pool<UserAllocator>::difference_type difference_type; //!< pool<UserAllocator>::difference_type |
| |
| protected: |
| //! \return The underlying boost:: \ref pool storage used by *this. |
| pool<UserAllocator> & store() |
| { |
| return *this; |
| } |
| //! \return The underlying boost:: \ref pool storage used by *this. |
| const pool<UserAllocator> & store() const |
| { |
| return *this; |
| } |
| |
| // for the sake of code readability :) |
| static void * & nextof(void * const ptr) |
| { //! \returns The next memory block after ptr (for the sake of code readability :) |
| return *(static_cast<void **>(ptr)); |
| } |
| |
| public: |
| explicit object_pool(const size_type arg_next_size = 32, const size_type arg_max_size = 0) |
| : |
| pool<UserAllocator>(sizeof(T), arg_next_size, arg_max_size) |
| { //! Constructs a new (empty by default) ObjectPool. |
| //! \param next_size Number of chunks to request from the system the next time that object needs to allocate system memory (default 32). |
| //! \pre next_size != 0. |
| //! \param max_size Maximum number of chunks to ever request from the system - this puts a cap on the doubling algorithm |
| //! used by the underlying pool. |
| } |
| |
| ~object_pool(); |
| |
| // Returns 0 if out-of-memory. |
| element_type * malloc BOOST_PREVENT_MACRO_SUBSTITUTION() |
| { //! Allocates memory that can hold one object of type ElementType. |
| //! |
| //! If out of memory, returns 0. |
| //! |
| //! Amortized O(1). |
| return static_cast<element_type *>(store().ordered_malloc()); |
| } |
| void free BOOST_PREVENT_MACRO_SUBSTITUTION(element_type * const chunk) |
| { //! De-Allocates memory that holds a chunk of type ElementType. |
| //! |
| //! Note that p may not be 0.\n |
| //! |
| //! Note that the destructor for p is not called. O(N). |
| store().ordered_free(chunk); |
| } |
| bool is_from(element_type * const chunk) const |
| { /*! \returns true if chunk was allocated from *this or |
| may be returned as the result of a future allocation from *this. |
| |
| Returns false if chunk was allocated from some other pool or |
| may be returned as the result of a future allocation from some other pool. |
| |
| Otherwise, the return value is meaningless. |
| |
| \note This function may NOT be used to reliably test random pointer values! |
| */ |
| return store().is_from(chunk); |
| } |
| |
| element_type * construct() |
| { //! \returns A pointer to an object of type T, allocated in memory from the underlying pool |
| //! and default constructed. The returned objected can be freed by a call to \ref destroy. |
| //! Otherwise the returned object will be automatically destroyed when *this is destroyed. |
| element_type * const ret = (malloc)(); |
| if (ret == 0) |
| return ret; |
| try { new (ret) element_type(); } |
| catch (...) { (free)(ret); throw; } |
| return ret; |
| } |
| |
| |
| #if defined(BOOST_DOXYGEN) |
| template <class Arg1, ... class ArgN> |
| element_type * construct(Arg1&, ... ArgN&) |
| { |
| //! \returns A pointer to an object of type T, allocated in memory from the underlying pool |
| //! and constructed from arguments Arg1 to ArgN. The returned objected can be freed by a call to \ref destroy. |
| //! Otherwise the returned object will be automatically destroyed when *this is destroyed. |
| //! |
| //! \note Since the number and type of arguments to this function is totally arbitrary, a simple system has been |
| //! set up to automatically generate template construct functions. This system is based on the macro preprocessor |
| //! m4, which is standard on UNIX systems and also available for Win32 systems.\n\n |
| //! detail/pool_construct.m4, when run with m4, will create the file detail/pool_construct.ipp, which only defines |
| //! the construct functions for the proper number of arguments. The number of arguments may be passed into the |
| //! file as an m4 macro, NumberOfArguments; if not provided, it will default to 3.\n\n |
| //! For each different number of arguments (1 to NumberOfArguments), a template function is generated. There |
| //! are the same number of template parameters as there are arguments, and each argument's type is a reference |
| //! to that (possibly cv-qualified) template argument. Each possible permutation of the cv-qualifications is also generated.\n\n |
| //! Because each permutation is generated for each possible number of arguments, the included file size grows |
| //! exponentially in terms of the number of constructor arguments, not linearly. For the sake of rational |
| //! compile times, only use as many arguments as you need.\n\n |
| //! detail/pool_construct.bat and detail/pool_construct.sh are also provided to call m4, defining NumberOfArguments |
| //! to be their command-line parameter. See these files for more details. |
| } |
| #else |
| // Include automatically-generated file for family of template construct() functions. |
| // Copy .inc renamed .ipp to conform to Doxygen include filename expectations, PAB 12 Jan 11. |
| // But still get Doxygen warning: |
| // I:/boost-sandbox/guild/pool/boost/pool/object_pool.hpp:82: |
| // Warning: include file boost/pool/detail/pool_construct.ipp |
| // not found, perhaps you forgot to add its directory to INCLUDE_PATH? |
| // But the file IS found and referenced OK, but cannot view code. |
| // This seems because not at the head of the file |
| // But if moved this up, Doxygen is happy, but of course it won't compile, |
| // because the many constructors *must* go here. |
| |
| #ifndef BOOST_NO_TEMPLATE_CV_REF_OVERLOADS |
| # include <boost/pool/detail/pool_construct.ipp> |
| #else |
| # include <boost/pool/detail/pool_construct_simple.ipp> |
| #endif |
| #endif |
| void destroy(element_type * const chunk) |
| { //! Destroys an object allocated with \ref construct. |
| //! |
| //! Equivalent to: |
| //! |
| //! p->~ElementType(); this->free(p); |
| //! |
| //! \pre p must have been previously allocated from *this via a call to \ref construct. |
| chunk->~T(); |
| (free)(chunk); |
| } |
| |
| size_type get_next_size() const |
| { //! \returns The number of chunks that will be allocated next time we run out of memory. |
| return store().get_next_size(); |
| } |
| void set_next_size(const size_type x) |
| { //! Set a new number of chunks to allocate the next time we run out of memory. |
| //! \param x wanted next_size (must not be zero). |
| store().set_next_size(x); |
| } |
| }; |
| |
| template <typename T, typename UserAllocator> |
| object_pool<T, UserAllocator>::~object_pool() |
| { |
| #ifndef BOOST_POOL_VALGRIND |
| // handle trivial case of invalid list. |
| if (!this->list.valid()) |
| return; |
| |
| details::PODptr<size_type> iter = this->list; |
| details::PODptr<size_type> next = iter; |
| |
| // Start 'freed_iter' at beginning of free list |
| void * freed_iter = this->first; |
| |
| const size_type partition_size = this->alloc_size(); |
| |
| do |
| { |
| // increment next |
| next = next.next(); |
| |
| // delete all contained objects that aren't freed. |
| |
| // Iterate 'i' through all chunks in the memory block. |
| for (char * i = iter.begin(); i != iter.end(); i += partition_size) |
| { |
| // If this chunk is free, |
| if (i == freed_iter) |
| { |
| // Increment freed_iter to point to next in free list. |
| freed_iter = nextof(freed_iter); |
| |
| // Continue searching chunks in the memory block. |
| continue; |
| } |
| |
| // This chunk is not free (allocated), so call its destructor, |
| static_cast<T *>(static_cast<void *>(i))->~T(); |
| // and continue searching chunks in the memory block. |
| } |
| |
| // free storage. |
| (UserAllocator::free)(iter.begin()); |
| |
| // increment iter. |
| iter = next; |
| } while (iter.valid()); |
| |
| // Make the block list empty so that the inherited destructor doesn't try to |
| // free it again. |
| this->list.invalidate(); |
| #else |
| // destruct all used elements: |
| for(std::set<void*>::iterator pos = this->used_list.begin(); pos != this->used_list.end(); ++pos) |
| { |
| static_cast<T*>(*pos)->~T(); |
| } |
| // base class will actually free the memory... |
| #endif |
| } |
| |
| } // namespace boost |
| |
| // The following code might be put into some Boost.Config header in a later revision |
| #ifdef __BORLANDC__ |
| # pragma option pop |
| #endif |
| |
| #endif |