/Users/deen/code/yugabyte-db/src/yb/util/bitmap.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | // Utility functions for dealing with a byte array as if it were a bitmap. |
33 | | #ifndef YB_UTIL_BITMAP_H |
34 | | #define YB_UTIL_BITMAP_H |
35 | | |
36 | | #include <string> |
37 | | |
38 | | #include <boost/container/small_vector.hpp> |
39 | | |
40 | | #include "yb/gutil/bits.h" |
41 | | |
42 | | #include "yb/util/status_fwd.h" |
43 | | |
44 | | namespace yb { |
45 | | |
46 | | class Slice; |
47 | | |
48 | | // Return the number of bytes necessary to store the given number of bits. |
49 | 42 | inline size_t BitmapSize(size_t num_bits) { |
50 | 42 | return (num_bits + 7) / 8; |
51 | 42 | } |
52 | | |
53 | | // Set the given bit. |
54 | 12.0k | inline void BitmapSet(uint8_t *bitmap, size_t idx) { |
55 | 12.0k | bitmap[idx >> 3] |= 1 << (idx & 7); |
56 | 12.0k | } |
57 | | |
58 | | // Switch the given bit to the specified value. |
59 | 168 | inline void BitmapChange(uint8_t *bitmap, size_t idx, bool value) { |
60 | 168 | bitmap[idx >> 3] = (bitmap[idx >> 3] & ~(1 << (idx & 7))) | ((!!value) << (idx & 7)); |
61 | 168 | } |
62 | | |
63 | | // Clear the given bit. |
64 | 31 | inline void BitmapClear(uint8_t *bitmap, size_t idx) { |
65 | 31 | bitmap[idx >> 3] &= ~(1 << (idx & 7)); |
66 | 31 | } |
67 | | |
68 | | // Test/get the given bit. |
69 | 763k | inline bool BitmapTest(const uint8_t *bitmap, size_t idx) { |
70 | 763k | return bitmap[idx >> 3] & (1 << (idx & 7)); |
71 | 763k | } |
72 | | |
73 | | // Merge the two bitmaps using bitwise or. Both bitmaps should have at least |
74 | | // n_bits valid bits. |
75 | 0 | inline void BitmapMergeOr(uint8_t *dst, const uint8_t *src, size_t n_bits) { |
76 | 0 | size_t n_bytes = BitmapSize(n_bits); |
77 | 0 | for (size_t i = 0; i < n_bytes; i++) { |
78 | 0 | *dst++ |= *src++; |
79 | 0 | } |
80 | 0 | } |
81 | | |
82 | | // Set bits from offset to (offset + num_bits) to the specified value |
83 | | void BitmapChangeBits(uint8_t *bitmap, size_t offset, size_t num_bits, bool value); |
84 | | |
85 | | // Find the first bit of the specified value, starting from the specified offset. |
86 | | bool BitmapFindFirst(const uint8_t *bitmap, size_t offset, size_t bitmap_size, |
87 | | bool value, size_t *idx); |
88 | | |
89 | | // Find the first set bit in the bitmap, at the specified offset. |
90 | | inline bool BitmapFindFirstSet(const uint8_t *bitmap, size_t offset, |
91 | 97.7k | size_t bitmap_size, size_t *idx) { |
92 | 97.7k | return BitmapFindFirst(bitmap, offset, bitmap_size, true, idx); |
93 | 97.7k | } |
94 | | |
95 | | // Find the first zero bit in the bitmap, at the specified offset. |
96 | | inline bool BitmapFindFirstZero(const uint8_t *bitmap, size_t offset, |
97 | 97.7k | size_t bitmap_size, size_t *idx) { |
98 | 97.7k | return BitmapFindFirst(bitmap, offset, bitmap_size, false, idx); |
99 | 97.7k | } |
100 | | |
101 | | // Returns true if the bitmap contains only ones. |
102 | 81.4k | inline bool BitMapIsAllSet(const uint8_t *bitmap, size_t offset, size_t bitmap_size) { |
103 | 81.4k | DCHECK_LT(offset, bitmap_size); |
104 | 81.4k | size_t idx; |
105 | 81.4k | return !BitmapFindFirstZero(bitmap, offset, bitmap_size, &idx); |
106 | 81.4k | } |
107 | | |
108 | | // Returns true if the bitmap contains only zeros. |
109 | 81.4k | inline bool BitmapIsAllZero(const uint8_t *bitmap, size_t offset, size_t bitmap_size) { |
110 | 81.4k | DCHECK_LT(offset, bitmap_size); |
111 | 81.4k | size_t idx; |
112 | 81.4k | return !BitmapFindFirstSet(bitmap, offset, bitmap_size, &idx); |
113 | 81.4k | } |
114 | | |
115 | | std::string BitmapToString(const uint8_t *bitmap, size_t num_bits); |
116 | | |
117 | | // Iterator which yields ranges of set and unset bits. |
118 | | // Example usage: |
119 | | // bool value; |
120 | | // size_t size; |
121 | | // BitmapIterator iter(bitmap, n_bits); |
122 | | // while ((size = iter.Next(&value))) { |
123 | | // printf("bitmap block len=%lu value=%d\n", size, value); |
124 | | // } |
125 | | class BitmapIterator { |
126 | | public: |
127 | | BitmapIterator(const uint8_t *map, size_t num_bits) |
128 | | : offset_(0), num_bits_(num_bits), map_(map) |
129 | 1 | {} |
130 | | |
131 | 0 | bool done() const { |
132 | 0 | return (num_bits_ - offset_) == 0; |
133 | 0 | } |
134 | | |
135 | 0 | void SeekTo(size_t bit) { |
136 | 0 | DCHECK_LE(bit, num_bits_); |
137 | 0 | offset_ = bit; |
138 | 0 | } |
139 | | |
140 | 8 | size_t Next(bool *value) { |
141 | 8 | size_t len = num_bits_ - offset_; |
142 | 8 | if (PREDICT_FALSE(len == 0)) |
143 | 1 | return(0); |
144 | | |
145 | 7 | *value = BitmapTest(map_, offset_); |
146 | | |
147 | 7 | size_t index; |
148 | 7 | if (BitmapFindFirst(map_, offset_, num_bits_, !(*value), &index)) { |
149 | 6 | len = index - offset_; |
150 | 1 | } else { |
151 | 1 | index = num_bits_; |
152 | 1 | } |
153 | | |
154 | 7 | offset_ = index; |
155 | 7 | return len; |
156 | 7 | } |
157 | | |
158 | | private: |
159 | | size_t offset_; |
160 | | size_t num_bits_; |
161 | | const uint8_t *map_; |
162 | | }; |
163 | | |
164 | | // Iterator which yields the set bits in a bitmap. |
165 | | // Example usage: |
166 | | // for (TrueBitIterator iter(bitmap, n_bits); |
167 | | // !iter.done(); |
168 | | // ++iter) { |
169 | | // int next_onebit_position = *iter; |
170 | | // } |
171 | | class TrueBitIterator { |
172 | | public: |
173 | | TrueBitIterator(const uint8_t *bitmap, size_t n_bits) |
174 | | : bitmap_(bitmap), |
175 | | cur_byte_(0), |
176 | | cur_byte_idx_(0), |
177 | | n_bits_(n_bits), |
178 | | n_bytes_(BitmapSize(n_bits_)), |
179 | 2 | bit_idx_(0) { |
180 | 2 | if (n_bits_ == 0) { |
181 | 0 | cur_byte_idx_ = 1; // sets done |
182 | 2 | } else { |
183 | 2 | cur_byte_ = bitmap[0]; |
184 | 2 | AdvanceToNextOneBit(); |
185 | 2 | } |
186 | 2 | } |
187 | | |
188 | 7 | TrueBitIterator &operator ++() { |
189 | 7 | DCHECK(!done()); |
190 | 7 | DCHECK(cur_byte_ & 1); |
191 | 7 | cur_byte_ &= (~1); |
192 | 7 | AdvanceToNextOneBit(); |
193 | 7 | return *this; |
194 | 7 | } |
195 | | |
196 | 23 | bool done() const { |
197 | 23 | return cur_byte_idx_ >= n_bytes_; |
198 | 23 | } |
199 | | |
200 | 7 | size_t operator *() const { |
201 | 7 | DCHECK(!done()); |
202 | 7 | return bit_idx_; |
203 | 7 | } |
204 | | |
205 | | private: |
206 | 9 | void AdvanceToNextOneBit() { |
207 | 16 | while (cur_byte_ == 0) { |
208 | 9 | cur_byte_idx_++; |
209 | 9 | if (cur_byte_idx_ >= n_bytes_) return; |
210 | 7 | cur_byte_ = bitmap_[cur_byte_idx_]; |
211 | 7 | bit_idx_ = cur_byte_idx_ * 8; |
212 | 7 | } |
213 | 0 | DVLOG(2) << "Found next nonzero byte at " << cur_byte_idx_ |
214 | 0 | << " val=" << cur_byte_; |
215 | | |
216 | 7 | DCHECK_NE(cur_byte_, 0); |
217 | 7 | int set_bit = Bits::FindLSBSetNonZero(cur_byte_); |
218 | 7 | bit_idx_ += set_bit; |
219 | 7 | cur_byte_ >>= set_bit; |
220 | 7 | } |
221 | | |
222 | | const uint8_t *bitmap_; |
223 | | uint8_t cur_byte_; |
224 | | uint8_t cur_byte_idx_; |
225 | | |
226 | | const size_t n_bits_; |
227 | | const size_t n_bytes_; |
228 | | size_t bit_idx_; |
229 | | }; |
230 | | |
231 | | // Bitmap that is optimized for the following scenario: |
232 | | // 1) Bits could only be set, i.e. clear is not allowed. |
233 | | // 2) Usually bits are getting set in increasing order. |
234 | | // 3) Bitmap is frequently encoded and skipped, but rarely decoded. |
235 | | // |
236 | | // Since we optimize for frequent encoding, we prefer size optimization over performance. |
237 | | class OneWayBitmap { |
238 | | public: |
239 | | void Set(size_t bit); |
240 | | bool Test(size_t bit) const; |
241 | | |
242 | | // Returns number of bits set. |
243 | 6.92k | size_t CountSet() const { |
244 | 6.92k | return ones_counter_; |
245 | 6.92k | } |
246 | | |
247 | | // Encodes current representation into provided buffer. |
248 | | void EncodeTo(boost::container::small_vector_base<uint8_t>* out) const; |
249 | | |
250 | | // Encodes current representation into hex string, useful for encoding debugging. |
251 | | std::string EncodeToHexString() const; |
252 | | |
253 | | std::string ToString() const; |
254 | | |
255 | | // Decodes bitmap from start of the slice, removing decoded prefix from it. |
256 | | static Result<OneWayBitmap> Decode(Slice* slice); |
257 | | |
258 | | // Removes encoded bitmap from slice prefix, w/o decoding slice. |
259 | | static CHECKED_STATUS Skip(Slice* slice); |
260 | | |
261 | | private: |
262 | | typedef uint8_t ElementType; |
263 | | static constexpr size_t kBitsPerElement = sizeof(ElementType) * 8; |
264 | | static constexpr ElementType kAllOnes = ~static_cast<ElementType>(0); |
265 | | size_t ones_counter_ = 0; |
266 | | |
267 | | // Bitmap is stored as number of bits in fully filled bytes at start of the set, |
268 | | // followed by remaining bitmap state. |
269 | | size_t fully_filled_bits_ = 0; |
270 | | boost::container::small_vector<ElementType, sizeof(size_t)> data_; |
271 | | }; |
272 | | |
273 | | } // namespace yb |
274 | | |
275 | | #endif // YB_UTIL_BITMAP_H |