| Index: src/core/SkMiniData.cpp
|
| diff --git a/src/core/SkMiniData.cpp b/src/core/SkMiniData.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ded62d1687a97220b83168b87be51372103f72d0
|
| --- /dev/null
|
| +++ b/src/core/SkMiniData.cpp
|
| @@ -0,0 +1,80 @@
|
| +#include "SkMiniData.h"
|
| +
|
| +namespace {
|
| +
|
| +// SkMiniData::fRep either stores a LongData* or is punned into a ShortData.
|
| +// We use the low bits to distinguish the two: all pointers from malloc are at
|
| +// least 8-byte aligned, leaving those low bits clear when it's a LongData*.
|
| +
|
| +static bool is_long(uint64_t rep) {
|
| + // Even on 32-bit machines, we require the bottom 3 bits from malloc'd pointers are clear.
|
| + // If any of those bottom 3 bits are set, it's from a ShortData's len. And if no bits are
|
| + // set anywhere, it's an empty SkMiniData, which also follows the ShortData path.
|
| + return rep && SkIsAlign8(rep);
|
| +}
|
| +
|
| +// Can be used for any length, but we always use it for >=8.
|
| +struct LongData {
|
| + size_t len;
|
| + uint8_t data[8]; // There are actually len >= 8 bytes here.
|
| +
|
| + static uint64_t Create(const void* data, size_t len) {
|
| + SkASSERT(len > 7);
|
| + LongData* s = (LongData*)sk_malloc_throw(sizeof(size_t) + len);
|
| + s->len = len;
|
| + memcpy(s->data, data, len);
|
| +
|
| + uint64_t rep = reinterpret_cast<uint64_t>(s);
|
| + SkASSERT(is_long(rep));
|
| + return rep;
|
| + }
|
| +};
|
| +
|
| +// At most 7 bytes fit, but never mallocs.
|
| +struct ShortData {
|
| + // Order matters here. len must align with the least signficant bits of a pointer.
|
| +#ifdef SK_CPU_LENDIAN
|
| + uint8_t len;
|
| + uint8_t data[7];
|
| +#else // Warning! Only the little-endian path has been tested.
|
| + uint8_t data[7];
|
| + uint8_t len;
|
| +#endif
|
| +
|
| + static uint64_t Create(const void* data, size_t len) {
|
| + SkASSERT(len <= 7);
|
| +#ifdef SK_CPU_LENDIAN
|
| + ShortData s = { (uint8_t)len, {0, 0, 0, 0, 0, 0, 0} };
|
| +#else // Warning! Only the little-endian path has been tested.
|
| + ShortData s = { {0, 0, 0, 0, 0, 0, 0}, (uint8_t)len };
|
| +#endif
|
| + memcpy(s.data, data, len);
|
| + return *reinterpret_cast<uint64_t*>(&s);
|
| + }
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +SkMiniData::SkMiniData(const void* data, size_t len)
|
| + : fRep(len <= 7 ? ShortData::Create(data, len)
|
| + : LongData::Create(data, len)) {}
|
| +
|
| +SkMiniData::SkMiniData(const SkMiniData& s)
|
| + : fRep(s.len() <= 7 ? ShortData::Create(s.data(), s.len())
|
| + : LongData::Create(s.data(), s.len())) {}
|
| +
|
| +SkMiniData::~SkMiniData() {
|
| + if (is_long(fRep)) {
|
| + sk_free(reinterpret_cast<void*>(fRep));
|
| + }
|
| +}
|
| +
|
| +const void* SkMiniData::data() const {
|
| + return is_long(fRep) ? reinterpret_cast<const LongData*>( fRep)->data
|
| + : reinterpret_cast<const ShortData*>(&fRep)->data;
|
| +}
|
| +
|
| +size_t SkMiniData::len() const {
|
| + return is_long(fRep) ? reinterpret_cast<const LongData*>( fRep)->len
|
| + : reinterpret_cast<const ShortData*>(&fRep)->len;
|
| +}
|
|
|