pool.hpp

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////////////////
00002 //    This material is provided "as is", with absolutely no warranty
00003 //  expressed or implied. Any use is at your own risk.
00004 //
00005 //    Permission to use or copy this software for any purpose is hereby
00006 //  granted without fee, provided the above notices are retained on all
00007 //  copies. Permission to modify the code and to distribute modified code
00008 //  is granted, provided the above notices are retained, and a notice that
00009 //  the code was modified is included with the above copyright notice.
00010 //////////////////////////////////////////////////////////////////////////
00011 /** @file
00012   @brief Fast memory management.
00013 
00014 @author Sergey Polichnoy
00015 @see @ref omni_pool
00016 */
00017 #ifndef __OMNI_POOL_HPP_
00018 #define __OMNI_POOL_HPP_
00019 
00020 #include <omni/defs.hpp>
00021 
00022 #include <assert.h>
00023 #include <memory.h>
00024 
00025 #include <new>
00026 
00027 namespace omni
00028 {
00029   namespace pool
00030   {
00031     /// @brief Implementation specific.
00032     namespace details
00033     {
00034 
00035 //////////////////////////////////////////////////////////////////////////
00036 /// @brief %RAW memory operations.
00037 /**
00038     This class makes %RAW memory read/write operations easy.
00039   To read the value at custom address, you should use read() method.
00040   To write the value at custom address, you should use write() method.
00041 
00042     For example:
00043 
00044 @code
00045   void f(void *ptr)
00046   {
00047     int a = RAW<int>::read(ptr); // read integer
00048     RAW<int>::write(ptr, a + 1); // write integer
00049   }
00050 @endcode
00051 
00052     Template argument @a T should be of POD type.
00053 */
00054 template<typename T>
00055 class RAW {
00056 public:
00057   typedef void* pointer; ///< @brief Pointer type.
00058   typedef T value_type;  ///< @brief Value type.
00059 
00060 public:
00061 
00062 //////////////////////////////////////////////////////////////////////////
00063 /// @brief Write the value.
00064 /**
00065   This method writes the value @a x at the custom address @a p.
00066 
00067 @param[in] p The custom address.
00068 @param[in] x The value.
00069 */
00070   static void write(pointer p, value_type x)
00071   {
00072     *static_cast<value_type*>(p) = x;
00073   }
00074 
00075 
00076 //////////////////////////////////////////////////////////////////////////
00077 /// @brief Read the value.
00078 /**
00079   This method reads the value at the custom address @a p.
00080 
00081 @param[in] p The custom address.
00082 @return The value.
00083 */
00084   static value_type read(pointer p)
00085   {
00086     return *static_cast<value_type*>(p);
00087   }
00088 };
00089 
00090 
00091 //////////////////////////////////////////////////////////////////////////
00092 /// @brief Constants.
00093 enum {
00094   /// @brief Default chunk size. @hideinitializer
00095   DEFAULT_CHUNK_SIZE = 16*4096 // = 64Kb
00096 };
00097 
00098     } // details namespace
00099   } // pool namespace
00100 
00101 
00102   // ObjPool
00103   namespace pool
00104   {
00105 
00106 //////////////////////////////////////////////////////////////////////////
00107 /// @brief The pool of fixed-size memory blocks.
00108 /**
00109     The class manages the fixed-size memory blocks. These memory blocks
00110   are organized as a single-linked list (list of unused blocks or pool).
00111   The get() method returns the first memory block from the pool.
00112   The put() method puts the memory block back into the pool.
00113   If there are no unused memory blocks (i.e. the pool is empty),
00114   then you should call grow() method. The grow() method allocates
00115   memory chunk (several adjacent memory blocks) and puts these
00116   blocks into the list of unused blocks.
00117 
00118     For chunk allocation/deallocation global
00119   @b new / @b delete operators are used.
00120 
00121     The template parameter @a A is an alignment of memory blocks. It should
00122   be integer power of two: 1, 2, 4, 8, 16, ...
00123 
00124     The class does not contain the memory block size. So you should provide
00125   the correct block size each time the grow() method is called.
00126 
00127     As an example of using ObjPool class see implementation of FastObjT class.
00128 
00129 @see @ref omni_pool
00130 */
00131 template<size_t A> // A - alignment (for example: 1, 4, 16)
00132 class ObjPool: private omni::NonCopyable {
00133 public:
00134   typedef size_t size_type; ///< @brief Size type.
00135   typedef void* pointer;    ///< @brief Pointer type.
00136 
00137 public:
00138 
00139 //////////////////////////////////////////////////////////////////////////
00140 /// @brief Constants.
00141   enum {
00142     ALIGNMENT = A ///< @brief Alignment of memory blocks. @hideinitializer
00143   };
00144 
00145 public:
00146 
00147 //////////////////////////////////////////////////////////////////////////
00148 /// @brief Construction.
00149 /**
00150     The constructor initializes an empty pool. The empty pool has no unused
00151   memory blocks. So, before getting the memory block you should call
00152   grow() method.
00153 
00154 @see empty()
00155 @see grow()
00156 */
00157   ObjPool()
00158     : m_unused(0),
00159       m_chunks(0)
00160 #if OMNI_DEBUG
00161     , m_N_used(0)
00162 #endif
00163   {
00164     assert(0!=ALIGNMENT && 0==(ALIGNMENT&(ALIGNMENT-1)) // see utils::is_ipow2()
00165       && "alignment must be integer power of two");
00166   }
00167 
00168 
00169 //////////////////////////////////////////////////////////////////////////
00170 /// @brief Destruction.
00171 /**
00172     The destructor releases all (used and unused) memory blocks.
00173 
00174   @warning Make sure that all memory blocks are returned to the pool.
00175 
00176     In debug version there is a memory leak checking.
00177 */
00178   ~ObjPool()
00179   {
00180 #if OMNI_DEBUG
00181     assert(0 == m_N_used
00182       && "memory leak");
00183 #endif
00184 
00185     while (m_chunks)
00186     {
00187       typedef details::RAW<pointer> xRAW;
00188       pointer next = xRAW::read(m_chunks);
00189       release_chunk(m_chunks);
00190       m_chunks = next;
00191     }
00192   }
00193 
00194 public:
00195 
00196 //////////////////////////////////////////////////////////////////////////
00197 /// @brief Grow the pool.
00198 /**
00199     One memory chunk is several adjacent memory blocks. This method
00200   allocates one memory chunk and puts these blocks into the list
00201   of unused blocks.
00202 
00203     Allocated memory chunk contains at least one memory block.
00204 
00205     The ObjPool class does not contain memory block size, so, you should
00206   provide the correct memory block size each time grow() method is called. You should
00207   specify the same memory block size @a obj_size each time grow() is called.
00208   Otherwise your program will have undefined behavior.
00209 
00210 @param[in] obj_size The memory block size in bytes.
00211 @param[in] chunk_size Approximate memory chunk size in bytes.
00212 
00213 @see empty()
00214 */
00215   void grow(size_type obj_size, size_type chunk_size = details::DEFAULT_CHUNK_SIZE)
00216   {
00217     const size_type ptr_size = sizeof(pointer);
00218     const size_type aux_size = ptr_size + ALIGNMENT-1;
00219     obj_size = align(obj_size ? obj_size : 1);
00220 
00221     // number of blocks
00222     size_type No = (chunk_size - aux_size) / obj_size;
00223     if (!No) No = 1; // (?) minimum one block
00224 
00225     char *chunk = static_cast<char*>(alloc_chunk(No*obj_size + aux_size));
00226 
00227     // single-linked list of chunks
00228     typedef details::RAW<pointer> xRAW;
00229     xRAW::write(chunk, m_chunks);
00230     m_chunks = chunk;
00231 
00232     // update list of unused elements
00233     chunk = static_cast<char*>(align(chunk + ptr_size)); // "useful" memory
00234     for (size_type i = 0; i < No; ++i)
00235       put(chunk + (No-1-i)*obj_size); // (!) locality
00236     OMNI_DEBUG_CODE(m_N_used += No);  // (!) put() make (--m_N_used);
00237   }
00238 
00239 
00240 //////////////////////////////////////////////////////////////////////////
00241 /// @brief Is the pool empty?
00242 /**
00243     This method checks the list of unused blocks. If the pool is empty,
00244   then you should call grow() method before using get().
00245 
00246     For example:
00247 
00248 @code
00249   ObjPool<4> m_pool;
00250   size_t m_block_size;
00251 
00252   // ...
00253 
00254   void* my_alloc()
00255   {
00256     if (m_pool.empty())
00257       m_pool.grow(m_block_size);
00258 
00259     return m_pool.get();
00260   }
00261 @endcode
00262 
00263 @return @b true if the pool is empty, otherwise @b false.
00264 */
00265   bool empty() const
00266   {
00267     return (0 == m_unused);
00268   }
00269 
00270 public:
00271 
00272 //////////////////////////////////////////////////////////////////////////
00273 /// @brief Get the memory block from the pool.
00274 /**
00275     This method returns the first unused memory block.
00276   To ensure that the pool has unused memory block
00277   call empty() and grow() if needed.
00278 
00279 @return Pointer to the memory block.
00280 
00281 @see empty()
00282 @see grow()
00283 */
00284   pointer get()
00285   {
00286     assert(0 != m_unused
00287       && "pool is empty");
00288 
00289     pointer obj = m_unused;
00290     typedef details::RAW<pointer> xRAW;
00291     m_unused = xRAW::read(obj);
00292 
00293     OMNI_DEBUG_CODE(++m_N_used);
00294     return obj;
00295   }
00296 
00297 
00298 //////////////////////////////////////////////////////////////////////////
00299 /// @brief Put the memory block back into the pool.
00300 /**
00301     This method puts the memory block @a obj back into the pool.
00302   The memory block is inserted into the beginning of unused blocks list.
00303   So, next call of the get() method will return memory block @a obj again.
00304 
00305 @param[in] obj Pointer to the memory block.
00306 */
00307   void put(pointer obj)
00308   {
00309     OMNI_DEBUG_CODE(--m_N_used);
00310 
00311     typedef details::RAW<pointer> xRAW;
00312     xRAW::write(obj, m_unused);
00313     m_unused = obj;
00314   }
00315 
00316 public:
00317 
00318 //////////////////////////////////////////////////////////////////////////
00319 /// @brief Align block size.
00320 /**
00321     This method aligns the memory block size @a obj_size.
00322 
00323 @param[in] obj_size The memory block size.
00324 @return The aligned memory block size.
00325 */
00326   static size_type align(size_type obj_size)
00327   {
00328     return (obj_size + ALIGNMENT-1) & ~size_type(ALIGNMENT-1);
00329   }
00330 
00331 
00332 //////////////////////////////////////////////////////////////////////////
00333 /// @brief Align block pointer.
00334 /**
00335     This method aligns the memory block pointer @a ptr.
00336 
00337 @param[in] ptr The memory block pointer.
00338 @return The aligned memory block pointer.
00339 */
00340   static pointer align(pointer ptr)
00341   {
00342     const size_type x = reinterpret_cast<size_type>(ptr);
00343     return reinterpret_cast<pointer>(align(x));
00344   }
00345 
00346 private:
00347 
00348 //////////////////////////////////////////////////////////////////////////
00349 /// @brief Allocate memory chunk.
00350 /**
00351     This method allocates @a chunk_size bytes memory chunk using global
00352   @b new operator.
00353 
00354 @param[in] chunk_size The chunk size in bytes.
00355 @return Pointer to allocated chunk.
00356 */
00357   static pointer alloc_chunk(size_type chunk_size)
00358   {
00359     return ::operator new(chunk_size);
00360   }
00361 
00362 
00363 //////////////////////////////////////////////////////////////////////////
00364 /// @brief Release memory chunk.
00365 /**
00366     This method releases memory chunk @a chunk using global
00367   @b delete operator.
00368 
00369 @param[in] chunk Pointer to chunk.
00370 */
00371   static void release_chunk(pointer chunk)
00372   {
00373     ::operator delete(chunk);
00374   }
00375 
00376 private:
00377   pointer m_unused; ///< @brief List of unused memory blocks.
00378   pointer m_chunks; ///< @brief List of memory chunks.
00379 
00380 #if OMNI_DEBUG
00381   size_type m_N_used; ///< @brief Total number of memory blocks used.
00382 #endif // OMNI_DEBUG
00383 };
00384 
00385   } // ObjPool
00386 
00387 
00388   // FastObjT
00389   namespace pool
00390   {
00391 
00392 //////////////////////////////////////////////////////////////////////////
00393 /// @brief Fast object with individual pool.
00394 /**
00395     The FastObjT class contains individual pool object.
00396   The @b new / @b delete operators of this class use this individual pool object.
00397 
00398     To use fast memory management your class should be derived
00399   from the FastObjT<> class. See the example below.
00400 
00401     Since the pool object can manage only one memory block size,
00402   the FastObjT class can't be used with polymorphic classes.
00403 
00404 @param T Object type. This object type is used to determine memory
00405   block size. The memory block size is equal to @b sizeof(T).
00406 
00407 @param A Alignment of pointers. Should be integer power of two.
00408 @param CS Approximate memory chunk size in bytes.
00409 
00410   Example of using the FastObjT class:
00411 
00412 @code
00413   class Packet: public omni::pool::FastObjT<Packet> {
00414   public:
00415     char data[188]; // 188 bytes data payload
00416     int a, b;       // custom parameters
00417   };
00418 
00419   void f()
00420   {
00421     Packet *p1 = new Packet(); // ObjPool::get() used
00422     // ...
00423     delete p1;                 // ObjPool::put() used
00424     // ...
00425     Packet *p2 = new Packet(); // ObjPool::get() used
00426     // ...
00427     delete p2;                 // ObjPool::put() used
00428   }
00429 @endcode
00430 
00431     Note: The Packet class is derived from FastObjT<Packet>.
00432   The same technique is widely used in WTL library.
00433 
00434 @see @ref omni_pool
00435 */
00436 template<typename T, size_t A = sizeof(void*),
00437   size_t CS = details::DEFAULT_CHUNK_SIZE>
00438 class FastObjT {
00439 public:
00440   typedef ObjPool<A> pool_type; ///< @brief The pool type.
00441 
00442 //////////////////////////////////////////////////////////////////////////
00443 /// @brief Constants.
00444   enum {
00445     CHUNK_SIZE = CS, ///< @brief Approximate chunk size. @hideinitializer
00446     ALIGNMENT = A    ///< @brief Alignment of objects. @hideinitializer
00447   };
00448 
00449 protected:
00450 
00451 //////////////////////////////////////////////////////////////////////////
00452 /// @brief Trivial constructor.
00453   FastObjT()
00454   {}
00455 
00456 //////////////////////////////////////////////////////////////////////////
00457 /// @brief Trivial destructor.
00458   ~FastObjT()
00459   {}
00460 
00461 public:
00462 
00463 //////////////////////////////////////////////////////////////////////////
00464 /// @brief The memory allocation.
00465 /**
00466     This operator allocates the @a buf_size bytes memory block.
00467   Argument @a buf_size should be less than or equal to the @b sizeof(T)!
00468 
00469 @throw std::bad_alloc If there's no available memory.
00470 @param[in] buf_size The memory block size.
00471 @return The memory block.
00472 */
00473   static void* operator new(size_t buf_size) // throw(std::bad_alloc);
00474   {
00475     assert(buf_size <= sizeof(T)
00476       && "invalid object size");
00477     buf_size; // argument not used
00478 
00479     return alloc();
00480   }
00481 
00482 
00483 //////////////////////////////////////////////////////////////////////////
00484 /// @brief The memory allocation.
00485 /**
00486     This operator allocates the @a buf_size bytes memory block.
00487   Argument @a buf_size should be less than or equal to the @b sizeof(T)!
00488 
00489     If there is no available memory, then this operator
00490   will return null pointer.
00491 
00492 @param[in] buf_size The memory block size.
00493 @return The memory block or null.
00494 */
00495   static void* operator new(size_t buf_size, const std::nothrow_t&) // throw();
00496   {
00497     assert(buf_size <= sizeof(T)
00498       && "invalid object size");
00499     buf_size; // argument not used
00500 
00501     try { return alloc(); }
00502     catch (const std::bad_alloc&) {}
00503 
00504     return 0;
00505   }
00506 
00507 
00508 //////////////////////////////////////////////////////////////////////////
00509 /// @brief Placement new operator.
00510 /**
00511     This operator is used only for correct overloading of
00512   other @b new operators. It uses global placement @b new operator.
00513 
00514 @param[in] buf_size The memory block size.
00515 @param[in] p The memory block.
00516 @return The memory block.
00517 */
00518   static void* operator new(size_t buf_size, void *p) // throw();
00519   {
00520     return ::operator new(buf_size, p);
00521   }
00522 
00523 public:
00524 
00525 //////////////////////////////////////////////////////////////////////////
00526 ///@brief The memory deallocation.
00527 /**
00528     This operator deallocates the @a buf memory block.
00529 
00530 @param[in] buf The memory block.
00531 */
00532   static void operator delete(void *buf)
00533   {
00534     obj_pool().put(buf);
00535   }
00536 
00537 //////////////////////////////////////////////////////////////////////////
00538 ///@brief The memory deallocation.
00539 /**
00540     This operator deallocates the @a buf memory block.
00541 
00542 @param[in] buf The memory block.
00543 */
00544   static void operator delete(void *buf, const std::nothrow_t&) // throw();
00545   {
00546     obj_pool().put(buf);
00547   }
00548 
00549 //////////////////////////////////////////////////////////////////////////
00550 /// @brief Placement delete operator?
00551 /**
00552     This operator is used only for correct overloading of
00553   other @b delete operators. It uses global placement @b delete operator.
00554 
00555 @param[in] buf The memory block?
00556 @param[in] p The memory block?
00557 */
00558   static void operator delete(void *buf, void *p) // throw();
00559   {
00560     ::operator delete(buf, p);
00561   }
00562 
00563 private:
00564 
00565 //////////////////////////////////////////////////////////////////////////
00566 /// @brief The individual pool object.
00567 /**
00568     This static method returns the ObjPool object.
00569   This pool object is used for memory management operations.
00570 
00571 @return The static ObjPool object.
00572 */
00573   static pool_type& obj_pool()
00574   {
00575     static pool_type G;
00576     return G;
00577   }
00578 
00579 
00580 //////////////////////////////////////////////////////////////////////////
00581 /// @brief Get memory block.
00582 /**
00583     This static method returns the memory block from the individual pool.
00584   The size of allocated memory block is equal to @b sizeof(T).
00585 
00586 @return The memory block.
00587 */
00588   static void* alloc()
00589   {
00590     pool_type &x = obj_pool();
00591 
00592     if (x.empty())
00593       x.grow(sizeof(T),
00594         CHUNK_SIZE);
00595 
00596     return x.get();
00597   }
00598 };
00599 
00600   } // FastObjT
00601 
00602 
00603   // Manager
00604   namespace pool
00605   {
00606 
00607 //////////////////////////////////////////////////////////////////////////
00608 /// @brief The pool manager.
00609 /**
00610     The Manager class contains and manages several pool objects.
00611   The number of managed pool objects is equal to POOL_SIZE.
00612 
00613     The granularity argument is the difference between block sizes
00614   of the two adjacent pool objects. For example, if granularity is 2,
00615   then pools are 2, 4, 6, 8, ... bytes. If granularity is 4, then
00616   pools are 4, 8, 12, 16, ... bytes.
00617 
00618 @param A Alignment of pointers. Should be integer power of two.
00619 @param G Granularity of memory block sizes. Recommended 4 or 16.
00620 @param PS Total number of managed pool objects.
00621 @param CS Approximate chunk size in bytes.
00622 
00623 @see @ref omni_pool
00624 */
00625 template<size_t A, size_t G, size_t PS = 1024, size_t CS = details::DEFAULT_CHUNK_SIZE> // A - alignment
00626 class Manager: private omni::NonCopyable {
00627 public:
00628 
00629 //////////////////////////////////////////////////////////////////////////
00630 /// @brief Constants.
00631   enum {
00632     MAX_SIZE = G*PS, ///< @brief Maximum available block size. @hideinitializer
00633     GRANULARITY = G, ///< @brief Block size granularity. @hideinitializer
00634     CHUNK_SIZE = CS, ///< @brief Approximate chunk size. @hideinitializer
00635     POOL_SIZE = PS,  ///< @brief Total number of pools. @hideinitializer
00636     ALIGNMENT = A    ///< @brief Alignment of pointers. @hideinitializer
00637   };
00638 
00639 public:
00640   typedef ObjPool<ALIGNMENT> pool_type;            ///< @brief The pool type.
00641   typedef typename pool_type::size_type size_type; ///< @brief Size type.
00642   typedef typename pool_type::pointer   pointer;   ///< @brief Pointer type.
00643 
00644 public:
00645 
00646 //////////////////////////////////////////////////////////////////////////
00647 /// @brief Construction.
00648 /**
00649     The constructor initializes all managed pools.
00650 */
00651   Manager()
00652   {}
00653 
00654 
00655 //////////////////////////////////////////////////////////////////////////
00656 /// @brief Destruction.
00657 /**
00658     The destructor destroys all managed pools.
00659 */
00660   ~Manager()
00661   {}
00662 
00663 public:
00664 
00665 //////////////////////////////////////////////////////////////////////////
00666 /// @brief Get the memory block.
00667 /**
00668     This method gets the memory block from
00669   the corresponding managed pool object.
00670 
00671     The memory block size @a obj_size
00672   should be less than or equal to MAX_SIZE.
00673 
00674 @param[in] obj_size The memory block size in bytes.
00675 @return The memory block.
00676 
00677 @see ObjPool::get()
00678 */
00679   pointer get(size_type obj_size)
00680   {
00681     assert(obj_size <= MAX_SIZE
00682       && "object size too big");
00683 
00684     pool_type &obj_pool = find(obj_size);
00685 
00686     if (obj_pool.empty())
00687       obj_pool.grow(obj_size,
00688         CHUNK_SIZE);
00689 
00690     return obj_pool.get();
00691   }
00692 
00693 
00694 //////////////////////////////////////////////////////////////////////////
00695 /// @brief Put the memory block.
00696 /**
00697     This method puts the memory block @a obj back
00698   into the corresponding managed pool object.
00699 
00700     The memory block size @a obj_size
00701   should be less than or equal to MAX_SIZE.
00702 
00703 @param[in] obj The memory block.
00704 @param[in] obj_size The memory block size in bytes.
00705 
00706 @see ObjPool::put()
00707 */
00708   void put(pointer obj, size_type obj_size)
00709   {
00710     assert(obj_size <= MAX_SIZE
00711       && "object size too big");
00712 
00713     pool_type &obj_pool = find(obj_size);
00714     obj_pool.put(obj);
00715   }
00716 
00717 private:
00718 
00719 //////////////////////////////////////////////////////////////////////////
00720 /// @brief Find pool with specified block size.
00721 /**
00722     This method finds the managed pool object
00723   by memory block size @a obj_size.
00724 
00725 @param[in] obj_size The memory block size in bytes.
00726 @return The pool object.
00727 */
00728   pool_type& find(size_type obj_size)
00729   {
00730     const size_type x = !obj_size ? 0
00731       : (obj_size - 1) / GRANULARITY;
00732 
00733     assert(x < POOL_SIZE
00734       && "object size too big");
00735     return m_pools[x];
00736   }
00737 
00738 private:
00739   pool_type m_pools[POOL_SIZE]; ///< @brief Managed pool objects.
00740 };
00741 
00742   } // Manager
00743 
00744 
00745   // global pool manager
00746   namespace pool
00747   {
00748 
00749     void* mem_get(size_t buf_size);            ///< @brief Allocate the memory block.
00750     void mem_put(void *buf, size_t buf_size);  ///< @brief Release the memory block.
00751 
00752     void* mem_get_sized(size_t buf_size);      ///< @brief Allocate the memory block.
00753     void mem_put_sized(void *buf);             ///< @brief Release the memory block.
00754 
00755   } // global pool manager
00756 
00757 
00758   // FastObj
00759   namespace pool
00760   {
00761 
00762 //////////////////////////////////////////////////////////////////////////
00763 /// @brief Fast object with global pool.
00764 /**
00765     The FastObj class uses global pool. So, the FastObj class may
00766   be used with polymorphic classes in contrast to FastObjT class.
00767   Any allocation/deallocation operations use mem_get_sized()
00768   and mem_put_sized() functions.
00769 
00770     To use fast memory management your class should be derived
00771   from the FastObj class. See the example below.
00772 
00773   @code
00774     class MyClass: public omni::pool::FastObj {
00775       // ...
00776     };
00777 
00778     class Test: public MyClass {
00779       // ...
00780     };
00781 
00782     void f()
00783     {
00784       MyClass *p1 = new MyClass(); // mem_get_sized() used
00785       // ...
00786       delete p1; // mem_put_sized() used
00787 
00788       Test *p2 = new Test(); // mem_get_sized() used
00789       // ...
00790       delete p2; // mem_put_sized() used
00791     }
00792   @endcode
00793 
00794 @see @ref omni_pool
00795 */
00796 class FastObj {
00797 protected:
00798   FastObj();
00799   virtual ~FastObj();
00800 
00801 public:
00802   static void* operator new(size_t buf_size); // throw(std::bad_alloc);
00803   static void* operator new(size_t buf_size, const std::nothrow_t&); // throw();
00804   static void* operator new(size_t buf_size, void *p); // throw();
00805 
00806   static void operator delete(void *buf);
00807   static void operator delete(void *buf, const std::nothrow_t&); // throw();
00808   static void operator delete(void *buf, void *p); // throw();
00809 };
00810 
00811   } // FastObj
00812 
00813 
00814   // Allocator
00815   namespace pool
00816   {
00817 
00818 //////////////////////////////////////////////////////////////////////////
00819 /// @brief Fast allocator for STL containers.
00820 /**
00821     This class uses global pool and can be used with many STL containers.
00822   Any allocation/deallocation methods use mem_get_sized()
00823   and mem_put_sized() functions.
00824 
00825   For example:
00826 
00827 @code
00828   std::vector<double, omni::pool::Allocator<double> > a;
00829   std::list<int, omni::pool::Allocator<int> > b;
00830 @endcode
00831 */
00832 template<typename T>
00833 class Allocator {
00834 public:
00835   typedef T value_type; ///< @brief Value type.
00836 
00837   typedef const T& const_reference; ///< @brief Constant reference type.
00838   typedef       T&       reference; ///< @brief Reference type.
00839   typedef const T* const_pointer;   ///< @brief Constant pointer type.
00840   typedef       T*       pointer;   ///< @brief Pointer type.
00841 
00842   typedef ptrdiff_t difference_type;    ///< @brief Difference type.
00843   typedef size_t size_type; ///< @brief Size type.
00844 
00845 public:
00846 
00847 //////////////////////////////////////////////////////////////////////////
00848 /// @brief Auxiliary structure.
00849 /**
00850     This structure is used to change current allocator's type.
00851 */
00852   template<typename U>
00853     struct rebind {
00854       typedef Allocator<U> other; ///< @brief New allocator's type.
00855     };
00856 
00857 public:
00858 
00859 //////////////////////////////////////////////////////////////////////////
00860 /// @brief Get address by constant reference.
00861 /**
00862 @param[in] x The constant reference.
00863 @return The constant pointer.
00864 */
00865   const_pointer address(const_reference x) const
00866   {
00867     return &x;
00868   }
00869 
00870 
00871 //////////////////////////////////////////////////////////////////////////
00872 /// @brief Get address by reference.
00873 /**
00874 @param[in] x The reference.
00875 @return The pointer.
00876 */
00877   pointer address(reference x) const
00878   {
00879     return &x;
00880   }
00881 
00882 public:
00883 
00884 //////////////////////////////////////////////////////////////////////////
00885 /// @brief Default constructor.
00886   Allocator()
00887   {}
00888 
00889 //////////////////////////////////////////////////////////////////////////
00890 /// @brief Auxiliary copy-constructor.
00891   template<typename U>
00892     Allocator(const Allocator<U>&)
00893   {}
00894 
00895 //////////////////////////////////////////////////////////////////////////
00896 /// @brief Auxiliary assignment operator.
00897   template<typename U>
00898     Allocator<T>& operator=(const Allocator<U>&)
00899   {
00900     return (*this);
00901   }
00902 
00903 public:
00904 
00905 //////////////////////////////////////////////////////////////////////////
00906 /// @brief The memory allocation.
00907 /**
00908     This method allocates memory block for @a n objects.
00909 
00910 @param[in] n The number of adjacent objects.
00911 @return The memory block.
00912 */
00913   pointer allocate(size_type n)
00914   {
00915     return static_cast<pointer>(mem_get_sized(n*sizeof(value_type)));
00916   }
00917 
00918 
00919 //////////////////////////////////////////////////////////////////////////
00920 /// @brief The memory allocation.
00921 /**
00922     This method allocates memory block for @a n objects.
00923   Second argument (allocation hint) is not used.
00924 
00925 @param[in] n The number of adjacent objects.
00926 @return The memory block.
00927 */
00928   pointer allocate(size_type n, const void*)
00929   {
00930     return allocate(n);
00931   }
00932 
00933 
00934 //////////////////////////////////////////////////////////////////////////
00935 /// @brief The memory allocation.
00936 /**
00937     This method allocates memory block of @a n bytes.
00938   It is used by STL containers in Visual C++ 6.0!
00939 
00940 @param[in] n The memory block size in bytes.
00941 @return The memory block.
00942 */
00943   char* _Charalloc(size_type n)
00944   {
00945     return static_cast<char*>(mem_get_sized(n));
00946   }
00947 
00948 
00949 //////////////////////////////////////////////////////////////////////////
00950 /// @brief The memory deallocation.
00951 /**
00952     This method deallocates memory block @a p.
00953   the second argument (memory block size) is not used.
00954 
00955 @param[in] p The memory block.
00956 */
00957   void deallocate(void *p, size_type)
00958   {
00959     mem_put_sized(p);
00960   }
00961 
00962 
00963 //////////////////////////////////////////////////////////////////////////
00964 /// @brief Object construction.
00965 /**
00966     This method constructs the object at address @a p
00967   using placement @b new operator.
00968 
00969 @param[in] p The address of object.
00970 @param[in] x Construction prototype.
00971 */
00972   void construct(pointer p, const_reference x)
00973   {
00974     new (static_cast<void*>(p)) value_type(x);
00975   }
00976 
00977 
00978 //////////////////////////////////////////////////////////////////////////
00979 /// @brief Object destruction.
00980 /**
00981     This method destroys object @a p.
00982 
00983 @param[in] p The address of object.
00984 */
00985   void destroy(pointer p)
00986   {
00987     p->~T(); p;
00988   }
00989 
00990 
00991 //////////////////////////////////////////////////////////////////////////
00992 /// @brief Maximum number of objects.
00993 /**
00994     This method returns the maximum number of objects,
00995   which can be allocated using this allocator.
00996 
00997 @return The maximum number of objects.
00998 */
00999   size_type max_size() const
01000   {
01001     return size_type(-1) / sizeof(value_type); // (?)
01002   }
01003 };
01004 
01005 
01006 //////////////////////////////////////////////////////////////////////////
01007 /// @brief Are two allocators equal?
01008 /**
01009   The two allocators are always equal.
01010 
01011 @return @b true.
01012 */
01013 template<typename T, typename U> inline
01014   bool operator==(const Allocator<T>&, const Allocator<U>&)
01015 {
01016   return true;
01017 }
01018 
01019 
01020 //////////////////////////////////////////////////////////////////////////
01021 /// @brief Are two allocators non-equal?
01022 /**
01023   The two allocators are always equal.
01024 
01025 @return @b false.
01026 */
01027 template<typename T, typename U> inline
01028   bool operator!=(const Allocator<T>&, const Allocator<U>&)
01029 {
01030   return false;
01031 }
01032 
01033   } // Allocator
01034 
01035 } // omni namespace
01036 
01037 #endif // __OMNI_POOL_HPP_

Generated on Wed Jun 6 17:27:46 2007 for OMNI by  doxygen 1.5.2