YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/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