diff options
-rw-r--r-- | include/core/SkWriter32.h | 22 | ||||
-rw-r--r-- | src/core/SkWriter32.cpp | 101 | ||||
-rw-r--r-- | tests/Writer32Test.cpp | 27 |
3 files changed, 128 insertions, 22 deletions
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h index 78cfb2b165..f961736dcc 100644 --- a/include/core/SkWriter32.h +++ b/include/core/SkWriter32.h @@ -49,6 +49,14 @@ public: */ void* getSingleBlock() const { return fSingleBlock; } + // return the current offset (will always be a multiple of 4) + uint32_t bytesWritten() const { return fSize; } + // DEPRECATED: use byetsWritten instead + uint32_t size() const { return this->bytesWritten(); } + + void reset(); + uint32_t* reserve(size_t size); // size MUST be multiple of 4 + /** * Specify the single block to back the writer, rathern than dynamically * allocating the memory. If block == NULL, then the writer reverts to @@ -152,16 +160,18 @@ public: */ static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); - // return the current offset (will always be a multiple of 4) - uint32_t size() const { return fSize; } - void reset(); - uint32_t* reserve(size_t size); // size MUST be multiple of 4 - // return the address of the 4byte int at the specified offset (which must // be a multiple of 4. This does not allocate any new space, so the returned // address is only valid for 1 int. uint32_t* peek32(size_t offset); + /** + * Move the cursor back to offset bytes from the beginning. + * This has the same restrictions as peek32: offset must be <= size() and + * offset must be a multiple of 4. + */ + void rewindToOffset(size_t offset); + // copy into a single buffer (allocated by caller). Must be at least size() void flatten(void* dst) const; @@ -185,6 +195,8 @@ private: bool fHeadIsExternalStorage; Block* newBlock(size_t bytes); + + SkDEBUGCODE(void validate() const;) }; /** diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp index 636af360c4..a94a92fd88 100644 --- a/src/core/SkWriter32.cpp +++ b/src/core/SkWriter32.cpp @@ -9,40 +9,40 @@ struct SkWriter32::Block { Block* fNext; - size_t fSize; // total space allocated (after this) - size_t fAllocated; // space used so far + size_t fSizeOfBlock; // total space allocated (after this) + size_t fAllocatedSoFar; // space used so far - size_t available() const { return fSize - fAllocated; } + size_t available() const { return fSizeOfBlock - fAllocatedSoFar; } char* base() { return (char*)(this + 1); } const char* base() const { return (const char*)(this + 1); } uint32_t* alloc(size_t size) { SkASSERT(SkAlign4(size) == size); SkASSERT(this->available() >= size); - void* ptr = this->base() + fAllocated; - fAllocated += size; - SkASSERT(fAllocated <= fSize); + void* ptr = this->base() + fAllocatedSoFar; + fAllocatedSoFar += size; + SkASSERT(fAllocatedSoFar <= fSizeOfBlock); return (uint32_t*)ptr; } uint32_t* peek32(size_t offset) { - SkASSERT(offset <= fAllocated + 4); + SkASSERT(offset <= fAllocatedSoFar + 4); void* ptr = this->base() + offset; return (uint32_t*)ptr; } void rewind() { fNext = NULL; - fAllocated = 0; - // keep fSize as is + fAllocatedSoFar = 0; + // keep fSizeOfBlock as is } static Block* Create(size_t size) { SkASSERT(SkAlign4(size) == size); Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); block->fNext = NULL; - block->fSize = size; - block->fAllocated = 0; + block->fSizeOfBlock = size; + block->fAllocatedSoFar = 0; return block; } @@ -50,8 +50,8 @@ struct SkWriter32::Block { SkASSERT(SkIsAlign4((intptr_t)storage)); Block* block = (Block*)storage; block->fNext = NULL; - block->fSize = size - sizeof(Block); - block->fAllocated = 0; + block->fSizeOfBlock = size - sizeof(Block); + block->fAllocatedSoFar = 0; return block; } @@ -140,6 +140,8 @@ uint32_t* SkWriter32::reserve(size_t size) { } uint32_t* SkWriter32::peek32(size_t offset) { + SkDEBUGCODE(this->validate();) + SkASSERT(SkAlign4(offset) == offset); SkASSERT(offset <= fSize); @@ -150,14 +152,55 @@ uint32_t* SkWriter32::peek32(size_t offset) { Block* block = fHead; SkASSERT(NULL != block); - while (offset >= block->fAllocated) { - offset -= block->fAllocated; + while (offset >= block->fAllocatedSoFar) { + offset -= block->fAllocatedSoFar; block = block->fNext; SkASSERT(NULL != block); } return block->peek32(offset); } +void SkWriter32::rewindToOffset(size_t offset) { + if (0 == offset) { + this->reset(NULL, 0); + return; + } + + SkDEBUGCODE(this->validate();) + + SkASSERT(SkAlign4(offset) == offset); + SkASSERT(offset <= fSize); + fSize = offset; + + if (fSingleBlock) { + return; + } + + // Similar to peek32, except that we free up any following blocks + Block* block = fHead; + SkASSERT(NULL != block); + + while (offset >= block->fAllocatedSoFar) { + offset -= block->fAllocatedSoFar; + block = block->fNext; + SkASSERT(NULL != block); + } + + fTail = block; + block->fAllocatedSoFar = offset; + + // free up any following blocks + SkASSERT(block); + block = block->fNext; + while (block) { + Block* next = block->fNext; + sk_free(block); + block = next; + } + + SkDEBUGCODE(this->validate();) +} + void SkWriter32::flatten(void* dst) const { if (fSingleBlock) { memcpy(dst, fSingleBlock, fSize); @@ -168,7 +211,7 @@ void SkWriter32::flatten(void* dst) const { SkDEBUGCODE(size_t total = 0;) while (block) { - size_t allocated = block->fAllocated; + size_t allocated = block->fAllocatedSoFar; memcpy(dst, block->base(), allocated); dst = (char*)dst + allocated; block = block->fNext; @@ -232,7 +275,7 @@ bool SkWriter32::writeToStream(SkWStream* stream) { const Block* block = fHead; while (block) { - if (!stream->write(block->base(), block->fAllocated)) { + if (!stream->write(block->base(), block->fAllocatedSoFar)) { return false; } block = block->fNext; @@ -240,6 +283,30 @@ bool SkWriter32::writeToStream(SkWStream* stream) { return true; } +#ifdef SK_DEBUG +void SkWriter32::validate() const { + SkASSERT(SkIsAlign4(fSize)); + SkASSERT(SkIsAlign4(fSingleBlockSize)); + + if (fSingleBlock) { + SkASSERT(fSize <= fSingleBlockSize); + return; + } + + size_t accum = 0; + const Block* block = fHead; + while (block) { + SkASSERT(SkIsAlign4(block->fSizeOfBlock)); + SkASSERT(SkIsAlign4(block->fAllocatedSoFar)); + SkASSERT(block->fAllocatedSoFar <= block->fSizeOfBlock); + accum += block->fAllocatedSoFar; + SkASSERT(accum <= fSize); + block = block->fNext; + } + SkASSERT(accum == fSize); +} +#endif + /////////////////////////////////////////////////////////////////////////////// #include "SkReader32.h" diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp index f2dcf90ea7..fdc074547d 100644 --- a/tests/Writer32Test.cpp +++ b/tests/Writer32Test.cpp @@ -13,6 +13,32 @@ #include "SkWriter32.h" #include "Test.h" +static void check_contents(skiatest::Reporter* reporter, const SkWriter32& writer, + const void* expected, size_t size) { + SkAutoSMalloc<256> storage(size); + REPORTER_ASSERT(reporter, writer.bytesWritten() == size); + writer.flatten(storage.get()); + REPORTER_ASSERT(reporter, !memcmp(storage.get(), expected, size)); +} + +static void test_rewind(skiatest::Reporter* reporter) { + SkSWriter32<32> writer(32); + int32_t array[3] = { 1, 2, 4 }; + + REPORTER_ASSERT(reporter, 0 == writer.bytesWritten()); + for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) { + writer.writeInt(array[i]); + } + check_contents(reporter, writer, array, sizeof(array)); + + writer.rewindToOffset(2*sizeof(int32_t)); + REPORTER_ASSERT(reporter, sizeof(array) - 4 == writer.bytesWritten()); + writer.writeInt(3); + REPORTER_ASSERT(reporter, sizeof(array) == writer.bytesWritten()); + array[2] = 3; + check_contents(reporter, writer, array, sizeof(array)); +} + static void test_ptr(skiatest::Reporter* reporter) { SkSWriter32<32> writer(32); @@ -182,6 +208,7 @@ static void Tests(skiatest::Reporter* reporter) { } test_ptr(reporter); + test_rewind(reporter); } #include "TestClassDef.h" |