Home | History | Annotate | Download | only in core
      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