SparseBitSet.cpp revision 1bbe03d215c9452bc9917111e63f19160cc5f56a
19cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien/*
29cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Copyright (C) 2012 The Android Open Source Project
39cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien *
49cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Licensed under the Apache License, Version 2.0 (the "License");
59cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * you may not use this file except in compliance with the License.
69cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * You may obtain a copy of the License at
79cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien *
89cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien *      http://www.apache.org/licenses/LICENSE-2.0
99cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien *
109cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Unless required by applicable law or agreed to in writing, software
119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * distributed under the License is distributed on an "AS IS" BASIS,
129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * See the License for the specific language governing permissions and
149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * limitations under the License.
159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien */
169cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
179cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <stddef.h>
189cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <string.h>
199cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/SparseBitSet.h>
209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Leviennamespace android {
229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienconst uint32_t SparseBitSet::kNotFound;
249cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
259cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienvoid SparseBitSet::clear() {
269cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    mMaxVal = 0;
279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    mIndices.reset();
289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    mBitmaps.reset();
299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienuint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) {
329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    bool haveZeroPage = false;
339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t nonzeroPageEnd = 0;
349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t nPages = 0;
359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (size_t i = 0; i < nRanges; i++) {
369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t start = ranges[i * 2];
379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t end = ranges[i * 2 + 1];
389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t startPage = start >> kLogValuesPerPage;
399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t endPage = (end - 1) >> kLogValuesPerPage;
409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (startPage >= nonzeroPageEnd) {
419cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            if (startPage > nonzeroPageEnd) {
429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                if (!haveZeroPage) {
439cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    haveZeroPage = true;
449cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    nPages++;
459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            }
479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            nPages++;
489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
499cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        nPages += endPage - startPage;
509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        nonzeroPageEnd = endPage + 1;
519cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
529cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    return nPages;
539cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
549cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
559cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienvoid SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
569cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (nRanges == 0) {
579cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        mMaxVal = 0;
589cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        mIndices.reset();
599cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        mBitmaps.reset();
609cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return;
619cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
629cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    mMaxVal = ranges[nRanges * 2 - 1];
639cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
649cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    mIndices.reset(new uint32_t[indexSize]);
659cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t nPages = calcNumPages(ranges, nRanges);
669cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]);
679cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    memset(mBitmaps.get(), 0, nPages << (kLogValuesPerPage - 3));
689cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    mZeroPageIndex = noZeroPage;
699cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t nonzeroPageEnd = 0;
709cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t currentPage = 0;
719cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (size_t i = 0; i < nRanges; i++) {
729cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t start = ranges[i * 2];
739cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t end = ranges[i * 2 + 1];
749cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t startPage = start >> kLogValuesPerPage;
759cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t endPage = (end - 1) >> kLogValuesPerPage;
769cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (startPage >= nonzeroPageEnd) {
779cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            if (startPage > nonzeroPageEnd) {
789cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                if (mZeroPageIndex == noZeroPage) {
799cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
809cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
819cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
829cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    mIndices[j] = mZeroPageIndex;
839cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
849cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            }
859cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
869cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
879cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
889cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
899cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            ((start & kPageMask) >> kLogBitsPerEl);
909cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;
919cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (nElements == 1) {
929cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
931bbe03d215c9452bc9917111e63f19160cc5f56aDan Austin                (kElAllOnes << ((~end + 1) & kElMask));
949cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        } else {
959cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            mBitmaps[index] |= kElAllOnes >> (start & kElMask);
969cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            for (size_t j = 1; j < nElements - 1; j++) {
979cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                mBitmaps[index + j] = kElAllOnes;
989cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            }
991bbe03d215c9452bc9917111e63f19160cc5f56aDan Austin            mBitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask);
1009cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
1019cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        for (size_t j = startPage + 1; j < endPage + 1; j++) {
1029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
1039cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
1049cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        nonzeroPageEnd = endPage + 1;
1059cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1069cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1079cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
1089cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienint SparseBitSet::CountLeadingZeros(element x) {
109329ae0639e332fa0ca85049f738776083b6dbafcBehdad Esfahbod    // Note: GCC / clang builtin
110329ae0639e332fa0ca85049f738776083b6dbafcBehdad Esfahbod    return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x);
1119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
1139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienuint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const {
1149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (fromIndex >= mMaxVal) {
1159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return kNotFound;
1169cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1179cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t fromPage = fromIndex >> kLogValuesPerPage;
1189cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const element* bitmap = &mBitmaps[mIndices[fromPage]];
1199cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl;
1209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask));
1219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (e != 0) {
1229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return (fromIndex & ~kElMask) + CountLeadingZeros(e);
1239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1249cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (uint32_t j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
1259cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        e = bitmap[j];
1269cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (e != 0) {
1279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
1289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
1299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage;
1319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (uint32_t page = fromPage + 1; page < maxPage; page++) {
1329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t index = mIndices[page];
1339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (index == mZeroPageIndex) {
1349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            continue;
1359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
1369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        bitmap = &mBitmaps[index];
1379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
1389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            e = bitmap[j];
1399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            if (e != 0) {
1409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                return (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
1419cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            }
1429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
1439cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1449cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    return kNotFound;
1459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
1479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}  // namespace android
148