mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
148 lines
5.2 KiB
C++
148 lines
5.2 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.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <minikin/SparseBitSet.h>
|
|
|
|
namespace android {
|
|
|
|
const uint32_t SparseBitSet::kNotFound;
|
|
|
|
void SparseBitSet::clear() {
|
|
mMaxVal = 0;
|
|
mIndices.reset();
|
|
mBitmaps.reset();
|
|
}
|
|
|
|
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) {
|
|
mMaxVal = 0;
|
|
mIndices.reset();
|
|
mBitmaps.reset();
|
|
return;
|
|
}
|
|
mMaxVal = ranges[nRanges * 2 - 1];
|
|
size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
|
|
mIndices.reset(new uint32_t[indexSize]);
|
|
uint32_t nPages = calcNumPages(ranges, nRanges);
|
|
mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]);
|
|
memset(mBitmaps.get(), 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];
|
|
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++) {
|
|
mIndices[j] = mZeroPageIndex;
|
|
}
|
|
}
|
|
mIndices[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)) &
|
|
(kElAllOnes << ((-end) & kElMask));
|
|
} else {
|
|
mBitmaps[index] |= kElAllOnes >> (start & kElMask);
|
|
for (size_t j = 1; j < nElements - 1; j++) {
|
|
mBitmaps[index + j] = kElAllOnes;
|
|
}
|
|
mBitmaps[index + nElements - 1] |= kElAllOnes << ((-end) & kElMask);
|
|
}
|
|
for (size_t j = startPage + 1; j < endPage + 1; j++) {
|
|
mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
|
|
}
|
|
nonzeroPageEnd = endPage + 1;
|
|
}
|
|
}
|
|
|
|
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 android
|