MemoryPool.hpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #ifndef ORO_MEMORY_POOL_HPP
00040 #define ORO_MEMORY_POOL_HPP
00041
00042 #include "AtomicQueue.hpp"
00043 #include <vector>
00044 #include <boost/shared_ptr.hpp>
00045
00046 namespace RTT
00047 {
00048
00062 template<class T>
00063 class MemoryPool
00064 {
00065 public:
00066 typedef T* pointer;
00067
00068 typedef unsigned int size_type;
00069
00070 protected:
00071 struct Item;
00073 typedef AtomicQueue<void*> QueueType;
00074 typedef boost::shared_ptr<QueueType> QueueTypePtr;
00076 typedef std::vector<std::pair<QueueTypePtr,Item*> > PoolType;
00077
00078 unsigned int used_cap, alloc_cnt;
00079 PoolType mpool;
00080
00081 T minit;
00082
00086 struct Item {
00087 Item( const T& initial_value )
00088 : content(initial_value) {
00089 oro_atomic_set(&rc, 0);
00090 }
00091 Item()
00092 : content() {
00093 oro_atomic_set(&rc, 0);
00094 }
00095
00096 T content;
00097 oro_atomic_t rc;
00098 };
00099
00103 void make_pool( size_type growsize )
00104 {
00105 Item* newit = new Item[growsize];
00106 mpool.push_back( std::make_pair(QueueTypePtr(new QueueType( growsize )), newit) );
00107 for( unsigned int i = 0; i < growsize; ++i ) {
00108 newit[i].content = minit;
00109 mpool.back().first->enqueue( static_cast<void*>(&newit[i]) );
00110 }
00111 assert( mpool.back().first->size() == growsize );
00112 }
00113 public:
00131 MemoryPool(unsigned int startsize = 4, const T& initial_value = T() )
00132 :used_cap(0), alloc_cnt(startsize == 0 ? 1 : startsize), minit( initial_value )
00133 {
00134 this->make_pool( alloc_cnt );
00135 }
00136
00140 ~MemoryPool()
00141 {
00142
00143 for ( typename PoolType::iterator it = mpool.begin(); it != mpool.end(); ++it ) {
00144 delete[] it->second;
00145 }
00146
00147 }
00148
00152 size_type size() const {
00153 size_type res(0);
00154
00155 for ( typename PoolType::const_iterator it = mpool.begin(); it != mpool.end(); ++it )
00156 res += it->first->size();
00157 return res;
00158 }
00159
00163 size_type capacity() const {
00164 return alloc_cnt;
00165 }
00166
00171 void reserve()
00172 {
00173
00174
00175
00176
00177 if ( ++used_cap > alloc_cnt ) {
00178 unsigned int growsize = mpool.back().first->capacity() * 2;
00179 alloc_cnt += growsize;
00180
00181 this->make_pool( growsize );
00182 }
00183 }
00184
00189 void shrink()
00190 {
00191 --used_cap;
00192 }
00193
00197 pointer allocate()
00198 {
00199 void* result;
00200
00201 for ( typename PoolType::iterator it = mpool.begin(); it != mpool.end(); ++it ) {
00202 if ( it->first->dequeue( result ) ) {
00203 oro_atomic_inc( &static_cast<Item*>(result)->rc);
00204 return static_cast<pointer>( result );
00205 }
00206 }
00207 return 0;
00208 }
00209
00214 bool lock(pointer m) {
00215 Item* it = reinterpret_cast<Item*>(m);
00216 if ( oro_atomic_read(&it->rc) == 0 )
00217 return false;
00218 oro_atomic_inc(&(it->rc) );
00219 return true;
00220 }
00221
00226 bool unlock( pointer m ) {
00227 return this->deallocate(m);
00228 }
00229
00234 bool deallocate( pointer m )
00235 {
00236 Item* item = reinterpret_cast<Item*>(m);
00237 if ( oro_atomic_read(&item->rc) == 0 )
00238 return false;
00239 if( oro_atomic_dec_and_test( &(item->rc) ) ) {
00240 for ( typename PoolType::iterator it = mpool.begin(); it != mpool.end(); ++it ) {
00241 if ( it->first->enqueue( static_cast<void*>(m) ) ) {
00242 return true;
00243 }
00244 }
00245 assert(false && "Deallocating more elements than allocated !");
00246 }
00247 return true;
00248 }
00249
00254 size_type useCount( pointer m ) {
00255 return oro_atomic_read( &static_cast< Item* >(m)->rc );
00256 }
00257 };
00258
00265 template<class T>
00266 class FixedSizeMemoryPool
00267 {
00268 public:
00269 typedef T* pointer;
00270
00271 typedef unsigned int size_type;
00272
00273 protected:
00277 struct Item {
00278 Item( const T& initial_value )
00279 : content(initial_value) {
00280 oro_atomic_set(&rc, 0);
00281 }
00282 Item()
00283 : content() {
00284 oro_atomic_set(&rc, 0);
00285 }
00286
00287 T content;
00288 oro_atomic_t rc;
00289 };
00290
00294 void make_pool( size_type growsize )
00295 {
00296 mpit = new Item[growsize];
00297 for( unsigned int i = 0; i < growsize; ++i ) {
00298 mpit[i].content = minit;
00299 mpool.enqueue( static_cast<void*>(&mpit[i]) );
00300 }
00301 }
00302
00304 typedef AtomicQueue<void*> QueueType;
00305
00306 QueueType mpool;
00307 T minit;
00308 Item* mpit;
00309
00310 public:
00315 FixedSizeMemoryPool(size_type fixed_size, const T& initial_value = T() )
00316 : mpool(fixed_size == 0 ? 1 : fixed_size), minit( initial_value ), mpit(0)
00317 {
00318 this->make_pool(fixed_size);
00319 }
00320
00324 ~FixedSizeMemoryPool()
00325 {
00326 delete[] mpit;
00327 }
00328
00332 size_type size() const {
00333 return mpool.size();
00334 }
00335
00339 size_type capacity() const {
00340 return mpool.capacity();
00341 }
00342
00346 pointer allocate()
00347 {
00348 void* result;
00349
00350 if ( mpool.dequeue( result ) ) {
00351 Item* it = static_cast<Item*>(result);
00352 oro_atomic_inc( &(it->rc) );
00353 return (&it->content);
00354 }
00355 return 0;
00356 }
00357
00362 bool lock(pointer m) {
00363 Item* it = reinterpret_cast<Item*>(m);
00364 if ( oro_atomic_read(&it->rc) == 0 )
00365 return false;
00366 oro_atomic_inc(&(it->rc) );
00367 return true;
00368 }
00369
00374 bool unlock( pointer m ) {
00375 return this->deallocate(m);
00376 }
00377
00382 bool deallocate( pointer m )
00383 {
00384 Item* it = reinterpret_cast<Item*>(m);
00385 if ( oro_atomic_read(&it->rc) == 0 )
00386 return false;
00387 if( oro_atomic_dec_and_test( &(it->rc) ) )
00388 if ( mpool.enqueue( static_cast<void*>(m) ) == false )
00389 assert(false && "Deallocating more elements than allocated !");
00390 return true;
00391 }
00392 };
00393
00394 }
00395
00396 #endif