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