aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-21 15:36:33 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-21 15:36:33 +0000
commit5595af1b2ebe6590e98641464d43d22281a7f295 (patch)
tree0534fea47765d36fea593666cda4633241a61e65
parent2859eb74f9c87471b2429cd12b84144b97157efb (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.h107
-rw-r--r--src/core/SkWriter32.cpp142
-rw-r--r--tests/Writer32Test.cpp10
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