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 #include "SkData.h"
      9 #include "SkDataTable.h"
     10 
     11 static void malloc_freeproc(void* context) {
     12     sk_free(context);
     13 }
     14 
     15 // Makes empty table
     16 SkDataTable::SkDataTable() {
     17     fCount = 0;
     18     fElemSize = 0;   // 0 signals that we use fDir instead of fElems
     19     fU.fDir = NULL;
     20     fFreeProc = NULL;
     21     fFreeProcContext = NULL;
     22 }
     23 
     24 SkDataTable::SkDataTable(const void* array, size_t elemSize, int count,
     25                          FreeProc proc, void* context) {
     26     SkASSERT(count > 0);
     27 
     28     fCount = count;
     29     fElemSize = elemSize;   // non-zero signals we use fElems instead of fDir
     30     fU.fElems = (const char*)array;
     31     fFreeProc = proc;
     32     fFreeProcContext = context;
     33 }
     34 
     35 SkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) {
     36     SkASSERT(count > 0);
     37 
     38     fCount = count;
     39     fElemSize = 0;  // 0 signals that we use fDir instead of fElems
     40     fU.fDir = dir;
     41     fFreeProc = proc;
     42     fFreeProcContext = ctx;
     43 }
     44 
     45 SkDataTable::~SkDataTable() {
     46     if (fFreeProc) {
     47         fFreeProc(fFreeProcContext);
     48     }
     49 }
     50 
     51 size_t SkDataTable::atSize(int index) const {
     52     SkASSERT((unsigned)index < (unsigned)fCount);
     53 
     54     if (fElemSize) {
     55         return fElemSize;
     56     } else {
     57         return fU.fDir[index].fSize;
     58     }
     59 }
     60 
     61 const void* SkDataTable::at(int index, size_t* size) const {
     62     SkASSERT((unsigned)index < (unsigned)fCount);
     63 
     64     if (fElemSize) {
     65         if (size) {
     66             *size = fElemSize;
     67         }
     68         return fU.fElems + index * fElemSize;
     69     } else {
     70         if (size) {
     71             *size = fU.fDir[index].fSize;
     72         }
     73         return fU.fDir[index].fPtr;
     74     }
     75 }
     76 
     77 ///////////////////////////////////////////////////////////////////////////////
     78 
     79 SkDataTable* SkDataTable::NewEmpty() {
     80     static SkDataTable* gEmpty;
     81     if (NULL == gEmpty) {
     82         gEmpty = SkNEW(SkDataTable);
     83     }
     84     gEmpty->ref();
     85     return gEmpty;
     86 }
     87 
     88 SkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs,
     89                                         const size_t sizes[], int count) {
     90     if (count <= 0) {
     91         return SkDataTable::NewEmpty();
     92     }
     93 
     94     size_t dataSize = 0;
     95     for (int i = 0; i < count; ++i) {
     96         dataSize += sizes[i];
     97     }
     98 
     99     size_t bufferSize = count * sizeof(Dir) + dataSize;
    100     void* buffer = sk_malloc_throw(bufferSize);
    101 
    102     Dir* dir = (Dir*)buffer;
    103     char* elem = (char*)(dir + count);
    104     for (int i = 0; i < count; ++i) {
    105         dir[i].fPtr = elem;
    106         dir[i].fSize = sizes[i];
    107         memcpy(elem, ptrs[i], sizes[i]);
    108         elem += sizes[i];
    109     }
    110 
    111     return SkNEW_ARGS(SkDataTable, (dir, count, malloc_freeproc, buffer));
    112 }
    113 
    114 SkDataTable* SkDataTable::NewCopyArray(const void* array, size_t elemSize,
    115                                        int count) {
    116     if (count <= 0) {
    117         return SkDataTable::NewEmpty();
    118     }
    119 
    120     size_t bufferSize = elemSize * count;
    121     void* buffer = sk_malloc_throw(bufferSize);
    122     memcpy(buffer, array, bufferSize);
    123 
    124     return SkNEW_ARGS(SkDataTable,
    125                       (buffer, elemSize, count, malloc_freeproc, buffer));
    126 }
    127 
    128 SkDataTable* SkDataTable::NewArrayProc(const void* array, size_t elemSize,
    129                                        int count, FreeProc proc, void* ctx) {
    130     if (count <= 0) {
    131         return SkDataTable::NewEmpty();
    132     }
    133     return SkNEW_ARGS(SkDataTable, (array, elemSize, count, proc, ctx));
    134 }
    135 
    136 ///////////////////////////////////////////////////////////////////////////////
    137 
    138 static void chunkalloc_freeproc(void* context) {
    139     SkDELETE((SkChunkAlloc*)context);
    140 }
    141 
    142 SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize)
    143     : fHeap(NULL)
    144     , fMinChunkSize(minChunkSize) {}
    145 
    146 SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); }
    147 
    148 void SkDataTableBuilder::reset(size_t minChunkSize) {
    149     fMinChunkSize = minChunkSize;
    150     fDir.reset();
    151     if (fHeap) {
    152         SkDELETE(fHeap);
    153         fHeap = NULL;
    154     }
    155 }
    156 
    157 void SkDataTableBuilder::append(const void* src, size_t size) {
    158     if (NULL == fHeap) {
    159         fHeap = SkNEW_ARGS(SkChunkAlloc, (fMinChunkSize));
    160     }
    161 
    162     void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType);
    163     memcpy(dst, src, size);
    164 
    165     SkDataTable::Dir* dir = fDir.append();
    166     dir->fPtr = dst;
    167     dir->fSize = size;
    168 }
    169 
    170 SkDataTable* SkDataTableBuilder::detachDataTable() {
    171     const int count = fDir.count();
    172     if (0 == count) {
    173         return SkDataTable::NewEmpty();
    174     }
    175 
    176     // Copy the dir into the heap;
    177     void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir),
    178                              SkChunkAlloc::kThrow_AllocFailType);
    179     memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir));
    180 
    181     SkDataTable* table = SkNEW_ARGS(SkDataTable,
    182                                     ((SkDataTable::Dir*)dir, count,
    183                                      chunkalloc_freeproc, fHeap));
    184     // we have to detach our fHeap, since we are giving that to the table
    185     fHeap = NULL;
    186     fDir.reset();
    187     return table;
    188 }
    189