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