Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/core/SkRWBuffer.cpp

Issue 1106113002: SkRWBuffer for thread-safe 'stream' sharing (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: add tests for stream Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
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
8 #include "SkData.h"
9 #include "SkRWBuffer.h"
10 #include "SkStream.h"
11
12 struct SkBufferBlock {
13 SkBufferBlock* fNext;
14 size_t fUsed;
15 size_t fCapacity;
16
17 const void* startData() const { return this + 1; };
18
19 static SkBufferBlock* Alloc(size_t length) {
20 size_t capacity = LengthToCapacity(length);
21 SkBufferBlock* block = (SkBufferBlock*)sk_malloc_throw(sizeof(SkBufferBl ock) + capacity);
22 block->fNext = NULL;
23 block->fUsed = 0;
24 block->fCapacity = capacity;
25 return block;
26 }
27
28 // Return number of bytes actually appended
29 size_t append(const void* src, size_t length) {
30 this->validate();
31 size_t avail = SkTMin(fCapacity - fUsed, length);
32 memcpy((char*)(this + 1) + fUsed, src, avail);
33 fUsed += avail;
34 this->validate();
35 return avail;
36 }
37
38 void validate() const {
39 #ifdef SK_DEBUG
40 SkASSERT(fCapacity > 0);
41 SkASSERT(fUsed <= fCapacity);
42 #endif
43 }
44
45 private:
46 static size_t LengthToCapacity(size_t length) {
47 const size_t minSize = 4096 - sizeof(SkBufferBlock);
48 return SkTMax(length, minSize);
49 }
50 };
51
52 struct SkBufferHead {
53 mutable int32_t fRefCnt;
54 SkBufferBlock fBlock;
55
56 static size_t LengthToCapacity(size_t length) {
57 const size_t minSize = 4096 - sizeof(SkBufferHead);
58 return SkTMax(length, minSize);
59 }
60
61 static SkBufferHead* Alloc(size_t length) {
62 size_t capacity = LengthToCapacity(length);
63 size_t size = sizeof(SkBufferHead) + capacity;
64 SkBufferHead* head = (SkBufferHead*)sk_malloc_throw(size);
65 head->fRefCnt = 1;
66 head->fBlock.fNext = NULL;
67 head->fBlock.fUsed = 0;
68 head->fBlock.fCapacity = capacity;
69 return head;
70 }
71
72 void ref() const {
73 SkASSERT(fRefCnt > 0);
74 sk_atomic_inc(&fRefCnt);
75 }
76
77 void unref() const {
78 SkASSERT(fRefCnt > 0);
79 // A release here acts in place of all releases we "should" have been do ing in ref().
80 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
81 // Like unique(), the acquire is only needed on success.
82 SkBufferBlock* block = fBlock.fNext;
83 sk_free((void*)this);
84 while (block) {
85 SkBufferBlock* next = block->fNext;
86 sk_free(block);
87 block = next;
88 }
89 SkDebugf("done\n");
90 }
91 }
92
93 void validate(size_t minUsed, SkBufferBlock* tail = NULL) const {
94 #ifdef SK_DEBUG
95 SkASSERT(fRefCnt > 0);
96 size_t totalUsed = 0;
97 const SkBufferBlock* block = &fBlock;
98 const SkBufferBlock* lastBlock = block;
99 while (block) {
100 block->validate();
101 totalUsed += block->fUsed;
102 lastBlock = block;
103 block = block->fNext;
104 }
105 SkASSERT(minUsed <= totalUsed);
106 if (tail) {
107 SkASSERT(tail == lastBlock);
108 }
109 #endif
110 }
111 };
112
113 SkRBuffer::SkRBuffer(const SkBufferHead* head, size_t used) : fHead(SkRef(head)) , fUsed(used) {
114 if (head) {
115 SkASSERT(used > 0);
116 head->validate(used);
117 } else {
118 SkASSERT(0 == used);
119 }
120 }
121
122 SkRBuffer::~SkRBuffer() {
123 if (fHead) {
124 fHead->validate(fUsed);
125 fHead->unref();
126 }
127 }
128
129 SkRBuffer::Iter::Iter(const SkRBuffer* buffer) {
130 this->reset(buffer);
131 }
132
133 void SkRBuffer::Iter::reset(const SkRBuffer* buffer) {
134 if (buffer) {
135 fBlock = &buffer->fHead->fBlock;
136 fRemaining = buffer->fUsed;
137 } else {
138 fBlock = NULL;
139 fRemaining = 0;
140 }
141 }
142
143 const void* SkRBuffer::Iter::data() const {
144 return fRemaining ? fBlock->startData() : NULL;
145 }
146
147 size_t SkRBuffer::Iter::size() const {
148 return SkTMin(fBlock->fUsed, fRemaining);
149 }
150
151 bool SkRBuffer::Iter::next() {
152 if (fRemaining) {
153 fRemaining -= this->size();
154 fBlock = fBlock->fNext;
155 }
156 return fRemaining != 0;
157 }
158
159 SkRWBuffer::SkRWBuffer(size_t initialCapacity) : fHead(NULL), fTail(NULL), fTota lUsed(0) {}
160
161 SkRWBuffer::~SkRWBuffer() {
162 this->validate();
163 fHead->unref();
164 }
165
166 void SkRWBuffer::append(const void* src, size_t length) {
167 this->validate();
168 if (0 == length) {
169 return;
170 }
171
172 fTotalUsed += length;
173
174 if (NULL == fHead) {
175 fHead = SkBufferHead::Alloc(length);
176 fTail = &fHead->fBlock;
177 }
178
179 size_t written = fTail->append(src, length);
180 SkASSERT(written <= length);
181 src = (const char*)src + written;
182 length -= written;
183
184 if (length) {
185 SkBufferBlock* block = SkBufferBlock::Alloc(length);
186 fTail->fNext = block;
187 fTail = block;
188 written = fTail->append(src, length);
189 SkASSERT(written == length);
190 }
191 this->validate();
192 }
193
194 #ifdef SK_DEBUG
195 void SkRWBuffer::validate() const {
196 if (fHead) {
197 fHead->validate(fTotalUsed, fTail);
198 } else {
199 SkASSERT(NULL == fTail);
200 SkASSERT(0 == fTotalUsed);
201 }
202 }
203 #endif
204
205 SkRBuffer* SkRWBuffer::newRBufferSnapshot() const {
206 return SkNEW_ARGS(SkRBuffer, (fHead, fTotalUsed));
207 }
208
209 SkData* SkRWBuffer::newDataSnapshot() const {
210 SkData* data = SkData::NewUninitialized(fTotalUsed);
211
212 const SkBufferBlock* block = &fHead->fBlock;
213 char* dst = (char*)data->writable_data();
214 while (block) {
215 memcpy(dst, block->startData(), block->fUsed);
216 dst += block->fUsed;
217 block = block->fNext;
218 }
219 return data;
220 }
221
222 //////////////////////////////////////////////////////////////////////////////// ///////////////////
223
224 class SkRBufferStreamAsset : public SkStreamAsset {
bungeman-skia 2015/04/27 14:52:42 You may want to take a look at SkBlockMemoryStream
reed2 2015/04/28 02:25:00 Acknowledged.
225 void validate() const {
226 #ifdef SK_DEBUG
227 SkASSERT(fGlobalOffset <= fBuffer->size());
228 SkASSERT(fLocalOffset <= fIter.size());
229 SkASSERT(fLocalOffset <= fGlobalOffset);
230 #endif
231 }
232
233 class AutoValidate {
234 SkRBufferStreamAsset* fStream;
235 public:
236 AutoValidate(SkRBufferStreamAsset* stream) : fStream(stream) { stream->v alidate(); }
237 ~AutoValidate() { fStream->validate(); }
238 };
239
240 #ifdef SK_DEBUG
241 #define AUTO_VALIDATE AutoValidate av(this);
242 #else
243 #define AUTO_VALIDATE
244 #endif
245
246 public:
247 SkRBufferStreamAsset(const SkRBuffer* buffer) : fBuffer(SkRef(buffer)), fIte r(buffer) {
248 fGlobalOffset = fLocalOffset = 0;
249 }
250
251 virtual ~SkRBufferStreamAsset() { fBuffer->unref(); }
252
253 size_t getLength() const override { return fBuffer->size(); }
254
255 bool rewind() override {
256 AUTO_VALIDATE
257 fIter.reset(fBuffer);
258 fGlobalOffset = fLocalOffset = 0;
259 return true;
260 }
261
262 size_t read(void* dst, size_t request) override {
263 AUTO_VALIDATE
264 size_t bytesRead = 0;
265 for (;;) {
266 size_t size = fIter.size();
267 SkASSERT(fLocalOffset <= size);
268 size_t avail = SkTMin(size - fLocalOffset, request - bytesRead);
269 if (dst) {
270 memcpy(dst, (const char*)fIter.data() + fLocalOffset, avail);
271 dst = (char*)dst + avail;
272 }
273 bytesRead += avail;
274 fLocalOffset += avail;
275 SkASSERT(bytesRead <= request);
276 if (bytesRead == request) {
277 break;
278 }
279 // If we get here, we've exhausted the current iter
280 SkASSERT(fLocalOffset == size);
281 fLocalOffset = 0;
282 if (!fIter.next()) {
283 break; // ran out of data
284 }
285 }
286 fGlobalOffset += bytesRead;
287 SkASSERT(fGlobalOffset <= fBuffer->size());
288 return bytesRead;
289 }
290
291 bool isAtEnd() const override {
292 return fBuffer->size() == fGlobalOffset;
293 }
294
295 SkStreamAsset* duplicate() const override {
296 return SkNEW_ARGS(SkRBufferStreamAsset, (fBuffer));
297 }
298
299 size_t getPosition() const {
300 return fGlobalOffset;
301 }
302
303 bool seek(size_t position) {
304 AUTO_VALIDATE
305 if (position < fGlobalOffset) {
306 this->rewind();
307 }
308 (void)this->skip(position - fGlobalOffset);
309 return true;
310 }
311
312 bool move(long offset) {
313 AUTO_VALIDATE
314 offset += fGlobalOffset;
315 if (offset <= 0) {
316 this->rewind();
317 } else {
318 (void)this->seek(SkToSizeT(offset));
319 }
320 return true;
321 }
322
323 SkStreamAsset* fork() const override {
324 SkStreamAsset* clone = this->duplicate();
325 clone->seek(this->getPosition());
326 return clone;
327 }
328
329
330 private:
331 const SkRBuffer* fBuffer;
332 SkRBuffer::Iter fIter;
333 size_t fLocalOffset;
334 size_t fGlobalOffset;
335 };
336
337 SkStreamAsset* SkRWBuffer::newStreamSnapshot() const {
338 SkAutoTUnref<SkRBuffer> buffer(this->newRBufferSnapshot());
339 return SkNEW_ARGS(SkRBufferStreamAsset, (buffer));
340 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698