bmv2
Designing your own switch target with bmv2
Loading...
Searching...
No Matches
dynamic_bitset.h
1/* Copyright 2021 VMware, Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/*
17 * Antonin Bas
18 *
19 */
20
21#ifndef BM_BM_SIM_DYNAMIC_BITSET_H_
22#define BM_BM_SIM_DYNAMIC_BITSET_H_
23
24#include <bitset>
25#include <cassert>
26#include <limits>
27#include <vector>
28
29namespace bm {
30
31template <typename T>
32inline int find_lowest_bit(T v);
33
34template<>
35inline int find_lowest_bit<uint32_t>(uint32_t v) {
36 static const int kMultiplyDeBruijnBitPosition[32] = {
37 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
38 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
39 };
40 return kMultiplyDeBruijnBitPosition[((v & -v) * 0x077CB531U) >> 27];
41}
42
43template<>
44inline int find_lowest_bit<uint64_t>(uint64_t v) {
45 auto sw = static_cast<uint32_t>(v & 0xFFFFFFFF);
46 return (sw == 0) ?
47 32 + find_lowest_bit<uint32_t>(static_cast<uint32_t>(v >> 32)) :
48 find_lowest_bit<uint32_t>(sw);
49}
50
51class DynamicBitset {
52 public:
53 using Block = unsigned long; // NOLINT(runtime/int)
54 using Backend = std::vector<Block>;
55 using size_type = Backend::size_type;
56
57 static constexpr size_type npos = static_cast<size_type>(-1);
58
59 size_type size() const {
60 return num_bits;
61 }
62
63 size_type count() const {
64 return num_bits_set;
65 }
66
67 bool test(size_type idx) const {
68 assert(idx < num_bits);
69 auto word_idx = static_cast<size_type>(idx / block_width);
70 auto bit_idx = static_cast<int>(idx % block_width);
71 return words[word_idx] & static_cast<Block>(1) << bit_idx;
72 }
73
74 bool set(size_type idx) {
75 assert(idx < num_bits);
76 auto word_idx = static_cast<size_type>(idx / block_width);
77 auto bit_idx = static_cast<int>(idx % block_width);
78 auto mask = static_cast<Block>(1) << bit_idx;
79 auto bit = words[word_idx] & mask;
80 words[word_idx] |= mask;
81 num_bits_set += (bit >> bit_idx) ^ 1;
82 return (bit == 0);
83 }
84
85 bool reset(size_type idx) {
86 assert(idx < num_bits);
87 auto word_idx = static_cast<size_type>(idx / block_width);
88 auto bit_idx = static_cast<int>(idx % block_width);
89 auto mask = static_cast<Block>(1) << bit_idx;
90 auto bit = words[word_idx] & mask;
91 words[word_idx] &= ~mask;
92 num_bits_set -= (bit >> bit_idx);
93 return (bit != 0);
94 }
95
96 void push_back(bool v) {
97 auto bit_idx = static_cast<int>(num_bits % block_width);
98 if (bit_idx == 0) words.push_back(0);
99 num_bits++;
100 if (v) set(num_bits - 1);
101 }
102
103 void clear() {
104 words.clear();
105 num_bits = 0;
106 num_bits_set = 0;
107 }
108
109 size_type find_first() const {
110 return find_from_block(0);
111 }
112
113 size_type find_next(size_type idx) const {
114 idx++;
115 if (idx >= num_bits) return npos;
116 auto word_idx = static_cast<size_type>(idx / block_width);
117 auto bit_idx = static_cast<int>(idx % block_width);
118 auto sw = words[word_idx] & (ones << bit_idx);
119 if (sw == 0) return find_from_block(word_idx + 1);
120 return word_idx * block_width + find_lowest_bit(sw);
121 }
122
123 size_type find_unset_first() const {
124 return find_unset_from_block(0);
125 }
126
127 size_type find_unset_next(size_type idx) const {
128 idx++;
129 if (idx >= num_bits) return npos;
130 auto word_idx = static_cast<size_type>(idx / block_width);
131 auto bit_idx = static_cast<int>(idx % block_width);
132 auto sw = words[word_idx] | ~(ones << bit_idx);
133 if (sw == ones) return find_unset_from_block(word_idx + 1);
134 return word_idx * block_width + find_lowest_bit(~sw);
135 }
136
137 bool operator==(const DynamicBitset &other) const {
138 return (num_bits == other.num_bits) && (words == other.words);
139 }
140
141 bool operator!=(const DynamicBitset &other) const {
142 return !(*this == other);
143 }
144
145 void resize(size_type new_num_bits) {
146 num_bits = new_num_bits;
147 words.resize((num_bits + block_width - 1) / block_width);
148 }
149
150 private:
151 size_type find_from_block(size_type word_idx) const {
152 for (size_type i = word_idx; i < words.size(); i++) {
153 if (words[i] == 0) continue;
154 return i * block_width + find_lowest_bit(words[i]);
155 }
156 return npos;
157 }
158
159 size_type find_unset_from_block(size_type word_idx) const {
160 for (size_type i = word_idx; i < words.size(); i++) {
161 if (words[i] == ones) continue;
162 return i * block_width + find_lowest_bit(~words[i]);
163 }
164 return npos;
165 }
166
167 static constexpr size_type block_width = std::numeric_limits<Block>::digits;
168 static constexpr Block ones = ~static_cast<Block>(0);
169 Backend words;
170 size_type num_bits{0};
171 size_type num_bits_set{0};
172};
173
174} // namespace bm
175
176#endif // BM_BM_SIM_DYNAMIC_BITSET_H_