Blender V5.0
BLI_bit_span_ops.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 "BLI_bit_span.hh"
12#include "BLI_math_bits.h"
13
14namespace blender::bits {
15
16namespace detail {
17
24template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
25inline void mix_into_first_expr(ExprFn &&expr,
26 const FirstBitSpanT &first_arg,
27 const BitSpanT &...args)
28{
29 const int64_t size = first_arg.size();
30 BLI_assert(((size == args.size()) && ...));
31 if (size == 0) {
32 return;
33 }
34
35 if constexpr (all_bounded_spans<FirstBitSpanT, BitSpanT...>) {
36 BitInt *first_data = first_arg.data();
37 const int64_t first_offset = first_arg.offset();
38 const int64_t full_ints_num = first_arg.full_ints_num();
39 /* Compute expression without any masking, all the spans are expected to be aligned to the
40 * beginning of a #BitInt. */
41 for (const int64_t i : IndexRange(full_ints_num)) {
42 first_data[i] = expr(first_data[i], args.data()[i]...);
43 }
44 /* Compute expression for the remaining bits. */
45 if (const int64_t final_bits = first_arg.final_bits_num()) {
46 const BitInt result = expr(first_data[full_ints_num] >> first_offset,
47 (args.data()[full_ints_num] >> args.offset())...);
48 const BitInt mask = mask_range_bits(first_offset, final_bits);
49 first_data[full_ints_num] = ((result << first_offset) & mask) |
50 (first_data[full_ints_num] & ~mask);
51 }
52 }
53 else {
54 /* Fallback for arbitrary bit spans. This could be implemented more efficiently but adds more
55 * complexity and is not necessary yet. */
56 for (const int64_t i : IndexRange(size)) {
57 const bool result = expr(BitInt(first_arg[i].test()), BitInt(args[i].test())...) != 0;
58 first_arg[i].set(result);
59 }
60 }
61}
62
70template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
71inline bool any_set_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
72{
73 const int64_t size = first_arg.size();
74 BLI_assert(((size == args.size()) && ...));
75 if (size == 0) {
76 return false;
77 }
78
79 if constexpr (all_bounded_spans<FirstBitSpanT, BitSpanT...>) {
80 const BitInt *first_data = first_arg.data();
81 const int64_t full_ints_num = first_arg.full_ints_num();
82 /* Compute expression without any masking, all the spans are expected to be aligned to the
83 * beginning of a #BitInt. */
84 for (const int64_t i : IndexRange(full_ints_num)) {
85 if (expr(first_data[i], args.data()[i]...) != 0) {
86 return true;
87 }
88 }
89 /* Compute expression for the remaining bits. */
90 if (const int64_t final_bits = first_arg.final_bits_num()) {
91 const BitInt result = expr(first_data[full_ints_num] >> first_arg.offset(),
92 (args.data()[full_ints_num] >> args.offset())...);
93 const BitInt mask = mask_first_n_bits(final_bits);
94 if ((result & mask) != 0) {
95 return true;
96 }
97 }
98 return false;
99 }
100 else {
101 /* Fallback for arbitrary bit spans. This could be implemented more efficiently but adds more
102 * complexity and is not necessary yet. */
103 for (const int64_t i : IndexRange(size)) {
104 const BitInt result = expr(BitInt(first_arg[i].test()), BitInt(args[i].test())...);
105 if (result & 1) {
106 return true;
107 }
108 }
109 return false;
110 }
111}
112
120template<typename ExprFn, typename HandleFn, typename FirstBitSpanT, typename... BitSpanT>
121inline void foreach_1_index_expr(ExprFn &&expr,
122 HandleFn &&handle,
123 const FirstBitSpanT &first_arg,
124 const BitSpanT &...args)
125{
126 static_assert(std::is_invocable_v<HandleFn, int64_t>);
127 constexpr bool is_cancellable = std::is_invocable_r_v<bool, HandleFn, int64_t>;
128
129 const int64_t size = first_arg.size();
130 BLI_assert(((size == args.size()) && ...));
131 if (size == 0) {
132 return;
133 }
134
135 if constexpr (all_bounded_spans<FirstBitSpanT, BitSpanT...>) {
136 const BitInt *first_data = first_arg.data();
137 const int64_t full_ints_num = first_arg.full_ints_num();
138 /* Iterate over full ints without any bit masks. */
139 for (const int64_t int_i : IndexRange(full_ints_num)) {
140 BitInt tmp = expr(first_data[int_i], args.data()[int_i]...);
141 const int64_t offset = int_i << BitToIntIndexShift;
142 while (tmp != 0) {
143 static_assert(std::is_same_v<BitInt, uint64_t>);
144 const int index_in_int = bitscan_forward_uint64(tmp);
145 const int64_t index_in_span = index_in_int + offset;
146 if constexpr (is_cancellable) {
147 if (!handle(index_in_span)) {
148 return;
149 }
150 }
151 else {
152 handle(index_in_span);
153 }
154 tmp &= ~mask_single_bit(index_in_int);
155 }
156 }
157 /* Iterate over remaining bits. */
158 if (const int64_t final_bits = first_arg.final_bits_num()) {
159 BitInt tmp = expr(first_data[full_ints_num] >> first_arg.offset(),
160 (args.data()[full_ints_num] >> args.offset())...) &
161 mask_first_n_bits(final_bits);
162 const int64_t offset = full_ints_num << BitToIntIndexShift;
163 while (tmp != 0) {
164 static_assert(std::is_same_v<BitInt, uint64_t>);
165 const int index_in_int = bitscan_forward_uint64(tmp);
166 const int64_t index_in_span = index_in_int + offset;
167 if constexpr (is_cancellable) {
168 if (!handle(index_in_span)) {
169 return;
170 }
171 }
172 else {
173 handle(index_in_span);
174 }
175 tmp &= ~mask_single_bit(index_in_int);
176 }
177 }
178 }
179 else {
180 /* Fallback for arbitrary bit spans. This could be implemented more efficiently but adds more
181 * complexity and is not necessary yet. */
182 for (const int64_t i : IndexRange(size)) {
183 const BitInt result = expr(BitInt(first_arg[i].test()), BitInt(args[i].test())...);
184 if (result & 1) {
185 if constexpr (is_cancellable) {
186 if (!handle(i)) {
187 return;
188 }
189 }
190 else {
191 handle(i);
192 }
193 }
194 }
195 }
196}
197
198template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
199inline std::optional<int64_t> find_first_1_index_expr(ExprFn &&expr,
200 const FirstBitSpanT &first_arg,
201 const BitSpanT &...args)
202{
203 std::optional<int64_t> result;
205 expr,
206 [&](const int64_t i) {
207 result = i;
208 return false;
209 },
210 first_arg,
211 args...);
212 return result;
213}
214
215} // namespace detail
216
217template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
218inline void mix_into_first_expr(ExprFn &&expr, FirstBitSpanT &&first_arg, const BitSpanT &...args)
219{
221}
222
223template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
224inline bool any_set_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
225{
226 return detail::any_set_expr(expr, to_best_bit_span(first_arg), to_best_bit_span(args)...);
227}
228
229template<typename ExprFn, typename HandleFn, typename FirstBitSpanT, typename... BitSpanT>
230inline void foreach_1_index_expr(ExprFn &&expr,
231 HandleFn &&handle,
232 const FirstBitSpanT &first_arg,
233 const BitSpanT &...args)
234{
236 expr, handle, to_best_bit_span(first_arg), to_best_bit_span(args)...);
237}
238
239template<typename BitSpanT> inline void invert(BitSpanT &&data)
240{
241 mix_into_first_expr([](const BitInt x) { return ~x; }, data);
242}
243
244template<typename FirstBitSpanT, typename... BitSpanT>
245inline void inplace_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
246{
247 mix_into_first_expr([](const auto... x) { return (x | ...); }, first_arg, args...);
248}
249
250template<typename FirstBitSpanT, typename MaskBitSpanT, typename... BitSpanT>
251inline void inplace_or_masked(FirstBitSpanT &&first_arg,
252 const MaskBitSpanT &mask,
253 const BitSpanT &...args)
254{
256 [](const BitInt a, const BitInt mask, const auto... x) { return a | ((x | ...) & mask); },
257 first_arg,
258 mask,
259 args...);
260}
261
262template<typename FirstBitSpanT, typename... BitSpanT>
263inline void copy_from_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
264{
266 [](auto /*first*/, auto... rest) { return (rest | ...); }, first_arg, args...);
267}
268
269template<typename FirstBitSpanT, typename... BitSpanT>
270inline void inplace_and(FirstBitSpanT &first_arg, const BitSpanT &...args)
271{
272 mix_into_first_expr([](const auto... x) { return (x & ...); }, first_arg, args...);
273}
274
275template<typename... BitSpanT>
276inline void operator|=(MutableBitSpan first_arg, const BitSpanT &...args)
277{
278 inplace_or(first_arg, args...);
279}
280
281template<typename... BitSpanT>
282inline void operator|=(MutableBoundedBitSpan first_arg, const BitSpanT &...args)
283{
284 inplace_or(first_arg, args...);
285}
286
287template<typename... BitSpanT>
288inline void operator&=(MutableBitSpan first_arg, const BitSpanT &...args)
289{
290 inplace_and(first_arg, args...);
291}
292
293template<typename... BitSpanT>
294inline void operator&=(MutableBoundedBitSpan first_arg, const BitSpanT &...args)
295{
296 inplace_and(first_arg, args...);
297}
298
299template<typename... BitSpanT> inline bool has_common_set_bits(const BitSpanT &...args)
300{
301 return any_set_expr([](const auto... x) { return (x & ...); }, args...);
302}
303
304template<typename BitSpanT> inline bool any_bit_set(const BitSpanT &arg)
305{
306 return has_common_set_bits(arg);
307}
308
309template<typename... BitSpanT> inline bool has_common_unset_bits(const BitSpanT &...args)
310{
311 return any_set_expr([](const auto... x) { return ~(x | ...); }, args...);
312}
313
314template<typename BitSpanT> inline bool any_bit_unset(const BitSpanT &arg)
315{
316 return has_common_unset_bits(arg);
317}
318
319template<typename BitSpanT, typename Fn> inline void foreach_1_index(const BitSpanT &data, Fn &&fn)
320{
321 foreach_1_index_expr([](const BitInt x) { return x; }, fn, data);
322}
323
324template<typename BitSpanT, typename Fn> inline void foreach_0_index(const BitSpanT &data, Fn &&fn)
325{
326 foreach_1_index_expr([](const BitInt x) { return ~x; }, fn, data);
327}
328
329template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
330inline std::optional<int64_t> find_first_1_index_expr(ExprFn &&Expr,
331 const FirstBitSpanT &first_arg,
332 const BitSpanT &...args)
333{
335 Expr, to_best_bit_span(first_arg), to_best_bit_span(args)...);
336}
337
338template<typename BitSpanT> inline std::optional<int64_t> find_first_1_index(const BitSpanT &data)
339{
340 return find_first_1_index_expr([](const BitInt x) { return x; }, data);
341}
342
343template<typename BitSpanT> inline std::optional<int64_t> find_first_0_index(const BitSpanT &data)
344{
345 return find_first_1_index_expr([](const BitInt x) { return ~x; }, data);
346}
347
348template<typename BitSpanT1, typename BitSpanT2>
349inline bool spans_equal(const BitSpanT1 &a, const BitSpanT2 &b)
350{
351 if (a.size() != b.size()) {
352 return false;
353 }
354 return !any_set_expr([](const BitInt a, const BitInt b) { return a ^ b; }, a, b);
355}
356
357template<typename BitSpanT1, typename BitSpanT2, typename BitSpanT3>
358inline bool spans_equal_masked(const BitSpanT1 &a, const BitSpanT2 &b, const BitSpanT3 &mask)
359{
360 BLI_assert(mask.size() == a.size());
361 BLI_assert(mask.size() == b.size());
362 return !bits::any_set_expr(
363 [](const BitInt a, const BitInt b, const BitInt mask) { return (a ^ b) & mask; },
364 a,
365 b,
366 mask);
367}
368
369} // namespace blender::bits
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE unsigned int bitscan_forward_uint64(unsigned long long a)
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
bool any_set_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
void foreach_1_index_expr(ExprFn &&expr, HandleFn &&handle, const FirstBitSpanT &first_arg, const BitSpanT &...args)
void mix_into_first_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
std::optional< int64_t > find_first_1_index_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
uint64_t BitInt
void operator|=(MutableBitSpan first_arg, const BitSpanT &...args)
std::optional< int64_t > find_first_1_index_expr(ExprFn &&Expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
constexpr bool all_bounded_spans
bool has_common_set_bits(const BitSpanT &...args)
void inplace_or_masked(FirstBitSpanT &&first_arg, const MaskBitSpanT &mask, const BitSpanT &...args)
T to_best_bit_span(const T &data)
bool has_common_unset_bits(const BitSpanT &...args)
static constexpr int64_t BitToIntIndexShift
void foreach_0_index(const BitSpanT &data, Fn &&fn)
BitInt mask_single_bit(const int64_t bit_index)
bool any_bit_unset(const BitSpanT &arg)
void mix_into_first_expr(ExprFn &&expr, FirstBitSpanT &&first_arg, const BitSpanT &...args)
void operator&=(MutableBitSpan first_arg, const BitSpanT &...args)
bool any_bit_set(const BitSpanT &arg)
void inplace_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
void inplace_and(FirstBitSpanT &first_arg, const BitSpanT &...args)
bool any_set_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
void copy_from_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
BitInt mask_first_n_bits(const int64_t n)
std::optional< int64_t > find_first_0_index(const BitSpanT &data)
void foreach_1_index(const BitSpanT &data, Fn &&fn)
bool spans_equal(const BitSpanT1 &a, const BitSpanT2 &b)
std::optional< int64_t > find_first_1_index(const BitSpanT &data)
BitInt mask_range_bits(const int64_t start, const int64_t size)
void invert(BitSpanT &&data)
void foreach_1_index_expr(ExprFn &&expr, HandleFn &&handle, const FirstBitSpanT &first_arg, const BitSpanT &...args)
bool spans_equal_masked(const BitSpanT1 &a, const BitSpanT2 &b, const BitSpanT3 &mask)
i
Definition text_draw.cc:230