michael@0: /* michael@0: * Copyright 2013 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef SkDataTable_DEFINED michael@0: #define SkDataTable_DEFINED michael@0: michael@0: #include "SkChunkAlloc.h" michael@0: #include "SkData.h" michael@0: #include "SkString.h" michael@0: #include "SkTDArray.h" michael@0: michael@0: /** michael@0: * Like SkData, SkDataTable holds an immutable data buffer. The data buffer is michael@0: * organized into a table of entries, each with a length, so the entries are michael@0: * not required to all be the same size. michael@0: */ michael@0: class SK_API SkDataTable : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkDataTable) michael@0: michael@0: /** michael@0: * Returns true if the table is empty (i.e. has no entries). michael@0: */ michael@0: bool isEmpty() const { return 0 == fCount; } michael@0: michael@0: /** michael@0: * Return the number of entries in the table. 0 for an empty table michael@0: */ michael@0: int count() const { return fCount; } michael@0: michael@0: /** michael@0: * Return the size of the index'th entry in the table. The caller must michael@0: * ensure that index is valid for this table. michael@0: */ michael@0: size_t atSize(int index) const; michael@0: michael@0: /** michael@0: * Return a pointer to the data of the index'th entry in the table. michael@0: * The caller must ensure that index is valid for this table. michael@0: * michael@0: * @param size If non-null, this returns the byte size of this entry. This michael@0: * will be the same value that atSize(index) would return. michael@0: */ michael@0: const void* at(int index, size_t* size = NULL) const; michael@0: michael@0: template michael@0: const T* atT(int index, size_t* size = NULL) const { michael@0: return reinterpret_cast(this->at(index, size)); michael@0: } michael@0: michael@0: /** michael@0: * Returns the index'th entry as a c-string, and assumes that the trailing michael@0: * null byte had been copied into the table as well. michael@0: */ michael@0: const char* atStr(int index) const { michael@0: size_t size; michael@0: const char* str = this->atT(index, &size); michael@0: SkASSERT(strlen(str) + 1 == size); michael@0: return str; michael@0: } michael@0: michael@0: typedef void (*FreeProc)(void* context); michael@0: michael@0: static SkDataTable* NewEmpty(); michael@0: michael@0: /** michael@0: * Return a new DataTable that contains a copy of the data stored in each michael@0: * "array". michael@0: * michael@0: * @param ptrs array of points to each element to be copied into the table. michael@0: * @param sizes array of byte-lengths for each entry in the corresponding michael@0: * ptrs[] array. michael@0: * @param count the number of array elements in ptrs[] and sizes[] to copy. michael@0: */ michael@0: static SkDataTable* NewCopyArrays(const void * const * ptrs, michael@0: const size_t sizes[], int count); michael@0: michael@0: /** michael@0: * Return a new table that contains a copy of the data in array. michael@0: * michael@0: * @param array contiguous array of data for all elements to be copied. michael@0: * @param elemSize byte-length for a given element. michael@0: * @param count the number of entries to be copied out of array. The number michael@0: * of bytes that will be copied is count * elemSize. michael@0: */ michael@0: static SkDataTable* NewCopyArray(const void* array, size_t elemSize, michael@0: int count); michael@0: michael@0: static SkDataTable* NewArrayProc(const void* array, size_t elemSize, michael@0: int count, FreeProc proc, void* context); michael@0: michael@0: private: michael@0: struct Dir { michael@0: const void* fPtr; michael@0: uintptr_t fSize; michael@0: }; michael@0: michael@0: int fCount; michael@0: size_t fElemSize; michael@0: union { michael@0: const Dir* fDir; michael@0: const char* fElems; michael@0: } fU; michael@0: michael@0: FreeProc fFreeProc; michael@0: void* fFreeProcContext; michael@0: michael@0: SkDataTable(); michael@0: SkDataTable(const void* array, size_t elemSize, int count, michael@0: FreeProc, void* context); michael@0: SkDataTable(const Dir*, int count, FreeProc, void* context); michael@0: virtual ~SkDataTable(); michael@0: michael@0: friend class SkDataTableBuilder; // access to Dir michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: /** michael@0: * Helper class that allows for incrementally building up the data needed to michael@0: * create a SkDataTable. michael@0: */ michael@0: class SK_API SkDataTableBuilder : SkNoncopyable { michael@0: public: michael@0: SkDataTableBuilder(size_t minChunkSize); michael@0: ~SkDataTableBuilder(); michael@0: michael@0: int count() const { return fDir.count(); } michael@0: size_t minChunkSize() const { return fMinChunkSize; } michael@0: michael@0: /** michael@0: * Forget any previously appended entries, setting count() back to 0. michael@0: */ michael@0: void reset(size_t minChunkSize); michael@0: void reset() { michael@0: this->reset(fMinChunkSize); michael@0: } michael@0: michael@0: /** michael@0: * Copy size-bytes from data, and append it to the growing SkDataTable. michael@0: */ michael@0: void append(const void* data, size_t size); michael@0: michael@0: /** michael@0: * Helper version of append() passes strlen() + 1 for the size, michael@0: * so the trailing-zero will be copied as well. michael@0: */ michael@0: void appendStr(const char str[]) { michael@0: this->append(str, strlen(str) + 1); michael@0: } michael@0: michael@0: /** michael@0: * Helper version of append() passes string.size() + 1 for the size, michael@0: * so the trailing-zero will be copied as well. michael@0: */ michael@0: void appendString(const SkString& string) { michael@0: this->append(string.c_str(), string.size() + 1); michael@0: } michael@0: michael@0: /** michael@0: * Return an SkDataTable from the accumulated entries that were added by michael@0: * calls to append(). This call also clears any accumluated entries from michael@0: * this builder, so its count() will be 0 after this call. michael@0: */ michael@0: SkDataTable* detachDataTable(); michael@0: michael@0: private: michael@0: SkTDArray fDir; michael@0: SkChunkAlloc* fHeap; michael@0: size_t fMinChunkSize; michael@0: }; michael@0: michael@0: #endif