1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2015 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRWBuffer.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkAtomics.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMalloc.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMakeUnique.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkStream.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <atomic>
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Force small chunks to be a page's worth
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const size_t kMinAllocSize = 4096;
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SkBufferBlock {
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBufferBlock*  fNext;      // updated by the writer
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t          fUsed;      // updated by the writer
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const size_t    fCapacity;
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBufferBlock(size_t capacity) : fNext(nullptr), fUsed(0), fCapacity(capacity) {}
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const void* startData() const { return this + 1; }
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t avail() const { return fCapacity - fUsed; }
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void* availData() { return (char*)this->startData() + fUsed; }
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static SkBufferBlock* Alloc(size_t length) {
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t capacity = LengthToCapacity(length);
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void* buffer = sk_malloc_throw(sizeof(SkBufferBlock) + capacity);
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return new (buffer) SkBufferBlock(capacity);
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Return number of bytes actually appended. Important that we always completely this block
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // before spilling into the next, since the reader uses fCapacity to know how many it can read.
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t append(const void* src, size_t length) {
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->validate();
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t amount = SkTMin(this->avail(), length);
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        memcpy(this->availData(), src, amount);
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fUsed += amount;
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->validate();
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return amount;
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Do not call in the reader thread, since the writer may be updating fUsed.
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // (The assertion is still true, but TSAN still may complain about its raciness.)
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void validate() const {
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fCapacity > 0);
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fUsed <= fCapacity);
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static size_t LengthToCapacity(size_t length) {
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const size_t minSize = kMinAllocSize - sizeof(SkBufferBlock);
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return SkTMax(length, minSize);
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SkBufferHead {
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    mutable std::atomic<int32_t> fRefCnt;
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBufferBlock   fBlock;
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBufferHead(size_t capacity) : fRefCnt(1), fBlock(capacity) {}
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static size_t LengthToCapacity(size_t length) {
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const size_t minSize = kMinAllocSize - sizeof(SkBufferHead);
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return SkTMax(length, minSize);
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static SkBufferHead* Alloc(size_t length) {
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t capacity = LengthToCapacity(length);
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t size = sizeof(SkBufferHead) + capacity;
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void* buffer = sk_malloc_throw(size);
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return new (buffer) SkBufferHead(capacity);
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void ref() const {
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkAssertResult(fRefCnt.fetch_add(+1, std::memory_order_relaxed));
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void unref() const {
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // A release here acts in place of all releases we "should" have been doing in ref().
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int32_t oldRefCnt = fRefCnt.fetch_add(-1, std::memory_order_acq_rel);
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(oldRefCnt);
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (1 == oldRefCnt) {
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Like unique(), the acquire is only needed on success.
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkBufferBlock* block = fBlock.fNext;
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            sk_free((void*)this);
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (block) {
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkBufferBlock* next = block->fNext;
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                sk_free(block);
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                block = next;
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void validate(size_t minUsed, const SkBufferBlock* tail = nullptr) const {
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fRefCnt.load(std::memory_order_relaxed) > 0);
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t totalUsed = 0;
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkBufferBlock* block = &fBlock;
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkBufferBlock* lastBlock = block;
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while (block) {
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            block->validate();
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            totalUsed += block->fUsed;
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            lastBlock = block;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            block = block->fNext;
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(minUsed <= totalUsed);
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (tail) {
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(tail == lastBlock);
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////////////////////////
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// The reader can only access block.fCapacity (which never changes), and cannot access
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// block.fUsed, which may be updated by the writer.
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkROBuffer::SkROBuffer(const SkBufferHead* head, size_t available, const SkBufferBlock* tail)
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : fHead(head), fAvailable(available), fTail(tail)
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot{
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (head) {
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fHead->ref();
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(available > 0);
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        head->validate(available, tail);
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(0 == available);
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!tail);
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkROBuffer::~SkROBuffer() {
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fHead) {
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fHead->unref();
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkROBuffer::Iter::Iter(const SkROBuffer* buffer) {
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->reset(buffer);
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkROBuffer::Iter::Iter(const sk_sp<SkROBuffer>& buffer) {
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->reset(buffer.get());
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkROBuffer::Iter::reset(const SkROBuffer* buffer) {
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBuffer = buffer;
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (buffer && buffer->fHead) {
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlock = &buffer->fHead->fBlock;
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRemaining = buffer->fAvailable;
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlock = nullptr;
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRemaining = 0;
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst void* SkROBuffer::Iter::data() const {
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fRemaining ? fBlock->startData() : nullptr;
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsize_t SkROBuffer::Iter::size() const {
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fBlock) {
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return 0;
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkTMin(fBlock->fCapacity, fRemaining);
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkROBuffer::Iter::next() {
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fRemaining) {
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRemaining -= this->size();
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fBuffer->fTail == fBlock) {
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // There are more blocks, but fBuffer does not know about them.
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(0 == fRemaining);
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlock = nullptr;
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlock = fBlock->fNext;
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fRemaining != 0;
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////////////////////////
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRWBuffer::SkRWBuffer(size_t initialCapacity) : fHead(nullptr), fTail(nullptr), fTotalUsed(0) {
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (initialCapacity) {
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fHead = SkBufferHead::Alloc(initialCapacity);
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTail = &fHead->fBlock;
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRWBuffer::~SkRWBuffer() {
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fHead) {
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fHead->unref();
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// It is important that we always completely fill the current block before spilling over to the
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// next, since our reader will be using fCapacity (min'd against its total available) to know how
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// many bytes to read from a given block.
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkRWBuffer::append(const void* src, size_t length, size_t reserve) {
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == length) {
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTotalUsed += length;
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (nullptr == fHead) {
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fHead = SkBufferHead::Alloc(length + reserve);
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTail = &fHead->fBlock;
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t written = fTail->append(src, length);
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(written <= length);
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src = (const char*)src + written;
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    length -= written;
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (length) {
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkBufferBlock* block = SkBufferBlock::Alloc(length + reserve);
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTail->fNext = block;
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTail = block;
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        written = fTail->append(src, length);
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(written == length);
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkRWBuffer::validate() const {
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fHead) {
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fHead->validate(fTotalUsed, fTail);
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(nullptr == fTail);
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(0 == fTotalUsed);
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////////////////////////
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkROBufferStreamAsset : public SkStreamAsset {
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void validate() const {
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fGlobalOffset <= fBuffer->size());
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fLocalOffset <= fIter.size());
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fLocalOffset <= fGlobalOffset);
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    class AutoValidate {
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkROBufferStreamAsset* fStream;
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    public:
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        AutoValidate(SkROBufferStreamAsset* stream) : fStream(stream) { stream->validate(); }
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ~AutoValidate() { fStream->validate(); }
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #define AUTO_VALIDATE   AutoValidate av(this);
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #define AUTO_VALIDATE
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkROBufferStreamAsset(sk_sp<SkROBuffer> buffer) : fBuffer(std::move(buffer)), fIter(fBuffer) {
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fGlobalOffset = fLocalOffset = 0;
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t getLength() const override { return fBuffer->size(); }
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool rewind() override {
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        AUTO_VALIDATE
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fIter.reset(fBuffer.get());
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fGlobalOffset = fLocalOffset = 0;
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t read(void* dst, size_t request) override {
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        AUTO_VALIDATE
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t bytesRead = 0;
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (;;) {
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            size_t size = fIter.size();
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(fLocalOffset <= size);
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            size_t avail = SkTMin(size - fLocalOffset, request - bytesRead);
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (dst) {
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                memcpy(dst, (const char*)fIter.data() + fLocalOffset, avail);
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst = (char*)dst + avail;
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bytesRead += avail;
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLocalOffset += avail;
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(bytesRead <= request);
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (bytesRead == request) {
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // If we get here, we've exhausted the current iter
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(fLocalOffset == size);
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLocalOffset = 0;
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!fIter.next()) {
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;   // ran out of data
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fGlobalOffset += bytesRead;
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fGlobalOffset <= fBuffer->size());
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return bytesRead;
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool isAtEnd() const override {
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fBuffer->size() == fGlobalOffset;
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t getPosition() const override {
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fGlobalOffset;
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool seek(size_t position) override {
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        AUTO_VALIDATE
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (position < fGlobalOffset) {
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->rewind();
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        (void)this->skip(position - fGlobalOffset);
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool move(long offset)  override{
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        AUTO_VALIDATE
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        offset += fGlobalOffset;
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (offset <= 0) {
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->rewind();
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            (void)this->seek(SkToSizeT(offset));
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkStreamAsset* onDuplicate() const override {
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return new SkROBufferStreamAsset(fBuffer);
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkStreamAsset* onFork() const override {
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        auto clone = this->duplicate();
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        clone->seek(this->getPosition());
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return clone.release();
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<SkROBuffer> fBuffer;
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkROBuffer::Iter  fIter;
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t            fLocalOffset;
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t            fGlobalOffset;
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstd::unique_ptr<SkStreamAsset> SkRWBuffer::makeStreamSnapshot() const {
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return skstd::make_unique<SkROBufferStreamAsset>(this->makeROBufferSnapshot());
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
364