aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkWriter32.h22
-rw-r--r--src/core/SkWriter32.cpp101
-rw-r--r--tests/Writer32Test.cpp27
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"