EasyNav Plugins
Loading...
Searching...
No Matches
mask.hpp
Go to the documentation of this file.
1/*
2 * Copyright Contributors to the Bonxai Project
3 * Copyright Contributors to the OpenVDB Project
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
8 */
9
10#pragma once
11
12#include <algorithm>
13#include <cmath>
14#include <cstdint>
15#include <utility>
16
17namespace Bonxai
18{
19
20class Mask {
21 uint64_t * words_ = nullptr;
22 // small object optimization, that will be used when
23 // SIZE <= 512 bits, i.e LOG2DIM <= 3
24 uint64_t static_words_[8];
25
26public:
28 Mask(size_t log2dim);
30 Mask(size_t log2dim, bool on);
31
32 Mask(const Mask & other);
33 Mask(Mask && other);
34
35 ~Mask();
36
38 size_t memUsage() const;
39
41 uint32_t bitCount() const
42 {
43 return SIZE;
44 }
45
47 uint32_t wordCount() const
48 {
49 return WORD_COUNT;
50 }
51
52 uint64_t getWord(size_t n) const
53 {
54 return words_[n];
55 }
56
57 void setWord(size_t n, uint64_t v)
58 {
59 words_[n] = v;
60 }
61
62 uint32_t countOn() const;
63
64 class Iterator {
65public:
66 Iterator(const Mask * parent)
67 : pos_(parent->SIZE),
68 parent_(parent) {}
69 Iterator(uint32_t pos, const Mask * parent)
70 : pos_(pos),
71 parent_(parent) {}
72 Iterator & operator=(const Iterator &) = default;
73
74 uint32_t operator*() const
75 {
76 return pos_;
77 }
78
79 operator bool() const {
80 return pos_ != parent_->SIZE;
81 }
82
84 {
85 pos_ = parent_->findNextOn(pos_ + 1);
86 return *this;
87 }
88
89private:
90 uint32_t pos_;
91 const Mask * parent_;
92 };
93
94 bool operator==(const Mask & other) const;
95
96 bool operator!=(const Mask & other) const
97 {
98 return !((*this) == other);
99 }
100
102 {
103 return Iterator(this->findFirstOn(), this);
104 }
105
107 bool isOn(uint32_t n) const;
109 bool isOn() const;
110
111 bool isOff() const;
112
113 bool setOn(uint32_t n);
114
115 bool setOff(uint32_t n);
116
117 void set(uint32_t n, bool On);
118
120 void setOn();
121
123 void setOff();
124
126 void set(bool on);
127
129 void toggle();
131 void toggle(uint32_t n);
132
133 uint32_t findFirstOn() const;
134
135 uint32_t size() const
136 {
137 return SIZE;
138 }
139
140private:
141 uint32_t findNextOn(uint32_t start) const;
142
143 static uint32_t FindLowestOn(uint64_t v);
144 static uint32_t CountOn(uint64_t v);
145
146 // Number of bits in mask
147 uint32_t SIZE;
148 // Number of 64 bit words
149 uint32_t WORD_COUNT;
150};
151
152//----------------------------------------------------
153//----------------- Implementations ------------------
154//----------------------------------------------------
155
156#define BONXAI_USE_INTRINSICS
157
163
164inline uint32_t Mask::FindLowestOn(uint64_t v)
165{
166#if defined(_MSC_VER) && defined(BONXAI_USE_INTRINSICS)
167 unsigned long index;
168 _BitScanForward64(&index, v);
169 return static_cast<uint32_t>(index);
170#elif (defined(__GNUC__) || defined(__clang__)) && defined(BONXAI_USE_INTRINSICS)
171 return static_cast<uint32_t>(__builtin_ctzll(v));
172#else
173 static const unsigned char DeBruijn[64] = {
174 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, 62, 5, 39, 46, 44, 42,
175 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21,
176 23, 58, 17, 10, 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12,
177 };
178// disable unary minus on unsigned warning
179#if defined(_MSC_VER) && !defined(__NVCC__)
180#pragma warning(push)
181#pragma warning(disable : 4146)
182#endif
184 return DeBruijn[uint64_t((v & -v) * UINT64_C(0x022FDD63CC95386D)) >> 58];
185#if defined(_MSC_VER) && !defined(__NVCC__)
186#pragma warning(pop)
187#endif
188
189#endif
190}
191
193
194inline uint32_t Mask::CountOn(uint64_t v)
195{
196#if defined(_MSC_VER) && defined(_M_X64)
197 v = __popcnt64(v);
198#elif (defined(__GNUC__) || defined(__clang__))
199 v = __builtin_popcountll(v);
200#else
201 // Software Implementation
203 v = v - ((v >> 1) & uint64_t(0x5555555555555555));
204 v = (v & uint64_t(0x3333333333333333)) + ((v >> 2) & uint64_t(0x3333333333333333));
205 v = (((v + (v >> 4)) & uint64_t(0xF0F0F0F0F0F0F0F)) * uint64_t(0x101010101010101)) >> 56;
206#endif
207 return static_cast<uint32_t>(v);
208}
209
210inline void Mask::setOn()
211{
212 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
213 words_[i] = ~uint64_t(0);
214 }
215}
216
217inline void Mask::setOff()
218{
219 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
220 words_[i] = uint64_t(0);
221 }
222}
223
224inline void Mask::set(bool on)
225{
226 const uint64_t v = on ? ~uint64_t(0) : uint64_t(0);
227 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
228 words_[i] = v;
229 }
230}
231
232inline void Mask::toggle()
233{
234 uint32_t n = WORD_COUNT;
235 for (auto * w = words_; n--; ++w) {
236 *w = ~*w;
237 }
238}
239
240inline void Mask::toggle(uint32_t n)
241{
242 words_[n >> 6] ^= uint64_t(1) << (n & 63);
243}
244
245inline uint32_t Mask::findFirstOn() const
246{
247 const uint64_t * w = words_;
248 uint32_t n = 0;
249 while (n < WORD_COUNT && !*w) {
250 ++w;
251 ++n;
252 }
253 return n == WORD_COUNT ? SIZE : (n << 6) + FindLowestOn(*w);
254}
255
256inline uint32_t Mask::findNextOn(uint32_t start) const
257{
258 uint32_t n = start >> 6; // initiate
259 if (n >= WORD_COUNT) {
260 return SIZE; // check for out of bounds
261 }
262 uint32_t m = start & 63;
263 uint64_t b = words_[n];
264 if (b & (uint64_t(1) << m)) {
265 return start; // simple case: start is on
266 }
267 b &= ~uint64_t(0) << m; // mask out lower bits
268 while (!b && ++n < WORD_COUNT) {
269 b = words_[n];
270 } // find next non-zero word
271 return !b ? SIZE : (n << 6) + FindLowestOn(b); // catch last word=0
272}
273
274inline Mask::Mask(size_t log2dim)
275: SIZE(1U << (3 * log2dim)),
276 WORD_COUNT(std::max(SIZE >> 6, 1u))
277{
278 words_ = (WORD_COUNT <= 8) ? static_words_ : new uint64_t[WORD_COUNT];
279
280 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
281 words_[i] = 0;
282 }
283}
284
285inline Mask::Mask(size_t log2dim, bool on)
286: SIZE(1U << (3 * log2dim)),
287 WORD_COUNT(std::max(SIZE >> 6, 1u))
288{
289 words_ = (WORD_COUNT <= 8) ? static_words_ : new uint64_t[WORD_COUNT];
290
291 const uint64_t v = on ? ~uint64_t(0) : uint64_t(0);
292 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
293 words_[i] = v;
294 }
295}
296
297inline Mask::Mask(const Mask & other)
298: SIZE(other.SIZE),
299 WORD_COUNT(other.WORD_COUNT)
300{
301 words_ = (WORD_COUNT <= 8) ? static_words_ : new uint64_t[WORD_COUNT];
302
303 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
304 words_[i] = other.words_[i];
305 }
306}
307
308inline Mask::Mask(Mask && other)
309: SIZE(other.SIZE),
310 WORD_COUNT(other.WORD_COUNT)
311{
312 if (WORD_COUNT <= 8) {
313 words_ = static_words_;
314 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
315 words_[i] = other.words_[i];
316 }
317 } else {
318 std::swap(words_, other.words_);
319 }
320}
321
323{
324 if (WORD_COUNT > 8) {
325 delete[] words_;
326 }
327}
328
329inline size_t Mask::memUsage() const
330{
331 if (WORD_COUNT > 8) {
332 return sizeof(Mask) + sizeof(uint64_t) * WORD_COUNT;
333 }
334 return sizeof(Mask);
335}
336
337inline uint32_t Mask::countOn() const
338{
339 uint32_t sum = 0, n = WORD_COUNT;
340 for (const uint64_t * w = words_; n--; ++w) {
341 sum += CountOn(*w);
342 }
343 return sum;
344}
345
346inline bool Mask::operator==(const Mask & other) const
347{
348 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
349 if (words_[i] != other.words_[i]) {
350 return false;
351 }
352 }
353 return true;
354}
355
356inline bool Mask::isOn(uint32_t n) const
357{
358 return 0 != (words_[n >> 6] & (uint64_t(1) << (n & 63)));
359}
360
361inline bool Mask::isOn() const
362{
363 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
364 if (words_[i] != ~uint64_t(0)) {
365 return false;
366 }
367 }
368 return true;
369}
370
371inline bool Mask::isOff() const
372{
373 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
374 if (words_[i] != uint64_t(0)) {
375 return false;
376 }
377 }
378 return true;
379}
380
381inline bool Mask::setOn(uint32_t n)
382{
383 uint64_t & word = words_[n >> 6];
384 const uint64_t on_bit = (uint64_t(1) << (n & 63));
385 bool was_on = word & on_bit;
386 word |= on_bit;
387 return was_on;
388}
389
390inline bool Mask::setOff(uint32_t n)
391{
392 uint64_t & word = words_[n >> 6];
393 const uint64_t on_bit = (uint64_t(1) << (n & 63));
394 bool was_on = word & on_bit;
395 word &= ~(on_bit);
396 return was_on;
397}
398
399inline void Mask::set(uint32_t n, bool On)
400{
401#if 1 // switch between branchless
402 auto & word = words_[n >> 6];
403 n &= 63;
404 word &= ~(uint64_t(1) << n);
405 word |= uint64_t(On) << n;
406#else
407 On ? this->setOn(n) : this->setOff(n);
408#endif
409}
410
411} // namespace Bonxai
Definition mask.hpp:64
Iterator & operator=(const Iterator &)=default
uint32_t operator*() const
Definition mask.hpp:74
Iterator(uint32_t pos, const Mask *parent)
Definition mask.hpp:69
Iterator & operator++()
Definition mask.hpp:83
Iterator(const Mask *parent)
Definition mask.hpp:66
Definition mask.hpp:20
uint32_t bitCount() const
Return the number of bits available in this Mask.
Definition mask.hpp:41
Iterator beginOn() const
Definition mask.hpp:101
uint32_t findFirstOn() const
Definition mask.hpp:245
size_t memUsage() const
Return the memory footprint in bytes of this Mask.
Definition mask.hpp:329
void set(uint32_t n, bool On)
Definition mask.hpp:399
void setWord(size_t n, uint64_t v)
Definition mask.hpp:57
bool operator==(const Mask &other) const
Definition mask.hpp:346
Mask(size_t log2dim)
Initialize all bits to zero.
Definition mask.hpp:274
void setOn()
Set all bits on.
Definition mask.hpp:210
uint32_t size() const
Definition mask.hpp:135
uint32_t countOn() const
Definition mask.hpp:337
void setOff()
Set all bits off.
Definition mask.hpp:217
uint64_t getWord(size_t n) const
Definition mask.hpp:52
bool isOff() const
Definition mask.hpp:371
bool operator!=(const Mask &other) const
Definition mask.hpp:96
void toggle()
Toggle the state of all bits in the mask.
Definition mask.hpp:232
uint32_t wordCount() const
Return the number of machine words used by this Mask.
Definition mask.hpp:47
~Mask()
Definition mask.hpp:322
bool isOn() const
Return true if any bit is set.
Definition mask.hpp:361
Definition bonxai.hpp:28
Definition grid_coord.hpp:226