| Index: src/core/SkRWBuffer.cpp
|
| diff --git a/src/core/SkRWBuffer.cpp b/src/core/SkRWBuffer.cpp
|
| index c0a93bdf53c037ce768a0699983f1d7cf1ce30d5..c7f39e292455a7ddc79f3ae7203e06fa69f42757 100644
|
| --- a/src/core/SkRWBuffer.cpp
|
| +++ b/src/core/SkRWBuffer.cpp
|
| @@ -12,9 +12,11 @@
|
| static const size_t kMinAllocSize = 4096;
|
|
|
| struct SkBufferBlock {
|
| - SkBufferBlock* fNext;
|
| - size_t fUsed;
|
| - size_t fCapacity;
|
| + SkBufferBlock* fNext; // updated by the writer
|
| + size_t fUsed; // updated by the writer
|
| + const size_t fCapacity;
|
| +
|
| + SkBufferBlock(size_t capacity) : fNext(nullptr), fUsed(0), fCapacity(capacity) {}
|
|
|
| const void* startData() const { return this + 1; };
|
|
|
| @@ -23,14 +25,13 @@ struct SkBufferBlock {
|
|
|
| static SkBufferBlock* Alloc(size_t length) {
|
| size_t capacity = LengthToCapacity(length);
|
| - SkBufferBlock* block = (SkBufferBlock*)sk_malloc_throw(sizeof(SkBufferBlock) + capacity);
|
| - block->fNext = nullptr;
|
| - block->fUsed = 0;
|
| - block->fCapacity = capacity;
|
| - return block;
|
| + void* buffer = sk_malloc_throw(sizeof(SkBufferBlock) + capacity);
|
| + return new (buffer) SkBufferBlock(capacity);
|
| }
|
|
|
| - // Return number of bytes actually appended
|
| + // Return number of bytes actually appended. Important that we always completely this block
|
| + // before spilling into the next, since the reader uses fCapacity to know how many it can read.
|
| + //
|
| size_t append(const void* src, size_t length) {
|
| this->validate();
|
| size_t amount = SkTMin(this->avail(), length);
|
| @@ -58,6 +59,8 @@ struct SkBufferHead {
|
| mutable int32_t fRefCnt;
|
| SkBufferBlock fBlock;
|
|
|
| + SkBufferHead(size_t capacity) : fRefCnt(1), fBlock(capacity) {}
|
| +
|
| static size_t LengthToCapacity(size_t length) {
|
| const size_t minSize = kMinAllocSize - sizeof(SkBufferHead);
|
| return SkTMax(length, minSize);
|
| @@ -66,12 +69,8 @@ struct SkBufferHead {
|
| static SkBufferHead* Alloc(size_t length) {
|
| size_t capacity = LengthToCapacity(length);
|
| size_t size = sizeof(SkBufferHead) + capacity;
|
| - SkBufferHead* head = (SkBufferHead*)sk_malloc_throw(size);
|
| - head->fRefCnt = 1;
|
| - head->fBlock.fNext = nullptr;
|
| - head->fBlock.fUsed = 0;
|
| - head->fBlock.fCapacity = capacity;
|
| - return head;
|
| + void* buffer = sk_malloc_throw(size);
|
| + return new (buffer) SkBufferHead(capacity);
|
| }
|
|
|
| void ref() const {
|
| @@ -114,19 +113,25 @@ struct SkBufferHead {
|
| }
|
| };
|
|
|
| -SkROBuffer::SkROBuffer(const SkBufferHead* head, size_t used) : fHead(head), fUsed(used) {
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +// The reader can only access block.fCapacity (which never changes), and cannot access
|
| +// block.fUsed, which may be updated by the writer.
|
| +//
|
| +SkROBuffer::SkROBuffer(const SkBufferHead* head, size_t available)
|
| + : fHead(head), fAvailable(available)
|
| +{
|
| if (head) {
|
| fHead->ref();
|
| - SkASSERT(used > 0);
|
| - head->validate(used);
|
| + SkASSERT(available > 0);
|
| + head->validate(available);
|
| } else {
|
| - SkASSERT(0 == used);
|
| + SkASSERT(0 == available);
|
| }
|
| }
|
|
|
| SkROBuffer::~SkROBuffer() {
|
| if (fHead) {
|
| - fHead->validate(fUsed);
|
| + fHead->validate(fAvailable);
|
| fHead->unref();
|
| }
|
| }
|
| @@ -138,7 +143,7 @@ SkROBuffer::Iter::Iter(const SkROBuffer* buffer) {
|
| void SkROBuffer::Iter::reset(const SkROBuffer* buffer) {
|
| if (buffer) {
|
| fBlock = &buffer->fHead->fBlock;
|
| - fRemaining = buffer->fUsed;
|
| + fRemaining = buffer->fAvailable;
|
| } else {
|
| fBlock = nullptr;
|
| fRemaining = 0;
|
| @@ -153,7 +158,7 @@ size_t SkROBuffer::Iter::size() const {
|
| if (!fBlock) {
|
| return 0;
|
| }
|
| - return SkTMin(fBlock->fUsed, fRemaining);
|
| + return SkTMin(fBlock->fCapacity, fRemaining);
|
| }
|
|
|
| bool SkROBuffer::Iter::next() {
|
| @@ -164,6 +169,8 @@ bool SkROBuffer::Iter::next() {
|
| return fRemaining != 0;
|
| }
|
|
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +
|
| SkRWBuffer::SkRWBuffer(size_t initialCapacity) : fHead(nullptr), fTail(nullptr), fTotalUsed(0) {}
|
|
|
| SkRWBuffer::~SkRWBuffer() {
|
| @@ -173,6 +180,10 @@ SkRWBuffer::~SkRWBuffer() {
|
| }
|
| }
|
|
|
| +// It is important that we always completely fill the current block before spilling over to the
|
| +// next, since our reader will be using fCapacity (min'd against its total available) to know how
|
| +// many bytes to read from a given block.
|
| +//
|
| void SkRWBuffer::append(const void* src, size_t length) {
|
| this->validate();
|
| if (0 == length) {
|
| @@ -201,28 +212,6 @@ void SkRWBuffer::append(const void* src, size_t length) {
|
| this->validate();
|
| }
|
|
|
| -void* SkRWBuffer::append(size_t length) {
|
| - this->validate();
|
| - if (0 == length) {
|
| - return nullptr;
|
| - }
|
| -
|
| - fTotalUsed += length;
|
| -
|
| - if (nullptr == fHead) {
|
| - fHead = SkBufferHead::Alloc(length);
|
| - fTail = &fHead->fBlock;
|
| - } else if (fTail->avail() < length) {
|
| - SkBufferBlock* block = SkBufferBlock::Alloc(length);
|
| - fTail->fNext = block;
|
| - fTail = block;
|
| - }
|
| -
|
| - fTail->fUsed += length;
|
| - this->validate();
|
| - return (char*)fTail->availData() - length;
|
| -}
|
| -
|
| #ifdef SK_DEBUG
|
| void SkRWBuffer::validate() const {
|
| if (fHead) {
|
|
|