Blender V4.3
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
5#pragma once
6
7#include <optional>
8
9#include "BLI_bit_ref.hh"
10#include "BLI_index_range.hh"
11#include "BLI_memory_utils.hh"
12
13namespace blender::bits {
14
17 protected:
18 const BitInt *data_;
20
21 public:
22 BitIteratorBase(const BitInt *data, const int64_t bit_index) : data_(data), bit_index_(bit_index)
23 {
24 }
25
27 {
28 bit_index_++;
29 return *this;
30 }
31
32 friend bool operator!=(const BitIteratorBase &a, const BitIteratorBase &b)
33 {
34 BLI_assert(a.data_ == b.data_);
35 return a.bit_index_ != b.bit_index_;
36 }
37};
38
41 public:
42 BitIterator(const BitInt *data, const int64_t bit_index) : BitIteratorBase(data, bit_index) {}
43
45 {
46 return BitRef(data_, bit_index_);
47 }
48};
49
52 public:
53 MutableBitIterator(BitInt *data, const int64_t bit_index) : BitIteratorBase(data, bit_index) {}
54
56 {
57 return MutableBitRef(const_cast<BitInt *>(data_), bit_index_);
58 }
59};
60
68class BitSpan {
69 protected:
72 const BitInt *data_ = nullptr;
75
76 public:
78 BitSpan() = default;
79
80 BitSpan(const BitInt *data, const int64_t size_in_bits) : data_(data), bit_range_(size_in_bits)
81 {
82 }
83
84 BitSpan(const BitInt *data, const IndexRange bit_range) : data_(data), bit_range_(bit_range) {}
85
87 int64_t size() const
88 {
89 return bit_range_.size();
90 }
91
92 bool is_empty() const
93 {
94 return bit_range_.is_empty();
95 }
96
98 {
99 return IndexRange(bit_range_.size());
100 }
101
102 [[nodiscard]] BitRef operator[](const int64_t index) const
103 {
104 BLI_assert(index >= 0);
105 BLI_assert(index < bit_range_.size());
106 return {data_, bit_range_.start() + index};
107 }
108
109 [[nodiscard]] BitSpan slice(const IndexRange range) const
110 {
111 return {data_, bit_range_.slice(range)};
112 }
113
115 {
116 return {data_, bit_range_.take_front(n)};
117 }
118
119 BitSpan take_back(const int64_t n) const
120 {
121 return {data_, bit_range_.take_back(n)};
122 }
123
124 const BitInt *data() const
125 {
126 return data_;
127 }
128
129 const IndexRange &bit_range() const
130 {
131 return bit_range_;
132 }
133
135 {
136 return {data_, bit_range_.start()};
137 }
138
140 {
141 return {data_, bit_range_.one_after_last()};
142 }
143};
144
152inline bool is_bounded_span(const BitSpan span)
153{
154 const int64_t offset = span.bit_range().start();
155 const int64_t size = span.size();
156 if (offset >= BitsPerInt) {
157 /* The data pointer must point at the first int already. If the offset is a multiple of
158 * #BitsPerInt, the bit span could theoretically become bounded as well if the data pointer is
159 * adjusted. But that is not handled here. */
160 return false;
161 }
162 if (size < BitsPerInt) {
164 return offset + size <= 64;
165 }
166 if (offset != 0) {
167 /* Start of larger spans must be aligned to `BitInt` boundaries. */
168 return false;
169 }
170 return true;
171}
172
176class BoundedBitSpan : public BitSpan {
177 public:
178 BoundedBitSpan() = default;
179
180 BoundedBitSpan(const BitInt *data, const int64_t size_in_bits) : BitSpan(data, size_in_bits)
181 {
183 }
184
186 {
188 }
189
190 explicit BoundedBitSpan(const BitSpan other) : BitSpan(other)
191 {
193 }
194
196 {
197 return bit_range_.start();
198 }
199
201 {
203 }
204
206 {
207 return bit_range_.size() & BitIndexMask;
208 }
209
211 {
212 return {data_, bit_range_.take_front(n)};
213 }
214};
215
218 protected:
219 BitInt *data_ = nullptr;
221
222 public:
223 MutableBitSpan() = default;
224
225 MutableBitSpan(BitInt *data, const int64_t size) : data_(data), bit_range_(size) {}
226
228
229 int64_t size() const
230 {
231 return bit_range_.size();
232 }
233
234 bool is_empty() const
235 {
236 return bit_range_.is_empty();
237 }
238
240 {
241 return IndexRange(bit_range_.size());
242 }
243
245 {
246 BLI_assert(index >= 0);
247 BLI_assert(index < bit_range_.size());
248 return {data_, bit_range_.start() + index};
249 }
250
251 MutableBitSpan slice(const IndexRange range) const
252 {
253 return {data_, bit_range_.slice(range)};
254 }
255
257 {
258 return {data_, bit_range_.take_front(n)};
259 }
260
262 {
263 return {data_, bit_range_.take_back(n)};
264 }
265
266 BitInt *data() const
267 {
268 return data_;
269 }
270
271 const IndexRange &bit_range() const
272 {
273 return bit_range_;
274 }
275
277 {
278 return {data_, bit_range_.start()};
279 }
280
282 {
283 return {data_, bit_range_.one_after_last()};
284 }
285
286 operator BitSpan() const
287 {
288 return {data_, bit_range_};
289 }
290
292 void set_all();
293
295 void reset_all();
296
297 void copy_from(const BitSpan other);
298 void copy_from(const BoundedBitSpan other);
299
301 void set_all(const bool value)
302 {
303 if (value) {
304 this->set_all();
305 }
306 else {
307 this->reset_all();
308 }
309 }
310
312 void fill(const bool value)
313 {
314 this->set_all(value);
315 }
316};
317
322 public:
324
325 MutableBoundedBitSpan(BitInt *data, const int64_t size) : MutableBitSpan(data, size)
326 {
328 }
329
334
336 {
338 }
339
340 operator BoundedBitSpan() const
341 {
342 return BoundedBitSpan{BitSpan(*this)};
343 }
344
346 {
347 return bit_range_.start();
348 }
349
351 {
353 }
354
356 {
357 return bit_range_.size() & BitIndexMask;
358 }
359
361 {
362 return {data_, bit_range_.take_front(n)};
363 }
364
366 {
368 }
369
370 void copy_from(const BitSpan other);
371 void copy_from(const BoundedBitSpan other);
372};
373
374inline std::optional<BoundedBitSpan> try_get_bounded_span(const BitSpan span)
375{
376 if (is_bounded_span(span)) {
377 return BoundedBitSpan(span);
378 }
379 if (span.bit_range().start() % BitsPerInt == 0) {
380 return BoundedBitSpan(span.data() + (span.bit_range().start() >> BitToIntIndexShift),
381 span.size());
382 }
383 return std::nullopt;
384}
385
390template<typename T> inline T to_best_bit_span(const T &data)
391{
392 static_assert(is_same_any_v<std::decay_t<T>,
393 BitSpan,
397 return data;
398}
399
400template<typename... Args>
401constexpr bool all_bounded_spans =
403
404std::ostream &operator<<(std::ostream &stream, const BitSpan &span);
405std::ostream &operator<<(std::ostream &stream, const MutableBitSpan &span);
406
407} // namespace blender::bits
408
409namespace blender {
410using bits::BitSpan;
414} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:50
constexpr int64_t one_after_last() const
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr int64_t start() const
constexpr IndexRange take_back(int64_t n) const
constexpr IndexRange slice(int64_t start, int64_t size) const
constexpr IndexRange take_front(int64_t n) 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)
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
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:62
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:74
local_group_size(16, 16) .push_constant(Type b
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:11
bool is_bounded_span(const BitSpan span)
constexpr bool is_same_any_v
__int64 int64_t
Definition stdint.h:89