diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-12-21 15:36:33 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-12-21 15:36:33 +0000 |
commit | 5595af1b2ebe6590e98641464d43d22281a7f295 (patch) | |
tree | 0534fea47765d36fea593666cda4633241a61e65 | |
parent | 2859eb74f9c87471b2429cd12b84144b97157efb (diff) |
unify how we handle externally-provided storage in SkWriter32, with the goal
of simplifying the logic in reserve() so it can be inlined/accelerated.
Review URL: https://codereview.appspot.com/6962048
git-svn-id: http://skia.googlecode.com/svn/trunk@6923 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkWriter32.h | 107 | ||||
-rw-r--r-- | src/core/SkWriter32.cpp | 142 | ||||
-rw-r--r-- | tests/Writer32Test.cpp | 10 |
3 files changed, 104 insertions, 155 deletions
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h index 3f5a2433ed..3e0b012997 100644 --- a/include/core/SkWriter32.h +++ b/include/core/SkWriter32.h @@ -24,6 +24,7 @@ class SkStream; class SkWStream; class SkWriter32 : SkNoncopyable { + struct BlockHeader; public: /** * The caller can specify an initial block of storage, which the caller manages. @@ -36,35 +37,32 @@ public: SkWriter32(size_t minSize) : fMinSize(minSize), fSize(0), - fSingleBlock(NULL), - fSingleBlockSize(0), fWrittenBeforeLastBlock(0), fHead(NULL), - fTail(NULL), - fHeadIsExternalStorage(false) {} + fTail(NULL) {} ~SkWriter32(); - /** - * Returns the single block backing the writer, or NULL if the memory is - * to be dynamically allocated. - */ - 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 + + // size MUST be multiple of 4 + uint32_t* reserve(size_t size) { + SkASSERT(SkAlign4(size) == size); + + Block* block = fTail; + if (NULL == block || block->available() < size) { + block = this->doReserve(size); + } + fSize += size; + return block->alloc(size); + } - /** - * Specify the single block to back the writer, rathern than dynamically - * allocating the memory. If block == NULL, then the writer reverts to - * dynamic allocation (and resets). - */ - void reset(void* block, size_t size); + void reset(void* storage, size_t size); bool writeBool(bool value) { this->writeInt(value); @@ -197,22 +195,79 @@ public: bool writeToStream(SkWStream*); private: - size_t fMinSize; - uint32_t fSize; + struct Block { + Block* fNext; + char* fBasePtr; + size_t fSizeOfBlock; // total space allocated (after this) + size_t fAllocatedSoFar; // space used so far + + size_t available() const { return fSizeOfBlock - fAllocatedSoFar; } + char* base() { return fBasePtr; } + const char* base() const { return fBasePtr; } + + uint32_t* alloc(size_t size) { + SkASSERT(SkAlign4(size) == size); + SkASSERT(this->available() >= size); + void* ptr = this->base() + fAllocatedSoFar; + fAllocatedSoFar += size; + SkASSERT(fAllocatedSoFar <= fSizeOfBlock); + return (uint32_t*)ptr; + } - char* fSingleBlock; - uint32_t fSingleBlockSize; + uint32_t* peek32(size_t offset) { + SkASSERT(offset <= fAllocatedSoFar + 4); + void* ptr = this->base() + offset; + return (uint32_t*)ptr; + } + + void rewind() { + fNext = NULL; + fAllocatedSoFar = 0; + // keep fSizeOfBlock as is + } + + static Block* Create(size_t size) { + SkASSERT(SkIsAlign4(size)); + Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); + block->fNext = NULL; + block->fBasePtr = (char*)(block + 1); + block->fSizeOfBlock = size; + block->fAllocatedSoFar = 0; + return block; + } + Block* initFromStorage(void* storage, size_t size) { + SkASSERT(SkIsAlign4((intptr_t)storage)); + SkASSERT(SkIsAlign4(size)); + Block* block = this; + block->fNext = NULL; + block->fBasePtr = (char*)storage; + block->fSizeOfBlock = size; + block->fAllocatedSoFar = 0; + return block; + } + }; + + enum { + MIN_BLOCKSIZE = sizeof(SkWriter32::Block) + sizeof(intptr_t) + }; + + Block fExternalBlock; + Block* fHead; + Block* fTail; + size_t fMinSize; + uint32_t fSize; // sum of bytes written in all blocks *before* fTail uint32_t fWrittenBeforeLastBlock; - struct Block; - Block* fHead; - Block* fTail; - - bool fHeadIsExternalStorage; + bool isHeadExternallyAllocated() const { + return fHead == &fExternalBlock; + } Block* newBlock(size_t bytes); + + // only call from reserve() + Block* doReserve(size_t bytes); SkDEBUGCODE(void validate() const;) }; diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp index 4bb83b3e37..b66a7fe70c 100644 --- a/src/core/SkWriter32.cpp +++ b/src/core/SkWriter32.cpp @@ -1,80 +1,20 @@ - /* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#include "SkWriter32.h" - -struct SkWriter32::Block { - Block* fNext; - size_t fSizeOfBlock; // total space allocated (after this) - size_t fAllocatedSoFar; // space used so far - - 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() + fAllocatedSoFar; - fAllocatedSoFar += size; - SkASSERT(fAllocatedSoFar <= fSizeOfBlock); - return (uint32_t*)ptr; - } - - uint32_t* peek32(size_t offset) { - SkASSERT(offset <= fAllocatedSoFar + 4); - void* ptr = this->base() + offset; - return (uint32_t*)ptr; - } - void rewind() { - fNext = NULL; - 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->fSizeOfBlock = size; - block->fAllocatedSoFar = 0; - return block; - } - - static Block* CreateFromStorage(void* storage, size_t size) { - SkASSERT(SkIsAlign4((intptr_t)storage)); - Block* block = (Block*)storage; - block->fNext = NULL; - block->fSizeOfBlock = size - sizeof(Block); - block->fAllocatedSoFar = 0; - return block; - } - -}; - -#define MIN_BLOCKSIZE (sizeof(SkWriter32::Block) + sizeof(intptr_t)) - -/////////////////////////////////////////////////////////////////////////////// +#include "SkWriter32.h" SkWriter32::SkWriter32(size_t minSize, void* storage, size_t storageSize) { fMinSize = minSize; fSize = 0; - fSingleBlock = NULL; - fSingleBlockSize = 0; fWrittenBeforeLastBlock = 0; + fHead = fTail = NULL; - storageSize &= ~3; // trunc down to multiple of 4 - if (storageSize >= MIN_BLOCKSIZE) { - fHead = fTail = Block::CreateFromStorage(storage, storageSize); - fHeadIsExternalStorage = true; - } else { - fHead = fTail = NULL; - fHeadIsExternalStorage = false; + if (storageSize) { + this->reset(storage, storageSize); } } @@ -85,7 +25,7 @@ SkWriter32::~SkWriter32() { void SkWriter32::reset() { Block* block = fHead; - if (fHeadIsExternalStorage) { + if (this->isHeadExternallyAllocated()) { SkASSERT(block); // don't 'free' the first block, since it is owned by the caller block = block->fNext; @@ -98,40 +38,29 @@ void SkWriter32::reset() { fSize = 0; fWrittenBeforeLastBlock = 0; - fSingleBlock = NULL; - if (fHeadIsExternalStorage) { - SkASSERT(fHead); - fHead->rewind(); - fTail = fHead; - } else { - fHead = fTail = NULL; - } + fHead = fTail = NULL; } -void SkWriter32::reset(void* block, size_t size) { +void SkWriter32::reset(void* storage, size_t storageSize) { this->reset(); - SkASSERT(0 == ((fSingleBlock - (char*)0) & 3)); // need 4-byte alignment - fSingleBlock = (char*)block; - fSingleBlockSize = (size & ~3); + + storageSize &= ~3; // trunc down to multiple of 4 + if (storageSize > 0 && SkIsAlign4((intptr_t)storage)) { + fHead = fTail = fExternalBlock.initFromStorage(storage, storageSize); + } } -uint32_t* SkWriter32::reserve(size_t size) { +SkWriter32::Block* SkWriter32::doReserve(size_t size) { SkASSERT(SkAlign4(size) == size); - if (fSingleBlock) { - uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize); - fSize += size; - SkASSERT(fSize <= fSingleBlockSize); - return ptr; - } - Block* block = fTail; + SkASSERT(NULL == block || block->available() < size); if (NULL == block) { SkASSERT(NULL == fHead); fHead = fTail = block = Block::Create(SkMax32(size, fMinSize)); SkASSERT(0 == fWrittenBeforeLastBlock); - } else if (block->available() < size) { + } else { SkASSERT(fSize > 0); fWrittenBeforeLastBlock = fSize; @@ -139,10 +68,7 @@ uint32_t* SkWriter32::reserve(size_t size) { block->fNext = fTail; block = fTail; } - - fSize += size; - - return block->alloc(size); + return block; } uint32_t* SkWriter32::peek32(size_t offset) { @@ -151,10 +77,6 @@ uint32_t* SkWriter32::peek32(size_t offset) { SkASSERT(SkAlign4(offset) == offset); SkASSERT(offset <= fSize); - if (fSingleBlock) { - return (uint32_t*)(fSingleBlock + offset); - } - // try the fast case, where offset is within fTail if (offset >= fWrittenBeforeLastBlock) { return fTail->peek32(offset - fWrittenBeforeLastBlock); @@ -176,7 +98,7 @@ void SkWriter32::rewindToOffset(size_t offset) { return; } if (0 == offset) { - this->reset(NULL, 0); + this->reset(); return; } @@ -186,10 +108,6 @@ void SkWriter32::rewindToOffset(size_t offset) { SkASSERT(offset <= fSize); fSize = offset; - if (fSingleBlock) { - return; - } - // Try the fast case, where offset is within fTail if (offset >= fWrittenBeforeLastBlock) { fTail->fAllocatedSoFar = offset - fWrittenBeforeLastBlock; @@ -227,11 +145,6 @@ void SkWriter32::rewindToOffset(size_t offset) { } void SkWriter32::flatten(void* dst) const { - if (fSingleBlock) { - memcpy(dst, fSingleBlock, fSize); - return; - } - const Block* block = fHead; SkDEBUGCODE(size_t total = 0;) @@ -270,17 +183,6 @@ void SkWriter32::writePad(const void* src, size_t size) { #include "SkStream.h" size_t SkWriter32::readFromStream(SkStream* stream, size_t length) { - if (fSingleBlock) { - SkASSERT(fSingleBlockSize >= fSize); - size_t remaining = fSingleBlockSize - fSize; - if (length > remaining) { - length = remaining; - } - stream->read(fSingleBlock + fSize, length); - fSize += length; - return length; - } - char scratch[1024]; const size_t MAX = sizeof(scratch); size_t remaining = length; @@ -301,10 +203,6 @@ size_t SkWriter32::readFromStream(SkStream* stream, size_t length) { } bool SkWriter32::writeToStream(SkWStream* stream) { - if (fSingleBlock) { - return stream->write(fSingleBlock, fSize); - } - const Block* block = fHead; while (block) { if (!stream->write(block->base(), block->fAllocatedSoFar)) { @@ -318,12 +216,6 @@ bool SkWriter32::writeToStream(SkWStream* stream) { #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; diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp index 4715f7a613..bcdc559407 100644 --- a/tests/Writer32Test.cpp +++ b/tests/Writer32Test.cpp @@ -173,7 +173,6 @@ static void Tests(skiatest::Reporter* reporter) { // dynamic allocator { SkWriter32 writer(256 * 4); - REPORTER_ASSERT(reporter, NULL == writer.getSingleBlock()); test1(reporter, &writer); writer.reset(); @@ -183,13 +182,11 @@ static void Tests(skiatest::Reporter* reporter) { testWritePad(reporter, &writer); } - // single-block + // storage-block { SkWriter32 writer(0); uint32_t storage[256]; - REPORTER_ASSERT(reporter, NULL == writer.getSingleBlock()); writer.reset(storage, sizeof(storage)); - REPORTER_ASSERT(reporter, (void*)storage == writer.getSingleBlock()); test1(reporter, &writer); writer.reset(storage, sizeof(storage)); @@ -197,6 +194,11 @@ static void Tests(skiatest::Reporter* reporter) { writer.reset(storage, sizeof(storage)); testWritePad(reporter, &writer); + + // try overflowing the storage-block + uint32_t smallStorage[8]; + writer.reset(smallStorage, sizeof(smallStorage)); + test2(reporter, &writer); } // small storage |