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

Side by Side Diff: include/core/SkWriter32.h

Issue 137433003: Convert SkWriter32 to use an SkTDArray for its internal storage. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: of course 0's fine too... Created 6 years, 11 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
« no previous file with comments | « bench/WriterBench.cpp ('k') | src/core/SkFlattenableSerialization.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2008 The Android Open Source Project 3 * Copyright 2008 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #ifndef SkWriter32_DEFINED 10 #ifndef SkWriter32_DEFINED
11 #define SkWriter32_DEFINED 11 #define SkWriter32_DEFINED
12 12
13 #include "SkMatrix.h"
14 #include "SkPath.h"
15 #include "SkPoint.h"
16 #include "SkRRect.h"
17 #include "SkRect.h"
18 #include "SkRegion.h"
19 #include "SkScalar.h"
20 #include "SkStream.h"
21 #include "SkTDArray.h"
13 #include "SkTypes.h" 22 #include "SkTypes.h"
14 23
15 #include "SkScalar.h"
16 #include "SkPath.h"
17 #include "SkPoint.h"
18 #include "SkRect.h"
19 #include "SkRRect.h"
20 #include "SkMatrix.h"
21 #include "SkRegion.h"
22
23 class SkStream;
24 class SkWStream;
25
26 class SkWriter32 : SkNoncopyable { 24 class SkWriter32 : SkNoncopyable {
27 struct BlockHeader;
28 public: 25 public:
29 /** 26 /**
30 * The caller can specify an initial block of storage, which the caller man ages. 27 * The caller can specify an initial block of storage, which the caller man ages.
31 * SkWriter32 will not attempt to free this in its destructor. It is up to the 28 *
32 * implementation to decide if, and how much, of the storage to utilize, an d it 29 * SkWriter32 will try to back reserve and write calls with this external s torage until the
33 * is possible that it may be ignored entirely. 30 * first time an allocation doesn't fit. From then it will use dynamically allocated storage.
31 * This used to be optional behavior, but pipe now relies on it.
34 */ 32 */
35 SkWriter32(size_t minSize, void* initialStorage, size_t storageSize); 33 SkWriter32(void* external = NULL, size_t externalBytes = 0) {
36 34 this->reset(external, externalBytes);
37 SkWriter32(size_t minSize) 35 }
38 : fHead(NULL)
39 , fTail(NULL)
40 , fMinSize(minSize)
41 , fSize(0)
42 , fWrittenBeforeLastBlock(0)
43 {}
44
45 ~SkWriter32();
46 36
47 // return the current offset (will always be a multiple of 4) 37 // return the current offset (will always be a multiple of 4)
48 size_t bytesWritten() const { return fSize; } 38 size_t bytesWritten() const { return fCount * 4; }
49 39
50 SK_ATTR_DEPRECATED("use bytesWritten") 40 SK_ATTR_DEPRECATED("use bytesWritten")
51 size_t size() const { return this->bytesWritten(); } 41 size_t size() const { return this->bytesWritten(); }
52 42
53 // Returns true if we've written only into the storage passed into construct or or reset. 43 void reset(void* external = NULL, size_t externalBytes = 0) {
54 // (You may be able to use this to avoid a call to flatten.) 44 SkASSERT(SkIsAlign4((uintptr_t)external));
55 bool wroteOnlyToStorage() const { 45 SkASSERT(SkIsAlign4(externalBytes));
56 return fHead == &fExternalBlock && this->bytesWritten() <= fExternalBloc k.fSizeOfBlock; 46 fExternal = (uint32_t*)external;
47 fExternalLimit = externalBytes/4;
48 fCount = 0;
49 fInternal.rewind();
57 } 50 }
58 51
59 void reset(); 52 // If all data written is contiguous, then this returns a pointer to it, oth erwise NULL.
60 void reset(void* storage, size_t size); 53 // This will work if we've only written to the externally supplied block of storage, or if we've
54 // only written to our internal dynamic storage, but will fail if we have wr itten into both.
55 const uint32_t* contiguousArray() const {
56 if (this->externalCount() == 0) {
57 return fInternal.begin();
58 } else if (fInternal.isEmpty()) {
59 return fExternal;
60 }
61 return NULL;
62 }
61 63
62 // size MUST be multiple of 4 64 // size MUST be multiple of 4
63 uint32_t* reserve(size_t size) { 65 uint32_t* reserve(size_t size) {
64 SkASSERT(SkAlign4(size) == size); 66 SkASSERT(SkAlign4(size) == size);
67 const int count = size/4;
65 68
66 Block* block = fTail; 69 uint32_t* p;
67 if (NULL == block || block->available() < size) { 70 // Once we start writing to fInternal, we never write to fExternal again .
68 block = this->doReserve(size); 71 // This simplifies tracking what data is where.
72 if (fInternal.isEmpty() && this->externalCount() + count <= fExternalLim it) {
73 p = fExternal + fCount;
74 } else {
75 p = fInternal.append(count);
69 } 76 }
70 fSize += size; 77
71 return block->alloc(size); 78 fCount += count;
79 return p;
80 }
81
82 // return the address of the 4byte int at the specified offset (which must
83 // be a multiple of 4. This does not allocate any new space, so the returned
84 // address is only valid for 1 int.
85 uint32_t* peek32(size_t offset) {
86 SkASSERT(SkAlign4(offset) == offset);
87 const int count = offset/4;
88 SkASSERT(count < fCount);
89
90 if (count < this->externalCount()) {
91 return fExternal + count;
92 }
93 return &fInternal[count - this->externalCount()];
72 } 94 }
73 95
74 bool writeBool(bool value) { 96 bool writeBool(bool value) {
75 this->writeInt(value); 97 this->write32(value);
76 return value; 98 return value;
77 } 99 }
78 100
79 void writeInt(int32_t value) { 101 void writeInt(int32_t value) {
80 *(int32_t*)this->reserve(sizeof(value)) = value; 102 this->write32(value);
81 } 103 }
82 104
83 void write8(int32_t value) { 105 void write8(int32_t value) {
84 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF; 106 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF;
85 } 107 }
86 108
87 void write16(int32_t value) { 109 void write16(int32_t value) {
88 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF; 110 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF;
89 } 111 }
90 112
91 void write32(int32_t value) { 113 void write32(int32_t value) {
92 *(int32_t*)this->reserve(sizeof(value)) = value; 114 *(int32_t*)this->reserve(sizeof(value)) = value;
93 } 115 }
94 116
95 void writePtr(void* ptr) { 117 void writePtr(void* value) {
96 // Since we "know" that we're always 4-byte aligned, we can tell the 118 *(void**)this->reserve(sizeof(value)) = value;
97 // compiler that here, by assigning to an int32 ptr.
98 int32_t* addr = (int32_t*)this->reserve(sizeof(void*));
99 if (4 == sizeof(void*)) {
100 *(void**)addr = ptr;
101 } else {
102 memcpy(addr, &ptr, sizeof(void*));
103 }
104 } 119 }
105 120
106 void writeScalar(SkScalar value) { 121 void writeScalar(SkScalar value) {
107 *(SkScalar*)this->reserve(sizeof(value)) = value; 122 *(SkScalar*)this->reserve(sizeof(value)) = value;
108 } 123 }
109 124
110 void writePoint(const SkPoint& pt) { 125 void writePoint(const SkPoint& pt) {
111 *(SkPoint*)this->reserve(sizeof(pt)) = pt; 126 *(SkPoint*)this->reserve(sizeof(pt)) = pt;
112 } 127 }
113 128
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 void writeMul4(const void* values, size_t size) { 160 void writeMul4(const void* values, size_t size) {
146 this->write(values, size); 161 this->write(values, size);
147 } 162 }
148 163
149 /** 164 /**
150 * Write size bytes from values. size must be a multiple of 4, though 165 * Write size bytes from values. size must be a multiple of 4, though
151 * values need not be 4-byte aligned. 166 * values need not be 4-byte aligned.
152 */ 167 */
153 void write(const void* values, size_t size) { 168 void write(const void* values, size_t size) {
154 SkASSERT(SkAlign4(size) == size); 169 SkASSERT(SkAlign4(size) == size);
155 // if we could query how much is avail in the current block, we might 170 // TODO: If we're going to spill from fExternal to fInternal, we might w ant to fill
156 // copy that much, and then alloc the rest. That would reduce the waste 171 // fExternal as much as possible before writing to fInternal.
157 // in the current block
158 memcpy(this->reserve(size), values, size); 172 memcpy(this->reserve(size), values, size);
159 } 173 }
160 174
161 /** 175 /**
162 * Reserve size bytes. Does not need to be 4 byte aligned. The remaining sp ace (if any) will be 176 * Reserve size bytes. Does not need to be 4 byte aligned. The remaining sp ace (if any) will be
163 * filled in with zeroes. 177 * filled in with zeroes.
164 */ 178 */
165 uint32_t* reservePad(size_t size); 179 uint32_t* reservePad(size_t size) {
180 uint32_t* p = this->reserve(SkAlign4(size));
181 uint8_t* tail = (uint8_t*)p + size;
182 switch (SkAlign4(size) - size) {
183 default: SkDEBUGFAIL("SkAlign4(x) - x should always be 0, 1, 2, or 3 .");
184 case 3: *tail++ = 0x00; // fallthrough is intentional
185 case 2: *tail++ = 0x00; // fallthrough is intentional
186 case 1: *tail++ = 0x00;
187 case 0: ;/*nothing to do*/
188 }
189 return p;
190 }
166 191
167 /** 192 /**
168 * Write size bytes from src, and pad to 4 byte alignment with zeroes. 193 * Write size bytes from src, and pad to 4 byte alignment with zeroes.
169 */ 194 */
170 void writePad(const void* src, size_t size); 195 void writePad(const void* src, size_t size) {
196 memcpy(this->reservePad(size), src, size);
197 }
171 198
172 /** 199 /**
173 * Writes a string to the writer, which can be retrieved with 200 * Writes a string to the writer, which can be retrieved with
174 * SkReader32::readString(). 201 * SkReader32::readString().
175 * The length can be specified, or if -1 is passed, it will be computed by 202 * The length can be specified, or if -1 is passed, it will be computed by
176 * calling strlen(). The length must be < max size_t. 203 * calling strlen(). The length must be < max size_t.
177 * 204 *
178 * If you write NULL, it will be read as "". 205 * If you write NULL, it will be read as "".
179 */ 206 */
180 void writeString(const char* str, size_t len = (size_t)-1); 207 void writeString(const char* str, size_t len = (size_t)-1);
181 208
182 /** 209 /**
183 * Computes the size (aligned to multiple of 4) need to write the string 210 * Computes the size (aligned to multiple of 4) need to write the string
184 * in a call to writeString(). If the length is not specified, it will be 211 * in a call to writeString(). If the length is not specified, it will be
185 * computed by calling strlen(). 212 * computed by calling strlen().
186 */ 213 */
187 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); 214 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
188 215
189 // return the address of the 4byte int at the specified offset (which must
190 // be a multiple of 4. This does not allocate any new space, so the returned
191 // address is only valid for 1 int.
192 uint32_t* peek32(size_t offset);
193
194 /** 216 /**
195 * Move the cursor back to offset bytes from the beginning. 217 * Move the cursor back to offset bytes from the beginning.
196 * This has the same restrictions as peek32: offset must be <= size() and 218 * This has the same restrictions as peek32: offset must be <= size() and
197 * offset must be a multiple of 4. 219 * offset must be a multiple of 4.
198 */ 220 */
199 void rewindToOffset(size_t offset); 221 void rewindToOffset(size_t offset) {
222 SkASSERT(SkAlign4(offset) == offset);
223 const int count = offset/4;
224 if (count < this->externalCount()) {
225 fInternal.setCount(0);
226 } else {
227 fInternal.setCount(count - this->externalCount());
228 }
229 fCount = count;
230 }
200 231
201 // copy into a single buffer (allocated by caller). Must be at least size() 232 // copy into a single buffer (allocated by caller). Must be at least size()
202 void flatten(void* dst) const; 233 void flatten(void* dst) const {
234 const size_t externalBytes = this->externalCount()*4;
235 memcpy(dst, fExternal, externalBytes);
236 dst = (uint8_t*)dst + externalBytes;
237 memcpy(dst, fInternal.begin(), fInternal.bytes());
238 }
239
240 bool writeToStream(SkWStream* stream) const {
241 return stream->write(fExternal, this->externalCount()*4)
242 && stream->write(fInternal.begin(), fInternal.bytes());
243 }
203 244
204 // read from the stream, and write up to length bytes. Return the actual 245 // read from the stream, and write up to length bytes. Return the actual
205 // number of bytes written. 246 // number of bytes written.
206 size_t readFromStream(SkStream*, size_t length); 247 size_t readFromStream(SkStream* stream, size_t length) {
207 248 return stream->read(this->reservePad(length), length);
208 bool writeToStream(SkWStream*); 249 }
209 250
210 private: 251 private:
211 struct Block { 252 // Number of uint32_t written into fExternal. <= fExternalLimit.
212 Block* fNext; 253 int externalCount() const { return fCount - fInternal.count(); }
213 char* fBasePtr;
214 size_t fSizeOfBlock; // total space allocated (after this)
215 size_t fAllocatedSoFar; // space used so far
216 254
217 size_t available() const { return fSizeOfBlock - fAllocatedSoFar; } 255 int fCount; // Total number of uint32_t written.
218 char* base() { return fBasePtr; } 256 int fExternalLimit; // Number of uint32_t we can write to fExter nal.
219 const char* base() const { return fBasePtr; } 257 uint32_t* fExternal; // Unmanaged memory block.
220 258 SkTDArray<uint32_t> fInternal; // Managed memory block.
221 uint32_t* alloc(size_t size) {
222 SkASSERT(SkAlign4(size) == size);
223 SkASSERT(this->available() >= size);
224 void* ptr = this->base() + fAllocatedSoFar;
225 fAllocatedSoFar += size;
226 SkASSERT(fAllocatedSoFar <= fSizeOfBlock);
227 return (uint32_t*)ptr;
228 }
229
230 uint32_t* peek32(size_t offset) {
231 SkASSERT(offset <= fAllocatedSoFar + 4);
232 void* ptr = this->base() + offset;
233 return (uint32_t*)ptr;
234 }
235
236 void rewind() {
237 fNext = NULL;
238 fAllocatedSoFar = 0;
239 // keep fSizeOfBlock as is
240 }
241
242 static Block* Create(size_t size) {
243 SkASSERT(SkIsAlign4(size));
244 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
245 block->fNext = NULL;
246 block->fBasePtr = (char*)(block + 1);
247 block->fSizeOfBlock = size;
248 block->fAllocatedSoFar = 0;
249 return block;
250 }
251
252 Block* initFromStorage(void* storage, size_t size) {
253 SkASSERT(SkIsAlign4((intptr_t)storage));
254 SkASSERT(SkIsAlign4(size));
255 Block* block = this;
256 block->fNext = NULL;
257 block->fBasePtr = (char*)storage;
258 block->fSizeOfBlock = size;
259 block->fAllocatedSoFar = 0;
260 return block;
261 }
262 };
263
264 enum {
265 MIN_BLOCKSIZE = sizeof(SkWriter32::Block) + sizeof(intptr_t)
266 };
267
268 Block fExternalBlock;
269 Block* fHead;
270 Block* fTail;
271 size_t fMinSize;
272 size_t fSize;
273 // sum of bytes written in all blocks *before* fTail
274 size_t fWrittenBeforeLastBlock;
275
276 bool isHeadExternallyAllocated() const {
277 return fHead == &fExternalBlock;
278 }
279
280 Block* newBlock(size_t bytes);
281
282 // only call from reserve()
283 Block* doReserve(size_t bytes);
284
285 SkDEBUGCODE(void validate() const;)
286 }; 259 };
287 260
288 /** 261 /**
289 * Helper class to allocated SIZE bytes as part of the writer, and to provide 262 * Helper class to allocated SIZE bytes as part of the writer, and to provide
290 * that storage to the constructor as its initial storage buffer. 263 * that storage to the constructor as its initial storage buffer.
291 * 264 *
292 * This wrapper ensures proper alignment rules are met for the storage. 265 * This wrapper ensures proper alignment rules are met for the storage.
293 */ 266 */
294 template <size_t SIZE> class SkSWriter32 : public SkWriter32 { 267 template <size_t SIZE> class SkSWriter32 : public SkWriter32 {
295 public: 268 public:
296 SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {} 269 SkSWriter32() : SkWriter32(fData.fStorage, SIZE) {}
297 270
298 private: 271 private:
299 union { 272 union {
300 void* fPtrAlignment; 273 void* fPtrAlignment;
301 double fDoubleAlignment; 274 double fDoubleAlignment;
302 char fStorage[SIZE]; 275 char fStorage[SIZE];
303 } fData; 276 } fData;
304 }; 277 };
305 278
306 #endif 279 #endif
OLDNEW
« no previous file with comments | « bench/WriterBench.cpp ('k') | src/core/SkFlattenableSerialization.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698