Blender V4.5
array_utils.cc
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#include <functional>
10
11#include "BLI_array_utils.hh"
12#include "BLI_threads.h"
13
14#include "atomic_ops.h"
15
16namespace blender::array_utils {
17
18void copy(const GVArray &src, GMutableSpan dst, const int64_t grain_size)
19{
20 BLI_assert(src.type() == dst.type());
21 BLI_assert(src.size() == dst.size());
22 threading::parallel_for(src.index_range(), grain_size, [&](const IndexRange range) {
23 src.materialize_to_uninitialized(range, dst.data());
24 });
25}
26
27void copy(const GVArray &src,
28 const IndexMask &selection,
29 GMutableSpan dst,
30 const int64_t grain_size)
31{
32 BLI_assert(src.type() == dst.type());
33 BLI_assert(src.size() >= selection.min_array_size());
34 BLI_assert(dst.size() >= selection.min_array_size());
35 threading::parallel_for(selection.index_range(), grain_size, [&](const IndexRange range) {
36 src.materialize_to_uninitialized(selection.slice(range), dst.data());
37 });
38}
39
40void gather(const GVArray &src,
41 const IndexMask &indices,
42 GMutableSpan dst,
43 const int64_t grain_size)
44{
45 BLI_assert(src.type() == dst.type());
46 BLI_assert(indices.size() == dst.size());
47 threading::parallel_for(indices.index_range(), grain_size, [&](const IndexRange range) {
48 src.materialize_compressed_to_uninitialized(indices.slice(range), dst.slice(range).data());
49 });
50}
51
52void gather(const GSpan src, const IndexMask &indices, GMutableSpan dst, const int64_t grain_size)
53{
54 gather(GVArray::ForSpan(src), indices, dst, grain_size);
55}
56
58 const OffsetIndices<int> dst_offsets,
59 const IndexMask &selection,
60 const GSpan src,
61 GMutableSpan dst)
62{
63 /* Each group might be large, so a threaded copy might make sense here too. */
64 selection.foreach_index(GrainSize(512), [&](const int i) {
65 dst.slice(dst_offsets[i]).copy_from(src.slice(src_offsets[i]));
66 });
67}
68
70{
71 if (indices.size() < 8192 || BLI_system_thread_count() < 4) {
72 for (const int i : indices) {
73 counts[i]++;
74 }
75 }
76 else {
77 threading::parallel_for(indices.index_range(), 4096, [&](const IndexRange range) {
78 for (const int i : indices.slice(range)) {
79 atomic_add_and_fetch_int32(&counts[i], 1);
80 }
81 });
82 }
83}
84
86{
87 threading::parallel_for(span.index_range(), 4096, [&](IndexRange range) {
88 for (const int i : range) {
89 span[i] = !span[i];
90 }
91 });
92}
93
95{
96 mask.foreach_index_optimized<int64_t>([&](const int64_t i) { span[i] = !span[i]; });
97}
98
99static bool all_equal(const Span<bool> span, const bool test)
100{
101 return std::all_of(span.begin(), span.end(), [&](const bool value) { return value == test; });
102}
103
104static bool all_equal(const VArray<bool> &varray, const IndexRange range, const bool test)
105{
106 return std::all_of(
107 range.begin(), range.end(), [&](const int64_t i) { return varray[i] == test; });
108}
109
110BooleanMix booleans_mix_calc(const VArray<bool> &varray, const IndexRange range_to_check)
111{
112 if (varray.is_empty()) {
113 return BooleanMix::None;
114 }
115 const CommonVArrayInfo info = varray.common_info();
117 return *static_cast<const bool *>(info.data) ? BooleanMix::AllTrue : BooleanMix::AllFalse;
118 }
120 const Span<bool> span(static_cast<const bool *>(info.data), varray.size());
122 range_to_check,
123 4096,
125 [&](const IndexRange range, const BooleanMix init) {
126 if (init == BooleanMix::Mixed) {
127 return init;
128 }
129 const Span<bool> slice = span.slice(range);
130 const bool compare = (init == BooleanMix::None) ? slice.first() :
132 if (all_equal(slice, compare)) {
133 return compare ? BooleanMix::AllTrue : BooleanMix::AllFalse;
134 }
135 return BooleanMix::Mixed;
136 },
137 [&](BooleanMix a, BooleanMix b) { return (a == b) ? a : BooleanMix::Mixed; });
138 }
140 range_to_check,
141 2048,
143 [&](const IndexRange range, const BooleanMix init) {
144 if (init == BooleanMix::Mixed) {
145 return init;
146 }
147 /* Alternatively, this could use #materialize to retrieve many values at once. */
148 const bool compare = (init == BooleanMix::None) ? varray[range.first()] :
150 if (all_equal(varray, range, compare)) {
151 return compare ? BooleanMix::AllTrue : BooleanMix::AllFalse;
152 }
153 return BooleanMix::Mixed;
154 },
155 [&](BooleanMix a, BooleanMix b) { return (a == b) ? a : BooleanMix::Mixed; });
156}
157
159{
160 if (varray.is_empty() || mask.is_empty()) {
161 return 0;
162 }
163 /* Check if mask is full. */
164 if (varray.size() == mask.size()) {
165 const CommonVArrayInfo info = varray.common_info();
167 return *static_cast<const bool *>(info.data) ? varray.size() : 0;
168 }
170 const Span<bool> span(static_cast<const bool *>(info.data), varray.size());
172 varray.index_range(),
173 4096,
174 0,
175 [&](const IndexRange range, const int64_t init) {
176 const Span<bool> slice = span.slice(range);
177 return init + std::count(slice.begin(), slice.end(), true);
178 },
179 std::plus<>());
180 }
182 varray.index_range(),
183 2048,
184 0,
185 [&](const IndexRange range, const int64_t init) {
186 int64_t value = init;
187 /* Alternatively, this could use #materialize to retrieve many values at once. */
188 for (const int64_t i : range) {
189 value += int64_t(varray[i]);
190 }
191 return value;
192 },
193 std::plus<>());
194 }
195 const CommonVArrayInfo info = varray.common_info();
197 return *static_cast<const bool *>(info.data) ? mask.size() : 0;
198 }
199 int64_t value = 0;
200 mask.foreach_segment([&](const IndexMaskSegment segment) {
201 for (const int64_t i : segment) {
202 value += int64_t(varray[i]);
203 }
204 });
205 return value;
206}
207
209{
210 return count_booleans(varray, IndexMask(varray.size()));
211}
212
214{
215 if (indices.size() != range.size()) {
216 return false;
217 }
219 range.index_range(),
220 4096,
221 true,
222 [&](const IndexRange part, const bool is_range) {
223 const Span<int> local_indices = indices.slice(part);
224 const IndexRange local_range = range.slice(part);
225 return is_range &&
226 std::equal(local_indices.begin(), local_indices.end(), local_range.begin());
227 },
228 std::logical_and<>());
229}
230
231} // namespace blender::array_utils
#define BLI_assert(a)
Definition BLI_assert.h:46
int BLI_system_thread_count(void)
Definition threads.cc:253
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
long long int int64_t
void copy_from(GSpan values)
GMutableSpan slice(const int64_t start, int64_t size) const
const CPPType & type() const
GSpan slice(const int64_t start, int64_t size) const
static GVArray ForSpan(GSpan span)
constexpr int64_t first() const
constexpr Iterator end() const
constexpr int64_t size() const
constexpr Iterator begin() const
constexpr IndexRange index_range() const
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr const T & first() const
Definition BLI_span.hh:315
constexpr const T * end() const
Definition BLI_span.hh:224
constexpr const T * begin() const
Definition BLI_span.hh:220
IndexRange index_range() const
CommonVArrayInfo common_info() const
void foreach_index(Fn &&fn) const
static ushort indices[]
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void invert_booleans(MutableSpan< bool > span)
void count_indices(Span< int > indices, MutableSpan< int > counts)
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
bool indices_are_range(Span< int > indices, IndexRange range)
void copy_group_to_group(OffsetIndices< int > src_offsets, OffsetIndices< int > dst_offsets, const IndexMask &selection, GSpan src, GMutableSpan dst)
BooleanMix booleans_mix_calc(const VArray< bool > &varray, IndexRange range_to_check)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
static bool all_equal(const Span< bool > span, const bool test)
int64_t count_booleans(const VArray< bool > &varray)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
static void init(bNodeTree *, bNode *node)
i
Definition text_draw.cc:230