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
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #include <base/SmallObj>
00056 #include <cassert>
00057 #include <algorithm>
00058 #include <iostream>
00059
00060 #include <base/MemoryTracer>
00061
00062 using namespace base;
00063
00064
00065
00066
00067
00068
00069 void FixedAllocator::Chunk::Init(std::size_t blockSize, unsigned char blocks)
00070 {
00071 assert(blockSize > 0);
00072 assert(blocks > 0);
00073
00074 assert((blockSize * blocks) / blockSize == blocks);
00075
00076 pData_ = NewNamedObj("FixedAllocator::pData") unsigned char[blockSize * blocks];
00077
00078 Reset(blockSize, blocks);
00079 }
00080
00081
00082
00083
00084
00085
00086 void FixedAllocator::Chunk::Reset(std::size_t blockSize, unsigned char blocks)
00087 {
00088 assert(blockSize > 0);
00089 assert(blocks > 0);
00090
00091 assert((blockSize * blocks) / blockSize == blocks);
00092
00093 firstAvailableBlock_ = 0;
00094 blocksAvailable_ = blocks;
00095
00096 unsigned char i = 0;
00097 unsigned char* p = pData_;
00098 for (; i != blocks; p += blockSize)
00099 {
00100 *p = ++i;
00101 }
00102 }
00103
00104
00105
00106
00107
00108
00109 void FixedAllocator::Chunk::Release()
00110 {
00111 delete[] pData_;
00112 }
00113
00114
00115
00116
00117
00118
00119 void* FixedAllocator::Chunk::Allocate(std::size_t blockSize)
00120 {
00121 if (!blocksAvailable_) return 0;
00122
00123 assert((firstAvailableBlock_ * blockSize) / blockSize ==
00124 firstAvailableBlock_);
00125
00126 unsigned char* pResult =
00127 pData_ + (firstAvailableBlock_ * blockSize);
00128 firstAvailableBlock_ = *pResult;
00129 --blocksAvailable_;
00130
00131 return pResult;
00132 }
00133
00134
00135
00136
00137
00138
00139 void FixedAllocator::Chunk::Deallocate(void* p, std::size_t blockSize)
00140 {
00141 assert(p >= pData_);
00142
00143 unsigned char* toRelease = static_cast<unsigned char*>(p);
00144
00145 assert((toRelease - pData_) % blockSize == 0);
00146
00147 *toRelease = firstAvailableBlock_;
00148 firstAvailableBlock_ = static_cast<unsigned char>(
00149 (toRelease - pData_) / blockSize);
00150
00151 assert(firstAvailableBlock_ == (toRelease - pData_) / blockSize);
00152
00153 ++blocksAvailable_;
00154 }
00155
00156
00157
00158
00159
00160
00161 FixedAllocator::FixedAllocator(std::size_t blockSize)
00162 : blockSize_(blockSize)
00163 , allocChunk_(0)
00164 , deallocChunk_(0)
00165 {
00166 assert(blockSize_ > 0);
00167
00168 prev_ = next_ = this;
00169
00170 std::size_t numBlocks = DEFAULT_CHUNK_SIZE / blockSize;
00171 if (numBlocks > UCHAR_MAX) numBlocks = UCHAR_MAX;
00172 else if (numBlocks == 0) numBlocks = 8 * blockSize;
00173
00174 numBlocks_ = static_cast<unsigned char>(numBlocks);
00175 assert(numBlocks_ == numBlocks);
00176 }
00177
00178
00179
00180
00181
00182
00183 FixedAllocator::FixedAllocator(const FixedAllocator& rhs)
00184 : blockSize_(rhs.blockSize_)
00185 , numBlocks_(rhs.numBlocks_)
00186 , chunks_(rhs.chunks_)
00187 {
00188 prev_ = &rhs;
00189 next_ = rhs.next_;
00190 rhs.next_->prev_ = this;
00191 rhs.next_ = this;
00192
00193 allocChunk_ = rhs.allocChunk_
00194 ? &chunks_.front() + (rhs.allocChunk_ - &rhs.chunks_.front())
00195 : 0;
00196
00197 deallocChunk_ = rhs.deallocChunk_
00198 ? &chunks_.front() + (rhs.deallocChunk_ - &rhs.chunks_.front())
00199 : 0;
00200 }
00201
00202 FixedAllocator& FixedAllocator::operator=(const FixedAllocator& rhs)
00203 {
00204 FixedAllocator copy(rhs);
00205 copy.Swap(*this);
00206 return *this;
00207 }
00208
00209
00210
00211
00212
00213 FixedAllocator::~FixedAllocator()
00214 {
00215 if (prev_ != this)
00216 {
00217 prev_->next_ = next_;
00218 next_->prev_ = prev_;
00219 return;
00220 }
00221
00222 assert(prev_ == next_);
00223 int allocatedBlocks = 0;
00224 Chunks::iterator i = chunks_.begin();
00225 for (; i != chunks_.end(); ++i)
00226 {
00227 allocatedBlocks += (numBlocks_ - i->blocksAvailable_);
00228
00229
00230 i->Release();
00231 }
00232
00233 if (allocatedBlocks > 0)
00234 fprintf(stderr,"SmallObj/FixedAllocator::~FixedAllocator - Warning: %d objects (of size %d) left allocated on allocator destruction.\n",allocatedBlocks,blockSize_);
00235 }
00236
00237
00238
00239
00240
00241 void FixedAllocator::Swap(FixedAllocator& rhs)
00242 {
00243 using namespace std;
00244
00245 swap(blockSize_, rhs.blockSize_);
00246 swap(numBlocks_, rhs.numBlocks_);
00247 chunks_.swap(rhs.chunks_);
00248 swap(allocChunk_, rhs.allocChunk_);
00249 swap(deallocChunk_, rhs.deallocChunk_);
00250 }
00251
00252
00253
00254
00255
00256
00257 void* FixedAllocator::Allocate()
00258 {
00259 if (allocChunk_ == 0 || allocChunk_->blocksAvailable_ == 0)
00260 {
00261 Chunks::iterator i = chunks_.begin();
00262 for (;; ++i)
00263 {
00264 if (i == chunks_.end())
00265 {
00266
00267 chunks_.reserve(chunks_.size() + 1);
00268 Chunk newChunk;
00269 newChunk.Init(blockSize_, numBlocks_);
00270 chunks_.push_back(newChunk);
00271 allocChunk_ = &chunks_.back();
00272 deallocChunk_ = &chunks_.front();
00273 break;
00274 }
00275 if (i->blocksAvailable_ > 0)
00276 {
00277 allocChunk_ = &*i;
00278 break;
00279 }
00280 }
00281 }
00282 assert(allocChunk_ != 0);
00283 assert(allocChunk_->blocksAvailable_ > 0);
00284
00285 return allocChunk_->Allocate(blockSize_);
00286 }
00287
00288
00289
00290
00291
00292
00293
00294 void FixedAllocator::Deallocate(void* p)
00295 {
00296 assert(!chunks_.empty());
00297 assert(&chunks_.front() <= deallocChunk_);
00298 assert(&chunks_.back() >= deallocChunk_);
00299
00300 deallocChunk_ = VicinityFind(p);
00301 assert(deallocChunk_);
00302
00303 DoDeallocate(p);
00304 }
00305
00306
00307
00308
00309
00310
00311 FixedAllocator::Chunk* FixedAllocator::VicinityFind(void* p)
00312 {
00313 assert(!chunks_.empty());
00314 assert(deallocChunk_);
00315
00316 const std::size_t chunkLength = numBlocks_ * blockSize_;
00317
00318 Chunk* lo = deallocChunk_;
00319 Chunk* hi = deallocChunk_ + 1;
00320 Chunk* loBound = &chunks_.front();
00321 Chunk* hiBound = &chunks_.back() + 1;
00322
00323 for (;;)
00324 {
00325 if (lo)
00326 {
00327 if (p >= lo->pData_ && p < lo->pData_ + chunkLength)
00328 {
00329 return lo;
00330 }
00331 if (lo == loBound) lo = 0;
00332 else --lo;
00333 }
00334
00335 if (hi)
00336 {
00337 if (p >= hi->pData_ && p < hi->pData_ + chunkLength)
00338 {
00339 return hi;
00340 }
00341 if (++hi == hiBound) hi = 0;
00342 }
00343 }
00344 assert(false);
00345 return 0;
00346 }
00347
00348
00349
00350
00351
00352
00353 void FixedAllocator::DoDeallocate(void* p)
00354 {
00355 assert(deallocChunk_->pData_ <= p);
00356 assert(deallocChunk_->pData_ + numBlocks_ * blockSize_ > p);
00357
00358
00359 deallocChunk_->Deallocate(p, blockSize_);
00360
00361 if (deallocChunk_->blocksAvailable_ == numBlocks_)
00362 {
00363
00364
00365 Chunk& lastChunk = chunks_.back();
00366
00367 if (&lastChunk == deallocChunk_)
00368 {
00369
00370
00371 if (chunks_.size() > 1 &&
00372 deallocChunk_[-1].blocksAvailable_ == numBlocks_)
00373 {
00374
00375 lastChunk.Release();
00376 chunks_.pop_back();
00377 allocChunk_ = deallocChunk_ = &chunks_.front();
00378 }
00379 return;
00380 }
00381
00382 if (lastChunk.blocksAvailable_ == numBlocks_)
00383 {
00384
00385 lastChunk.Release();
00386 chunks_.pop_back();
00387 allocChunk_ = deallocChunk_;
00388 }
00389 else
00390 {
00391
00392 std::swap(*deallocChunk_, lastChunk);
00393 allocChunk_ = &chunks_.back();
00394 }
00395 }
00396 }
00397
00398
00399
00400
00401
00402
00403
00404 SmallObjAllocator::SmallObjAllocator(
00405 std::size_t chunkSize,
00406 std::size_t maxObjectSize)
00407 : pLastAlloc_(0), pLastDealloc_(0)
00408 , chunkSize_(chunkSize), maxObjectSize_(maxObjectSize)
00409 {
00410 }
00411
00412
00413
00414
00415
00416
00417
00418 void* SmallObjAllocator::Allocate(std::size_t numBytes)
00419 {
00420 if (numBytes > maxObjectSize_) return operator new(numBytes,"SmallObjAllocator::Allocate");
00421
00422 if (pLastAlloc_ && pLastAlloc_->BlockSize() == numBytes)
00423 {
00424 return pLastAlloc_->Allocate();
00425 }
00426
00427 Pool::iterator i = std::lower_bound(pool_.begin(), pool_.end(), numBytes);
00428 if (i == pool_.end() || i->BlockSize() != numBytes)
00429 {
00430 i = pool_.insert(i, FixedAllocator(numBytes));
00431 pLastDealloc_ = &*pool_.begin();
00432 }
00433 pLastAlloc_ = &*i;
00434 return pLastAlloc_->Allocate();
00435 }
00436
00437
00438
00439
00440
00441
00442
00443 void SmallObjAllocator::Deallocate(void* p, std::size_t numBytes)
00444 {
00445 if (numBytes > maxObjectSize_) return operator delete(p);
00446
00447 if (pLastDealloc_ && pLastDealloc_->BlockSize() == numBytes)
00448 {
00449 pLastDealloc_->Deallocate(p);
00450 return;
00451 }
00452
00453 Pool::iterator i = std::lower_bound(pool_.begin(), pool_.end(), numBytes);
00454 assert(i != pool_.end());
00455 assert(i->BlockSize() == numBytes);
00456 pLastDealloc_ = &*i;
00457 pLastDealloc_->Deallocate(p);
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468