1 /* 2 * Copyright 2013 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 #ifndef SkDataTable_DEFINED 9 #define SkDataTable_DEFINED 10 11 #include "SkChunkAlloc.h" 12 #include "SkData.h" 13 #include "SkFlattenable.h" 14 #include "SkString.h" 15 #include "SkTDArray.h" 16 17 /** 18 * Like SkData, SkDataTable holds an immutable data buffer. The data buffer is 19 * organized into a table of entries, each with a length, so the entries are 20 * not required to all be the same size. 21 */ 22 class SK_API SkDataTable : public SkFlattenable { 23 public: 24 SK_DECLARE_INST_COUNT(SkDataTable) 25 26 /** 27 * Returns true if the table is empty (i.e. has no entries). 28 */ 29 bool isEmpty() const { return 0 == fCount; } 30 31 /** 32 * Return the number of entries in the table. 0 for an empty table 33 */ 34 int count() const { return fCount; } 35 36 /** 37 * Return the size of the index'th entry in the table. The caller must 38 * ensure that index is valid for this table. 39 */ 40 size_t atSize(int index) const; 41 42 /** 43 * Return a pointer to the data of the index'th entry in the table. 44 * The caller must ensure that index is valid for this table. 45 * 46 * @param size If non-null, this returns the byte size of this entry. This 47 * will be the same value that atSize(index) would return. 48 */ 49 const void* at(int index, size_t* size = NULL) const; 50 51 template <typename T> 52 const T* atT(int index, size_t* size = NULL) const { 53 return reinterpret_cast<const T*>(this->at(index, size)); 54 } 55 56 /** 57 * Returns the index'th entry as a c-string, and assumes that the trailing 58 * null byte had been copied into the table as well. 59 */ 60 const char* atStr(int index) const { 61 size_t size; 62 const char* str = this->atT<const char>(index, &size); 63 SkASSERT(strlen(str) + 1 == size); 64 return str; 65 } 66 67 typedef void (*FreeProc)(void* context); 68 69 static SkDataTable* NewEmpty(); 70 71 /** 72 * Return a new DataTable that contains a copy of the data stored in each 73 * "array". 74 * 75 * @param ptrs array of points to each element to be copied into the table. 76 * @param sizes array of byte-lengths for each entry in the corresponding 77 * ptrs[] array. 78 * @param count the number of array elements in ptrs[] and sizes[] to copy. 79 */ 80 static SkDataTable* NewCopyArrays(const void * const * ptrs, 81 const size_t sizes[], int count); 82 83 /** 84 * Return a new table that contains a copy of the data in array. 85 * 86 * @param array contiguous array of data for all elements to be copied. 87 * @param elemSize byte-length for a given element. 88 * @param count the number of entries to be copied out of array. The number 89 * of bytes that will be copied is count * elemSize. 90 */ 91 static SkDataTable* NewCopyArray(const void* array, size_t elemSize, 92 int count); 93 94 static SkDataTable* NewArrayProc(const void* array, size_t elemSize, 95 int count, FreeProc proc, void* context); 96 97 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDataTable) 98 99 protected: 100 SkDataTable(SkFlattenableReadBuffer&); 101 virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; 102 103 private: 104 struct Dir { 105 const void* fPtr; 106 uintptr_t fSize; 107 }; 108 109 int fCount; 110 size_t fElemSize; 111 union { 112 const Dir* fDir; 113 const char* fElems; 114 } fU; 115 116 FreeProc fFreeProc; 117 void* fFreeProcContext; 118 119 SkDataTable(); 120 SkDataTable(const void* array, size_t elemSize, int count, 121 FreeProc, void* context); 122 SkDataTable(const Dir*, int count, FreeProc, void* context); 123 virtual ~SkDataTable(); 124 125 friend class SkDataTableBuilder; // access to Dir 126 127 typedef SkFlattenable INHERITED; 128 }; 129 130 /** 131 * Helper class that allows for incrementally building up the data needed to 132 * create a SkDataTable. 133 */ 134 class SK_API SkDataTableBuilder : SkNoncopyable { 135 public: 136 SkDataTableBuilder(size_t minChunkSize); 137 ~SkDataTableBuilder(); 138 139 int count() const { return fDir.count(); } 140 size_t minChunkSize() const { return fMinChunkSize; } 141 142 /** 143 * Forget any previously appended entries, setting count() back to 0. 144 */ 145 void reset(size_t minChunkSize); 146 void reset() { 147 this->reset(fMinChunkSize); 148 } 149 150 /** 151 * Copy size-bytes from data, and append it to the growing SkDataTable. 152 */ 153 void append(const void* data, size_t size); 154 155 /** 156 * Helper version of append() passes strlen() + 1 for the size, 157 * so the trailing-zero will be copied as well. 158 */ 159 void appendStr(const char str[]) { 160 this->append(str, strlen(str) + 1); 161 } 162 163 /** 164 * Helper version of append() passes string.size() + 1 for the size, 165 * so the trailing-zero will be copied as well. 166 */ 167 void appendString(const SkString& string) { 168 this->append(string.c_str(), string.size() + 1); 169 } 170 171 /** 172 * Return an SkDataTable from the accumulated entries that were added by 173 * calls to append(). This call also clears any accumluated entries from 174 * this builder, so its count() will be 0 after this call. 175 */ 176 SkDataTable* detachDataTable(); 177 178 private: 179 SkTDArray<SkDataTable::Dir> fDir; 180 SkChunkAlloc* fHeap; 181 size_t fMinChunkSize; 182 }; 183 184 #endif 185