mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Make SparseBitSet serializable.
To share the calculated coverage information across the processes, make SparseBitSet serializable. Bug: 34042446 Test: minikin_tests passes Change-Id: I0463138adcf234739bb3ce1cdadf382021921f3e
This commit is contained in:
parent
d78f260a98
commit
fbbc5a6b36
@ -128,8 +128,23 @@ public:
|
||||
FontFamily(int variant, std::vector<Font>&& fonts);
|
||||
FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts);
|
||||
|
||||
// The accelerator table won't be copied. Do not release the memory until the created FontFamily
|
||||
// is destructed.
|
||||
FontFamily(std::vector<Font>&& fonts, const uint8_t* acceleratorTable, size_t tableSize);
|
||||
FontFamily(int variant, std::vector<Font>&& fonts, const uint8_t* acceleratorTable,
|
||||
size_t tableSize);
|
||||
FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts,
|
||||
const uint8_t* acceleratorTable, size_t tableSize);
|
||||
|
||||
~FontFamily();
|
||||
|
||||
// Writes internal accelerator tables into the 'out' buffer.
|
||||
//
|
||||
// This method returns the number of bytes written to the buffer. By calling the method with
|
||||
// 'out' set to nullptr, the method just returns the size needed, which the caller can then use
|
||||
// for allocating a buffer for a second call.
|
||||
size_t writeAcceleratorTable(uint8_t* out) const;
|
||||
|
||||
// TODO: Good to expose FontUtil.h.
|
||||
static bool analyzeStyle(const std::shared_ptr<MinikinFont>& typeface, int* weight,
|
||||
bool* italic);
|
||||
@ -164,6 +179,8 @@ public:
|
||||
|
||||
private:
|
||||
void computeCoverage();
|
||||
void readAcceleratorTable(const uint8_t* data, size_t size);
|
||||
|
||||
uint32_t mLangId;
|
||||
int mVariant;
|
||||
std::vector<Font> mFonts;
|
||||
|
||||
@ -34,7 +34,7 @@ namespace minikin {
|
||||
|
||||
class SparseBitSet {
|
||||
public:
|
||||
SparseBitSet(): mMaxVal(0) {
|
||||
SparseBitSet(): mMaxVal(0), mOwnIndicesAndBitmaps(false) {
|
||||
}
|
||||
|
||||
// Clear the set
|
||||
@ -45,10 +45,21 @@ public:
|
||||
// inclusive of start, exclusive of end, laid out in a uint32 array.
|
||||
void initFromRanges(const uint32_t* ranges, size_t nRanges);
|
||||
|
||||
// Initializes the set with pre-calculted data. Returns false if the serialized data is invalid.
|
||||
// Even if this function returns false, the internal data is cleared.
|
||||
bool initFromBuffer(const uint8_t* data, size_t size);
|
||||
|
||||
// Serialize the set and write into out.
|
||||
//
|
||||
// This method returns the number of bytes written to the buffer. By calling the method with
|
||||
// 'out' set to nullptr, the method just returns the size needed, which the caller can then use
|
||||
// for allocating a buffer for a second call.
|
||||
size_t writeToBuffer(uint8_t* out) const;
|
||||
|
||||
// Determine whether the value is included in the set
|
||||
bool get(uint32_t ch) const {
|
||||
if (ch >= mMaxVal) return false;
|
||||
uint32_t *bitmap = &mBitmaps[mIndices[ch >> kLogValuesPerPage]];
|
||||
const uint32_t *bitmap = &mBitmaps[mIndices[ch >> kLogValuesPerPage]];
|
||||
uint32_t index = ch & kPageMask;
|
||||
return (bitmap[index >> kLogBitsPerEl] & (kElFirst >> (index & kElMask))) != 0;
|
||||
}
|
||||
@ -80,8 +91,14 @@ private:
|
||||
static int CountLeadingZeros(element x);
|
||||
|
||||
uint32_t mMaxVal;
|
||||
std::unique_ptr<uint32_t[]> mIndices;
|
||||
std::unique_ptr<element[]> mBitmaps;
|
||||
|
||||
// True if this SparseBitSet is responsible for freeing mIndices and mBitamps.
|
||||
bool mOwnIndicesAndBitmaps;
|
||||
|
||||
uint32_t mIndexSize;
|
||||
const uint32_t* mIndices;
|
||||
uint32_t mBitmapSize;
|
||||
const element* mBitmaps;
|
||||
uint32_t mZeroPageIndex;
|
||||
};
|
||||
|
||||
|
||||
@ -112,6 +112,22 @@ FontFamily::FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts)
|
||||
computeCoverage();
|
||||
}
|
||||
|
||||
FontFamily::FontFamily(std::vector<Font>&& fonts, const uint8_t* acceleratorTable, size_t tableSize)
|
||||
: FontFamily(0 /* variant */, std::move(fonts), acceleratorTable, tableSize) {
|
||||
}
|
||||
|
||||
FontFamily::FontFamily(int variant, std::vector<Font>&& fonts, const uint8_t* acceleratorTable,
|
||||
size_t tableSize)
|
||||
: FontFamily(FontLanguageListCache::kEmptyListId, variant, std::move(fonts), acceleratorTable,
|
||||
tableSize) {
|
||||
}
|
||||
|
||||
FontFamily::FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts,
|
||||
const uint8_t* acceleratorTable, size_t tableSize)
|
||||
: mLangId(langId), mVariant(variant), mFonts(std::move(fonts)), mHasVSTable(false) {
|
||||
readAcceleratorTable(acceleratorTable, tableSize);
|
||||
}
|
||||
|
||||
FontFamily::~FontFamily() {
|
||||
}
|
||||
|
||||
@ -247,4 +263,12 @@ std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
|
||||
return std::shared_ptr<FontFamily>(new FontFamily(mLangId, mVariant, std::move(fonts)));
|
||||
}
|
||||
|
||||
size_t FontFamily::writeAcceleratorTable(uint8_t* out) const {
|
||||
return mCoverage.writeToBuffer(out);
|
||||
}
|
||||
|
||||
void FontFamily::readAcceleratorTable(const uint8_t* data, size_t size) {
|
||||
bool result = mCoverage.initFromBuffer(data, size);
|
||||
LOG_ALWAYS_FATAL_IF(!result, "Failed to reconstruct accelerator table from buffer");
|
||||
}
|
||||
} // namespace minikin
|
||||
|
||||
@ -29,8 +29,13 @@ const uint32_t SparseBitSet::kNotFound;
|
||||
|
||||
void SparseBitSet::clear() {
|
||||
mMaxVal = 0;
|
||||
mIndices.reset();
|
||||
mBitmaps.reset();
|
||||
if (mOwnIndicesAndBitmaps) {
|
||||
delete[] mIndices;
|
||||
delete[] mBitmaps;
|
||||
mIndexSize = 0;
|
||||
mBitmapSize = 0;
|
||||
mOwnIndicesAndBitmaps = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) {
|
||||
@ -59,17 +64,17 @@ uint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) {
|
||||
|
||||
void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
|
||||
if (nRanges == 0) {
|
||||
mMaxVal = 0;
|
||||
mIndices.reset();
|
||||
mBitmaps.reset();
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
mMaxVal = ranges[nRanges * 2 - 1];
|
||||
size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
|
||||
mIndices.reset(new uint32_t[indexSize]);
|
||||
mIndexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
|
||||
uint32_t* indices = new uint32_t[mIndexSize];
|
||||
uint32_t nPages = calcNumPages(ranges, nRanges);
|
||||
mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]);
|
||||
memset(mBitmaps.get(), 0, nPages << (kLogValuesPerPage - 3));
|
||||
mBitmapSize = nPages << (kLogValuesPerPage - kLogBitsPerEl);
|
||||
element* bitmaps = new element[mBitmapSize];
|
||||
mOwnIndicesAndBitmaps = true;
|
||||
memset(bitmaps, 0, nPages << (kLogValuesPerPage - 3));
|
||||
mZeroPageIndex = noZeroPage;
|
||||
uint32_t nonzeroPageEnd = 0;
|
||||
uint32_t currentPage = 0;
|
||||
@ -85,30 +90,99 @@ void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
|
||||
mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
|
||||
}
|
||||
for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
|
||||
mIndices[j] = mZeroPageIndex;
|
||||
indices[j] = mZeroPageIndex;
|
||||
}
|
||||
}
|
||||
mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
|
||||
indices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
|
||||
}
|
||||
|
||||
size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
|
||||
((start & kPageMask) >> kLogBitsPerEl);
|
||||
size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;
|
||||
if (nElements == 1) {
|
||||
mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
|
||||
bitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
|
||||
(kElAllOnes << ((~end + 1) & kElMask));
|
||||
} else {
|
||||
mBitmaps[index] |= kElAllOnes >> (start & kElMask);
|
||||
bitmaps[index] |= kElAllOnes >> (start & kElMask);
|
||||
for (size_t j = 1; j < nElements - 1; j++) {
|
||||
mBitmaps[index + j] = kElAllOnes;
|
||||
bitmaps[index + j] = kElAllOnes;
|
||||
}
|
||||
mBitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask);
|
||||
bitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask);
|
||||
}
|
||||
for (size_t j = startPage + 1; j < endPage + 1; j++) {
|
||||
mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
|
||||
indices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
|
||||
}
|
||||
nonzeroPageEnd = endPage + 1;
|
||||
}
|
||||
mBitmaps = bitmaps;
|
||||
mIndices = indices;
|
||||
}
|
||||
|
||||
struct SparseBitSetHeader {
|
||||
uint32_t maxValue;
|
||||
uint32_t zeroPageIndex;
|
||||
uint32_t indexSize;
|
||||
uint32_t bitmapSize;
|
||||
};
|
||||
|
||||
bool SparseBitSet::initFromBuffer(const uint8_t* data, size_t size) {
|
||||
// No need to be concerned about endianness here since Intel x86 CPUs are little-endian. ARM
|
||||
// CPUs are bi-endian but the endianness is only changeable at reset time and is impossible to
|
||||
// change at runtime. Thus incoming data is guaranteed to have the same endianness as when it
|
||||
// was created.
|
||||
|
||||
if (data == nullptr || size < sizeof(SparseBitSetHeader)) {
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// The serialized data starts with SparseBitSetHeader.
|
||||
const SparseBitSetHeader* header = reinterpret_cast<const SparseBitSetHeader*>(data);
|
||||
mMaxVal = header->maxValue;
|
||||
mZeroPageIndex = header->zeroPageIndex;
|
||||
mIndexSize = header->indexSize;
|
||||
mBitmapSize = header->bitmapSize;
|
||||
|
||||
mOwnIndicesAndBitmaps = false;
|
||||
if (mIndexSize == 0 || mBitmapSize == 0 || mMaxVal == 0) {
|
||||
const bool isValidEmptyBitSet = (mIndexSize == 0 && mBitmapSize == 0 && mMaxVal == 0);
|
||||
if (!isValidEmptyBitSet) {
|
||||
clear();
|
||||
}
|
||||
return isValidEmptyBitSet;
|
||||
}
|
||||
|
||||
const size_t indicesSizeInBytes = sizeof(mIndices[0]) * mIndexSize;
|
||||
const size_t bitmapsSizeInBytes = sizeof(mBitmaps[0]) * mBitmapSize;
|
||||
if (size != sizeof(SparseBitSetHeader) + indicesSizeInBytes + bitmapsSizeInBytes) {
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
data += sizeof(SparseBitSetHeader);
|
||||
mIndices = reinterpret_cast<decltype(mIndices)>(data);
|
||||
data += indicesSizeInBytes;
|
||||
mBitmaps = reinterpret_cast<decltype(mBitmaps)>(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t SparseBitSet::writeToBuffer(uint8_t* out) const{
|
||||
// See comments in SparseBitSet::initFromBuffer for the data structure.
|
||||
const size_t indicesSizeInBytes = sizeof(mIndices[0]) * mIndexSize;
|
||||
const size_t bitmapsSizeInBytes = sizeof(mBitmaps[0]) * mBitmapSize;
|
||||
size_t necessarySize = sizeof(SparseBitSetHeader) + indicesSizeInBytes + bitmapsSizeInBytes;
|
||||
if (out != nullptr) {
|
||||
SparseBitSetHeader* header = reinterpret_cast<SparseBitSetHeader*>(out);
|
||||
header->maxValue = mMaxVal;
|
||||
header->zeroPageIndex = mZeroPageIndex;
|
||||
header->indexSize = mIndexSize;
|
||||
header->bitmapSize = mBitmapSize;
|
||||
|
||||
out += sizeof(SparseBitSetHeader);
|
||||
memcpy(out, mIndices, indicesSizeInBytes);
|
||||
out += indicesSizeInBytes;
|
||||
memcpy(out, mBitmaps, bitmapsSizeInBytes);
|
||||
}
|
||||
return necessarySize;
|
||||
}
|
||||
|
||||
int SparseBitSet::CountLeadingZeros(element x) {
|
||||
|
||||
@ -22,6 +22,7 @@ perftest_src_files := \
|
||||
../util/MinikinFontForTest.cpp \
|
||||
../util/UnicodeUtils.cpp \
|
||||
FontCollection.cpp \
|
||||
FontFamily.cpp \
|
||||
FontLanguage.cpp \
|
||||
GraphemeBreak.cpp \
|
||||
Hyphenator.cpp \
|
||||
|
||||
54
tests/perftests/FontFamily.cpp
Normal file
54
tests/perftests/FontFamily.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <minikin/FontFamily.h>
|
||||
#include "../util/MinikinFontForTest.h"
|
||||
|
||||
namespace minikin {
|
||||
|
||||
static void BM_FontFamily_create(benchmark::State& state) {
|
||||
std::shared_ptr<MinikinFontForTest> minikinFont =
|
||||
std::make_shared<MinikinFontForTest>("/system/fonts/NotoSansCJK-Regular.ttc", 0);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
std::shared_ptr<FontFamily> family = std::make_shared<FontFamily>(
|
||||
std::vector<Font>({Font(minikinFont, FontStyle())}));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_FontFamily_create);
|
||||
|
||||
static void BM_FontFamily_create_fromBuffer(benchmark::State& state) {
|
||||
std::shared_ptr<MinikinFontForTest> minikinFont =
|
||||
std::make_shared<MinikinFontForTest>("/system/fonts/NotoSansCJK-Regular.ttc", 0);
|
||||
|
||||
std::shared_ptr<FontFamily> family = std::make_shared<FontFamily>(
|
||||
std::vector<Font>({Font(minikinFont, FontStyle())}));
|
||||
|
||||
size_t bufSize = family->writeAcceleratorTable(nullptr);
|
||||
std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufSize]);
|
||||
family->writeAcceleratorTable(buffer.get());
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
std::shared_ptr<FontFamily> family = std::make_shared<FontFamily>(
|
||||
std::vector<Font>({Font(minikinFont, FontStyle())}), buffer.get(), bufSize);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_FontFamily_create_fromBuffer);
|
||||
|
||||
} // namespace minikin
|
||||
@ -76,6 +76,7 @@ LOCAL_SRC_FILES += \
|
||||
GraphemeBreakTests.cpp \
|
||||
LayoutTest.cpp \
|
||||
LayoutUtilsTest.cpp \
|
||||
SparseBitSetTest.cpp \
|
||||
UnicodeUtilsTest.cpp \
|
||||
WordBreakerTests.cpp
|
||||
|
||||
|
||||
140
tests/unittest/SparseBitSetTest.cpp
Normal file
140
tests/unittest/SparseBitSetTest.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <minikin/SparseBitSet.h>
|
||||
|
||||
namespace minikin {
|
||||
|
||||
TEST(SparseBitSetTest, randomTest) {
|
||||
const uint32_t kTestRangeNum = 4096;
|
||||
|
||||
std::mt19937 mt; // Fix seeds to be able to reproduce the result.
|
||||
std::uniform_int_distribution<uint16_t> distribution(1, 512);
|
||||
|
||||
std::vector<uint32_t> range { distribution(mt) };
|
||||
for (size_t i = 1; i < kTestRangeNum * 2; ++i) {
|
||||
range.push_back((range.back() - 1) + distribution(mt));
|
||||
}
|
||||
|
||||
SparseBitSet bitset;
|
||||
bitset.initFromRanges(range.data(), range.size() / 2);
|
||||
|
||||
uint32_t ch = 0;
|
||||
for (size_t i = 0; i < range.size() / 2; ++i) {
|
||||
uint32_t start = range[i * 2];
|
||||
uint32_t end = range[i * 2 + 1];
|
||||
|
||||
for (; ch < start; ch++) {
|
||||
ASSERT_FALSE(bitset.get(ch)) << std::hex << ch;
|
||||
}
|
||||
for (; ch < end; ch++) {
|
||||
ASSERT_TRUE(bitset.get(ch)) << std::hex << ch;
|
||||
}
|
||||
}
|
||||
for (; ch < 0x1FFFFFF; ++ch) {
|
||||
ASSERT_FALSE(bitset.get(ch)) << std::hex << ch;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SparseBitSetTest, randomTest_restoredFromBuffer) {
|
||||
const uint32_t kTestRangeNum = 4096;
|
||||
|
||||
std::mt19937 mt; // Fix seeds to be able to reproduce the result.
|
||||
std::uniform_int_distribution<uint16_t> distribution(1, 512);
|
||||
|
||||
std::vector<uint32_t> range { distribution(mt) };
|
||||
for (size_t i = 1; i < kTestRangeNum * 2; ++i) {
|
||||
range.push_back((range.back() - 1) + distribution(mt));
|
||||
}
|
||||
|
||||
SparseBitSet tmpBitset;
|
||||
tmpBitset.initFromRanges(range.data(), range.size() / 2);
|
||||
|
||||
size_t bufSize = tmpBitset.writeToBuffer(nullptr);
|
||||
ASSERT_NE(0U, bufSize);
|
||||
std::vector<uint8_t> buffer(bufSize);
|
||||
tmpBitset.writeToBuffer(buffer.data());
|
||||
|
||||
SparseBitSet bitset;
|
||||
bitset.initFromBuffer(buffer.data(), buffer.size());
|
||||
|
||||
uint32_t ch = 0;
|
||||
for (size_t i = 0; i < range.size() / 2; ++i) {
|
||||
uint32_t start = range[i * 2];
|
||||
uint32_t end = range[i * 2 + 1];
|
||||
|
||||
for (; ch < start; ch++) {
|
||||
ASSERT_FALSE(bitset.get(ch)) << std::hex << ch;
|
||||
}
|
||||
for (; ch < end; ch++) {
|
||||
ASSERT_TRUE(bitset.get(ch)) << std::hex << ch;
|
||||
}
|
||||
}
|
||||
for (; ch < 0x1FFFFFF; ++ch) {
|
||||
ASSERT_FALSE(bitset.get(ch)) << std::hex << ch;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SparseBitSetTest, emptyBitSet) {
|
||||
SparseBitSet bitset;
|
||||
uint32_t empty_bitset[4] = {
|
||||
0 /* max value */, 0 /* zero page index */, 0 /* index size */, 0 /* bitmap size */
|
||||
};
|
||||
EXPECT_TRUE(bitset.initFromBuffer(
|
||||
reinterpret_cast<uint8_t*>(empty_bitset), sizeof(empty_bitset)));
|
||||
}
|
||||
|
||||
TEST(SparseBitSetTest, invalidData) {
|
||||
SparseBitSet bitset;
|
||||
EXPECT_FALSE(bitset.initFromBuffer(nullptr, 0));
|
||||
|
||||
// Buffer is too small.
|
||||
uint32_t small_buffer[3] = { 0, 0, 0 };
|
||||
EXPECT_FALSE(bitset.initFromBuffer(
|
||||
reinterpret_cast<uint8_t*>(small_buffer), sizeof(small_buffer)));
|
||||
|
||||
// Buffer size does not match with necessary size.
|
||||
uint32_t invalid_size_buffer[4] = {
|
||||
0x12345678 /* max value */, 0 /* zero page index */, 0x50 /* index size*/,
|
||||
0x80 /* bitmap size */
|
||||
};
|
||||
EXPECT_FALSE(bitset.initFromBuffer(
|
||||
reinterpret_cast<uint8_t*>(invalid_size_buffer), sizeof(invalid_size_buffer)));
|
||||
|
||||
// max value, index size, bitmap size must be zero if the bitset is empty.
|
||||
uint32_t invalid_empty_bitset1[4] = {
|
||||
1 /* max value */, 0 /* zero page index */, 0 /* index size */, 0 /* bitmap size */
|
||||
};
|
||||
EXPECT_FALSE(bitset.initFromBuffer(
|
||||
reinterpret_cast<uint8_t*>(invalid_empty_bitset1), sizeof(invalid_empty_bitset1)));
|
||||
|
||||
uint32_t invalid_empty_bitset2[4] = {
|
||||
0 /* max value */, 0 /* zero page index */, 1 /* index size */, 0 /* bitmap size */
|
||||
};
|
||||
EXPECT_FALSE(bitset.initFromBuffer(
|
||||
reinterpret_cast<uint8_t*>(invalid_empty_bitset2), sizeof(invalid_empty_bitset2)));
|
||||
|
||||
uint32_t invalid_empty_bitset3[4] = {
|
||||
0 /* max value */, 0 /* zero page index */, 0 /* index size */, 1 /* bitmap size */
|
||||
};
|
||||
EXPECT_FALSE(bitset.initFromBuffer(
|
||||
reinterpret_cast<uint8_t*>(invalid_empty_bitset3), sizeof(invalid_empty_bitset3)));
|
||||
}
|
||||
|
||||
} // namespace minikin
|
||||
Loading…
x
Reference in New Issue
Block a user