Chromium Code Reviews| 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 |