Blender V5.0
BLI_bit_span.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include <optional>
12
13#include "BLI_bit_ref.hh"
14#include "BLI_index_range.hh"
15#include "BLI_memory_utils.hh"
16
17namespace blender::bits {
18
21 protected:
22 const BitInt *data_;
24
25 public:
26 BitIteratorBase(const BitInt *data, const int64_t bit_index) : data_(data), bit_index_(bit_index)
27 {
28 }
29
31 {
32 bit_index_++;
33 return *this;
34 }
35
36 friend bool operator!=(const BitIteratorBase &a, const BitIteratorBase &b)
37 {
38 BLI_assert(a.data_ == b.data_);
39 return a.bit_index_ != b.bit_index_;
40 }
41};
42
45 public:
46 BitIterator(const BitInt *data, const int64_t bit_index) : BitIteratorBase(data, bit_index) {}
47
49 {
50 return BitRef(data_, bit_index_);
51 }
52};
53
56 public:
57 MutableBitIterator(BitInt *data, const int64_t bit_index) : BitIteratorBase(data, bit_index) {}
58
60 {
61 return MutableBitRef(const_cast<BitInt *>(data_), bit_index_);
62 }
63};
64
72class BitSpan {
73 protected:
76 const BitInt *data_ = nullptr;
79
80 public:
82 BitSpan() = default;
83
84 BitSpan(const BitInt *data, const int64_t size_in_bits) : data_(data), bit_range_(size_in_bits)
85 {
86 }
87
89
91 int64_t size() const
92 {
93 return bit_range_.size();
94 }
95
96 bool is_empty() const
97 {
98 return bit_range_.is_empty();
99 }
100
102 {
103 return IndexRange(bit_range_.size());
104 }
105
106 [[nodiscard]] BitRef operator[](const int64_t index) const
107 {
108 BLI_assert(index >= 0);
109 BLI_assert(index < bit_range_.size());
110 return {data_, bit_range_.start() + index};
111 }
112
113 [[nodiscard]] BitSpan slice(const IndexRange range) const
114 {
115 return {data_, bit_range_.slice(range)};
116 }
117
119 {
120 return {data_, bit_range_.take_front(n)};
121 }
122
123 BitSpan take_back(const int64_t n) const
124 {
125 return {data_, bit_range_.take_back(n)};
126 }
127
129 {
130 return {data_, bit_range_.drop_front(n)};
131 }
132
133 BitSpan drop_back(const int64_t n) const
134 {
135 return {data_, bit_range_.drop_back(n)};
136 }
137
138 const BitInt *data() const
139 {
140 return data_;
141 }
142
143 const IndexRange &bit_range() const
144 {
145 return bit_range_;
146 }
147
149 {
150 return {data_, bit_range_.start()};
151 }
152
154 {
155 return {data_, bit_range_.one_after_last()};
156 }
157};
158
166inline bool is_bounded_span(const BitSpan span)
167{
168 const int64_t offset = span.bit_range().start();
169 const int64_t size = span.size();
170 if (offset >= BitsPerInt) {
171 /* The data pointer must point at the first int already. If the offset is a multiple of
172 * #BitsPerInt, the bit span could theoretically become bounded as well if the data pointer is
173 * adjusted. But that is not handled here. */
174 return false;
175 }
176 if (size < BitsPerInt) {
178 return offset + size <= 64;
179 }
180 if (offset != 0) {
181 /* Start of larger spans must be aligned to `BitInt` boundaries. */
182 return false;
183 }
184 return true;
185}
186
190class BoundedBitSpan : public BitSpan {
191 public:
192 BoundedBitSpan() = default;
193
194 BoundedBitSpan(const BitInt *data, const int64_t size_in_bits) : BitSpan(data, size_in_bits)
195 {
197 }
198
203
204 explicit BoundedBitSpan(const BitSpan other) : BitSpan(other)
205 {
207 }
208
210 {
211 return bit_range_.start();
212 }
213
215 {
216 return bit_range_.size() >> BitToIntIndexShift;
217 }
218
220 {
221 return bit_range_.size() & BitIndexMask;
222 }
223
225 {
226 return {data_, bit_range_.take_front(n)};
227 }
228};
229
232 protected:
233 BitInt *data_ = nullptr;
235
236 public:
237 MutableBitSpan() = default;
238
240
242
243 int64_t size() const
244 {
245 return bit_range_.size();
246 }
247
248 bool is_empty() const
249 {
250 return bit_range_.is_empty();
251 }
252
254 {
255 return IndexRange(bit_range_.size());
256 }
257
259 {
260 BLI_assert(index >= 0);
261 BLI_assert(index < bit_range_.size());
262 return {data_, bit_range_.start() + index};
263 }
264
265 MutableBitSpan slice(const IndexRange range) const
266 {
267 return {data_, bit_range_.slice(range)};
268 }
269
271 {
272 return {data_, bit_range_.take_front(n)};
273 }
274
276 {
277 return {data_, bit_range_.take_back(n)};
278 }
279
280 BitInt *data() const
281 {
282 return data_;
283 }
284
285 const IndexRange &bit_range() const
286 {
287 return bit_range_;
288 }
289
291 {
292 return {data_, bit_range_.start()};
293 }
294
296 {
297 return {data_, bit_range_.one_after_last()};
298 }
299
300 operator BitSpan() const
301 {
302 return {data_, bit_range_};
303 }
304
306 void set_all();
307
309 void reset_all();
310
311 void copy_from(const BitSpan other);
312 void copy_from(const BoundedBitSpan other);
313
315 void set_all(const bool value)
316 {
317 if (value) {
318 this->set_all();
319 }
320 else {
321 this->reset_all();
322 }
323 }
324
326 void fill(const bool value)
327 {
328 this->set_all(value);
329 }
330};
331
336 public:
338
343
348
350 {
352 }
353
354 operator BoundedBitSpan() const
355 {
356 return BoundedBitSpan{BitSpan(*this)};
357 }
358
360 {
361 return bit_range_.start();
362 }
363
365 {
366 return bit_range_.size() >> BitToIntIndexShift;
367 }
368
370 {
371 return bit_range_.size() & BitIndexMask;
372 }
373
375 {
376 return {data_, bit_range_.take_front(n)};
377 }
378
380 {
382 }
383
384 void copy_from(const BitSpan other);
385 void copy_from(const BoundedBitSpan other);
386};
387
388inline std::optional<BoundedBitSpan> try_get_bounded_span(const BitSpan span)
389{
390 if (is_bounded_span(span)) {
391 return BoundedBitSpan(span);
392 }
393 if (span.bit_range().start() % BitsPerInt == 0) {
394 return BoundedBitSpan(span.data() + (span.bit_range().start() >> BitToIntIndexShift),
395 span.size());
396 }
397 return std::nullopt;
398}
399
404template<typename T> inline T to_best_bit_span(const T &data)
405{
406 static_assert(is_same_any_v<std::decay_t<T>,
407 BitSpan,
411 return data;
412}
413
414template<typename... Args>
415constexpr bool all_bounded_spans =
417
418std::ostream &operator<<(std::ostream &stream, const BitSpan &span);
419std::ostream &operator<<(std::ostream &stream, const MutableBitSpan &span);
420
421} // namespace blender::bits
422
423namespace blender {
424using bits::BitSpan;
428} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:46
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
BitSpan()=default
constexpr int64_t start() const
BitIteratorBase & operator++()
friend bool operator!=(const BitIteratorBase &a, const BitIteratorBase &b)
BitIteratorBase(const BitInt *data, const int64_t bit_index)
BitIterator(const BitInt *data, const int64_t bit_index)
BitSpan drop_back(const int64_t n) const
BitIterator end() const
IndexRange index_range() const
const BitInt * data() const
BitRef operator[](const int64_t index) const
BitSpan take_front(const int64_t n) const
BitSpan(const BitInt *data, const IndexRange bit_range)
int64_t size() const
BitSpan take_back(const int64_t n) const
BitSpan slice(const IndexRange range) const
BitSpan(const BitInt *data, const int64_t size_in_bits)
const IndexRange & bit_range() const
BitSpan drop_front(const int64_t n) const
BitIterator begin() const
BoundedBitSpan(const BitInt *data, const IndexRange bit_range)
BoundedBitSpan(const BitSpan other)
BoundedBitSpan take_front(const int64_t n) const
BoundedBitSpan(const BitInt *data, const int64_t size_in_bits)
MutableBitIterator(BitInt *data, const int64_t bit_index)
MutableBitRef operator*() const
MutableBitSpan(BitInt *data, const int64_t size)
MutableBitSpan slice(const IndexRange range) const
MutableBitIterator end() const
const IndexRange & bit_range() const
MutableBitSpan take_front(const int64_t n) const
void set_all(const bool value)
IndexRange index_range() const
void copy_from(const BitSpan other)
Definition bit_span.cc:66
MutableBitRef operator[](const int64_t index) const
MutableBitSpan(BitInt *data, const IndexRange bit_range)
void fill(const bool value)
MutableBitIterator begin() const
MutableBitSpan take_back(const int64_t n) const
MutableBoundedBitSpan(BitInt *data, const IndexRange bit_range)
MutableBoundedBitSpan take_front(const int64_t n) const
MutableBoundedBitSpan(const MutableBitSpan other)
MutableBoundedBitSpan(BitInt *data, const int64_t size)
void copy_from(const BitSpan other)
Definition bit_span.cc:78
#define T
uint64_t BitInt
std::optional< BoundedBitSpan > try_get_bounded_span(const BitSpan span)
static constexpr BitInt BitIndexMask
constexpr bool all_bounded_spans
static constexpr int64_t BitsPerInt
T to_best_bit_span(const T &data)
static constexpr int64_t BitToIntIndexShift
std::ostream & operator<<(std::ostream &stream, const BitRef &bit)
Definition bit_ref.cc:15
bool is_bounded_span(const BitSpan span)
constexpr bool is_same_any_v