1 #include "SkMiniData.h" 2 3 namespace { 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 9 static 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. 17 struct 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. 34 struct 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 58 SkMiniData::SkMiniData(const void* data, size_t len) 59 : fRep(len <= 7 ? ShortData::Create(data, len) 60 : LongData::Create(data, len)) {} 61 62 SkMiniData::SkMiniData(const SkMiniData& s) 63 : fRep(s.len() <= 7 ? ShortData::Create(s.data(), s.len()) 64 : LongData::Create(s.data(), s.len())) {} 65 66 SkMiniData::~SkMiniData() { 67 if (is_long(fRep)) { 68 sk_free(reinterpret_cast<void*>(fRep)); 69 } 70 } 71 72 const void* SkMiniData::data() const { 73 return is_long(fRep) ? reinterpret_cast<const LongData*>( fRep)->data 74 : reinterpret_cast<const ShortData*>(&fRep)->data; 75 } 76 77 size_t SkMiniData::len() const { 78 return is_long(fRep) ? reinterpret_cast<const LongData*>( fRep)->len 79 : reinterpret_cast<const ShortData*>(&fRep)->len; 80 } 81