Home | History | Annotate | Download | only in core
      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