You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							251 lines
						
					
					
						
							9.7 KiB
						
					
					
				
			
		
		
	
	
							251 lines
						
					
					
						
							9.7 KiB
						
					
					
				| // 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_SINGLETON_POOL_HPP | |
| #define BOOST_SINGLETON_POOL_HPP | |
|  | |
| /*! | |
|   \file | |
|   \brief The <tt>singleton_pool</tt> class allows other pool interfaces | |
|   for types of the same size to share the same underlying pool. | |
|  | |
|   \details Header singleton_pool.hpp provides a template class <tt>singleton_pool</tt>, | |
|   which provides access to a pool as a singleton object. | |
|    | |
| */ | |
| 
 | |
| #include <boost/pool/poolfwd.hpp> | |
|  | |
| // boost::pool | |
| #include <boost/pool/pool.hpp> | |
| // boost::details::pool::guard | |
| #include <boost/pool/detail/guard.hpp> | |
|  | |
| #include <boost/type_traits/aligned_storage.hpp> | |
|  | |
| namespace boost { | |
| 
 | |
|  /*!  | |
|  The singleton_pool class allows other pool interfaces | |
|  for types of the same size to share the same pool.  Template | |
|  parameters are as follows: | |
|  | |
|  <b>Tag</b> User-specified type to uniquely identify this pool: allows different unbounded sets of singleton pools to exist. | |
|  | |
|  <b>RequestedSize</b> The size of each chunk returned by member function <tt>malloc()</tt>. | |
|  | |
|  <B>UserAllocator</b> User allocator, default = default_user_allocator_new_delete. | |
|  | |
|  <b>Mutex</B> This class is the type of mutex to use to protect simultaneous access to the underlying Pool.  | |
|  Can be any Boost.Thread Mutex type or <tt>boost::details::pool::null_mutex</tt>. | |
|  It is exposed so that users may declare some singleton pools normally (i.e., with synchronization), but  | |
|  some singleton pools without synchronization (by specifying <tt>boost::details::pool::null_mutex</tt>) for efficiency reasons. | |
|  The member typedef <tt>mutex</tt> exposes the value of this template parameter.  The default for this | |
|  parameter is boost::details::pool::default_mutex which is a synonym for either <tt>boost::details::pool::null_mutex</tt> | |
|  (when threading support is turned off in the compiler (so BOOST_HAS_THREADS is not set), or threading support | |
|  has ben explicitly disabled with BOOST_DISABLE_THREADS (Boost-wide disabling of threads) or BOOST_POOL_NO_MT (this library only)) | |
|  or for <tt>boost::mutex</tt> (when threading support is enabled in the compiler). | |
|  | |
|  <B>NextSize</b> The value of this parameter is passed to the underlying Pool when it is created and | |
|  specifies the number of chunks to allocate in the first allocation request (defaults to 32). | |
|  The member typedef <tt>static const value next_size</tt> exposes the value of this template parameter. | |
|  | |
|  <b>MaxSize</B>The value of this parameter is passed to the underlying Pool when it is created and | |
|  specifies the maximum number of chunks to allocate in any single allocation request (defaults to 0). | |
|  | |
|   <b>Notes:</b> | |
|  | |
|   The underlying pool <i>p</i> referenced by the static functions | |
|   in singleton_pool is actually declared in a way that is: | |
|  | |
|   1 Thread-safe if there is only one thread running before main() begins and after main() ends | |
|   -- all of the static functions of singleton_pool synchronize their access to p. | |
|  | |
|   2 Guaranteed to be constructed before it is used -- | |
|   thus, the simple static object in the synopsis above would actually be an incorrect implementation. | |
|   The actual implementation to guarantee this is considerably more complicated. | |
|  | |
|   3 Note too that a different underlying pool p exists | |
|   for each different set of template parameters, | |
|   including implementation-specific ones. | |
|  | |
|   4 The underlying pool is constructed "as if" by: | |
|  | |
|   pool<UserAllocator> p(RequestedSize, NextSize, MaxSize); | |
|  | |
|   \attention | |
|   The underlying pool constructed by the singleton  | |
|   <b>is never freed</b>.  This means that memory allocated | |
|   by a singleton_pool can be still used after main() has | |
|   completed, but may mean that some memory checking programs | |
|   will complain about leaks from singleton_pool. | |
|   | |
|   */ | |
| 
 | |
|  template <typename Tag, | |
|     unsigned RequestedSize, | |
|     typename UserAllocator, | |
|     typename Mutex, | |
|     unsigned NextSize, | |
|     unsigned MaxSize > | |
| class singleton_pool | |
| { | |
|   public: | |
|     typedef Tag tag; /*!< The Tag template parameter uniquely | |
|                      identifies this pool and allows | |
|       different unbounded sets of singleton pools to exist. | |
|       For example, the pool allocators use two tag classes to ensure that the | |
|       two different allocator types never share the same underlying singleton pool. | |
|       Tag is never actually used by singleton_pool. | |
|     */ | |
|     typedef Mutex mutex; //!< The type of mutex used to synchonise access to this pool (default <tt>details::pool::default_mutex</tt>). | |
|     typedef UserAllocator user_allocator; //!< The user-allocator used by this pool, default = <tt>default_user_allocator_new_delete</tt>. | |
|     typedef typename pool<UserAllocator>::size_type size_type; //!< size_type of user allocator. | |
|     typedef typename pool<UserAllocator>::difference_type difference_type; //!< difference_type of user allocator. | |
|  | |
|     BOOST_STATIC_CONSTANT(unsigned, requested_size = RequestedSize); //!< The size of each chunk allocated by this pool. | |
|     BOOST_STATIC_CONSTANT(unsigned, next_size = NextSize); //!< The number of chunks to allocate on the first allocation. | |
|  | |
| private: | |
|     singleton_pool(); | |
| 
 | |
| #ifndef BOOST_DOXYGEN | |
|     struct pool_type: public Mutex, public pool<UserAllocator> | |
|     { | |
|       pool_type() : pool<UserAllocator>(RequestedSize, NextSize, MaxSize) {} | |
|     }; //  struct pool_type: Mutex | |
|  | |
| #else | |
|     // | |
|     // This is invoked when we build with Doxygen only: | |
|     // | |
| public: | |
|     static pool<UserAllocator> p; //!< For exposition only! | |
| #endif | |
|  | |
| 
 | |
|   public: | |
|     static void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION() | |
|     { //! Equivalent to SingletonPool::p.malloc(); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       return (p.malloc)(); | |
|     } | |
|     static void * ordered_malloc() | |
|     {  //! Equivalent to SingletonPool::p.ordered_malloc(); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       return p.ordered_malloc(); | |
|     } | |
|     static void * ordered_malloc(const size_type n) | |
|     { //! Equivalent to SingletonPool::p.ordered_malloc(n); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       return p.ordered_malloc(n); | |
|     } | |
|     static bool is_from(void * const ptr) | |
|     { //! Equivalent to SingletonPool::p.is_from(chunk); synchronized. | |
|       //! \returns true if chunk is from SingletonPool::is_from(chunk) | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       return p.is_from(ptr); | |
|     } | |
|     static void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr) | |
|     { //! Equivalent to SingletonPool::p.free(chunk); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       (p.free)(ptr); | |
|     } | |
|     static void ordered_free(void * const ptr) | |
|     { //! Equivalent to SingletonPool::p.ordered_free(chunk); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       p.ordered_free(ptr); | |
|     } | |
|     static void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr, const size_type n) | |
|     { //! Equivalent to SingletonPool::p.free(chunk, n); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       (p.free)(ptr, n); | |
|     } | |
|     static void ordered_free(void * const ptr, const size_type n) | |
|     { //! Equivalent to SingletonPool::p.ordered_free(chunk, n); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       p.ordered_free(ptr, n); | |
|     } | |
|     static bool release_memory() | |
|     { //! Equivalent to SingletonPool::p.release_memory(); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       return p.release_memory(); | |
|     } | |
|     static bool purge_memory() | |
|     { //! Equivalent to SingletonPool::p.purge_memory(); synchronized. | |
|       pool_type & p = get_pool(); | |
|       details::pool::guard<Mutex> g(p); | |
|       return p.purge_memory(); | |
|     } | |
| 
 | |
