зеркало из https://github.com/mozilla/moz-skia.git
Add SkMiniData.
This is a bit like a limited SkData, geared to store really tiny byte strings. This is not hooked up anywhere beyond the new unit test. I did experimentally plumb it into SkRecord for drawPosTextH: just over 40% of drawPosTextH calls in our repo can fit into ShortData. BUG=skia: R=reed@google.com, mtklein@google.com Author: mtklein@chromium.org Review URL: https://codereview.chromium.org/573323002
This commit is contained in:
Родитель
ef59adba5b
Коммит
6a5c7085bc
|
@ -116,6 +116,7 @@
|
|||
'<(skia_src_path)/core/SkMatrix.cpp',
|
||||
'<(skia_src_path)/core/SkMessageBus.h',
|
||||
'<(skia_src_path)/core/SkMetaData.cpp',
|
||||
'<(skia_src_path)/core/SkMiniData.cpp',
|
||||
'<(skia_src_path)/core/SkMipMap.cpp',
|
||||
'<(skia_src_path)/core/SkMultiPictureDraw.cpp',
|
||||
'<(skia_src_path)/core/SkPackBits.cpp',
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
'../tests/MemsetTest.cpp',
|
||||
'../tests/MessageBusTest.cpp',
|
||||
'../tests/MetaDataTest.cpp',
|
||||
'../tests/MiniDataTest.cpp',
|
||||
'../tests/MipMapTest.cpp',
|
||||
'../tests/NameAllocatorTest.cpp',
|
||||
'../tests/OSPathTest.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;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef SkMiniData_DEFINED
|
||||
#define SkMiniData_DEFINED
|
||||
|
||||
// A class that can store any immutable byte string,
|
||||
// but optimized to store <=7 bytes.
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
class SkMiniData {
|
||||
public:
|
||||
SkMiniData(const void*, size_t);
|
||||
SkMiniData(const SkMiniData&);
|
||||
~SkMiniData();
|
||||
|
||||
const void* data() const;
|
||||
size_t len() const;
|
||||
|
||||
private:
|
||||
SkMiniData& operator=(const SkMiniData&);
|
||||
|
||||
const uint64_t fRep;
|
||||
};
|
||||
|
||||
#endif//SkMiniData_DEFINED
|
|
@ -0,0 +1,16 @@
|
|||
#include "SkMiniData.h"
|
||||
#include "Test.h"
|
||||
|
||||
DEF_TEST(MiniData, r) {
|
||||
static const char* s = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
for (size_t len = 0; len <= 26; len++) {
|
||||
SkMiniData md(s, len);
|
||||
REPORTER_ASSERT(r, md.len() == len);
|
||||
REPORTER_ASSERT(r, 0 == memcmp(md.data(), s, len));
|
||||
|
||||
SkMiniData copy(md);
|
||||
REPORTER_ASSERT(r, copy.len() == len);
|
||||
REPORTER_ASSERT(r, 0 == memcmp(copy.data(), s, len));
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче