forked from scylladb/scylladb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdynamic_bitset.cc
128 lines (112 loc) · 3.1 KB
/
dynamic_bitset.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
* Copyright 2015-present ScyllaDB
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
*/
#include <seastar/core/bitops.hh>
#include <seastar/core/align.hh>
#include <ranges>
#include "utils/dynamic_bitset.hh"
#include "seastarx.hh"
namespace utils {
void dynamic_bitset::set(size_t n) noexcept {
for (auto& level : _bits) {
auto idx = n / bits_per_int;
auto old = level[idx];
level[idx] |= int_type(1u) << (n % bits_per_int);
if (old) {
break;
}
n = idx; // prepare for next level
}
}
void dynamic_bitset::clear(size_t n) noexcept {
for (auto& level : _bits) {
auto idx = n / bits_per_int;
auto old = level[idx];
level[idx] &= ~(int_type(1u) << (n % bits_per_int));
if (!old || level[idx]) {
break;
}
n = idx; // prepare for next level
}
}
size_t dynamic_bitset::find_first_set() const noexcept
{
size_t pos = 0;
for (auto& vv : _bits | std::views::reverse) {
auto v = vv[pos];
pos *= bits_per_int;
if (v) {
pos += count_trailing_zeros(v);
} else {
return npos;
}
}
return pos;
}
size_t dynamic_bitset::find_next_set(size_t n) const noexcept
{
++n;
unsigned level = 0;
unsigned nlevels = _bits.size();
// Climb levels until we find a set bit in the right place
while (level != nlevels) {
if (n >= _bits_count) {
return npos;
}
auto v = _bits[level][level_idx(level, n)];
v &= ~mask_lower_bits(level_remainder(level, n));
if (v) {
break;
}
++level;
n = align_up(n, size_t(1) << (level_shift * level));
}
if (level == nlevels) {
return npos;
}
// Descend levels until we reach level 0
do {
auto v = _bits[level][level_idx(level, n)];
v &= ~mask_lower_bits(level_remainder(level, n));
n = align_down(n, size_t(1) << (level_shift * (level + 1)));
n += count_trailing_zeros(v) << (level_shift * level);
} while (level-- != 0);
return n;
}
size_t dynamic_bitset::find_last_set() const noexcept
{
size_t pos = 0;
for (auto& vv : _bits | std::views::reverse) {
auto v = vv[pos];
pos *= bits_per_int;
if (v) {
pos += bits_per_int - 1 - count_leading_zeros(v);
} else {
return npos;
}
}
return pos;
}
dynamic_bitset::dynamic_bitset(size_t nr_bits)
: _bits_count(nr_bits)
{
auto div_ceil = [] (size_t num, size_t den) {
return (num + den - 1) / den;
};
// 1-64: 1 level
// 65-4096: 2 levels
// 4097-262144: 3 levels
// etc.
unsigned nr_levels = div_ceil(log2ceil(align_up(nr_bits, size_t(bits_per_int))), level_shift);
_bits.resize(nr_levels);
size_t level_bits = nr_bits;
for (unsigned level = 0; level != nr_levels; ++level) {
auto level_words = align_up(level_bits, bits_per_int) / bits_per_int;
_bits[level].resize(level_words);
level_bits = level_words; // for next iteration
}
}
}