18c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com/*
28c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com * Copyright 2013 Google Inc.
38c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com *
48c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com * Use of this source code is governed by a BSD-style license that can be
58c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com * found in the LICENSE file.
68c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com */
78c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
88c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com#include "SkData.h"
98c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com#include "SkDataTable.h"
108c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
11cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgstatic void malloc_freeproc(void* context) {
12cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    sk_free(context);
13cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
148c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
15cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org// Makes empty table
16cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable::SkDataTable() {
17cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fCount = 0;
18cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fElemSize = 0;   // 0 signals that we use fDir instead of fElems
19cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fU.fDir = NULL;
20cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProc = NULL;
21cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProcContext = NULL;
228c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
238c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
24cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable::SkDataTable(const void* array, size_t elemSize, int count,
25cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org                         FreeProc proc, void* context) {
26cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    SkASSERT(count > 0);
27c9f3b38f67893b22c3e02a6a934bc676e36c5cfcrmistry@google.com
28cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fCount = count;
29cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fElemSize = elemSize;   // non-zero signals we use fElems instead of fDir
30cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fU.fElems = (const char*)array;
31cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProc = proc;
32cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProcContext = context;
33cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
348c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
35cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) {
36cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    SkASSERT(count > 0);
37c9f3b38f67893b22c3e02a6a934bc676e36c5cfcrmistry@google.com
38cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fCount = count;
39cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fElemSize = 0;  // 0 signals that we use fDir instead of fElems
40cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fU.fDir = dir;
41cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProc = proc;
42cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProcContext = ctx;
43cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
44cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
45cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable::~SkDataTable() {
46cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (fFreeProc) {
47cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        fFreeProc(fFreeProcContext);
488c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
49cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
508c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
518c5c7a905b708f7c0a991ca7c872af645544afefreed@google.comsize_t SkDataTable::atSize(int index) const {
528c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    SkASSERT((unsigned)index < (unsigned)fCount);
53cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
54cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (fElemSize) {
55cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return fElemSize;
56cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    } else {
57cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return fU.fDir[index].fSize;
58cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    }
598c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
608c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
61cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgconst void* SkDataTable::at(int index, size_t* size) const {
628c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    SkASSERT((unsigned)index < (unsigned)fCount);
63cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
64cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (fElemSize) {
65cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        if (size) {
66cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org            *size = fElemSize;
67cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        }
68cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return fU.fElems + index * fElemSize;
69cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    } else {
70cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        if (size) {
71cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org            *size = fU.fDir[index].fSize;
72cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        }
73cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return fU.fDir[index].fPtr;
748c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
758c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
768c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
773cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com///////////////////////////////////////////////////////////////////////////////
783cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com
793cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.comSkDataTable* SkDataTable::NewEmpty() {
803cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com    static SkDataTable* gEmpty;
813cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com    if (NULL == gEmpty) {
82cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        gEmpty = SkNEW(SkDataTable);
833cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com    }
843cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com    gEmpty->ref();
853cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com    return gEmpty;
863cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com}
873cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com
888c5c7a905b708f7c0a991ca7c872af645544afefreed@google.comSkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs,
898c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com                                        const size_t sizes[], int count) {
90cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (count <= 0) {
91cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return SkDataTable::NewEmpty();
928c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
938c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
948c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    size_t dataSize = 0;
958c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    for (int i = 0; i < count; ++i) {
968c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com        dataSize += sizes[i];
978c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
988c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
99cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    size_t bufferSize = count * sizeof(Dir) + dataSize;
1008c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    void* buffer = sk_malloc_throw(bufferSize);
1018c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
102cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    Dir* dir = (Dir*)buffer;
103cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    char* elem = (char*)(dir + count);
1048c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    for (int i = 0; i < count; ++i) {
105cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        dir[i].fPtr = elem;
106cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        dir[i].fSize = sizes[i];
107cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        memcpy(elem, ptrs[i], sizes[i]);
108cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        elem += sizes[i];
1098c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
110c9f3b38f67893b22c3e02a6a934bc676e36c5cfcrmistry@google.com
111cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    return SkNEW_ARGS(SkDataTable, (dir, count, malloc_freeproc, buffer));
1128c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
1138c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
1148c5c7a905b708f7c0a991ca7c872af645544afefreed@google.comSkDataTable* SkDataTable::NewCopyArray(const void* array, size_t elemSize,
1158c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com                                       int count) {
116cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (count <= 0) {
117cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return SkDataTable::NewEmpty();
1188c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
11964b682ca42c75667e49251d3ab04f192f92d0dd8skia.committer@gmail.com
120cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    size_t bufferSize = elemSize * count;
1218c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    void* buffer = sk_malloc_throw(bufferSize);
122cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    memcpy(buffer, array, bufferSize);
12364b682ca42c75667e49251d3ab04f192f92d0dd8skia.committer@gmail.com
124cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    return SkNEW_ARGS(SkDataTable,
125cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org                      (buffer, elemSize, count, malloc_freeproc, buffer));
126cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
12764b682ca42c75667e49251d3ab04f192f92d0dd8skia.committer@gmail.com
128cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable* SkDataTable::NewArrayProc(const void* array, size_t elemSize,
129cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org                                       int count, FreeProc proc, void* ctx) {
130cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (count <= 0) {
131cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return SkDataTable::NewEmpty();
132cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    }
133cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    return SkNEW_ARGS(SkDataTable, (array, elemSize, count, proc, ctx));
1348c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
1358c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
1368c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com///////////////////////////////////////////////////////////////////////////////
1378c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
138cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgstatic void chunkalloc_freeproc(void* context) {
139cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    SkDELETE((SkChunkAlloc*)context);
140cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
141cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
1428c5c7a905b708f7c0a991ca7c872af645544afefreed@google.comSkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize)
143cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    : fHeap(NULL)
144cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    , fMinChunkSize(minChunkSize) {}
1458c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
146cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTableBuilder::~SkDataTableBuilder() { this->reset(); }
1478c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
148cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgvoid SkDataTableBuilder::reset(size_t minChunkSize) {
149cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fMinChunkSize = minChunkSize;
150cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fDir.reset();
151cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (fHeap) {
152cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        SkDELETE(fHeap);
153cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        fHeap = NULL;
154cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    }
1558c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
1568c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
1578c5c7a905b708f7c0a991ca7c872af645544afefreed@google.comvoid SkDataTableBuilder::append(const void* src, size_t size) {
158cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (NULL == fHeap) {
159cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        fHeap = SkNEW_ARGS(SkChunkAlloc, (fMinChunkSize));
160cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    }
161cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
162cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType);
1638c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    memcpy(dst, src, size);
1648c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
165cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    SkDataTable::Dir* dir = fDir.append();
166cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    dir->fPtr = dst;
167cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    dir->fSize = size;
1688c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
1698c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
170cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable* SkDataTableBuilder::detachDataTable() {
171cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    const int count = fDir.count();
172cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (0 == count) {
173cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return SkDataTable::NewEmpty();
174cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    }
175cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
176cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    // Copy the dir into the heap;
177cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir),
178cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org                             SkChunkAlloc::kThrow_AllocFailType);
179cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir));
180cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
181cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    SkDataTable* table = SkNEW_ARGS(SkDataTable,
182cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org                                    ((SkDataTable::Dir*)dir, count,
183cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org                                     chunkalloc_freeproc, fHeap));
184cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    // we have to detach our fHeap, since we are giving that to the table
185cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fHeap = NULL;
186cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fDir.reset();
187cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    return table;
1888c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
189