Skip to content

Commit 507c5b3

Browse files
authored
Merge pull request #418 from hitonanode/dynamic-bitset
dynamic bitset
2 parents 00fb386 + 7807a3b commit 507c5b3

11 files changed

Lines changed: 781 additions & 0 deletions

data_structure/dynamic_bitset.hpp

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
#pragma once
2+
3+
#include <algorithm>
4+
#include <cassert>
5+
#include <initializer_list>
6+
#include <string>
7+
#include <vector>
8+
9+
struct dynamic_bitset {
10+
using ull = unsigned long long;
11+
static constexpr int W = 64;
12+
13+
int n = 0; // number of bits
14+
int m = 0; // number of 64-bit blocks
15+
std::vector<ull> a; // blocks
16+
17+
dynamic_bitset() = default;
18+
explicit dynamic_bitset(int n_, bool init_one = false) { reset_size(n_, init_one); }
19+
explicit dynamic_bitset(const std::string &s) : dynamic_bitset(int(s.size())) {
20+
const char *p = s.data();
21+
for (int blk = 0; blk < m; ++blk) {
22+
int l = std::max(0, n - ((blk + 1) << 6));
23+
int r = n - (blk << 6);
24+
ull x = 0;
25+
for (int i = l; i < r; ++i) x = (x << 1) | ull(p[i] == '1');
26+
a[blk] = x;
27+
}
28+
}
29+
30+
void reset_size(int n_, bool init_one = false) {
31+
n = n_;
32+
m = (n + W - 1) / W;
33+
a.assign(m, init_one ? ~0ULL : 0ULL);
34+
trim();
35+
}
36+
37+
int size() const { return n; }
38+
39+
// ---- low-level helpers ----
40+
ull last_mask() const {
41+
int r = n & (W - 1);
42+
if (r == 0) return ~0ULL;
43+
return (r == 64 ? ~0ULL : ((1ULL << r) - 1ULL));
44+
}
45+
void trim() {
46+
if (m == 0) return;
47+
a.back() &= last_mask();
48+
}
49+
50+
static inline int ctz64(ull x) { return __builtin_ctzll(x); }
51+
static inline int clz64(ull x) { return __builtin_clzll(x); }
52+
static inline int msb_index64(ull x) { return 63 - clz64(x); } // x != 0
53+
void assert_index(int i) const { assert(0 <= i && i < n); }
54+
void assert_same_size(const dynamic_bitset &o) const { assert(n == o.n); }
55+
56+
// ---- basic bit ops ----
57+
bool test(int i) const {
58+
assert_index(i);
59+
return (a[i >> 6] >> (i & 63)) & 1ULL;
60+
}
61+
void set(int i) {
62+
assert_index(i);
63+
a[i >> 6] |= (1ULL << (i & 63));
64+
}
65+
void reset(int i) {
66+
assert_index(i);
67+
a[i >> 6] &= ~(1ULL << (i & 63));
68+
}
69+
void flip(int i) {
70+
assert_index(i);
71+
a[i >> 6] ^= (1ULL << (i & 63));
72+
}
73+
void set(int i, bool v) { v ? set(i) : reset(i); }
74+
75+
void reset_all() { std::fill(a.begin(), a.end(), 0ULL); }
76+
void set_all() {
77+
std::fill(a.begin(), a.end(), ~0ULL);
78+
trim();
79+
}
80+
void flip_all() {
81+
for (auto &x : a) x = ~x;
82+
trim();
83+
}
84+
85+
// count (optional but handy)
86+
int popcount() const {
87+
int s = 0;
88+
for (ull x : a) s += __builtin_popcountll(x);
89+
return s;
90+
}
91+
int count() const { return popcount(); }
92+
93+
// ---- bitwise ops ----
94+
// ---- any / none ----
95+
bool any() const {
96+
for (ull x : a)
97+
if (x) return true;
98+
return false;
99+
}
100+
bool none() const { return !any(); }
101+
102+
// ---- bitwise assign ops ----
103+
dynamic_bitset &operator^=(const dynamic_bitset &o) {
104+
assert_same_size(o);
105+
for (int i = 0; i < m; i++) a[i] ^= o.a[i];
106+
trim();
107+
return *this;
108+
}
109+
dynamic_bitset &operator|=(const dynamic_bitset &o) {
110+
assert_same_size(o);
111+
for (int i = 0; i < m; i++) a[i] |= o.a[i];
112+
trim();
113+
return *this;
114+
}
115+
dynamic_bitset &operator&=(const dynamic_bitset &o) {
116+
assert_same_size(o);
117+
for (int i = 0; i < m; i++) a[i] &= o.a[i];
118+
trim();
119+
return *this;
120+
}
121+
122+
friend dynamic_bitset operator^(dynamic_bitset l, const dynamic_bitset &r) {
123+
l ^= r;
124+
return l;
125+
}
126+
friend dynamic_bitset operator|(dynamic_bitset l, const dynamic_bitset &r) {
127+
l |= r;
128+
return l;
129+
}
130+
friend dynamic_bitset operator&(dynamic_bitset l, const dynamic_bitset &r) {
131+
l &= r;
132+
return l;
133+
}
134+
135+
bool operator==(const dynamic_bitset &o) const { return n == o.n && a == o.a; }
136+
bool operator!=(const dynamic_bitset &o) const { return !(*this == o); }
137+
int compare(const dynamic_bitset &o) const {
138+
if (n != o.n) return n < o.n ? -1 : 1;
139+
for (int i = m - 1; i >= 0; --i) {
140+
if (a[i] != o.a[i]) return a[i] < o.a[i] ? -1 : 1;
141+
}
142+
return 0;
143+
}
144+
bool operator<(const dynamic_bitset &o) const { return compare(o) < 0; }
145+
bool operator<=(const dynamic_bitset &o) const { return compare(o) <= 0; }
146+
bool operator>(const dynamic_bitset &o) const { return compare(o) > 0; }
147+
bool operator>=(const dynamic_bitset &o) const { return compare(o) >= 0; }
148+
149+
// returns bitset b with b.test(i) == test(l + i) for 0 <= i < r - l
150+
dynamic_bitset slice(int l, int r) const {
151+
l = std::clamp(l, 0, n);
152+
r = std::clamp(r, 0, n);
153+
if (l >= r) return dynamic_bitset();
154+
155+
dynamic_bitset res(r - l);
156+
int ws = l >> 6;
157+
int bs = l & 63;
158+
for (int i = 0; i < res.m; ++i) {
159+
ull lo = (ws + i < m ? (a[ws + i] >> bs) : 0ULL);
160+
ull hi = (bs && ws + i + 1 < m ? (a[ws + i + 1] << (W - bs)) : 0ULL);
161+
res.a[i] = lo | hi;
162+
}
163+
res.trim();
164+
return res;
165+
}
166+
167+
private:
168+
template <class Range> static dynamic_bitset join_range(const Range &xs) {
169+
int total = 0;
170+
for (const auto &x : xs) total += x.n;
171+
172+
dynamic_bitset res(total);
173+
int cur = 0;
174+
for (const auto &x : xs) {
175+
int ws = cur >> 6;
176+
int bs = cur & 63;
177+
for (int i = 0; i < x.m; ++i) {
178+
ull v = x.a[i];
179+
if (!v) continue;
180+
res.a[ws + i] |= v << bs;
181+
if (bs && ws + i + 1 < res.m) res.a[ws + i + 1] |= v >> (W - bs);
182+
}
183+
cur += x.n;
184+
}
185+
res.trim();
186+
return res;
187+
}
188+
189+
public:
190+
static dynamic_bitset join(const std::vector<dynamic_bitset> &xs) { return join_range(xs); }
191+
static dynamic_bitset join(std::initializer_list<dynamic_bitset> xs) { return join_range(xs); }
192+
static dynamic_bitset join(const dynamic_bitset &a, const dynamic_bitset &b) {
193+
return join({a, b});
194+
}
195+
196+
dynamic_bitset operator~() const {
197+
dynamic_bitset r = *this;
198+
for (auto &x : r.a) x = ~x;
199+
r.trim();
200+
return r;
201+
}
202+
203+
// ---- shifts ----
204+
dynamic_bitset &operator<<=(int k) {
205+
if (k <= 0 || n == 0) return *this;
206+
if (k >= n) {
207+
reset_all();
208+
return *this;
209+
}
210+
int ws = k >> 6;
211+
int bs = k & 63;
212+
213+
if (ws) {
214+
for (int i = m - 1; i >= 0; --i) {
215+
ull v = (i - ws >= 0) ? a[i - ws] : 0ULL;
216+
a[i] = v;
217+
}
218+
}
219+
if (bs) {
220+
for (int i = m - 1; i >= 0; --i) {
221+
ull hi = a[i] << bs;
222+
ull lo = (i ? (a[i - 1] >> (64 - bs)) : 0ULL);
223+
a[i] = hi | lo;
224+
}
225+
}
226+
// zero-fill lower words introduced by ws shift
227+
if (ws) {
228+
for (int i = 0; i < ws && i < m; ++i) a[i] = 0ULL;
229+
}
230+
trim();
231+
return *this;
232+
}
233+
234+
dynamic_bitset &operator>>=(int k) {
235+
if (k <= 0 || n == 0) return *this;
236+
if (k >= n) {
237+
reset_all();
238+
return *this;
239+
}
240+
int ws = k >> 6;
241+
int bs = k & 63;
242+
243+
if (ws) {
244+
for (int i = 0; i < m; ++i) {
245+
ull v = (i + ws < m) ? a[i + ws] : 0ULL;
246+
a[i] = v;
247+
}
248+
}
249+
if (bs) {
250+
for (int i = 0; i < m; ++i) {
251+
ull lo = a[i] >> bs;
252+
ull hi = (i + 1 < m ? (a[i + 1] << (64 - bs)) : 0ULL);
253+
a[i] = lo | hi;
254+
}
255+
}
256+
// zero-fill upper words introduced by ws shift
257+
if (ws) {
258+
for (int i = m - ws; i < m; ++i)
259+
if (0 <= i && i < m) a[i] = 0ULL;
260+
}
261+
trim();
262+
return *this;
263+
}
264+
265+
friend dynamic_bitset operator<<(dynamic_bitset b, int k) {
266+
b <<= k;
267+
return b;
268+
}
269+
friend dynamic_bitset operator>>(dynamic_bitset b, int k) {
270+
b >>= k;
271+
return b;
272+
}
273+
274+
// ---- find set bits ----
275+
// returns smallest i with bit=1, or size()
276+
int first() const {
277+
for (int i = 0; i < m; ++i) {
278+
ull x = a[i];
279+
if (x) return (i << 6) + ctz64(x);
280+
}
281+
return size();
282+
}
283+
284+
// returns smallest j > i with bit=1, or size()
285+
int next(int i) const {
286+
if (n == 0) return size();
287+
int j = i + 1;
288+
if (j <= 0) return first();
289+
if (j >= n) return size();
290+
291+
int b = j >> 6;
292+
int off = j & 63;
293+
294+
// mask out bits < off
295+
ull x = a[b] & (~0ULL << off);
296+
if (x) return (b << 6) + ctz64(x);
297+
298+
for (int bb = b + 1; bb < m; ++bb) {
299+
ull y = a[bb];
300+
if (y) return (bb << 6) + ctz64(y);
301+
}
302+
return size();
303+
}
304+
305+
// returns largest i with bit=1, or -1
306+
int last() const {
307+
for (int i = m - 1; i >= 0; --i) {
308+
ull x = a[i];
309+
if (i == m - 1) x &= last_mask();
310+
if (x) return (i << 6) + msb_index64(x);
311+
}
312+
return -1;
313+
}
314+
315+
// returns largest j < i with bit=1, or -1
316+
int prev(int i) const {
317+
if (n == 0) return -1;
318+
int j = i - 1;
319+
if (j < 0) return -1;
320+
if (j >= n) return last();
321+
322+
int b = j >> 6;
323+
int off = j & 63;
324+
325+
ull mask = (off == 63) ? ~0ULL : ((1ULL << (off + 1)) - 1ULL);
326+
ull x = a[b] & mask;
327+
if (x) return (b << 6) + msb_index64(x);
328+
329+
for (int bb = b - 1; bb >= 0; --bb) {
330+
ull y = a[bb];
331+
if (y) return (bb << 6) + msb_index64(y);
332+
}
333+
return -1;
334+
}
335+
};

0 commit comments

Comments
 (0)