1 | /** |
2 | * Copyright 2021 Alibaba, Inc. and its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | |
16 | * \author Hechong.xyf |
17 | * \date Dec 2017 |
18 | * \brief Interface of AiLego Utility Bitmap |
19 | */ |
20 | |
21 | #ifndef __AILEGO_CONTAINER_BITMAP_H__ |
22 | #define __AILEGO_CONTAINER_BITMAP_H__ |
23 | |
24 | #include <algorithm> |
25 | #include <vector> |
26 | #include <ailego/utility/bitset_helper.h> |
27 | |
28 | namespace ailego { |
29 | |
30 | /*! Fixed Bitset |
31 | */ |
32 | template <size_t N, typename = typename std::enable_if<N % 32 == 0>::type> |
33 | class FixedBitset { |
34 | public: |
35 | enum { MAX_SIZE = N }; |
36 | |
37 | //! Constructor |
38 | FixedBitset(void) { |
39 | memset(array_, 0, sizeof(array_)); |
40 | } |
41 | |
42 | //! Constructor |
43 | FixedBitset(const FixedBitset &rhs) { |
44 | memcpy(array_, rhs.array_, sizeof(array_)); |
45 | } |
46 | |
47 | //! Destructor |
48 | ~FixedBitset(void) {} |
49 | |
50 | //! Assignment |
51 | FixedBitset &operator=(const FixedBitset &rhs) { |
52 | memcpy(array_, rhs.array_, sizeof(array_)); |
53 | return *this; |
54 | } |
55 | |
56 | //! Retrieve data pointer |
57 | uint32_t *data(void) { |
58 | return reinterpret_cast<uint32_t *>(array_); |
59 | } |
60 | |
61 | //! Retrieve data pointer |
62 | const uint32_t *data(void) const { |
63 | return reinterpret_cast<const uint32_t *>(array_); |
64 | } |
65 | |
66 | //! Retrieve count of bits in set |
67 | constexpr size_t size(void) const { |
68 | return MAX_SIZE; |
69 | } |
70 | |
71 | //!Clear the bitset |
72 | void clear(void) { |
73 | memset(array_, 0, sizeof(array_)); |
74 | } |
75 | |
76 | //! Test a bit in bitset |
77 | bool test(size_t num) const { |
78 | ailego_assert_with(N > num, "overflow argument" ); |
79 | return ((array_[num >> 5] & (1u << (num & 0x1f))) != 0); |
80 | } |
81 | |
82 | //! Set a bit in bitset |
83 | void set(size_t num) { |
84 | ailego_assert_with(N > num, "overflow argument" ); |
85 | uint32_t mask = (1u << (num & 0x1f)); |
86 | array_[num >> 5] |= mask; |
87 | } |
88 | |
89 | //! Clear a bit in bitset |
90 | void reset(size_t num) { |
91 | ailego_assert_with(N > num, "overflow argument" ); |
92 | uint32_t mask = (1u << (num & 0x1f)); |
93 | array_[num >> 5] &= ~mask; |
94 | } |
95 | |
96 | //! Toggle a bit in bitset |
97 | void flip(size_t num) { |
98 | ailego_assert_with(N > num, "overflow argument" ); |
99 | uint32_t mask = (1u << (num & 0x1f)); |
100 | array_[num >> 5] ^= mask; |
101 | } |
102 | |
103 | //! Perform binary AND |
104 | void bitwise_and(const FixedBitset &rhs) { |
105 | BitsetHelper::BitwiseAnd(array_, rhs.array_, ((N + 0x1f) >> 5)); |
106 | } |
107 | |
108 | //! Perform binary AND NOT |
109 | void bitwise_andnot(const FixedBitset &rhs) { |
110 | BitsetHelper::BitwiseAndnot(array_, rhs.array_, ((N + 0x1f) >> 5)); |
111 | } |
112 | |
113 | //! Perform binary OR |
114 | void bitwise_or(const FixedBitset &rhs) { |
115 | BitsetHelper::BitwiseOr(array_, rhs.array_, ((N + 0x1f) >> 5)); |
116 | } |
117 | |
118 | //! Perform binary XOR |
119 | void bitwise_xor(const FixedBitset &rhs) { |
120 | BitsetHelper::BitwiseXor(array_, rhs.array_, ((N + 0x1f) >> 5)); |
121 | } |
122 | |
123 | //! Perform binary NOT |
124 | void bitwise_not(void) { |
125 | BitsetHelper::BitwiseNot(array_, ((N + 0x1f) >> 5)); |
126 | } |
127 | |
128 | //! Check if all bits are set to true |
129 | bool test_all(void) const { |
130 | return BitsetHelper::TestAll(array_, ((N + 0x1f) >> 5)); |
131 | } |
132 | |
133 | //! Check if any bits are set to true |
134 | bool test_any(void) const { |
135 | return BitsetHelper::TestAny(array_, ((N + 0x1f) >> 5)); |
136 | } |
137 | |
138 | //! Check if none of the bits are set to true |
139 | bool test_none(void) const { |
140 | return BitsetHelper::TestNone(array_, ((N + 0x1f) >> 5)); |
141 | } |
142 | |
143 | //! Compute the cardinality of a bitset |
144 | size_t cardinality(void) const { |
145 | return BitsetHelper::Cardinality(array_, ((N + 0x1f) >> 5)); |
146 | } |
147 | |
148 | //! Extract the bitset to an array |
149 | void (size_t base, std::vector<size_t> *out) const { |
150 | const uint32_t *iter = array_; |
151 | const uint32_t *last = array_ + ((N + 0x1f) >> 5); |
152 | |
153 | for (; iter != last; ++iter) { |
154 | uint32_t w = *iter; |
155 | |
156 | while (w != 0) { |
157 | uint32_t c = ailego_ctz32(w); |
158 | w &= ~(1u << c); |
159 | out->push_back(base + c); |
160 | } |
161 | base += 32u; |
162 | } |
163 | } |
164 | |
165 | //! Extract the bitset to an array |
166 | void (std::vector<size_t> *out) const { |
167 | this->extract(0, out); |
168 | } |
169 | |
170 | //! Compute the AND cardinality between two bitsets |
171 | static size_t BitwiseAndCardinality(const FixedBitset &lhs, |
172 | const FixedBitset &rhs) { |
173 | return BitsetHelper::BitwiseAndCardinality(lhs.array_, rhs.array_, |
174 | ((N + 0x1f) >> 5)); |
175 | } |
176 | |
177 | //! Compute the ANDNOT cardinality between two bitsets |
178 | static size_t BitwiseAndnotCardinality(const FixedBitset &lhs, |
179 | const FixedBitset &rhs) { |
180 | return BitsetHelper::BitwiseAndnotCardinality(lhs.array_, rhs.array_, |
181 | ((N + 0x1f) >> 5)); |
182 | } |
183 | |
184 | //! Compute the XOR cardinality between two bitsets |
185 | static size_t BitwiseXorCardinality(const FixedBitset &lhs, |
186 | const FixedBitset &rhs) { |
187 | return BitsetHelper::BitwiseXorCardinality(lhs.array_, rhs.array_, |
188 | ((N + 0x1f) >> 5)); |
189 | } |
190 | |
191 | //! Compute the OR cardinality between two bitsets |
192 | static size_t BitwiseOrCardinality(const FixedBitset &lhs, |
193 | const FixedBitset &rhs) { |
194 | return BitsetHelper::BitwiseOrCardinality(lhs.array_, rhs.array_, |
195 | ((N + 0x1f) >> 5)); |
196 | } |
197 | |
198 | //! Convert a array pointer to bitset pointer |
199 | static FixedBitset *Cast(uint32_t *arr) { |
200 | return reinterpret_cast<FixedBitset<N> *>(arr); |
201 | } |
202 | |
203 | //! Convert a array pointer to bitset pointer |
204 | static const FixedBitset *Cast(const uint32_t *arr) { |
205 | return reinterpret_cast<const FixedBitset<N> *>(arr); |
206 | } |
207 | |
208 | //! Convert a array pointer to bitset pointer |
209 | static FixedBitset *Cast(uint64_t *arr) { |
210 | return reinterpret_cast<FixedBitset<N> *>(arr); |
211 | } |
212 | |
213 | //! Convert a array pointer to bitset pointer |
214 | static const FixedBitset *Cast(const uint64_t *arr) { |
215 | return reinterpret_cast<const FixedBitset<N> *>(arr); |
216 | } |
217 | |
218 | private: |
219 | uint32_t array_[(N + 0x1f) >> 5]; |
220 | }; |
221 | |
222 | /*! Fixed Bitset (Special) |
223 | */ |
224 | template <> |
225 | class FixedBitset<0> { |
226 | public: |
227 | enum { MAX_SIZE = 0 }; |
228 | |
229 | //! Retrieve max size of bitset |
230 | constexpr size_t size(void) const { |
231 | return MAX_SIZE; |
232 | } |
233 | }; |
234 | |
235 | /*! Bitset |
236 | */ |
237 | class Bitset { |
238 | public: |
239 | //! Constructor |
240 | Bitset(void) : array_() {} |
241 | |
242 | //! Constructor |
243 | Bitset(size_t bits) : array_((bits + 0x1f) >> 5) {} |
244 | |
245 | //! Constructor |
246 | Bitset(const Bitset &rhs) : array_(rhs.array_) {} |
247 | |
248 | //! Constructor |
249 | Bitset(Bitset &&rhs) : array_(std::move(rhs.array_)) {} |
250 | |
251 | //! Destructor |
252 | ~Bitset(void) {} |
253 | |
254 | //! Assignment |
255 | Bitset &operator=(const Bitset &rhs) { |
256 | array_ = rhs.array_; |
257 | return *this; |
258 | } |
259 | |
260 | //! Assignment |
261 | Bitset &operator=(Bitset &&rhs) { |
262 | array_ = std::move(rhs.array_); |
263 | return *this; |
264 | } |
265 | |
266 | //! Retrieve data pointer |
267 | uint32_t *data(void) { |
268 | return array_.data(); |
269 | } |
270 | |
271 | //! Retrieve data pointer |
272 | const uint32_t *data(void) const { |
273 | return array_.data(); |
274 | } |
275 | |
276 | //! Retrieve count of bits in set |
277 | size_t size(void) const { |
278 | return (array_.size() << 5); |
279 | } |
280 | |
281 | //! Resize the bitset |
282 | void resize(size_t bits) { |
283 | array_.resize((bits + 0x1f) >> 5); |
284 | } |
285 | |
286 | //!Clear the bitset |
287 | void clear(void) { |
288 | array_.clear(); |
289 | } |
290 | |
291 | //! Test a bit in bitset |
292 | bool test(size_t num) const { |
293 | ailego_assert_with(this->size() > num, "overflow argument" ); |
294 | return ((array_[num >> 5] & (1u << (num & 0x1f))) != 0); |
295 | } |
296 | |
297 | //! Set a bit in bitset |
298 | void set(size_t num) { |
299 | ailego_assert_with(this->size() > num, "overflow argument" ); |
300 | uint32_t mask = (1u << (num & 0x1f)); |
301 | array_[num >> 5] |= mask; |
302 | } |
303 | |
304 | //! Clear a bit in bitset |
305 | void reset(size_t num) { |
306 | ailego_assert_with(this->size() > num, "overflow argument" ); |
307 | uint32_t mask = (1u << (num & 0x1f)); |
308 | array_[num >> 5] &= ~mask; |
309 | } |
310 | |
311 | //! Toggle a bit in bitset |
312 | void flip(size_t num) { |
313 | ailego_assert_with(this->size() > num, "overflow argument" ); |
314 | uint32_t mask = (1u << (num & 0x1f)); |
315 | array_[num >> 5] ^= mask; |
316 | } |
317 | |
318 | //! Perform binary AND |
319 | void bitwise_and(const Bitset &rhs) { |
320 | BitsetHelper::BitwiseAnd(array_.data(), rhs.array_.data(), |
321 | std::min(array_.size(), rhs.array_.size())); |
322 | } |
323 | |
324 | //! Perform binary AND NOT |
325 | void bitwise_andnot(const Bitset &rhs) { |
326 | BitsetHelper::BitwiseAndnot(array_.data(), rhs.array_.data(), |
327 | std::min(array_.size(), rhs.array_.size())); |
328 | } |
329 | |
330 | //! Perform binary OR |
331 | void bitwise_or(const Bitset &rhs) { |
332 | BitsetHelper::BitwiseOr(array_.data(), rhs.array_.data(), |
333 | std::min(array_.size(), rhs.array_.size())); |
334 | } |
335 | |
336 | //! Perform binary XOR |
337 | void bitwise_xor(const Bitset &rhs) { |
338 | BitsetHelper::BitwiseXor(array_.data(), rhs.array_.data(), |
339 | std::min(array_.size(), rhs.array_.size())); |
340 | } |
341 | |
342 | //! Perform binary NOT |
343 | void bitwise_not(void) { |
344 | BitsetHelper::BitwiseNot(array_.data(), array_.size()); |
345 | } |
346 | |
347 | //! Check if all bits are set to true |
348 | bool test_all(void) const { |
349 | return BitsetHelper::TestAll(array_.data(), array_.size()); |
350 | } |
351 | |
352 | //! Check if any bits are set to true |
353 | bool test_any(void) const { |
354 | return BitsetHelper::TestAny(array_.data(), array_.size()); |
355 | } |
356 | |
357 | //! Check if none of the bits are set to true |
358 | bool test_none(void) const { |
359 | return BitsetHelper::TestNone(array_.data(), array_.size()); |
360 | } |
361 | |
362 | //! Compute the cardinality of a bitset |
363 | size_t cardinality(void) const { |
364 | return BitsetHelper::Cardinality(array_.data(), array_.size()); |
365 | } |
366 | |
367 | //! Extract the bitset to an array |
368 | void (size_t base, std::vector<size_t> *out) const { |
369 | const uint32_t *iter = array_.data(); |
370 | const uint32_t *last = array_.data() + array_.size(); |
371 | |
372 | for (; iter != last; ++iter) { |
373 | uint32_t w = *iter; |
374 | |
375 | while (w != 0) { |
376 | uint32_t c = ailego_ctz32(w); |
377 | w &= ~(1u << c); |
378 | out->push_back(base + c); |
379 | } |
380 | base += 32u; |
381 | } |
382 | } |
383 | |
384 | //! Extract the bitset to an array |
385 | void (std::vector<size_t> *out) const { |
386 | this->extract(0, out); |
387 | } |
388 | |
389 | //! Compute the AND cardinality between two bitsets |
390 | static size_t BitwiseAndCardinality(const Bitset &lhs, const Bitset &rhs); |
391 | |
392 | //! Compute the ANDNOT cardinality between two bitsets |
393 | static size_t BitwiseAndnotCardinality(const Bitset &lhs, const Bitset &rhs); |
394 | |
395 | //! Compute the XOR cardinality between two bitsets |
396 | static size_t BitwiseXorCardinality(const Bitset &lhs, const Bitset &rhs); |
397 | |
398 | //! Compute the OR cardinality between two bitsets |
399 | static size_t BitwiseOrCardinality(const Bitset &lhs, const Bitset &rhs); |
400 | |
401 | private: |
402 | std::vector<uint32_t> array_; |
403 | }; |
404 | |
405 | /*! Bitmap |
406 | */ |
407 | class Bitmap { |
408 | public: |
409 | typedef FixedBitset<65536u> Bucket; |
410 | |
411 | //! Constructor |
412 | Bitmap(void) : array_() {} |
413 | |
414 | //! Constructor |
415 | Bitmap(const Bitmap &rhs) { |
416 | this->copy(rhs); |
417 | } |
418 | |
419 | //! Destructor |
420 | ~Bitmap(void) { |
421 | this->clear(); |
422 | } |
423 | |
424 | //! Assignment |
425 | Bitmap &operator=(const Bitmap &rhs) { |
426 | this->copy(rhs); |
427 | return *this; |
428 | } |
429 | |
430 | //! Retrieve bucket size of bitmap |
431 | size_t bucket_size(void) const { |
432 | return array_.size(); |
433 | } |
434 | |
435 | //!Clear the bitmap |
436 | void clear(void); |
437 | |
438 | //! Remove the none buckets |
439 | void shrink_to_fit(void); |
440 | |
441 | //! Test a bit in bitmap |
442 | bool test(size_t num) const; |
443 | |
444 | //! Set a bit in bitmap |
445 | void set(size_t num); |
446 | |
447 | //! Reset a bit in bitmap |
448 | void reset(size_t num); |
449 | |
450 | //! Toggle a bit in bitmap |
451 | void flip(size_t num); |
452 | |
453 | //! Perform binary AND |
454 | void bitwise_and(const Bitmap &rhs); |
455 | |
456 | //! Perform binary AND NOT |
457 | void bitwise_andnot(const Bitmap &rhs); |
458 | |
459 | //! Perform binary OR |
460 | void bitwise_or(const Bitmap &rhs); |
461 | |
462 | //! Perform binary XOR |
463 | void bitwise_xor(const Bitmap &rhs); |
464 | |
465 | //! Perform binary NOT (It will expand the whole map) |
466 | void bitwise_not(void); |
467 | |
468 | //! Check if all bits are set to true |
469 | bool test_all(void) const; |
470 | |
471 | //! Check if any bits are set to true |
472 | bool test_any(void) const; |
473 | |
474 | //! Check if none of the bits are set to true |
475 | bool test_none(void) const; |
476 | |
477 | //! Compute the cardinality of a bitmap |
478 | size_t cardinality(void) const; |
479 | |
480 | //! Extract the bitmap to an array |
481 | void (size_t base, std::vector<size_t> *out) const; |
482 | |
483 | //! Extract the bitmap to an array |
484 | void (std::vector<size_t> *out) const { |
485 | this->extract(0, out); |
486 | } |
487 | |
488 | //! Compute the AND cardinality between two bitmaps |
489 | static size_t BitwiseAndCardinality(const Bitmap &lhs, const Bitmap &rhs); |
490 | |
491 | //! Compute the ANDNOT cardinality between two bitmaps |
492 | static size_t BitwiseAndnotCardinality(const Bitmap &lhs, const Bitmap &rhs); |
493 | |
494 | //! Compute the XOR cardinality between two bitmaps |
495 | static size_t BitwiseXorCardinality(const Bitmap &lhs, const Bitmap &rhs); |
496 | |
497 | //! Compute the OR cardinality between two bitmaps |
498 | static size_t BitwiseOrCardinality(const Bitmap &lhs, const Bitmap &rhs); |
499 | |
500 | protected: |
501 | //! Copy the content from another bitmap |
502 | void copy(const Bitmap &rhs); |
503 | |
504 | private: |
505 | std::vector<Bucket *> array_; |
506 | }; |
507 | |
508 | } // namespace ailego |
509 | |
510 | #endif // __AILEGO_CONTAINER_BITMAP_H__ |
511 | |