Blender V4.3
atomic_disjoint_set.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
7#include "BLI_map.hh"
8#include "BLI_sort.hh"
9#include "BLI_task.hh"
10
11namespace blender {
12
13AtomicDisjointSet::AtomicDisjointSet(const int size) : items_(size)
14{
15 threading::parallel_for(IndexRange(size), 4096, [&](const IndexRange range) {
16 for (const int i : range) {
17 items_[i].store(Item{i, 0}, relaxed);
18 }
19 });
20}
21
22static void update_first_occurrence(Map<int, int> &map, const int root, const int index)
23{
24 map.add_or_modify(
25 root,
26 [&](int *first_occurrence) { *first_occurrence = index; },
27 [&](int *first_occurrence) {
28 if (index < *first_occurrence) {
29 *first_occurrence = index;
30 }
31 });
32}
33
35{
36 BLI_assert(result.size() == items_.size());
37
38 const int size = result.size();
39
40 /* Find the root for element. With multi-threading, this root is not deterministic. So
41 * some postprocessing has to be done to make it deterministic. */
42 threading::EnumerableThreadSpecific<Map<int, int>> first_occurrence_by_root_per_thread;
43 threading::parallel_for(IndexRange(size), 1024, [&](const IndexRange range) {
44 Map<int, int> &first_occurrence_by_root = first_occurrence_by_root_per_thread.local();
45 for (const int i : range) {
46 const int root = this->find_root(i);
47 result[i] = root;
48 update_first_occurrence(first_occurrence_by_root, root, i);
49 }
50 });
51
52 /* Build a map that contains the first element index that has a certain root. */
53 Map<int, int> &combined_map = first_occurrence_by_root_per_thread.local();
54 for (const Map<int, int> &other_map : first_occurrence_by_root_per_thread) {
55 if (&combined_map == &other_map) {
56 continue;
57 }
58 for (const auto item : other_map.items()) {
59 update_first_occurrence(combined_map, item.key, item.value);
60 }
61 }
62
63 struct RootOccurence {
64 int root;
65 int first_occurrence;
66 };
67
68 /* Sort roots by first occurrence. This removes the non-determinism above. */
69 Vector<RootOccurence, 16> root_occurrences;
70 root_occurrences.reserve(combined_map.size());
71 for (const auto item : combined_map.items()) {
72 root_occurrences.append({item.key, item.value});
73 }
74 parallel_sort(root_occurrences.begin(),
75 root_occurrences.end(),
76 [](const RootOccurence &a, const RootOccurence &b) {
77 return a.first_occurrence < b.first_occurrence;
78 });
79
80 /* Remap original root values with deterministic values. */
81 Map<int, int> id_by_root;
82 id_by_root.reserve(root_occurrences.size());
83 for (const int i : root_occurrences.index_range()) {
84 id_by_root.add_new(root_occurrences[i].root, i);
85 }
86 threading::parallel_for(IndexRange(size), 1024, [&](const IndexRange range) {
87 for (const int i : range) {
88 result[i] = id_by_root.lookup(result[i]);
89 }
90 });
91 return id_by_root.size();
92}
93
95{
97 items_.index_range(),
98 1024,
99 0,
100 [&](const IndexRange range, int count) {
101 for (const int i : range) {
102 if (this->is_root(i)) {
103 count++;
104 }
105 }
106 return count;
107 },
108 [](const int a, const int b) { return a + b; });
109}
110
111} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:50
int64_t size() const
Definition BLI_array.hh:245
IndexRange index_range() const
Definition BLI_array.hh:349
int calc_reduced_ids(MutableSpan< int > result) const
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
int64_t size() const
Definition BLI_map.hh:927
void reserve(int64_t n)
Definition BLI_map.hh:979
int64_t size() const
void append(const T &value)
IndexRange index_range() const
void reserve(const int64_t min_capacity)
local_group_size(16, 16) .push_constant(Type b
IndexRange range
int count
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
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:153
static void update_first_occurrence(Map< int, int > &map, const int root, const int index)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
Definition BLI_sort.hh:23