SparseBitSet.cpp revision 9cc9bbe1461f359f0b27c5e7645c17dda001ab1d
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 <stddef.h> 18#include <string.h> 19#include <minikin/SparseBitSet.h> 20 21namespace android { 22 23const uint32_t SparseBitSet::kNotFound; 24 25void SparseBitSet::clear() { 26 mMaxVal = 0; 27 mIndices.reset(); 28 mBitmaps.reset(); 29} 30 31uint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) { 32 bool haveZeroPage = false; 33 uint32_t nonzeroPageEnd = 0; 34 uint32_t nPages = 0; 35 for (size_t i = 0; i < nRanges; i++) { 36 uint32_t start = ranges[i * 2]; 37 uint32_t end = ranges[i * 2 + 1]; 38 uint32_t startPage = start >> kLogValuesPerPage; 39 uint32_t endPage = (end - 1) >> kLogValuesPerPage; 40 if (startPage >= nonzeroPageEnd) { 41 if (startPage > nonzeroPageEnd) { 42 if (!haveZeroPage) { 43 haveZeroPage = true; 44 nPages++; 45 } 46 } 47 nPages++; 48 } 49 nPages += endPage - startPage; 50 nonzeroPageEnd = endPage + 1; 51 } 52 return nPages; 53} 54 55void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) { 56 if (nRanges == 0) { 57 mMaxVal = 0; 58 mIndices.reset(); 59 mBitmaps.reset(); 60 return; 61 } 62 mMaxVal = ranges[nRanges * 2 - 1]; 63 size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage; 64 mIndices.reset(new uint32_t[indexSize]); 65 uint32_t nPages = calcNumPages(ranges, nRanges); 66 mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]); 67 memset(mBitmaps.get(), 0, nPages << (kLogValuesPerPage - 3)); 68 mZeroPageIndex = noZeroPage; 69 uint32_t nonzeroPageEnd = 0; 70 uint32_t currentPage = 0; 71 for (size_t i = 0; i < nRanges; i++) { 72 uint32_t start = ranges[i * 2]; 73 uint32_t end = ranges[i * 2 + 1]; 74 uint32_t startPage = start >> kLogValuesPerPage; 75 uint32_t endPage = (end - 1) >> kLogValuesPerPage; 76 if (startPage >= nonzeroPageEnd) { 77 if (startPage > nonzeroPageEnd) { 78 if (mZeroPageIndex == noZeroPage) { 79 mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); 80 } 81 for (uint32_t j = nonzeroPageEnd; j < startPage; j++) { 82 mIndices[j] = mZeroPageIndex; 83 } 84 } 85 mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); 86 } 87 88 size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) + 89 ((start & kPageMask) >> kLogBitsPerEl); 90 size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl; 91 if (nElements == 1) { 92 mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) & 93 (kElAllOnes << ((-end) & kElMask)); 94 } else { 95 mBitmaps[index] |= kElAllOnes >> (start & kElMask); 96 for (size_t j = 1; j < nElements - 1; j++) { 97 mBitmaps[index + j] = kElAllOnes; 98 } 99 mBitmaps[index + nElements - 1] |= kElAllOnes << ((-end) & kElMask); 100 } 101 for (size_t j = startPage + 1; j < endPage + 1; j++) { 102 mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl); 103 } 104 nonzeroPageEnd = endPage + 1; 105 } 106} 107 108// Note: this implementation depends on GCC builtin, and also assumes 32-bit elements. 109int SparseBitSet::CountLeadingZeros(element x) { 110 return __builtin_clz(x); 111} 112 113uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const { 114 if (fromIndex >= mMaxVal) { 115 return kNotFound; 116 } 117 uint32_t fromPage = fromIndex >> kLogValuesPerPage; 118 const element* bitmap = &mBitmaps[mIndices[fromPage]]; 119 uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl; 120 element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask)); 121 if (e != 0) { 122 return (fromIndex & ~kElMask) + CountLeadingZeros(e); 123 } 124 for (uint32_t j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) { 125 e = bitmap[j]; 126 if (e != 0) { 127 return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e); 128 } 129 } 130 uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage; 131 for (uint32_t page = fromPage + 1; page < maxPage; page++) { 132 uint32_t index = mIndices[page]; 133 if (index == mZeroPageIndex) { 134 continue; 135 } 136 bitmap = &mBitmaps[index]; 137 for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) { 138 e = bitmap[j]; 139 if (e != 0) { 140 return (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + CountLeadingZeros(e); 141 } 142 } 143 } 144 return kNotFound; 145} 146 147} // namespace android 148