1#include "SkMiniData.h"
2
3namespace {
4
5// SkMiniData::fRep either stores a LongData* or is punned into a ShortData.
6// We use the low bits to distinguish the two: all pointers from malloc are at
7// least 8-byte aligned, leaving those low bits clear when it's a LongData*.
8
9static bool is_long(uint64_t rep) {
10    // Even on 32-bit machines, we require the bottom 3 bits from malloc'd pointers are clear.
11    // If any of those bottom 3 bits are set, it's from a ShortData's len.  And if no bits are
12    // set anywhere, it's an empty SkMiniData, which also follows the ShortData path.
13    return rep && SkIsAlign8(rep);
14}
15
16// Can be used for any length, but we always use it for >=8.
17struct LongData {
18    size_t len;
19    uint8_t data[8];  // There are actually len >= 8 bytes here.
20
21    static uint64_t Create(const void* data, size_t len) {
22        SkASSERT(len > 7);
23        LongData* s = (LongData*)sk_malloc_throw(sizeof(size_t) + len);
24        s->len = len;
25        memcpy(s->data, data, len);
26
27        uint64_t rep = reinterpret_cast<uint64_t>(s);
28        SkASSERT(is_long(rep));
29        return rep;
30    }
31};
32
33// At most 7 bytes fit, but never mallocs.
34struct ShortData {
35    // Order matters here. len must align with the least signficant bits of a pointer.
36#ifdef SK_CPU_LENDIAN
37    uint8_t len;
38    uint8_t data[7];
39#else  // Warning!  Only the little-endian path has been tested.
40    uint8_t data[7];
41    uint8_t len;
42#endif
43
44    static uint64_t Create(const void* data, size_t len) {
45        SkASSERT(len <= 7);
46#ifdef SK_CPU_LENDIAN
47        ShortData s = { (uint8_t)len, {0, 0, 0, 0, 0, 0, 0} };
48#else  // Warning!  Only the little-endian path has been tested.
49        ShortData s = { {0, 0, 0, 0, 0, 0, 0}, (uint8_t)len };
50#endif
51        memcpy(s.data, data, len);
52        return *reinterpret_cast<uint64_t*>(&s);
53    }
54};
55
56}  // namespace
57
58SkMiniData::SkMiniData(const void* data, size_t len)
59    : fRep(len <= 7 ? ShortData::Create(data, len)
60                    :  LongData::Create(data, len)) {}
61
62SkMiniData::SkMiniData(const SkMiniData& s)
63    : fRep(s.len() <= 7 ? ShortData::Create(s.data(), s.len())
64                        :  LongData::Create(s.data(), s.len())) {}
65
66SkMiniData::~SkMiniData() {
67    if (is_long(fRep)) {
68        sk_free(reinterpret_cast<void*>(fRep));
69    }
70}
71
72const void* SkMiniData::data() const {
73    return is_long(fRep) ? reinterpret_cast<const  LongData*>( fRep)->data
74                         : reinterpret_cast<const ShortData*>(&fRep)->data;
75}
76
77size_t SkMiniData::len() const {
78    return is_long(fRep) ? reinterpret_cast<const  LongData*>( fRep)->len
79                         : reinterpret_cast<const ShortData*>(&fRep)->len;
80}
81