• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2009 The Chromium Authors
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/blockfile/bitmap.h"
6 
7 #include <algorithm>
8 
9 #include "base/bits.h"
10 #include "base/check_op.h"
11 
12 namespace {
13 // Returns the index of the first bit set to |value| from |word|. This code
14 // assumes that we'll be able to find that bit.
FindLSBNonEmpty(uint32_t word,bool value)15 int FindLSBNonEmpty(uint32_t word, bool value) {
16   // If we are looking for 0, negate |word| and look for 1.
17   if (!value)
18     word = ~word;
19 
20   return base::bits::CountTrailingZeroBits(word);
21 }
22 
23 }  // namespace
24 
25 namespace disk_cache {
26 
27 Bitmap::Bitmap() = default;
28 
Bitmap(int num_bits,bool clear_bits)29 Bitmap::Bitmap(int num_bits, bool clear_bits)
30     : num_bits_(num_bits),
31       array_size_(RequiredArraySize(num_bits)),
32       allocated_map_(std::make_unique<uint32_t[]>(array_size_)) {
33   map_ = allocated_map_.get();
34 
35   // Initialize all of the bits.
36   if (clear_bits)
37     Clear();
38 }
39 
Bitmap(uint32_t * map,int num_bits,int num_words)40 Bitmap::Bitmap(uint32_t* map, int num_bits, int num_words)
41     : num_bits_(num_bits),
42       // If size is larger than necessary, trim because array_size_ is used
43       // as a bound by various methods.
44       array_size_(std::min(RequiredArraySize(num_bits), num_words)),
45       map_(map) {}
46 
47 Bitmap::~Bitmap() = default;
48 
Resize(int num_bits,bool clear_bits)49 void Bitmap::Resize(int num_bits, bool clear_bits) {
50   DCHECK(allocated_map_ || !map_);
51   const int old_maxsize = num_bits_;
52   const int old_array_size = array_size_;
53   array_size_ = RequiredArraySize(num_bits);
54 
55   if (array_size_ != old_array_size) {
56     auto new_map = std::make_unique<uint32_t[]>(array_size_);
57     // Always clear the unused bits in the last word.
58     new_map[array_size_ - 1] = 0;
59     memcpy(new_map.get(), map_,
60            sizeof(*map_) * std::min(array_size_, old_array_size));
61     map_ = new_map.get();
62     allocated_map_ = std::move(new_map);
63   }
64 
65   num_bits_ = num_bits;
66   if (old_maxsize < num_bits_ && clear_bits) {
67     SetRange(old_maxsize, num_bits_, false);
68   }
69 }
70 
Set(int index,bool value)71 void Bitmap::Set(int index, bool value) {
72   DCHECK_LT(index, num_bits_);
73   DCHECK_GE(index, 0);
74   const int i = index & (kIntBits - 1);
75   const int j = index / kIntBits;
76   if (value)
77     map_[j] |= (1 << i);
78   else
79     map_[j] &= ~(1 << i);
80 }
81 
Get(int index) const82 bool Bitmap::Get(int index) const {
83   DCHECK_LT(index, num_bits_);
84   DCHECK_GE(index, 0);
85   const int i = index & (kIntBits-1);
86   const int j = index / kIntBits;
87   return ((map_[j] & (1 << i)) != 0);
88 }
89 
Toggle(int index)90 void Bitmap::Toggle(int index) {
91   DCHECK_LT(index, num_bits_);
92   DCHECK_GE(index, 0);
93   const int i = index & (kIntBits - 1);
94   const int j = index / kIntBits;
95   map_[j] ^= (1 << i);
96 }
97 
SetMapElement(int array_index,uint32_t value)98 void Bitmap::SetMapElement(int array_index, uint32_t value) {
99   DCHECK_LT(array_index, array_size_);
100   DCHECK_GE(array_index, 0);
101   map_[array_index] = value;
102 }
103 
GetMapElement(int array_index) const104 uint32_t Bitmap::GetMapElement(int array_index) const {
105   DCHECK_LT(array_index, array_size_);
106   DCHECK_GE(array_index, 0);
107   return map_[array_index];
108 }
109 
SetMap(const uint32_t * map,int size)110 void Bitmap::SetMap(const uint32_t* map, int size) {
111   memcpy(map_, map, std::min(size, array_size_) * sizeof(*map_));
112 }
113 
SetRange(int begin,int end,bool value)114 void Bitmap::SetRange(int begin, int end, bool value) {
115   DCHECK_LE(begin, end);
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.
TestRange(int begin,int end,bool value) const139 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_t 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_t 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 
FindNextBit(int * index,int limit,bool value) const191 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_t 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_t mask = 0xFFFFFFFF << first_bit_offset;
216   if (value) {
217     one_word &= mask;
218   } else {
219     one_word |= ~mask;
220   }
221 
222   uint32_t 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 
FindBits(int * index,int limit,bool value) const254 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 
SetWordBits(int start,int len,bool value)272 void Bitmap::SetWordBits(int start, int len, bool value) {
273   DCHECK_LT(len, kIntBits);
274   DCHECK_GE(len, 0);
275   if (!len)
276     return;
277 
278   int word = start / kIntBits;
279   int offset = start % kIntBits;
280 
281   uint32_t to_add = 0xffffffff << len;
282   to_add = (~to_add) << offset;
283   if (value) {
284     map_[word] |= to_add;
285   } else {
286     map_[word] &= ~to_add;
287   }
288 }
289 
290 }  // namespace disk_cache
291