Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/manifold/src/disjoint_sets.h
9903 views
1
// from https://github.com/wjakob/dset, changed to add connected component
2
// computation
3
//
4
// Copyright (c) 2015 Wenzel Jakob <[email protected]>
5
//
6
// This software is provided 'as-is', without any express or implied
7
// warranty. In no event will the authors be held liable for any damages
8
// arising from the use of this software.
9
//
10
// Permission is granted to anyone to use this software for any purpose,
11
// including commercial applications, and to alter it and redistribute it
12
// freely, subject to the following restrictions:
13
//
14
// 1. The origin of this software must not be misrepresented; you must not
15
// claim that you wrote the original software. If you use this software
16
// in a product, an acknowledgment in the product documentation would be
17
// appreciated but is not required.
18
// 2. Altered source versions must be plainly marked as such, and must not be
19
// misrepresented as being the original software.
20
// 3. This notice may not be removed or altered from any source distribution.
21
//
22
#pragma once
23
#include <atomic>
24
#include <cstddef>
25
#include <cstdint>
26
#include <unordered_map>
27
#include <vector>
28
29
class DisjointSets {
30
public:
31
DisjointSets(uint32_t size) : mData(size) {
32
for (uint32_t i = 0; i < size; ++i) mData[i] = (uint32_t)i;
33
}
34
35
uint32_t find(uint32_t id) const {
36
while (id != parent(id)) {
37
uint64_t value = mData[id];
38
uint32_t new_parent = parent((uint32_t)value);
39
uint64_t new_value = (value & 0xFFFFFFFF00000000ULL) | new_parent;
40
/* Try to update parent (may fail, that's ok) */
41
if (value != new_value) mData[id].compare_exchange_weak(value, new_value);
42
id = new_parent;
43
}
44
return id;
45
}
46
47
bool same(uint32_t id1, uint32_t id2) const {
48
for (;;) {
49
id1 = find(id1);
50
id2 = find(id2);
51
if (id1 == id2) return true;
52
if (parent(id1) == id1) return false;
53
}
54
}
55
56
uint32_t unite(uint32_t id1, uint32_t id2) {
57
for (;;) {
58
id1 = find(id1);
59
id2 = find(id2);
60
61
if (id1 == id2) return id1;
62
63
uint32_t r1 = rank(id1), r2 = rank(id2);
64
65
if (r1 > r2 || (r1 == r2 && id1 < id2)) {
66
std::swap(r1, r2);
67
std::swap(id1, id2);
68
}
69
70
uint64_t oldEntry = ((uint64_t)r1 << 32) | id1;
71
uint64_t newEntry = ((uint64_t)r1 << 32) | id2;
72
73
if (!mData[id1].compare_exchange_strong(oldEntry, newEntry)) continue;
74
75
if (r1 == r2) {
76
oldEntry = ((uint64_t)r2 << 32) | id2;
77
newEntry = ((uint64_t)(r2 + 1) << 32) | id2;
78
/* Try to update the rank (may fail, retry if rank = 0) */
79
if (!mData[id2].compare_exchange_strong(oldEntry, newEntry) && r2 == 0)
80
continue;
81
}
82
83
break;
84
}
85
return id2;
86
}
87
88
uint32_t size() const { return (uint32_t)mData.size(); }
89
90
uint32_t rank(uint32_t id) const {
91
return ((uint32_t)(mData[id] >> 32)) & 0x7FFFFFFFu;
92
}
93
94
uint32_t parent(uint32_t id) const { return (uint32_t)mData[id]; }
95
96
int connectedComponents(std::vector<int>& components) {
97
components.resize(mData.size());
98
int lonelyNodes = 0;
99
std::unordered_map<uint32_t, int> toLabel;
100
for (size_t i = 0; i < mData.size(); ++i) {
101
// we optimize for connected component of size 1
102
// no need to put them into the hashmap
103
auto iParent = find(i);
104
if (rank(iParent) == 0) {
105
components[i] = static_cast<int>(toLabel.size()) + lonelyNodes++;
106
continue;
107
}
108
auto iter = toLabel.find(iParent);
109
if (iter == toLabel.end()) {
110
auto s = static_cast<uint32_t>(toLabel.size()) + lonelyNodes;
111
toLabel.insert(std::make_pair(iParent, s));
112
components[i] = s;
113
} else {
114
components[i] = iter->second;
115
}
116
}
117
return toLabel.size() + lonelyNodes;
118
}
119
120
mutable std::vector<std::atomic<uint64_t>> mData;
121
};
122
123