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