TPDE
Loading...
Searching...
No Matches
SmallBitSet.hpp
1// SPDX-FileCopyrightText: 2025 Contributors to TPDE <https://tpde.org>
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4#pragma once
5
6#include <optional>
7
8#include "SmallVector.hpp"
9#include "misc.hpp"
10#include "tpde/base.hpp"
11
12namespace tpde::util {
13/// BitSet implemented on top of SmallVector
14template <u32 InternalCapacity>
16 // we divide by 64 bits for the SmallVector
17 static_assert((InternalCapacity % 64) == 0);
18
19 SmallVector<u64, InternalCapacity / 64> data;
20 u32 bit_size = 0;
21
22 SmallBitSet() = default;
23
24 SmallBitSet(const SmallBitSet &other)
25 : data(other.data), bit_size(other.bit_size) {}
26
27 SmallBitSet(SmallBitSet &&other) noexcept {
28 data = std::move(other.data);
29 bit_size = other.bit_size;
30 }
31
32 SmallBitSet &operator=(const SmallBitSet &other) {
33 if (&other != this) {
34 data = other.data;
35 bit_size = other.bit_size;
36 }
37 return *this;
38 }
39
40 SmallBitSet &operator=(SmallBitSet &&other) noexcept {
41 if (&other != this) {
42 data = std::move(data);
43 bit_size = other.bit_size;
44 }
45 return *this;
46 }
47
48 void clear() noexcept {
49 data.clear();
50 bit_size = 0;
51 }
52
53 void resize(const u32 bit_size) noexcept {
54 const auto byte_size = align_up(bit_size, 64) / 64;
55 if (bit_size > this->bit_size && this->bit_size != 0) {
56 const auto last_bits = this->bit_size & 63;
57 const auto set_mask = (1ull << last_bits) - 1;
58 data.back() = data.back() & set_mask;
59 }
60
61 data.resize(byte_size);
62 this->bit_size = bit_size;
63 }
64
65 void zero() {
66 for (auto &v : data) {
67 v = 0;
68 }
69 }
70
71 void push_back(const bool val) noexcept {
72 if (bit_size / 64 != (bit_size - 1) / 64) {
73 data.push_back(0);
74 if (val) {
75 mark_set(bit_size);
76 }
77 ++bit_size;
78 return;
79 }
80 if (val) {
81 mark_set(bit_size++);
82 } else {
83 mark_unset(bit_size++);
84 }
85 }
86
87 [[nodiscard]] bool is_set(const u32 idx) const noexcept {
88 const u32 elem_idx = idx >> 6;
89 const u64 bit = 1ull << (idx & 63);
90 return data[elem_idx] & bit;
91 }
92
93 void mark_set(const u32 idx) noexcept {
94 const u32 elem_idx = idx >> 6;
95 const u64 bit = 1ull << (idx & 63);
96 data[elem_idx] |= bit;
97 }
98
99 void mark_unset(const u32 idx) noexcept {
100 const u32 elem_idx = idx >> 6;
101 const u64 bit = 1ull << (idx & 63);
102 data[elem_idx] &= ~bit;
103 }
104
105 std::optional<u32> first_set() noexcept {
106 for (u32 i = 0; i < data.size(); ++i) {
107 if (data[i] == 0) {
108 continue;
109 }
110 return i + util::cnt_tz(data[i]);
111 }
112 return {};
113 }
114};
115} // namespace tpde::util
BitSet implemented on top of SmallVector.