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