Home | History | Annotate | Download | only in minikin
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <cutils/log.h>
     18 #include <stddef.h>
     19 #include <string.h>
     20 #include <minikin/SparseBitSet.h>
     21 
     22 namespace android {
     23 
     24 const uint32_t SparseBitSet::kNotFound;
     25 
     26 void SparseBitSet::clear() {
     27     mMaxVal = 0;
     28     mIndices.reset();
     29     mBitmaps.reset();
     30 }
     31 
     32 uint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) {
     33     bool haveZeroPage = false;
     34     uint32_t nonzeroPageEnd = 0;
     35     uint32_t nPages = 0;
     36     for (size_t i = 0; i < nRanges; i++) {
     37         uint32_t start = ranges[i * 2];
     38         uint32_t end = ranges[i * 2 + 1];
     39         uint32_t startPage = start >> kLogValuesPerPage;
     40         uint32_t endPage = (end - 1) >> kLogValuesPerPage;
     41         if (startPage >= nonzeroPageEnd) {
     42             if (startPage > nonzeroPageEnd) {
     43                 if (!haveZeroPage) {
     44                     haveZeroPage = true;
     45                     nPages++;
     46                 }
     47             }
     48             nPages++;
     49         }
     50         nPages += endPage - startPage;
     51         nonzeroPageEnd = endPage + 1;
     52     }
     53     return nPages;
     54 }
     55 
     56 void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
     57     if (nRanges == 0) {
     58         mMaxVal = 0;
     59         mIndices.reset();
     60         mBitmaps.reset();
     61         return;
     62     }
     63     mMaxVal = ranges[nRanges * 2 - 1];
     64     size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
     65     mIndices.reset(new uint32_t[indexSize]);
     66     uint32_t nPages = calcNumPages(ranges, nRanges);
     67     mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]);
     68     memset(mBitmaps.get(), 0, nPages << (kLogValuesPerPage - 3));
     69     mZeroPageIndex = noZeroPage;
     70     uint32_t nonzeroPageEnd = 0;
     71     uint32_t currentPage = 0;
     72     for (size_t i = 0; i < nRanges; i++) {
     73         uint32_t start = ranges[i * 2];
     74         uint32_t end = ranges[i * 2 + 1];
     75         LOG_ALWAYS_FATAL_IF(end < start);  // make sure range size is nonnegative
     76         uint32_t startPage = start >> kLogValuesPerPage;
     77         uint32_t endPage = (end - 1) >> kLogValuesPerPage;
     78         if (startPage >= nonzeroPageEnd) {
     79             if (startPage > nonzeroPageEnd) {
     80                 if (mZeroPageIndex == noZeroPage) {
     81                     mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
     82                 }
     83                 for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
     84                     mIndices[j] = mZeroPageIndex;
     85                 }
     86             }
     87             mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
     88         }
     89 
     90         size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
     91             ((start & kPageMask) >> kLogBitsPerEl);
     92         size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;
     93         if (nElements == 1) {
     94             mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
     95                 (kElAllOnes << ((~end + 1) & kElMask));
     96         } else {
     97             mBitmaps[index] |= kElAllOnes >> (start & kElMask);
     98             for (size_t j = 1; j < nElements - 1; j++) {
     99                 mBitmaps[index + j] = kElAllOnes;
    100             }
    101             mBitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask);
    102         }
    103         for (size_t j = startPage + 1; j < endPage + 1; j++) {
    104             mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
    105         }
    106         nonzeroPageEnd = endPage + 1;
    107     }
    108 }
    109 
    110 int SparseBitSet::CountLeadingZeros(element x) {
    111     // Note: GCC / clang builtin
    112     return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x);
    113 }
    114 
    115 uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const {
    116     if (fromIndex >= mMaxVal) {
    117         return kNotFound;
    118     }
    119     uint32_t fromPage = fromIndex >> kLogValuesPerPage;
    120     const element* bitmap = &mBitmaps[mIndices[fromPage]];
    121     uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl;
    122     element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask));
    123     if (e != 0) {
    124         return (fromIndex & ~kElMask) + CountLeadingZeros(e);
    125     }
    126     for (uint32_t j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
    127         e = bitmap[j];
    128         if (e != 0) {
    129             return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
    130         }
    131     }
    132     uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage;
    133     for (uint32_t page = fromPage + 1; page < maxPage; page++) {
    134         uint32_t index = mIndices[page];
    135         if (index == mZeroPageIndex) {
    136             continue;
    137         }
    138         bitmap = &mBitmaps[index];
    139         for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
    140             e = bitmap[j];
    141             if (e != 0) {
    142                 return (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
    143             }
    144         }
    145     }
    146     return kNotFound;
    147 }
    148 
    149 }  // namespace android
    150