288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // 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
 | 
