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