1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkData.h"
9cb93a386Sopenharmony_ci#include "include/core/SkDataTable.h"
10cb93a386Sopenharmony_ci#include "include/private/SkOnce.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_cistatic void malloc_freeproc(void* context) {
13cb93a386Sopenharmony_ci    sk_free(context);
14cb93a386Sopenharmony_ci}
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci// Makes empty table
17cb93a386Sopenharmony_ciSkDataTable::SkDataTable() {
18cb93a386Sopenharmony_ci    fCount = 0;
19cb93a386Sopenharmony_ci    fElemSize = 0;   // 0 signals that we use fDir instead of fElems
20cb93a386Sopenharmony_ci    fU.fDir = nullptr;
21cb93a386Sopenharmony_ci    fFreeProc = nullptr;
22cb93a386Sopenharmony_ci    fFreeProcContext = nullptr;
23cb93a386Sopenharmony_ci}
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ciSkDataTable::SkDataTable(const void* array, size_t elemSize, int count,
26cb93a386Sopenharmony_ci                         FreeProc proc, void* context) {
27cb93a386Sopenharmony_ci    SkASSERT(count > 0);
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci    fCount = count;
30cb93a386Sopenharmony_ci    fElemSize = elemSize;   // non-zero signals we use fElems instead of fDir
31cb93a386Sopenharmony_ci    fU.fElems = (const char*)array;
32cb93a386Sopenharmony_ci    fFreeProc = proc;
33cb93a386Sopenharmony_ci    fFreeProcContext = context;
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ciSkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) {
37cb93a386Sopenharmony_ci    SkASSERT(count > 0);
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    fCount = count;
40cb93a386Sopenharmony_ci    fElemSize = 0;  // 0 signals that we use fDir instead of fElems
41cb93a386Sopenharmony_ci    fU.fDir = dir;
42cb93a386Sopenharmony_ci    fFreeProc = proc;
43cb93a386Sopenharmony_ci    fFreeProcContext = ctx;
44cb93a386Sopenharmony_ci}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ciSkDataTable::~SkDataTable() {
47cb93a386Sopenharmony_ci    if (fFreeProc) {
48cb93a386Sopenharmony_ci        fFreeProc(fFreeProcContext);
49cb93a386Sopenharmony_ci    }
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_cisize_t SkDataTable::atSize(int index) const {
53cb93a386Sopenharmony_ci    SkASSERT((unsigned)index < (unsigned)fCount);
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci    if (fElemSize) {
56cb93a386Sopenharmony_ci        return fElemSize;
57cb93a386Sopenharmony_ci    } else {
58cb93a386Sopenharmony_ci        return fU.fDir[index].fSize;
59cb93a386Sopenharmony_ci    }
60cb93a386Sopenharmony_ci}
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ciconst void* SkDataTable::at(int index, size_t* size) const {
63cb93a386Sopenharmony_ci    SkASSERT((unsigned)index < (unsigned)fCount);
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci    if (fElemSize) {
66cb93a386Sopenharmony_ci        if (size) {
67cb93a386Sopenharmony_ci            *size = fElemSize;
68cb93a386Sopenharmony_ci        }
69cb93a386Sopenharmony_ci        return fU.fElems + index * fElemSize;
70cb93a386Sopenharmony_ci    } else {
71cb93a386Sopenharmony_ci        if (size) {
72cb93a386Sopenharmony_ci            *size = fU.fDir[index].fSize;
73cb93a386Sopenharmony_ci        }
74cb93a386Sopenharmony_ci        return fU.fDir[index].fPtr;
75cb93a386Sopenharmony_ci    }
76cb93a386Sopenharmony_ci}
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_cisk_sp<SkDataTable> SkDataTable::MakeEmpty() {
81cb93a386Sopenharmony_ci    static SkDataTable* singleton;
82cb93a386Sopenharmony_ci    static SkOnce once;
83cb93a386Sopenharmony_ci    once([]{ singleton = new SkDataTable(); });
84cb93a386Sopenharmony_ci    return sk_ref_sp(singleton);
85cb93a386Sopenharmony_ci}
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_cisk_sp<SkDataTable> SkDataTable::MakeCopyArrays(const void * const * ptrs,
88cb93a386Sopenharmony_ci                                               const size_t sizes[], int count) {
89cb93a386Sopenharmony_ci    if (count <= 0) {
90cb93a386Sopenharmony_ci        return SkDataTable::MakeEmpty();
91cb93a386Sopenharmony_ci    }
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    size_t dataSize = 0;
94cb93a386Sopenharmony_ci    for (int i = 0; i < count; ++i) {
95cb93a386Sopenharmony_ci        dataSize += sizes[i];
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    size_t bufferSize = count * sizeof(Dir) + dataSize;
99cb93a386Sopenharmony_ci    void* buffer = sk_malloc_throw(bufferSize);
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    Dir* dir = (Dir*)buffer;
102cb93a386Sopenharmony_ci    char* elem = (char*)(dir + count);
103cb93a386Sopenharmony_ci    for (int i = 0; i < count; ++i) {
104cb93a386Sopenharmony_ci        dir[i].fPtr = elem;
105cb93a386Sopenharmony_ci        dir[i].fSize = sizes[i];
106cb93a386Sopenharmony_ci        memcpy(elem, ptrs[i], sizes[i]);
107cb93a386Sopenharmony_ci        elem += sizes[i];
108cb93a386Sopenharmony_ci    }
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci    return sk_sp<SkDataTable>(new SkDataTable(dir, count, malloc_freeproc, buffer));
111cb93a386Sopenharmony_ci}
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_cisk_sp<SkDataTable> SkDataTable::MakeCopyArray(const void* array, size_t elemSize, int count) {
114cb93a386Sopenharmony_ci    if (count <= 0) {
115cb93a386Sopenharmony_ci        return SkDataTable::MakeEmpty();
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    size_t bufferSize = elemSize * count;
119cb93a386Sopenharmony_ci    void* buffer = sk_malloc_throw(bufferSize);
120cb93a386Sopenharmony_ci    memcpy(buffer, array, bufferSize);
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_ci    return sk_sp<SkDataTable>(new SkDataTable(buffer, elemSize, count, malloc_freeproc, buffer));
123cb93a386Sopenharmony_ci}
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_cisk_sp<SkDataTable> SkDataTable::MakeArrayProc(const void* array, size_t elemSize, int count,
126cb93a386Sopenharmony_ci                                              FreeProc proc, void* ctx) {
127cb93a386Sopenharmony_ci    if (count <= 0) {
128cb93a386Sopenharmony_ci        return SkDataTable::MakeEmpty();
129cb93a386Sopenharmony_ci    }
130cb93a386Sopenharmony_ci    return sk_sp<SkDataTable>(new SkDataTable(array, elemSize, count, proc, ctx));
131cb93a386Sopenharmony_ci}
132