| private: | |
|    typedef boost::aligned_storage<sizeof(pool_type), boost::alignment_of<pool_type>::value> storage_type; | |
|    static storage_type storage; | |
| 
 | |
|    static pool_type& get_pool() | |
|    { | |
|       static bool f = false; | |
|       if(!f) | |
|       { | |
|          // This code *must* be called before main() starts,  | |
|          // and when only one thread is executing. | |
|          f = true; | |
|          new (&storage) pool_type; | |
|       } | |
| 
 | |
|       // The following line does nothing else than force the instantiation | |
|       //  of singleton<T>::create_object, whose constructor is | |
|       //  called before main() begins. | |
|       create_object.do_nothing(); | |
| 
 | |
|       return *static_cast<pool_type*>(static_cast<void*>(&storage)); | |
|    } | |
| 
 | |
|    struct object_creator | |
|    { | |
|       object_creator() | |
|       {  // This constructor does nothing more than ensure that instance() | |
|          //  is called before main() begins, thus creating the static | |
|          //  T object before multithreading race issues can come up. | |
|          singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::get_pool(); | |
|       } | |
|       inline void do_nothing() const | |
|       { | |
|       } | |
|    }; | |
|    static object_creator create_object; | |
| }; // struct singleton_pool | |
|  | |
| template <typename Tag, | |
|     unsigned RequestedSize, | |
|     typename UserAllocator, | |
|     typename Mutex, | |
|     unsigned NextSize, | |
|     unsigned MaxSize > | |
| typename singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::storage_type singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::storage; | |
| 
 | |
| template <typename Tag, | |
|     unsigned RequestedSize, | |
|     typename UserAllocator, | |
|     typename Mutex, | |
|     unsigned NextSize, | |
|     unsigned MaxSize > | |
| typename singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::object_creator singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::create_object; | |
| 
 | |
| } // namespace boost | |
|  | |
| #endif
 | |
| 
 |