OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/disk_cache/bitmap.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 |
| 9 namespace { |
| 10 |
| 11 // Returns the number of trailing zeros. |
| 12 int FindLSBSetNonZero(uint32 word) { |
| 13 // Get the LSB, put it on the exponent of a 32 bit float and remove the |
| 14 // mantisa and the bias. This code requires IEEE 32 bit float compliance. |
| 15 float f = static_cast<float>(word & -static_cast<int>(word)); |
| 16 |
| 17 // We use a union to go around strict-aliasing complains. |
| 18 union { |
| 19 float ieee_float; |
| 20 uint32 as_uint; |
| 21 } x; |
| 22 |
| 23 x.ieee_float = f; |
| 24 return (x.as_uint >> 23) - 0x7f; |
| 25 } |
| 26 |
| 27 // Returns the index of the first bit set to |value| from |word|. This code |
| 28 // assumes that we'll be able to find that bit. |
| 29 int FindLSBNonEmpty(uint32 word, bool value) { |
| 30 // If we are looking for 0, negate |word| and look for 1. |
| 31 if (!value) |
| 32 word = ~word; |
| 33 |
| 34 return FindLSBSetNonZero(word); |
| 35 } |
| 36 |
| 37 } |
| 38 |
| 39 namespace disk_cache { |
| 40 |
| 41 void Bitmap::Resize(int num_bits, bool clear_bits) { |
| 42 DCHECK(alloc_ || !map_); |
| 43 const int old_maxsize = num_bits_; |
| 44 const int old_array_size = array_size_; |
| 45 array_size_ = RequiredArraySize(num_bits); |
| 46 |
| 47 if (array_size_ != old_array_size) { |
| 48 uint32* new_map = new uint32[array_size_]; |
| 49 // Always clear the unused bits in the last word. |
| 50 new_map[array_size_ - 1] = 0; |
| 51 memcpy(new_map, map_, |
| 52 sizeof(*map_) * std::min(array_size_, old_array_size)); |
| 53 if (alloc_) |
| 54 delete[] map_; // No need to check for NULL. |
| 55 map_ = new_map; |
| 56 alloc_ = true; |
| 57 } |
| 58 |
| 59 num_bits_ = num_bits; |
| 60 if (old_maxsize < num_bits_ && clear_bits) { |
| 61 SetRange(old_maxsize, num_bits_, false); |
| 62 } |
| 63 } |
| 64 |
| 65 void Bitmap::Set(int index, bool value) { |
| 66 DCHECK_LT(index, num_bits_); |
| 67 DCHECK_GE(index, 0); |
| 68 const int i = index & (kIntBits - 1); |
| 69 const int j = index / kIntBits; |
| 70 if (value) |
| 71 map_[j] |= (1 << i); |
| 72 else |
| 73 map_[j] &= ~(1 << i); |
| 74 } |
| 75 |
| 76 bool Bitmap::Get(int index) const { |
| 77 DCHECK_LT(index, num_bits_); |
| 78 DCHECK_GE(index, 0); |
| 79 const int i = index & (kIntBits-1); |
| 80 const int j = index / kIntBits; |
| 81 return map_[j] & (1 << i) ? true : false; |
| 82 } |
| 83 |
| 84 void Bitmap::Toggle(int index) { |
| 85 DCHECK_LT(index, num_bits_); |
| 86 DCHECK_GE(index, 0); |
| 87 const int i = index & (kIntBits - 1); |
| 88 const int j = index / kIntBits; |
| 89 map_[j] ^= (1 << i); |
| 90 } |
| 91 |
| 92 void Bitmap::SetMapElement(int array_index, uint32 value) { |
| 93 DCHECK_LT(array_index, array_size_); |
| 94 DCHECK_GE(array_index, 0); |
| 95 map_[array_index] = value; |
| 96 } |
| 97 |
| 98 uint32 Bitmap::GetMapElement(int array_index) const { |
| 99 DCHECK_LT(array_index, array_size_); |
| 100 DCHECK_GE(array_index, 0); |
| 101 return map_[array_index]; |
| 102 } |
| 103 |
| 104 void Bitmap::SetMap(const uint32* map, int size) { |
| 105 memcpy(map_, map, std::min(size, array_size_) * sizeof(*map_)); |
| 106 } |
| 107 |
| 108 void Bitmap::SetWordBits(int start, int len, bool value) { |
| 109 DCHECK_LT(len, kIntBits); |
| 110 if (!len) |
| 111 return; |
| 112 |
| 113 int word = start / kIntBits; |
| 114 int offset = start % kIntBits; |
| 115 |
| 116 uint32 to_add = 0xffffffff << len; |
| 117 to_add = (~to_add) << offset; |
| 118 if (value) { |
| 119 map_[word] |= to_add; |
| 120 } else { |
| 121 map_[word] &= ~to_add; |
| 122 } |
| 123 } |
| 124 |
| 125 void Bitmap::SetRange(int begin, int end, bool value) { |
| 126 int start_offset = begin & (kIntBits - 1); |
| 127 if (start_offset) { |
| 128 // Set the bits in the first word. |
| 129 int len = std::min(end - begin, kIntBits - start_offset); |
| 130 SetWordBits(begin, len, value); |
| 131 begin += len; |
| 132 } |
| 133 |
| 134 if (begin == end) |
| 135 return; |
| 136 |
| 137 // Now set the bits in the last word. |
| 138 int end_offset = end & (kIntBits - 1); |
| 139 end -= end_offset; |
| 140 SetWordBits(end, end_offset, value); |
| 141 |
| 142 // Set all the words in the middle. |
| 143 memset(map_ + (begin / kIntBits), (value ? 0xFF : 0x00), |
| 144 ((end / kIntBits) - (begin / kIntBits)) * sizeof(*map_)); |
| 145 } |
| 146 |
| 147 // Return true if any bit between begin inclusive and end exclusive |
| 148 // is set. 0 <= begin <= end <= bits() is required. |
| 149 bool Bitmap::TestRange(int begin, int end, bool value) const { |
| 150 DCHECK_LT(begin, num_bits_); |
| 151 DCHECK_LE(end, num_bits_); |
| 152 DCHECK_LE(begin, end); |
| 153 DCHECK_GE(begin, 0); |
| 154 DCHECK_GE(end, 0); |
| 155 |
| 156 // Return false immediately if the range is empty. |
| 157 if (begin >= end || end <= 0) |
| 158 return false; |
| 159 |
| 160 // Calculate the indices of the words containing the first and last bits, |
| 161 // along with the positions of the bits within those words. |
| 162 int word = begin / kIntBits; |
| 163 int offset = begin & (kIntBits - 1); |
| 164 int last_word = (end - 1) / kIntBits; |
| 165 int last_offset = (end - 1) & (kIntBits - 1); |
| 166 |
| 167 // If we are looking for zeros, negate the data from the map. |
| 168 uint32 this_word = map_[word]; |
| 169 if (!value) |
| 170 this_word = ~this_word; |
| 171 |
| 172 // If the range spans multiple words, discard the extraneous bits of the |
| 173 // first word by shifting to the right, and then test the remaining bits. |
| 174 if (word < last_word) { |
| 175 if (this_word >> offset) |
| 176 return true; |
| 177 offset = 0; |
| 178 |
| 179 word++; |
| 180 // Test each of the "middle" words that lies completely within the range. |
| 181 while (word < last_word) { |
| 182 this_word = map_[word++]; |
| 183 if (!value) |
| 184 this_word = ~this_word; |
| 185 if (this_word) |
| 186 return true; |
| 187 } |
| 188 } |
| 189 |
| 190 // Test the portion of the last word that lies within the range. (This logic |
| 191 // also handles the case where the entire range lies within a single word.) |
| 192 const uint32 mask = ((2 << (last_offset - offset)) - 1) << offset; |
| 193 |
| 194 this_word = map_[last_word]; |
| 195 if (!value) |
| 196 this_word = ~this_word; |
| 197 |
| 198 return (this_word & mask) != 0; |
| 199 } |
| 200 |
| 201 bool Bitmap::FindNextBit(int* index, int limit, bool value) const { |
| 202 DCHECK_LT(*index, num_bits_); |
| 203 DCHECK_LE(limit, num_bits_); |
| 204 DCHECK_LE(*index, limit); |
| 205 DCHECK_GE(*index, 0); |
| 206 DCHECK_GE(limit, 0); |
| 207 |
| 208 const int bit_index = *index; |
| 209 if (bit_index >= limit || limit <= 0) |
| 210 return false; |
| 211 |
| 212 // From now on limit != 0, since if it was we would have returned false. |
| 213 int word_index = bit_index >> kLogIntBits; |
| 214 uint32 one_word = map_[word_index]; |
| 215 |
| 216 // Simple optimization where we can immediately return true if the first |
| 217 // bit is set. This helps for cases where many bits are set, and doesn't |
| 218 // hurt too much if not. |
| 219 if (Get(bit_index) == value) |
| 220 return true; |
| 221 |
| 222 const int first_bit_offset = bit_index & (kIntBits - 1); |
| 223 |
| 224 // First word is special - we need to mask off leading bits. |
| 225 uint32 mask = 0xFFFFFFFF << first_bit_offset; |
| 226 if (value) { |
| 227 one_word &= mask; |
| 228 } else { |
| 229 one_word |= ~mask; |
| 230 } |
| 231 |
| 232 uint32 empty_value = value ? 0 : 0xFFFFFFFF; |
| 233 |
| 234 // Loop through all but the last word. Note that 'limit' is one |
| 235 // past the last bit we want to check, and we don't want to read |
| 236 // past the end of "words". E.g. if num_bits_ == 32 only words[0] is |
| 237 // valid, so we want to avoid reading words[1] when limit == 32. |
| 238 const int last_word_index = (limit - 1) >> kLogIntBits; |
| 239 while (word_index < last_word_index) { |
| 240 if (one_word != empty_value) { |
| 241 *index = (word_index << kLogIntBits) + FindLSBNonEmpty(one_word, value); |
| 242 return true; |
| 243 } |
| 244 one_word = map_[++word_index]; |
| 245 } |
| 246 |
| 247 // Last word is special - we may need to mask off trailing bits. Note that |
| 248 // 'limit' is one past the last bit we want to check, and if limit is a |
| 249 // multiple of 32 we want to check all bits in this word. |
| 250 const int last_bit_offset = (limit - 1) & (kIntBits - 1); |
| 251 mask = 0xFFFFFFFE << last_bit_offset; |
| 252 if (value) { |
| 253 one_word &= ~mask; |
| 254 } else { |
| 255 one_word |= mask; |
| 256 } |
| 257 if (one_word != empty_value) { |
| 258 *index = (word_index << kLogIntBits) + FindLSBNonEmpty(one_word, value); |
| 259 return true; |
| 260 } |
| 261 return false; |
| 262 } |
| 263 |
| 264 int Bitmap::FindBits(int* index, int limit, bool value) const { |
| 265 DCHECK_LT(*index, num_bits_); |
| 266 DCHECK_LE(limit, num_bits_); |
| 267 DCHECK_LE(*index, limit); |
| 268 DCHECK_GE(*index, 0); |
| 269 DCHECK_GE(limit, 0); |
| 270 |
| 271 if (!FindNextBit(index, limit, value)) |
| 272 return false; |
| 273 |
| 274 // Now see how many bits have the same value. |
| 275 int end = *index; |
| 276 if (!FindNextBit(&end, limit, !value)) |
| 277 return limit - *index; |
| 278 |
| 279 return end - *index; |
| 280 } |
| 281 |
| 282 } // namespace disk_cache |
OLD | NEW |