SparseBitSet.cpp revision fbbc5a6b361c623e47a433f83e7200b4e2ba3501
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 121struct SparseBitSetHeader { 122 uint32_t maxValue; 123 uint32_t zeroPageIndex; 124 uint32_t indexSize; 125 uint32_t bitmapSize; 126}; 127 128bool SparseBitSet::initFromBuffer(const uint8_t* data, size_t size) { 129 // No need to be concerned about endianness here since Intel x86 CPUs are little-endian. ARM 130 // CPUs are bi-endian but the endianness is only changeable at reset time and is impossible to 131 // change at runtime. Thus incoming data is guaranteed to have the same endianness as when it 132 // was created. 133 134 if (data == nullptr || size < sizeof(SparseBitSetHeader)) { 135 clear(); 136 return false; 137 } 138 139 // The serialized data starts with SparseBitSetHeader. 140 const SparseBitSetHeader* header = reinterpret_cast<const SparseBitSetHeader*>(data); 141 mMaxVal = header->maxValue; 142 mZeroPageIndex = header->zeroPageIndex; 143 mIndexSize = header->indexSize; 144 mBitmapSize = header->bitmapSize; 145 146 mOwnIndicesAndBitmaps = false; 147 if (mIndexSize == 0 || mBitmapSize == 0 || mMaxVal == 0) { 148 const bool isValidEmptyBitSet = (mIndexSize == 0 && mBitmapSize == 0 && mMaxVal == 0); 149 if (!isValidEmptyBitSet) { 150 clear(); 151 } 152 return isValidEmptyBitSet; 153 } 154 155 const size_t indicesSizeInBytes = sizeof(mIndices[0]) * mIndexSize; 156 const size_t bitmapsSizeInBytes = sizeof(mBitmaps[0]) * mBitmapSize; 157 if (size != sizeof(SparseBitSetHeader) + indicesSizeInBytes + bitmapsSizeInBytes) { 158 clear(); 159 return false; 160 } 161 data += sizeof(SparseBitSetHeader); 162 mIndices = reinterpret_cast<decltype(mIndices)>(data); 163 data += indicesSizeInBytes; 164 mBitmaps = reinterpret_cast<decltype(mBitmaps)>(data); 165 return true; 166} 167 168size_t SparseBitSet::writeToBuffer(uint8_t* out) const{ 169 // See comments in SparseBitSet::initFromBuffer for the data structure. 170 const size_t indicesSizeInBytes = sizeof(mIndices[0]) * mIndexSize; 171 const size_t bitmapsSizeInBytes = sizeof(mBitmaps[0]) * mBitmapSize; 172 size_t necessarySize = sizeof(SparseBitSetHeader) + indicesSizeInBytes + bitmapsSizeInBytes; 173 if (out != nullptr) { 174 SparseBitSetHeader* header = reinterpret_cast<SparseBitSetHeader*>(out); 175 header->maxValue = mMaxVal; 176 header->zeroPageIndex = mZeroPageIndex; 177 header->indexSize = mIndexSize; 178 header->bitmapSize = mBitmapSize; 179 180 out += sizeof(SparseBitSetHeader); 181 memcpy(out, mIndices, indicesSizeInBytes); 182 out += indicesSizeInBytes; 183 memcpy(out, mBitmaps, bitmapsSizeInBytes); 184 } 185 return necessarySize; 186} 187 188int SparseBitSet::CountLeadingZeros(element x) { 189 // Note: GCC / clang builtin 190 return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x); 191} 192 193uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const { 194 if (fromIndex >= mMaxVal) { 195 return kNotFound; 196 } 197 uint32_t fromPage = fromIndex >> kLogValuesPerPage; 198 const element* bitmap = &mBitmaps[mIndices[fromPage]]; 199 uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl; 200 element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask)); 201 if (e != 0) { 202 return (fromIndex & ~kElMask) + CountLeadingZeros(e); 203 } 204 for (uint32_t j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) { 205 e = bitmap[j]; 206 if (e != 0) { 207 return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e); 208 } 209 } 210 uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage; 211 for (uint32_t page = fromPage + 1; page < maxPage; page++) { 212 uint32_t index = mIndices[page]; 213 if (index == mZeroPageIndex) { 214 continue; 215 } 216 bitmap = &mBitmaps[index]; 217 for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) { 218 e = bitmap[j]; 219 if (e != 0) { 220 return (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + CountLeadingZeros(e); 221 } 222 } 223 } 224 return kNotFound; 225} 226 227} // namespace minikin 228