mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
To share the calculated coverage information across the processes, make SparseBitSet serializable. Bug: 34042446 Test: minikin_tests passes Change-Id: I0463138adcf234739bb3ce1cdadf382021921f3e
228 lines
8.0 KiB
C++
228 lines
8.0 KiB
C++
/*
|
|
* Copyright (C) 2012 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.
|
|
*/
|
|
|
|
#define LOG_TAG "SparseBitSet"
|
|
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include <log/log.h>
|
|
|
|
#include <minikin/SparseBitSet.h>
|
|
|
|
namespace minikin {
|
|
|
|
const uint32_t SparseBitSet::kNotFound;
|
|
|
|
void SparseBitSet::clear() {
|
|
mMaxVal = 0;
|
|
if (mOwnIndicesAndBitmaps) {
|
|
delete[] mIndices;
|
|
delete[] mBitmaps;
|
|
mIndexSize = 0;
|
|
mBitmapSize = 0;
|
|
mOwnIndicesAndBitmaps = false;
|
|
}
|
|
}
|
|
|
|
uint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) {
|
|
bool haveZeroPage = false;
|
|
uint32_t nonzeroPageEnd = 0;
|
|
uint32_t nPages = 0;
|
|
for (size_t i = 0; i < nRanges; i++) {
|
|
uint32_t start = ranges[i * 2];
|
|
uint32_t end = ranges[i * 2 + 1];
|
|
uint32_t startPage = start >> kLogValuesPerPage;
|
|
uint32_t endPage = (end - 1) >> kLogValuesPerPage;
|
|
if (startPage >= nonzeroPageEnd) {
|
|
if (startPage > nonzeroPageEnd) {
|
|
if (!haveZeroPage) {
|
|
haveZeroPage = true;
|
|
nPages++;
|
|
}
|
|
}
|
|
nPages++;
|
|
}
|
|
nPages += endPage - startPage;
|
|
nonzeroPageEnd = endPage + 1;
|
|
}
|
|
return nPages;
|
|
}
|
|
|
|
void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
|
|
if (nRanges == 0) {
|
|
clear();
|
|
return;
|
|
}
|
|
mMaxVal = ranges[nRanges * 2 - 1];
|
|
mIndexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
|
|
uint32_t* indices = new uint32_t[mIndexSize];
|
|
uint32_t nPages = calcNumPages(ranges, nRanges);
|
|
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;
|
|
for (size_t i = 0; i < nRanges; i++) {
|
|
uint32_t start = ranges[i * 2];
|
|
uint32_t end = ranges[i * 2 + 1];
|
|
LOG_ALWAYS_FATAL_IF(end < start); // make sure range size is nonnegative
|
|
uint32_t startPage = start >> kLogValuesPerPage;
|
|
uint32_t endPage = (end - 1) >> kLogValuesPerPage;
|
|
if (startPage >= nonzeroPageEnd) {
|
|
if (startPage > nonzeroPageEnd) {
|
|
if (mZeroPageIndex == noZeroPage) {
|
|
mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
|
|
}
|
|
for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
|
|
indices[j] = mZeroPageIndex;
|
|
}
|
|
}
|
|
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) {
|
|
bitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
|
|
(kElAllOnes << ((~end + 1) & kElMask));
|
|
} else {
|
|
bitmaps[index] |= kElAllOnes >> (start & kElMask);
|
|
for (size_t j = 1; j < nElements - 1; j++) {
|
|
bitmaps[index + j] = kElAllOnes;
|
|
}
|
|
bitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask);
|
|
}
|
|
for (size_t j = startPage + 1; j < endPage + 1; j++) {
|
|
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) {
|
|
// Note: GCC / clang builtin
|
|
return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x);
|
|
}
|
|
|
|
uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const {
|
|
if (fromIndex >= mMaxVal) {
|
|
return kNotFound;
|
|
}
|
|
uint32_t fromPage = fromIndex >> kLogValuesPerPage;
|
|
const element* bitmap = &mBitmaps[mIndices[fromPage]];
|
|
uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl;
|
|
element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask));
|
|
if (e != 0) {
|
|
return (fromIndex & ~kElMask) + CountLeadingZeros(e);
|
|
}
|
|
for (uint32_t j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
|
|
e = bitmap[j];
|
|
if (e != 0) {
|
|
return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
|
|
}
|
|
}
|
|
uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage;
|
|
for (uint32_t page = fromPage + 1; page < maxPage; page++) {
|
|
uint32_t index = mIndices[page];
|
|
if (index == mZeroPageIndex) {
|
|
continue;
|
|
}
|
|
bitmap = &mBitmaps[index];
|
|
for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
|
|
e = bitmap[j];
|
|
if (e != 0) {
|
|
return (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
|
|
}
|
|
}
|
|
}
|
|
return kNotFound;
|
|
}
|
|
|
|
} // namespace minikin
|