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_