blob: e69070b5f908db75a1f6a61b70f99429805702dc [file] [log] [blame]
reed5b6db072015-04-28 17:50:31 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
bungeman2c4bd072016-04-08 06:58:51 -07008#include "SkAtomics.h"
reed5b6db072015-04-28 17:50:31 -07009#include "SkRWBuffer.h"
10#include "SkStream.h"
11
12// Force small chunks to be a page's worth
13static const size_t kMinAllocSize = 4096;
14
15struct SkBufferBlock {
reed377add72016-04-08 12:47:14 -070016 SkBufferBlock* fNext; // updated by the writer
17 size_t fUsed; // updated by the writer
18 const size_t fCapacity;
19
20 SkBufferBlock(size_t capacity) : fNext(nullptr), fUsed(0), fCapacity(capacity) {}
mtkleinf0599002015-07-13 06:18:39 -070021
Mike Kleinfc6c37b2016-09-27 09:34:10 -040022 const void* startData() const { return this + 1; }
mtkleinf0599002015-07-13 06:18:39 -070023
reed5b6db072015-04-28 17:50:31 -070024 size_t avail() const { return fCapacity - fUsed; }
25 void* availData() { return (char*)this->startData() + fUsed; }
mtkleinf0599002015-07-13 06:18:39 -070026
reed5b6db072015-04-28 17:50:31 -070027 static SkBufferBlock* Alloc(size_t length) {
28 size_t capacity = LengthToCapacity(length);
reed377add72016-04-08 12:47:14 -070029 void* buffer = sk_malloc_throw(sizeof(SkBufferBlock) + capacity);
30 return new (buffer) SkBufferBlock(capacity);
reed5b6db072015-04-28 17:50:31 -070031 }
32
reed377add72016-04-08 12:47:14 -070033 // Return number of bytes actually appended. Important that we always completely this block
34 // before spilling into the next, since the reader uses fCapacity to know how many it can read.
35 //
reed5b6db072015-04-28 17:50:31 -070036 size_t append(const void* src, size_t length) {
37 this->validate();
38 size_t amount = SkTMin(this->avail(), length);
39 memcpy(this->availData(), src, amount);
40 fUsed += amount;
41 this->validate();
42 return amount;
43 }
44
scroggo63516402016-04-22 06:59:01 -070045 // Do not call in the reader thread, since the writer may be updating fUsed.
46 // (The assertion is still true, but TSAN still may complain about its raciness.)
reed5b6db072015-04-28 17:50:31 -070047 void validate() const {
48#ifdef SK_DEBUG
49 SkASSERT(fCapacity > 0);
50 SkASSERT(fUsed <= fCapacity);
51#endif
52 }
53
54private:
55 static size_t LengthToCapacity(size_t length) {
56 const size_t minSize = kMinAllocSize - sizeof(SkBufferBlock);
57 return SkTMax(length, minSize);
58 }
59};
60
61struct SkBufferHead {
62 mutable int32_t fRefCnt;
63 SkBufferBlock fBlock;
64
reed377add72016-04-08 12:47:14 -070065 SkBufferHead(size_t capacity) : fRefCnt(1), fBlock(capacity) {}
66
reed5b6db072015-04-28 17:50:31 -070067 static size_t LengthToCapacity(size_t length) {
68 const size_t minSize = kMinAllocSize - sizeof(SkBufferHead);
69 return SkTMax(length, minSize);
70 }
71
72 static SkBufferHead* Alloc(size_t length) {
73 size_t capacity = LengthToCapacity(length);
74 size_t size = sizeof(SkBufferHead) + capacity;
reed377add72016-04-08 12:47:14 -070075 void* buffer = sk_malloc_throw(size);
76 return new (buffer) SkBufferHead(capacity);
reed5b6db072015-04-28 17:50:31 -070077 }
mtkleinf0599002015-07-13 06:18:39 -070078
reed5b6db072015-04-28 17:50:31 -070079 void ref() const {
80 SkASSERT(fRefCnt > 0);
81 sk_atomic_inc(&fRefCnt);
82 }
mtkleinf0599002015-07-13 06:18:39 -070083
reed5b6db072015-04-28 17:50:31 -070084 void unref() const {
85 SkASSERT(fRefCnt > 0);
86 // A release here acts in place of all releases we "should" have been doing in ref().
87 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
88 // Like unique(), the acquire is only needed on success.
89 SkBufferBlock* block = fBlock.fNext;
90 sk_free((void*)this);
91 while (block) {
92 SkBufferBlock* next = block->fNext;
93 sk_free(block);
94 block = next;
95 }
96 }
97 }
mtkleinf0599002015-07-13 06:18:39 -070098
scroggo63516402016-04-22 06:59:01 -070099 void validate(size_t minUsed, const SkBufferBlock* tail = nullptr) const {
reed5b6db072015-04-28 17:50:31 -0700100#ifdef SK_DEBUG
101 SkASSERT(fRefCnt > 0);
102 size_t totalUsed = 0;
103 const SkBufferBlock* block = &fBlock;
104 const SkBufferBlock* lastBlock = block;
105 while (block) {
106 block->validate();
107 totalUsed += block->fUsed;
108 lastBlock = block;
109 block = block->fNext;
110 }
111 SkASSERT(minUsed <= totalUsed);
112 if (tail) {
113 SkASSERT(tail == lastBlock);
114 }
115#endif
116 }
117};
118
reed377add72016-04-08 12:47:14 -0700119///////////////////////////////////////////////////////////////////////////////////////////////////
120// The reader can only access block.fCapacity (which never changes), and cannot access
121// block.fUsed, which may be updated by the writer.
122//
scroggo63516402016-04-22 06:59:01 -0700123SkROBuffer::SkROBuffer(const SkBufferHead* head, size_t available, const SkBufferBlock* tail)
124 : fHead(head), fAvailable(available), fTail(tail)
reed377add72016-04-08 12:47:14 -0700125{
reed5b6db072015-04-28 17:50:31 -0700126 if (head) {
127 fHead->ref();
reed377add72016-04-08 12:47:14 -0700128 SkASSERT(available > 0);
scroggo63516402016-04-22 06:59:01 -0700129 head->validate(available, tail);
reed5b6db072015-04-28 17:50:31 -0700130 } else {
reed377add72016-04-08 12:47:14 -0700131 SkASSERT(0 == available);
scroggo63516402016-04-22 06:59:01 -0700132 SkASSERT(!tail);
reed5b6db072015-04-28 17:50:31 -0700133 }
134}
135
136SkROBuffer::~SkROBuffer() {
137 if (fHead) {
reed5b6db072015-04-28 17:50:31 -0700138 fHead->unref();
139 }
140}
141
142SkROBuffer::Iter::Iter(const SkROBuffer* buffer) {
143 this->reset(buffer);
144}
145
146void SkROBuffer::Iter::reset(const SkROBuffer* buffer) {
scroggo63516402016-04-22 06:59:01 -0700147 fBuffer = buffer;
148 if (buffer && buffer->fHead) {
reed5b6db072015-04-28 17:50:31 -0700149 fBlock = &buffer->fHead->fBlock;
reed377add72016-04-08 12:47:14 -0700150 fRemaining = buffer->fAvailable;
reed5b6db072015-04-28 17:50:31 -0700151 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700152 fBlock = nullptr;
reed5b6db072015-04-28 17:50:31 -0700153 fRemaining = 0;
154 }
155}
156
157const void* SkROBuffer::Iter::data() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700158 return fRemaining ? fBlock->startData() : nullptr;
reed5b6db072015-04-28 17:50:31 -0700159}
160
161size_t SkROBuffer::Iter::size() const {
scroggob512aaa2016-01-11 06:38:00 -0800162 if (!fBlock) {
163 return 0;
164 }
reed377add72016-04-08 12:47:14 -0700165 return SkTMin(fBlock->fCapacity, fRemaining);
reed5b6db072015-04-28 17:50:31 -0700166}
167
168bool SkROBuffer::Iter::next() {
169 if (fRemaining) {
170 fRemaining -= this->size();
scroggo63516402016-04-22 06:59:01 -0700171 if (fBuffer->fTail == fBlock) {
172 // There are more blocks, but fBuffer does not know about them.
173 SkASSERT(0 == fRemaining);
174 fBlock = nullptr;
175 } else {
176 fBlock = fBlock->fNext;
177 }
reed5b6db072015-04-28 17:50:31 -0700178 }
179 return fRemaining != 0;
180}
181
reed377add72016-04-08 12:47:14 -0700182///////////////////////////////////////////////////////////////////////////////////////////////////
183
fmalita2e36e882016-09-30 10:52:08 -0700184SkRWBuffer::SkRWBuffer(size_t initialCapacity) : fHead(nullptr), fTail(nullptr), fTotalUsed(0) {
185 if (initialCapacity) {
186 fHead = SkBufferHead::Alloc(initialCapacity);
187 fTail = &fHead->fBlock;
188 }
189}
reed5b6db072015-04-28 17:50:31 -0700190
191SkRWBuffer::~SkRWBuffer() {
192 this->validate();
scroggo9dec5d22016-02-16 06:59:18 -0800193 if (fHead) {
194 fHead->unref();
195 }
reed5b6db072015-04-28 17:50:31 -0700196}
197
reed377add72016-04-08 12:47:14 -0700198// It is important that we always completely fill the current block before spilling over to the
199// next, since our reader will be using fCapacity (min'd against its total available) to know how
200// many bytes to read from a given block.
201//
fmalita57765082016-09-30 13:34:19 -0700202void SkRWBuffer::append(const void* src, size_t length, size_t reserve) {
reed5b6db072015-04-28 17:50:31 -0700203 this->validate();
204 if (0 == length) {
205 return;
206 }
207
208 fTotalUsed += length;
209
halcanary96fcdcc2015-08-27 07:41:13 -0700210 if (nullptr == fHead) {
fmalita57765082016-09-30 13:34:19 -0700211 fHead = SkBufferHead::Alloc(length + reserve);
reed5b6db072015-04-28 17:50:31 -0700212 fTail = &fHead->fBlock;
213 }
214
215 size_t written = fTail->append(src, length);
216 SkASSERT(written <= length);
217 src = (const char*)src + written;
218 length -= written;
219
220 if (length) {
fmalita57765082016-09-30 13:34:19 -0700221 SkBufferBlock* block = SkBufferBlock::Alloc(length + reserve);
reed5b6db072015-04-28 17:50:31 -0700222 fTail->fNext = block;
223 fTail = block;
224 written = fTail->append(src, length);
225 SkASSERT(written == length);
226 }
227 this->validate();
228}
229
reed5b6db072015-04-28 17:50:31 -0700230#ifdef SK_DEBUG
231void SkRWBuffer::validate() const {
232 if (fHead) {
233 fHead->validate(fTotalUsed, fTail);
234 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700235 SkASSERT(nullptr == fTail);
reed5b6db072015-04-28 17:50:31 -0700236 SkASSERT(0 == fTotalUsed);
237 }
238}
239#endif
240
scroggo63516402016-04-22 06:59:01 -0700241SkROBuffer* SkRWBuffer::newRBufferSnapshot() const {
242 return new SkROBuffer(fHead, fTotalUsed, fTail);
243}
reed5b6db072015-04-28 17:50:31 -0700244
245///////////////////////////////////////////////////////////////////////////////////////////////////
246
247class SkROBufferStreamAsset : public SkStreamAsset {
248 void validate() const {
249#ifdef SK_DEBUG
250 SkASSERT(fGlobalOffset <= fBuffer->size());
251 SkASSERT(fLocalOffset <= fIter.size());
252 SkASSERT(fLocalOffset <= fGlobalOffset);
253#endif
254 }
255
256#ifdef SK_DEBUG
257 class AutoValidate {
258 SkROBufferStreamAsset* fStream;
259 public:
260 AutoValidate(SkROBufferStreamAsset* stream) : fStream(stream) { stream->validate(); }
261 ~AutoValidate() { fStream->validate(); }
262 };
263 #define AUTO_VALIDATE AutoValidate av(this);
264#else
265 #define AUTO_VALIDATE
266#endif
267
268public:
269 SkROBufferStreamAsset(const SkROBuffer* buffer) : fBuffer(SkRef(buffer)), fIter(buffer) {
270 fGlobalOffset = fLocalOffset = 0;
271 }
272
273 virtual ~SkROBufferStreamAsset() { fBuffer->unref(); }
274
275 size_t getLength() const override { return fBuffer->size(); }
276
277 bool rewind() override {
278 AUTO_VALIDATE
279 fIter.reset(fBuffer);
280 fGlobalOffset = fLocalOffset = 0;
281 return true;
282 }
283
284 size_t read(void* dst, size_t request) override {
285 AUTO_VALIDATE
286 size_t bytesRead = 0;
287 for (;;) {
288 size_t size = fIter.size();
289 SkASSERT(fLocalOffset <= size);
290 size_t avail = SkTMin(size - fLocalOffset, request - bytesRead);
291 if (dst) {
292 memcpy(dst, (const char*)fIter.data() + fLocalOffset, avail);
293 dst = (char*)dst + avail;
294 }
295 bytesRead += avail;
296 fLocalOffset += avail;
297 SkASSERT(bytesRead <= request);
298 if (bytesRead == request) {
299 break;
300 }
301 // If we get here, we've exhausted the current iter
302 SkASSERT(fLocalOffset == size);
303 fLocalOffset = 0;
304 if (!fIter.next()) {
305 break; // ran out of data
306 }
307 }
308 fGlobalOffset += bytesRead;
309 SkASSERT(fGlobalOffset <= fBuffer->size());
310 return bytesRead;
311 }
312
313 bool isAtEnd() const override {
314 return fBuffer->size() == fGlobalOffset;
315 }
mtkleinf0599002015-07-13 06:18:39 -0700316
halcanary385fe4d2015-08-26 13:07:48 -0700317 SkStreamAsset* duplicate() const override { return new SkROBufferStreamAsset(fBuffer); }
mtkleinf0599002015-07-13 06:18:39 -0700318
319 size_t getPosition() const override {
reed5b6db072015-04-28 17:50:31 -0700320 return fGlobalOffset;
321 }
mtkleinf0599002015-07-13 06:18:39 -0700322
323 bool seek(size_t position) override {
reed5b6db072015-04-28 17:50:31 -0700324 AUTO_VALIDATE
325 if (position < fGlobalOffset) {
326 this->rewind();
327 }
328 (void)this->skip(position - fGlobalOffset);
329 return true;
330 }
mtkleinf0599002015-07-13 06:18:39 -0700331
332 bool move(long offset) override{
reed5b6db072015-04-28 17:50:31 -0700333 AUTO_VALIDATE
334 offset += fGlobalOffset;
335 if (offset <= 0) {
336 this->rewind();
337 } else {
338 (void)this->seek(SkToSizeT(offset));
339 }
340 return true;
341 }
mtkleinf0599002015-07-13 06:18:39 -0700342
reed5b6db072015-04-28 17:50:31 -0700343 SkStreamAsset* fork() const override {
344 SkStreamAsset* clone = this->duplicate();
345 clone->seek(this->getPosition());
346 return clone;
347 }
mtkleinf0599002015-07-13 06:18:39 -0700348
reed5b6db072015-04-28 17:50:31 -0700349
350private:
351 const SkROBuffer* fBuffer;
352 SkROBuffer::Iter fIter;
353 size_t fLocalOffset;
354 size_t fGlobalOffset;
355};
356
357SkStreamAsset* SkRWBuffer::newStreamSnapshot() const {
358 SkAutoTUnref<SkROBuffer> buffer(this->newRBufferSnapshot());
halcanary385fe4d2015-08-26 13:07:48 -0700359 return new SkROBufferStreamAsset(buffer);
reed5b6db072015-04-28 17:50:31 -0700360}