Blender V4.3
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
5#pragma once
6
7#include "BLI_bit_span.hh"
8#include "BLI_math_bits.h"
9
10namespace blender::bits {
11
12namespace detail {
13
20template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
21inline void mix_into_first_expr(ExprFn &&expr,
22 const FirstBitSpanT &first_arg,
23 const BitSpanT &...args)
24{
25 const int64_t size = first_arg.size();
26 BLI_assert(((size == args.size()) && ...));
27 if (size == 0) {
28 return;
29 }
30
31 if constexpr (all_bounded_spans<FirstBitSpanT, BitSpanT...>) {
32 BitInt *first_data = first_arg.data();
33 const int64_t first_offset = first_arg.offset();
34 const int64_t full_ints_num = first_arg.full_ints_num();
35 /* Compute expression without any masking, all the spans are expected to be aligned to the
36 * beginning of a #BitInt. */
37 for (const int64_t i : IndexRange(full_ints_num)) {
38 first_data[i] = expr(first_data[i], args.data()[i]...);
39 }
40 /* Compute expression for the remaining bits. */
41 if (const int64_t final_bits = first_arg.final_bits_num()) {
42 const BitInt result = expr(first_data[full_ints_num] >> first_offset,
43 (args.data()[full_ints_num] >> args.offset())...);
44 const BitInt mask = mask_range_bits(first_offset, final_bits);
45 first_data[full_ints_num] = ((result << first_offset) & mask) |
46 (first_data[full_ints_num] & ~mask);
47 }
48 }
49 else {
50 /* Fallback or arbitrary bit spans. This could be implemented more efficiently but adds more
51 * complexity and is not necessary yet. */
52 for (const int64_t i : IndexRange(size)) {
53 const bool result = expr(BitInt(first_arg[i].test()), BitInt(args[i].test())...) != 0;
54 first_arg[i].set(result);
55 }
56 }
57}
58
66template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
67inline bool any_set_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
68{
69 const int64_t size = first_arg.size();
70 BLI_assert(((size == args.size()) && ...));
71 if (size == 0) {
72 return false;
73 }
74
75 if constexpr (all_bounded_spans<FirstBitSpanT, BitSpanT...>) {
76 const BitInt *first_data = first_arg.data();
77 const int64_t full_ints_num = first_arg.full_ints_num();
78 /* Compute expression without any masking, all the spans are expected to be aligned to the
79 * beginning of a #BitInt. */
80 for (const int64_t i : IndexRange(full_ints_num)) {
81 if (expr(first_data[i], args.data()[i]...) != 0) {
82 return true;
83 }
84 }
85 /* Compute expression for the remaining bits. */
86 if (const int64_t final_bits = first_arg.final_bits_num()) {
87 const BitInt result = expr(first_data[full_ints_num] >> first_arg.offset(),
88 (args.data()[full_ints_num] >> args.offset())...);
89 const BitInt mask = mask_first_n_bits(final_bits);
90 if ((result & mask) != 0) {
91 return true;
92 }
93 }
94 return false;
95 }
96 else {
97 /* Fallback or arbitrary bit spans. This could be implemented more efficiently but adds more
98 * complexity and is not necessary yet. */
99 for (const int64_t i : IndexRange(size)) {
100 const BitInt result = expr(BitInt(first_arg[i].test()), BitInt(args[i].test())...);
101 if (result != 0) {
102 return true;
103 }
104 }
105 return false;
106 }
107}
108
116template<typename ExprFn, typename HandleFn, typename FirstBitSpanT, typename... BitSpanT>
117inline void foreach_1_index_expr(ExprFn &&expr,
118 HandleFn &&handle,
119 const FirstBitSpanT &first_arg,
120 const BitSpanT &...args)
121{
122 const int64_t size = first_arg.size();
123 BLI_assert(((size == args.size()) && ...));
124 if (size == 0) {
125 return;
126 }
127
128 if constexpr (all_bounded_spans<FirstBitSpanT, BitSpanT...>) {
129 const BitInt *first_data = first_arg.data();
130 const int64_t full_ints_num = first_arg.full_ints_num();
131 /* Iterate over full ints without any bit masks. */
132 for (const int64_t int_i : IndexRange(full_ints_num)) {
133 BitInt tmp = expr(first_data[int_i], args.data()[int_i]...);
134 const int64_t offset = int_i << BitToIntIndexShift;
135 while (tmp != 0) {
136 static_assert(std::is_same_v<BitInt, uint64_t>);
137 const int index = bitscan_forward_uint64(tmp);
138 handle(index + offset);
139 tmp &= ~mask_single_bit(index);
140 }
141 }
142 /* Iterate over remaining bits. */
143 if (const int64_t final_bits = first_arg.final_bits_num()) {
144 BitInt tmp = expr(first_data[full_ints_num] >> first_arg.offset(),
145 (args.data()[full_ints_num] >> args.offset())...) &
146 mask_first_n_bits(final_bits);
147 const int64_t offset = full_ints_num << BitToIntIndexShift;
148 while (tmp != 0) {
149 static_assert(std::is_same_v<BitInt, uint64_t>);
150 const int index = bitscan_forward_uint64(tmp);
151 handle(index + offset);
152 tmp &= ~mask_single_bit(index);
153 }
154 }
155 }
156 else {
157 /* Fallback or arbitrary bit spans. This could be implemented more efficiently but adds more
158 * complexity and is not necessary yet. */
159 for (const int64_t i : IndexRange(size)) {
160 const BitInt result = expr(BitInt(first_arg[i].test()), BitInt(args[i].test())...);
161 if (result) {
162 handle(i);
163 }
164 }
165 }
166}
167
168} // namespace detail
169
170template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
171inline void mix_into_first_expr(ExprFn &&expr, FirstBitSpanT &&first_arg, const BitSpanT &...args)
172{
174}
175
176template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
177inline bool any_set_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
178{
179 return detail::any_set_expr(expr, to_best_bit_span(first_arg), to_best_bit_span(args)...);
180}
181
182template<typename ExprFn, typename HandleFn, typename FirstBitSpanT, typename... BitSpanT>
183inline void foreach_1_index_expr(ExprFn &&expr,
184 HandleFn &&handle,
185 const FirstBitSpanT &first_arg,
186 const BitSpanT &...args)
187{
189 expr, handle, to_best_bit_span(first_arg), to_best_bit_span(args)...);
190}
191
192template<typename BitSpanT> inline void invert(BitSpanT &&data)
193{
194 mix_into_first_expr([](const BitInt x) { return ~x; }, data);
195}
196
197template<typename FirstBitSpanT, typename... BitSpanT>
198inline void inplace_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
199{
200 mix_into_first_expr([](const auto... x) { return (x | ...); }, first_arg, args...);
201}
202
203template<typename FirstBitSpanT, typename MaskBitSpanT, typename... BitSpanT>
204inline void inplace_or_masked(FirstBitSpanT &first_arg,
205 const MaskBitSpanT &mask,
206 const BitSpanT &...args)
207{
209 [](const BitInt a, const BitInt mask, const auto... x) { return a | ((x | ...) & mask); },
210 first_arg,
211 mask,
212 args...);
213}
214
215template<typename FirstBitSpanT, typename... BitSpanT>
216inline void copy_from_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
217{
219 [](auto /*first*/, auto... rest) { return (rest | ...); }, first_arg, args...);
220}
221
222template<typename FirstBitSpanT, typename... BitSpanT>
223inline void inplace_and(FirstBitSpanT &first_arg, const BitSpanT &...args)
224{
225 mix_into_first_expr([](const auto... x) { return (x & ...); }, first_arg, args...);
226}
227
228template<typename... BitSpanT>
229inline void operator|=(MutableBitSpan first_arg, const BitSpanT &...args)
230{
231 inplace_or(first_arg, args...);
232}
233
234template<typename... BitSpanT>
235inline void operator|=(MutableBoundedBitSpan first_arg, const BitSpanT &...args)
236{
237 inplace_or(first_arg, args...);
238}
239
240template<typename... BitSpanT>
241inline void operator&=(MutableBitSpan first_arg, const BitSpanT &...args)
242{
243 inplace_and(first_arg, args...);
244}
245
246template<typename... BitSpanT>
247inline void operator&=(MutableBoundedBitSpan first_arg, const BitSpanT &...args)
248{
249 inplace_and(first_arg, args...);
250}
251
252template<typename... BitSpanT> inline bool has_common_set_bits(const BitSpanT &...args)
253{
254 return any_set_expr([](const auto... x) { return (x & ...); }, args...);
255}
256
257template<typename BitSpanT> inline bool any_bit_set(const BitSpanT &arg)
258{
259 return has_common_set_bits(arg);
260}
261
262template<typename... BitSpanT> inline bool has_common_unset_bits(const BitSpanT &...args)
263{
264 return any_set_expr([](const auto... x) { return ~(x | ...); }, args...);
265}
266
267template<typename BitSpanT> inline bool any_bit_unset(const BitSpanT &arg)
268{
269 return has_common_unset_bits(arg);
270}
271
272template<typename BitSpanT, typename Fn> inline void foreach_1_index(const BitSpanT &data, Fn &&fn)
273{
274 foreach_1_index_expr([](const BitInt x) { return x; }, fn, data);
275}
276
277template<typename BitSpanT, typename Fn> inline void foreach_0_index(const BitSpanT &data, Fn &&fn)
278{
279 foreach_1_index_expr([](const BitInt x) { return ~x; }, fn, data);
280}
281
282template<typename BitSpanT1, typename BitSpanT2>
283inline bool spans_equal(const BitSpanT1 &a, const BitSpanT2 &b)
284{
285 if (a.size() != b.size()) {
286 return false;
287 }
288 return !any_set_expr([](const BitInt a, const BitInt b) { return a ^ b; }, a, b);
289}
290
291template<typename BitSpanT1, typename BitSpanT2, typename BitSpanT3>
292inline bool spans_equal_masked(const BitSpanT1 &a, const BitSpanT2 &b, const BitSpanT3 &mask)
293{
294 BLI_assert(mask.size() == a.size());
295 BLI_assert(mask.size() == b.size());
296 return !bits::any_set_expr(
297 [](const BitInt a, const BitInt b, const BitInt mask) { return (a ^ b) & mask; },
298 a,
299 b,
300 mask);
301}
302
303} // namespace blender::bits
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE unsigned int bitscan_forward_uint64(unsigned long long a)
local_group_size(16, 16) .push_constant(Type b
ccl_device_inline float4 mask(const int4 mask, const float4 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)
uint64_t BitInt
void operator|=(MutableBitSpan 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)
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)
void foreach_1_index(const BitSpanT &data, Fn &&fn)
bool spans_equal(const BitSpanT1 &a, const BitSpanT2 &b)
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)
__int64 int64_t
Definition stdint.h:89