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