Index: src/core/SkChunkAlloc.cpp |
diff --git a/src/core/SkChunkAlloc.cpp b/src/core/SkChunkAlloc.cpp |
index 62cdf1532f75b15738c296cf786d24b23ed1dfa0..4a71c2d2c43576263d00b2aeeac16aef90d50e61 100644 |
--- a/src/core/SkChunkAlloc.cpp |
+++ b/src/core/SkChunkAlloc.cpp |
@@ -23,6 +23,18 @@ struct SkChunkAlloc::Block { |
char* fFreePtr; |
// data[] follows |
+ size_t blockSize() { |
+ char* start = this->startOfData(); |
+ size_t bytes = fFreePtr - start; |
+ return fFreeSize + bytes; |
+ } |
+ |
+ void reset() { |
+ fNext = NULL; |
+ fFreeSize = this->blockSize(); |
+ fFreePtr = this->startOfData(); |
+ } |
+ |
char* startOfData() { |
return reinterpret_cast<char*>(this + 1); |
} |
@@ -53,7 +65,8 @@ SkChunkAlloc::SkChunkAlloc(size_t minSize) { |
fChunkSize = fMinSize; |
fTotalCapacity = 0; |
fTotalUsed = 0; |
- fBlockCount = 0; |
+ SkDEBUGCODE(fTotalLost = 0;) |
+ SkDEBUGCODE(fBlockCount = 0;) |
} |
SkChunkAlloc::~SkChunkAlloc() { |
@@ -66,7 +79,40 @@ void SkChunkAlloc::reset() { |
fChunkSize = fMinSize; // reset to our initial minSize |
fTotalCapacity = 0; |
fTotalUsed = 0; |
- fBlockCount = 0; |
+ SkDEBUGCODE(fTotalLost = 0;) |
+ SkDEBUGCODE(fBlockCount = 0;) |
+} |
+ |
+void SkChunkAlloc::rewind() { |
+ SkDEBUGCODE(this->validate();) |
+ |
+ Block* largest = fBlock; |
+ |
+ if (largest) { |
+ Block* next; |
+ for (Block* cur = largest->fNext; cur; cur = next) { |
+ next = cur->fNext; |
+ if (cur->blockSize() > largest->blockSize()) { |
+ sk_free(largest); |
+ largest = cur; |
+ } else { |
+ sk_free(cur); |
+ } |
+ } |
+ |
+ largest->reset(); |
+ fTotalCapacity = largest->blockSize(); |
+ SkDEBUGCODE(fBlockCount = 1;) |
+ } else { |
+ fTotalCapacity = 0; |
+ SkDEBUGCODE(fBlockCount = 0;) |
+ } |
+ |
+ fBlock = largest; |
+ fChunkSize = fMinSize; // reset to our initial minSize |
+ fTotalUsed = 0; |
+ SkDEBUGCODE(fTotalLost = 0;) |
+ SkDEBUGCODE(this->validate();) |
} |
SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { |
@@ -79,43 +125,60 @@ SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { |
ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0); |
if (block) { |
- // block->fNext = fBlock; |
block->fFreeSize = size; |
block->fFreePtr = block->startOfData(); |
fTotalCapacity += size; |
- fBlockCount += 1; |
+ SkDEBUGCODE(fBlockCount += 1;) |
fChunkSize = increase_next_size(fChunkSize); |
} |
return block; |
} |
-void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { |
- fTotalUsed += bytes; |
- |
- bytes = SkAlign4(bytes); |
- |
- Block* block = fBlock; |
+SkChunkAlloc::Block* SkChunkAlloc::addBlockIfNecessary(size_t bytes, AllocFailType ftype) { |
+ SkASSERT(SkIsAlign4(bytes)); |
- if (block == NULL || bytes > block->fFreeSize) { |
- block = this->newBlock(bytes, ftype); |
- if (NULL == block) { |
+ if (!fBlock || bytes > fBlock->fFreeSize) { |
+ Block* block = this->newBlock(bytes, ftype); |
+ if (!block) { |
return NULL; |
} |
+#ifdef SK_DEBUG |
+ if (fBlock) { |
+ fTotalLost += fBlock->fFreeSize; |
+ } |
+#endif |
block->fNext = fBlock; |
fBlock = block; |
} |
- SkASSERT(block && bytes <= block->fFreeSize); |
+ SkASSERT(fBlock && bytes <= fBlock->fFreeSize); |
+ return fBlock; |
+} |
+ |
+void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { |
+ SkDEBUGCODE(this->validate();) |
+ |
+ bytes = SkAlign4(bytes); |
+ |
+ Block* block = this->addBlockIfNecessary(bytes, ftype); |
+ if (!block) { |
+ return NULL; |
+ } |
+ |
char* ptr = block->fFreePtr; |
+ fTotalUsed += bytes; |
block->fFreeSize -= bytes; |
block->fFreePtr = ptr + bytes; |
+ SkDEBUGCODE(this->validate();) |
return ptr; |
} |
size_t SkChunkAlloc::unalloc(void* ptr) { |
+ SkDEBUGCODE(this->validate();) |
+ |
size_t bytes = 0; |
Block* block = fBlock; |
if (block) { |
@@ -123,10 +186,12 @@ size_t SkChunkAlloc::unalloc(void* ptr) { |
char* start = block->startOfData(); |
if (start <= cPtr && cPtr < block->fFreePtr) { |
bytes = block->fFreePtr - cPtr; |
+ fTotalUsed -= bytes; |
block->fFreeSize += bytes; |
block->fFreePtr = cPtr; |
} |
} |
+ SkDEBUGCODE(this->validate();) |
return bytes; |
} |
@@ -140,3 +205,31 @@ bool SkChunkAlloc::contains(const void* addr) const { |
} |
return false; |
} |
+ |
+#ifdef SK_DEBUG |
+void SkChunkAlloc::validate() { |
+ int numBlocks = 0; |
+ size_t totCapacity = 0; |
+ size_t totUsed = 0; |
+ size_t totLost = 0; |
+ size_t totAvailable = 0; |
+ |
+ for (Block* temp = fBlock; temp; temp = temp->fNext) { |
+ ++numBlocks; |
+ totCapacity += temp->blockSize(); |
+ totUsed += temp->fFreePtr - temp->startOfData(); |
+ if (temp == fBlock) { |
+ totAvailable += temp->fFreeSize; |
+ } else { |
+ totLost += temp->fFreeSize; |
+ } |
+ } |
+ |
+ SkASSERT(fBlockCount == numBlocks); |
+ SkASSERT(fTotalCapacity == totCapacity); |
+ SkASSERT(fTotalUsed == totUsed); |
+ SkASSERT(fTotalLost == totLost); |
+ SkASSERT(totCapacity == totUsed + totLost + totAvailable); |
+} |
+#endif |
+ |