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.
5 #include "net/disk_cache/blockfile/bitmap.h"
9 #include "base/logging.h"
13 // Returns the number of trailing zeros.
14 int FindLSBSetNonZero(uint32 word
) {
15 // Get the LSB, put it on the exponent of a 32 bit float and remove the
16 // mantisa and the bias. This code requires IEEE 32 bit float compliance.
17 float f
= static_cast<float>(word
& -static_cast<int>(word
));
19 // We use a union to go around strict-aliasing complains.
26 return (x
.as_uint
>> 23) - 0x7f;
29 // Returns the index of the first bit set to |value| from |word|. This code
30 // assumes that we'll be able to find that bit.
31 int FindLSBNonEmpty(uint32 word
, bool value
) {
32 // If we are looking for 0, negate |word| and look for 1.
36 return FindLSBSetNonZero(word
);
41 namespace disk_cache
{
43 Bitmap::Bitmap(int num_bits
, bool clear_bits
)
44 : num_bits_(num_bits
),
45 array_size_(RequiredArraySize(num_bits
)),
47 map_
= new uint32
[array_size_
];
49 // Initialize all of the bits.
54 Bitmap::Bitmap(uint32
* map
, int num_bits
, int num_words
)
57 // If size is larger than necessary, trim because array_size_ is used
58 // as a bound by various methods.
59 array_size_(std::min(RequiredArraySize(num_bits
), num_words
)),
68 void Bitmap::Resize(int num_bits
, bool clear_bits
) {
69 DCHECK(alloc_
|| !map_
);
70 const int old_maxsize
= num_bits_
;
71 const int old_array_size
= array_size_
;
72 array_size_
= RequiredArraySize(num_bits
);
74 if (array_size_
!= old_array_size
) {
75 uint32
* new_map
= new uint32
[array_size_
];
76 // Always clear the unused bits in the last word.
77 new_map
[array_size_
- 1] = 0;
79 sizeof(*map_
) * std::min(array_size_
, old_array_size
));
81 delete[] map_
; // No need to check for NULL.
87 if (old_maxsize
< num_bits_
&& clear_bits
) {
88 SetRange(old_maxsize
, num_bits_
, false);
92 void Bitmap::Set(int index
, bool value
) {
93 DCHECK_LT(index
, num_bits_
);
95 const int i
= index
& (kIntBits
- 1);
96 const int j
= index
/ kIntBits
;
100 map_
[j
] &= ~(1 << i
);
103 bool Bitmap::Get(int index
) const {
104 DCHECK_LT(index
, num_bits_
);
106 const int i
= index
& (kIntBits
-1);
107 const int j
= index
/ kIntBits
;
108 return ((map_
[j
] & (1 << i
)) != 0);
111 void Bitmap::Toggle(int index
) {
112 DCHECK_LT(index
, num_bits_
);
114 const int i
= index
& (kIntBits
- 1);
115 const int j
= index
/ kIntBits
;
119 void Bitmap::SetMapElement(int array_index
, uint32 value
) {
120 DCHECK_LT(array_index
, array_size_
);
121 DCHECK_GE(array_index
, 0);
122 map_
[array_index
] = value
;
125 uint32
Bitmap::GetMapElement(int array_index
) const {
126 DCHECK_LT(array_index
, array_size_
);
127 DCHECK_GE(array_index
, 0);
128 return map_
[array_index
];
131 void Bitmap::SetMap(const uint32
* map
, int size
) {
132 memcpy(map_
, map
, std::min(size
, array_size_
) * sizeof(*map_
));
135 void Bitmap::SetRange(int begin
, int end
, bool value
) {
136 DCHECK_LE(begin
, end
);
137 int start_offset
= begin
& (kIntBits
- 1);
139 // Set the bits in the first word.
140 int len
= std::min(end
- begin
, kIntBits
- start_offset
);
141 SetWordBits(begin
, len
, value
);
148 // Now set the bits in the last word.
149 int end_offset
= end
& (kIntBits
- 1);
151 SetWordBits(end
, end_offset
, value
);
153 // Set all the words in the middle.
154 memset(map_
+ (begin
/ kIntBits
), (value
? 0xFF : 0x00),
155 ((end
/ kIntBits
) - (begin
/ kIntBits
)) * sizeof(*map_
));
158 // Return true if any bit between begin inclusive and end exclusive
159 // is set. 0 <= begin <= end <= bits() is required.
160 bool Bitmap::TestRange(int begin
, int end
, bool value
) const {
161 DCHECK_LT(begin
, num_bits_
);
162 DCHECK_LE(end
, num_bits_
);
163 DCHECK_LE(begin
, end
);
167 // Return false immediately if the range is empty.
168 if (begin
>= end
|| end
<= 0)
171 // Calculate the indices of the words containing the first and last bits,
172 // along with the positions of the bits within those words.
173 int word
= begin
/ kIntBits
;
174 int offset
= begin
& (kIntBits
- 1);
175 int last_word
= (end
- 1) / kIntBits
;
176 int last_offset
= (end
- 1) & (kIntBits
- 1);
178 // If we are looking for zeros, negate the data from the map.
179 uint32 this_word
= map_
[word
];
181 this_word
= ~this_word
;
183 // If the range spans multiple words, discard the extraneous bits of the
184 // first word by shifting to the right, and then test the remaining bits.
185 if (word
< last_word
) {
186 if (this_word
>> offset
)
191 // Test each of the "middle" words that lies completely within the range.
192 while (word
< last_word
) {
193 this_word
= map_
[word
++];
195 this_word
= ~this_word
;
201 // Test the portion of the last word that lies within the range. (This logic
202 // also handles the case where the entire range lies within a single word.)
203 const uint32 mask
= ((2 << (last_offset
- offset
)) - 1) << offset
;
205 this_word
= map_
[last_word
];
207 this_word
= ~this_word
;
209 return (this_word
& mask
) != 0;
212 bool Bitmap::FindNextBit(int* index
, int limit
, bool value
) const {
213 DCHECK_LT(*index
, num_bits_
);
214 DCHECK_LE(limit
, num_bits_
);
215 DCHECK_LE(*index
, limit
);
216 DCHECK_GE(*index
, 0);
219 const int bit_index
= *index
;
220 if (bit_index
>= limit
|| limit
<= 0)
223 // From now on limit != 0, since if it was we would have returned false.
224 int word_index
= bit_index
>> kLogIntBits
;
225 uint32 one_word
= map_
[word_index
];
227 // Simple optimization where we can immediately return true if the first
228 // bit is set. This helps for cases where many bits are set, and doesn't
229 // hurt too much if not.
230 if (Get(bit_index
) == value
)
233 const int first_bit_offset
= bit_index
& (kIntBits
- 1);
235 // First word is special - we need to mask off leading bits.
236 uint32 mask
= 0xFFFFFFFF << first_bit_offset
;
243 uint32 empty_value
= value
? 0 : 0xFFFFFFFF;
245 // Loop through all but the last word. Note that 'limit' is one
246 // past the last bit we want to check, and we don't want to read
247 // past the end of "words". E.g. if num_bits_ == 32 only words[0] is
248 // valid, so we want to avoid reading words[1] when limit == 32.
249 const int last_word_index
= (limit
- 1) >> kLogIntBits
;
250 while (word_index
< last_word_index
) {
251 if (one_word
!= empty_value
) {
252 *index
= (word_index
<< kLogIntBits
) + FindLSBNonEmpty(one_word
, value
);
255 one_word
= map_
[++word_index
];
258 // Last word is special - we may need to mask off trailing bits. Note that
259 // 'limit' is one past the last bit we want to check, and if limit is a
260 // multiple of 32 we want to check all bits in this word.
261 const int last_bit_offset
= (limit
- 1) & (kIntBits
- 1);
262 mask
= 0xFFFFFFFE << last_bit_offset
;
268 if (one_word
!= empty_value
) {
269 *index
= (word_index
<< kLogIntBits
) + FindLSBNonEmpty(one_word
, value
);
275 int Bitmap::FindBits(int* index
, int limit
, bool value
) const {
276 DCHECK_LT(*index
, num_bits_
);
277 DCHECK_LE(limit
, num_bits_
);
278 DCHECK_LE(*index
, limit
);
279 DCHECK_GE(*index
, 0);
282 if (!FindNextBit(index
, limit
, value
))
285 // Now see how many bits have the same value.
287 if (!FindNextBit(&end
, limit
, !value
))
288 return limit
- *index
;
293 void Bitmap::SetWordBits(int start
, int len
, bool value
) {
294 DCHECK_LT(len
, kIntBits
);
299 int word
= start
/ kIntBits
;
300 int offset
= start
% kIntBits
;
302 uint32 to_add
= 0xffffffff << len
;
303 to_add
= (~to_add
) << offset
;
305 map_
[word
] |= to_add
;
307 map_
[word
] &= ~to_add
;
311 } // namespace disk_cache