- Main Page
- Namespaces
- Classes
- Files

# proto/Source/pool.h

Go to the documentation of this file.

    00001
    00029 #ifndef _POOL_H
    00030 #define _POOL_H
    00031
    00032 #include <cassert>
    00033 #include <map>
    00034
    00035 namespace ace {
    00036
    00038
    00043 template<class _Type>
    00044 class MemoryBlock {
    00047     const size_t _unit_size;
    00051     _Type *_memory;
    00055     _Type *_free;
    00059     _Type *_upper_bound;
    00060
    00061 protected:
    00062     // TODO: Block assignments between derived classes?
    00065     MemoryBlock<_Type>(const MemoryBlock<_Type>& mpb);
    00068     MemoryBlock<_Type>& operator=(const MemoryBlock<_Type>& mpb);
    00069
    00070 public:
    00077     MemoryBlock(size_t block_size): _unit_size(sizeof(_Type)), _memory(NULL), _free(NULL), _upper_bound(NULL) {
    00078         _free = _memory = static_cast<_Type *>(operator new(block_size*_unit_size));
    00079         _upper_bound = _memory + block_size;
    00080     }
    00083     virtual ~MemoryBlock(void) throw() {
    00084         operator delete(_memory);
    00085     }
    00088     inline _Type * assigned_mem_bound(void) const throw() { return _free; }
    00091     inline size_t count_free_memory(void) const throw() { return (_free != NULL) ? (_upper_bound - _free) : 0; }
    00094     inline bool is_full(void) const throw() { return ( (_memory != NULL) && (_free == _upper_bound) ); }
    00101     _Type * get_memory(size_t mem_size = 1) throw() {
    00102         if ( (_memory == NULL) || (count_free_memory() < mem_size) ) {
    00103             // Also catches when mem_size == 0.
    00104             return NULL;
    00105         }
    00106         _Type *alloc = _free;
    00107         // Advance internal free memory pointer by `mem_size`!
    00108         _free += mem_size;
    00109         return alloc;
    00110     }
    00113     inline _Type * lower_bound(void) const throw() { return _memory; }
    00116     inline _Type * upper_bound(void) const throw() { return _upper_bound; }
    00119     inline size_t unit_size(void) const throw() { return _unit_size; }
    00120 };
    00121
    00122
    00128 template<class _Type, template<typename _Type> class _Block>
    00129 class MemoryPool {
    00132     size_t _block_size;
    00133
    00134 protected:
    00135
    00138     virtual _Block<_Type> * create_new_block(void) = 0;
    00139
    00140 public:
    00144     MemoryPool(size_t block_size) throw(): _block_size(block_size) {}
    00147     virtual ~MemoryPool(void) throw() {}
    00150     inline size_t block_size(void) const throw() { return _block_size; }
    00153     virtual void clear(void) throw() = 0;
    00160     virtual _Type * get_memory(size_t mem_size) = 0;
    00161 };
    00162
    00163
    00170 template<class _Type>
    00171 class RandomSizedMemoryPool: public MemoryPool<_Type, MemoryBlock> {
    00172 protected:
    00175     typedef MemoryBlock<_Type> _block_type;
    00176
    00177     // TODO: Remember the pool with maximum free memory (heap-like approach)?
    00181     typedef typename std::multimap<size_t, _block_type *> _blocks_free_sizes_map;
    00184     _block_type *_recently_used_block;
    00187     _blocks_free_sizes_map _mem_blocks;
    00188
    00189 protected:
    00194     virtual _block_type * create_new_block(void) {
    00195         // Get new block with desired size and return.
    00196         return new _block_type(this->block_size()); // This may throw!
    00197     }
    00198
    00199 public:
    00203     RandomSizedMemoryPool(size_t block_size) throw(): MemoryPool<_Type, MemoryBlock>(block_size), _recently_used_block(NULL), _mem_blocks() {}
    00206     virtual ~RandomSizedMemoryPool(void) throw() {
    00207         this->clear();
    00208     }
    00212     virtual void clear(void) throw() {
    00213         // Call delete on every memory block.
    00214         for ( typename _blocks_free_sizes_map::iterator i_pool = _mem_blocks.begin(); i_pool != _mem_blocks.end(); ++i_pool ) {
    00215             delete i_pool->second;
    00216         }
    00217         // Clear pools map.
    00218         _mem_blocks.clear();
    00219     }
    00228     virtual _Type * get_memory(size_t mem_size) {
    00229
    00230         if ( mem_size > this->block_size() ) {
    00231             // No way to get so much memory...
    00232             return NULL;
    00233         }
    00234
    00235         _block_type *mb = NULL;
    00236
    00237         // So, which block to use (which has enough of memory?)
    00238         if ( _recently_used_block == NULL ) {
    00239             // First block to be created within the pool.
    00240             mb = _recently_used_block = this->create_new_block(); // This may throw!
    00241         } else if ( mem_size <= _recently_used_block->count_free_memory() ) {
    00242             // There is enough memory in recently used block.
    00243             mb = _recently_used_block;
    00244         } else {
    00245             // Recently used block has not enough free memory.
    00246             if ( !_mem_blocks.empty() && (mem_size <= _mem_blocks.rbegin()->first) ) {
    00247                 // There must be already allocated block with enough free memory.
    00248                 // Find the smallest one.
    00249                 typename _blocks_free_sizes_map::iterator i_pools = _mem_blocks.lower_bound(mem_size);
    00250                 // Following must be always true.
    00251                 assert(i_pools != _mem_blocks.end());
    00252                 // Get the block.
    00253                 mb = i_pools->second;
    00254                 // After memory retrieval this mapping will not be up-to-date anymore, so:
    00255                 _mem_blocks.erase(i_pools);
    00256             } else {
    00257                 // No allocated block within pool has enough memory.
    00258                 // Get brand new block.
    00259                 mb = create_new_block(); // This may throw!
    00260             }
    00261             // Recently used memory block will be no longer "recently used",
    00262             // so store it inside the memory blocks map.
    00263             _mem_blocks.insert(typename _blocks_free_sizes_map::value_type(_recently_used_block->count_free_memory(), _recently_used_block));
    00264             // Store for future use:
    00265             _recently_used_block = mb;
    00266         }
    00267         // Return pointer to desired memory:
    00268         return mb->get_memory(mem_size);
    00269     }
    00270 };
    00271
    00275 class VoidPool: public RandomSizedMemoryPool<char> {
    00276 public:
    00280     VoidPool(size_t block_size) throw(): RandomSizedMemoryPool<char>(block_size) {}
    00283     virtual ~VoidPool(void) throw() {}
    00284
    00292     virtual void * get_raw_memory(size_t mem_size) {
    00293         return this->get_memory(mem_size);
    00294     }
    00295
    00296 };
    00297
    00298 } // namespace ace
    00299
    00300 #endif