OLD | NEW |
---|---|
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 Loading... | |
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 case 3: *tail++ = 0x00; | |
184 case 2: *tail++ = 0x00; | |
185 case 1: *tail++ = 0x00; | |
reed1
2014/01/14 18:59:37
will we get a 'missing default:' warning here?
mtklein
2014/01/14 19:52:02
I am curious to find out. Kicking off our most an
mtklein
2014/01/14 20:38:16
All the buildbots were totally cool as-is with no
| |
186 } | |
187 return p; | |
188 } | |
166 | 189 |
167 /** | 190 /** |
168 * Write size bytes from src, and pad to 4 byte alignment with zeroes. | 191 * Write size bytes from src, and pad to 4 byte alignment with zeroes. |
169 */ | 192 */ |
170 void writePad(const void* src, size_t size); | 193 void writePad(const void* src, size_t size) { |
194 memcpy(this->reservePad(size), src, size); | |
195 } | |
171 | 196 |
172 /** | 197 /** |
173 * Writes a string to the writer, which can be retrieved with | 198 * Writes a string to the writer, which can be retrieved with |
174 * SkReader32::readString(). | 199 * SkReader32::readString(). |
175 * The length can be specified, or if -1 is passed, it will be computed by | 200 * 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. | 201 * calling strlen(). The length must be < max size_t. |
177 * | 202 * |
178 * If you write NULL, it will be read as "". | 203 * If you write NULL, it will be read as "". |
179 */ | 204 */ |
180 void writeString(const char* str, size_t len = (size_t)-1); | 205 void writeString(const char* str, size_t len = (size_t)-1); |
181 | 206 |
182 /** | 207 /** |
183 * Computes the size (aligned to multiple of 4) need to write the string | 208 * 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 | 209 * in a call to writeString(). If the length is not specified, it will be |
185 * computed by calling strlen(). | 210 * computed by calling strlen(). |
186 */ | 211 */ |
187 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); | 212 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); |
188 | 213 |
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 /** | 214 /** |
195 * Move the cursor back to offset bytes from the beginning. | 215 * Move the cursor back to offset bytes from the beginning. |
196 * This has the same restrictions as peek32: offset must be <= size() and | 216 * This has the same restrictions as peek32: offset must be <= size() and |
197 * offset must be a multiple of 4. | 217 * offset must be a multiple of 4. |
198 */ | 218 */ |
199 void rewindToOffset(size_t offset); | 219 void rewindToOffset(size_t offset) { |
220 SkASSERT(SkAlign4(offset) == offset); | |
221 const int count = offset/4; | |
222 if (count < this->externalCount()) { | |
223 fInternal.setCount(0); | |
224 } else { | |
225 fInternal.setCount(count - this->externalCount()); | |
226 } | |
227 fCount = count; | |
228 } | |
200 | 229 |
201 // copy into a single buffer (allocated by caller). Must be at least size() | 230 // copy into a single buffer (allocated by caller). Must be at least size() |
202 void flatten(void* dst) const; | 231 void flatten(void* dst) const { |
232 const size_t externalBytes = this->externalCount()*4; | |
233 memcpy(dst, fExternal, externalBytes); | |
234 dst = (uint8_t*)dst + externalBytes; | |
235 memcpy(dst, fInternal.begin(), fInternal.bytes()); | |
236 } | |
237 | |
238 bool writeToStream(SkWStream* stream) const { | |
239 return stream->write(fExternal, this->externalCount()*4) | |
240 && stream->write(fInternal.begin(), fInternal.bytes()); | |
241 } | |
203 | 242 |
204 // read from the stream, and write up to length bytes. Return the actual | 243 // read from the stream, and write up to length bytes. Return the actual |
205 // number of bytes written. | 244 // number of bytes written. |
206 size_t readFromStream(SkStream*, size_t length); | 245 size_t readFromStream(SkStream* stream, size_t length) { |
207 | 246 return stream->read(this->reservePad(length), length); |
208 bool writeToStream(SkWStream*); | 247 } |
209 | 248 |
210 private: | 249 private: |
211 struct Block { | 250 // Number of uint32_t written into fExternal. <= fExternalLimit. |
212 Block* fNext; | 251 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 | 252 |
217 size_t available() const { return fSizeOfBlock - fAllocatedSoFar; } | 253 int fCount; // Total number of uint32_t written. |
218 char* base() { return fBasePtr; } | 254 int fExternalLimit; // Number of uint32_t we can write to fExter nal. |
219 const char* base() const { return fBasePtr; } | 255 uint32_t* fExternal; // Unmanaged memory block. |
220 | 256 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 }; | 257 }; |
287 | 258 |
288 /** | 259 /** |
289 * Helper class to allocated SIZE bytes as part of the writer, and to provide | 260 * 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. | 261 * that storage to the constructor as its initial storage buffer. |
291 * | 262 * |
292 * This wrapper ensures proper alignment rules are met for the storage. | 263 * This wrapper ensures proper alignment rules are met for the storage. |
293 */ | 264 */ |
294 template <size_t SIZE> class SkSWriter32 : public SkWriter32 { | 265 template <size_t SIZE> class SkSWriter32 : public SkWriter32 { |
295 public: | 266 public: |
296 SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {} | 267 SkSWriter32() : SkWriter32(fData.fStorage, SIZE) {} |
297 | 268 |
298 private: | 269 private: |
299 union { | 270 union { |
300 void* fPtrAlignment; | 271 void* fPtrAlignment; |
301 double fDoubleAlignment; | 272 double fDoubleAlignment; |
302 char fStorage[SIZE]; | 273 char fStorage[SIZE]; |
303 } fData; | 274 } fData; |
304 }; | 275 }; |
305 | 276 |
306 #endif | 277 #endif |
OLD | NEW |