📄 smallobj.cpp
字号:
{ allocated = false; } if ( !allocated ) return false; allocChunk_ = &chunks_.back(); deallocChunk_ = &chunks_.front(); return true;}// FixedAllocator::Allocate ---------------------------------------------------void * FixedAllocator::Allocate( void ){ // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) ); assert( CountEmptyChunks() < 2 ); if ( ( NULL == allocChunk_ ) || allocChunk_->IsFilled() ) { if ( NULL != emptyChunk_ ) { allocChunk_ = emptyChunk_; emptyChunk_ = NULL; } else { for ( ChunkIter i( chunks_.begin() ); ; ++i ) { if ( chunks_.end() == i ) { if ( !MakeNewChunk() ) return NULL; break; } if ( !i->IsFilled() ) { allocChunk_ = &*i; break; } } } } else if ( allocChunk_ == emptyChunk_) // detach emptyChunk_ from allocChunk_, because after // calling allocChunk_->Allocate(blockSize_); the chunk // is no longer empty. emptyChunk_ = NULL; assert( allocChunk_ != NULL ); assert( !allocChunk_->IsFilled() ); void * place = allocChunk_->Allocate( blockSize_ ); // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) ); assert( CountEmptyChunks() < 2 );#ifdef LOKI_CHECK_FOR_CORRUPTION if ( allocChunk_->IsCorrupt( numBlocks_, blockSize_, true ) ) { assert( false ); return NULL; }#endif return place;}// FixedAllocator::Deallocate -------------------------------------------------bool FixedAllocator::Deallocate( void * p, Chunk * hint ){ assert(!chunks_.empty()); assert(&chunks_.front() <= deallocChunk_); assert(&chunks_.back() >= deallocChunk_); assert( &chunks_.front() <= allocChunk_ ); assert( &chunks_.back() >= allocChunk_ ); assert( CountEmptyChunks() < 2 ); Chunk * foundChunk = ( NULL == hint ) ? VicinityFind( p ) : hint; if ( NULL == foundChunk ) return false; assert( foundChunk->HasBlock( p, numBlocks_ * blockSize_ ) );#ifdef LOKI_CHECK_FOR_CORRUPTION if ( foundChunk->IsCorrupt( numBlocks_, blockSize_, true ) ) { assert( false ); return false; } if ( foundChunk->IsBlockAvailable( p, numBlocks_, blockSize_ ) ) { assert( false ); return false; }#endif deallocChunk_ = foundChunk; DoDeallocate(p); assert( CountEmptyChunks() < 2 ); return true;}// FixedAllocator::VicinityFind -----------------------------------------------Chunk * FixedAllocator::VicinityFind( void * p ) const{ if ( chunks_.empty() ) return NULL; assert(deallocChunk_); const std::size_t chunkLength = numBlocks_ * blockSize_; Chunk * lo = deallocChunk_; Chunk * hi = deallocChunk_ + 1; const Chunk * loBound = &chunks_.front(); const Chunk * hiBound = &chunks_.back() + 1; // Special case: deallocChunk_ is the last in the array if (hi == hiBound) hi = NULL; for (;;) { if (lo) { if ( lo->HasBlock( p, chunkLength ) ) return lo; if ( lo == loBound ) { lo = NULL; if ( NULL == hi ) break; } else --lo; } if (hi) { if ( hi->HasBlock( p, chunkLength ) ) return hi; if ( ++hi == hiBound ) { hi = NULL; if ( NULL == lo ) break; } } } return NULL;}// FixedAllocator::DoDeallocate -----------------------------------------------void FixedAllocator::DoDeallocate(void* p){ // Show that deallocChunk_ really owns the block at address p. assert( deallocChunk_->HasBlock( p, numBlocks_ * blockSize_ ) ); // Either of the next two assertions may fail if somebody tries to // delete the same block twice. assert( emptyChunk_ != deallocChunk_ ); assert( !deallocChunk_->HasAvailable( numBlocks_ ) ); // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) ); // call into the chunk, will adjust the inner list but won't release memory deallocChunk_->Deallocate(p, blockSize_); if ( deallocChunk_->HasAvailable( numBlocks_ ) ) { assert( emptyChunk_ != deallocChunk_ ); // deallocChunk_ is empty, but a Chunk is only released if there are 2 // empty chunks. Since emptyChunk_ may only point to a previously // cleared Chunk, if it points to something else besides deallocChunk_, // then FixedAllocator currently has 2 empty Chunks. if ( NULL != emptyChunk_ ) { // If last Chunk is empty, just change what deallocChunk_ // points to, and release the last. Otherwise, swap an empty // Chunk with the last, and then release it. Chunk * lastChunk = &chunks_.back(); if ( lastChunk == deallocChunk_ ) deallocChunk_ = emptyChunk_; else if ( lastChunk != emptyChunk_ ) std::swap( *emptyChunk_, *lastChunk ); assert( lastChunk->HasAvailable( numBlocks_ ) ); lastChunk->Release(); chunks_.pop_back(); if ( ( allocChunk_ == lastChunk ) || allocChunk_->IsFilled() ) allocChunk_ = deallocChunk_; } emptyChunk_ = deallocChunk_; } // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );}// GetOffset ------------------------------------------------------------------/// @ingroup SmallObjectGroupInternal/// Calculates index into array where a FixedAllocator of numBytes is located.inline std::size_t GetOffset( std::size_t numBytes, std::size_t alignment ){ const std::size_t alignExtra = alignment-1; return ( numBytes + alignExtra ) / alignment;}// DefaultAllocator -----------------------------------------------------------/** @ingroup SmallObjectGroupInternal Calls the default allocator when SmallObjAllocator decides not to handle a request. SmallObjAllocator calls this if the number of bytes is bigger than the size which can be handled by any FixedAllocator. @param numBytes number of bytes @param doThrow True if this function should throw an exception, or false if it should indicate failure by returning a NULL pointer.*/void * DefaultAllocator( std::size_t numBytes, bool doThrow ){#ifdef USE_NEW_TO_ALLOCATE return doThrow ? ::operator new( numBytes ) : ::operator new( numBytes, std::nothrow_t() );#else void * p = ::std::malloc( numBytes ); if ( doThrow && ( NULL == p ) ) throw std::bad_alloc(); return p;#endif}// DefaultDeallocator ---------------------------------------------------------/** @ingroup SmallObjectGroupInternal Calls default deallocator when SmallObjAllocator decides not to handle a request. The default deallocator could be the global delete operator or the free function. The free function is the preferred default deallocator since it matches malloc which is the preferred default allocator. SmallObjAllocator will call this if an address was not found among any of its own blocks. */void DefaultDeallocator( void * p ){#ifdef USE_NEW_TO_ALLOCATE ::operator delete( p );#else ::std::free( p );#endif}// SmallObjAllocator::SmallObjAllocator ---------------------------------------SmallObjAllocator::SmallObjAllocator( std::size_t pageSize, std::size_t maxObjectSize, std::size_t objectAlignSize ) : pool_( NULL ), maxSmallObjectSize_( maxObjectSize ), objectAlignSize_( objectAlignSize ){#ifdef DO_EXTRA_LOKI_TESTS std::cout << "SmallObjAllocator " << this << std::endl;#endif assert( 0 != objectAlignSize ); const std::size_t allocCount = GetOffset( maxObjectSize, objectAlignSize ); pool_ = new FixedAllocator[ allocCount ]; for ( std::size_t i = 0; i < allocCount; ++i ) pool_[ i ].Initialize( ( i+1 ) * objectAlignSize, pageSize );}// SmallObjAllocator::~SmallObjAllocator --------------------------------------SmallObjAllocator::~SmallObjAllocator( void ){#ifdef DO_EXTRA_LOKI_TESTS std::cout << "~SmallObjAllocator " << this << std::endl;#endif delete [] pool_;}// SmallObjAllocator::TrimExcessMemory ----------------------------------------bool SmallObjAllocator::TrimExcessMemory( void ){ bool found = false; const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); std::size_t i = 0; for ( ; i < allocCount; ++i ) { if ( pool_[ i ].TrimEmptyChunk() ) found = true; } for ( i = 0; i < allocCount; ++i ) { if ( pool_[ i ].TrimChunkList() ) found = true; } return found;}// SmallObjAllocator::Allocate ------------------------------------------------void * SmallObjAllocator::Allocate( std::size_t numBytes, bool doThrow ){ if ( numBytes > GetMaxObjectSize() ) return DefaultAllocator( numBytes, doThrow ); assert( NULL != pool_ ); if ( 0 == numBytes ) numBytes = 1; const std::size_t index = GetOffset( numBytes, GetAlignment() ) - 1; const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); (void) allocCount; assert( index < allocCount ); FixedAllocator & allocator = pool_[ index ]; assert( allocator.BlockSize() >= numBytes ); assert( allocator.BlockSize() < numBytes + GetAlignment() ); void * place = allocator.Allocate(); if ( ( NULL == place ) && TrimExcessMemory() ) place = allocator.Allocate(); if ( ( NULL == place ) && doThrow ) {#ifdef _MSC_VER throw std::bad_alloc( "could not allocate small object" );#else // GCC did not like a literal string passed to std::bad_alloc. // so just throw the default-constructed exception. throw std::bad_alloc();#endif } return place;}// SmallObjAllocator::Deallocate ----------------------------------------------void SmallObjAllocator::Deallocate( void * p, std::size_t numBytes ){ if ( NULL == p ) return; if ( numBytes > GetMaxObjectSize() ) { DefaultDeallocator( p ); return; } assert( NULL != pool_ ); if ( 0 == numBytes ) numBytes = 1; const std::size_t index = GetOffset( numBytes, GetAlignment() ) - 1; const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); (void) allocCount; assert( index < allocCount ); FixedAllocator & allocator = pool_[ index ]; assert( allocator.BlockSize() >= numBytes ); assert( allocator.BlockSize() < numBytes + GetAlignment() ); const bool found = allocator.Deallocate( p, NULL ); (void) found; assert( found );}// SmallObjAllocator::Deallocate ----------------------------------------------void SmallObjAllocator::Deallocate( void * p ){ if ( NULL == p ) return; assert( NULL != pool_ ); FixedAllocator * pAllocator = NULL; const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); Chunk * chunk = NULL; for ( std::size_t ii = 0; ii < allocCount; ++ii ) { chunk = pool_[ ii ].HasBlock( p ); if ( NULL != chunk ) { pAllocator = &pool_[ ii ]; break; } } if ( NULL == pAllocator ) { DefaultDeallocator( p ); return; } assert( NULL != chunk ); const bool found = pAllocator->Deallocate( p, chunk ); (void) found; assert( found );}// SmallObjAllocator::IsCorrupt -----------------------------------------------bool SmallObjAllocator::IsCorrupt( void ) const{ if ( NULL == pool_ ) { assert( false ); return true; } if ( 0 == GetAlignment() ) { assert( false ); return true; } if ( 0 == GetMaxObjectSize() ) { assert( false ); return true; } const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); for ( std::size_t ii = 0; ii < allocCount; ++ii ) { if ( pool_[ ii ].IsCorrupt() ) return true; } return false;}} // end namespace Loki
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -