TTK
Loading...
Searching...
No Matches
dset.h
Go to the documentation of this file.
1
14
15/*
16zlib license
17
18Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
19
20This software is provided 'as-is', without any express or implied
21warranty. In no event will the authors be held liable for any damages
22arising from the use of this software.
23
24Permission is granted to anyone to use this software for any purpose,
25including commercial applications, and to alter it and redistribute it
26freely, subject to the following restrictions:
27
281. The origin of this software must not be misrepresented; you must not
29claim that you wrote the original software. If you use this software
30in a product, an acknowledgment in the product documentation would be
31appreciated but is not required.
322. Altered source versions must be plainly marked as such, and must not be
33misrepresented as being the original software.
343. This notice may not be removed or altered from any source distribution.
35*/
36
37#pragma once
38
39#include <atomic>
40#include <vector>
41
58public:
59 DisjointSets(uint32_t size) : mData(size) {
60 for(uint32_t i = 0; i < size; ++i)
61 mData[i] = (uint32_t)i;
62 }
63
64 uint32_t find(uint32_t id) const {
65 while(id != parent(id)) {
66 uint64_t value = mData[id];
67 uint32_t new_parent = parent((uint32_t)value);
68 uint64_t new_value = (value & 0xFFFFFFFF00000000ULL) | new_parent;
69 /* Try to update parent (may fail, that's ok) */
70 if(value != new_value)
71 mData[id].compare_exchange_weak(value, new_value);
72 id = new_parent;
73 }
74 return id;
75 }
76
77 bool same(uint32_t id1, uint32_t id2) const {
78 for(;;) {
79 id1 = find(id1);
80 id2 = find(id2);
81 if(id1 == id2)
82 return true;
83 if(parent(id1) == id1)
84 return false;
85 }
86 }
87
88 uint32_t unite(uint32_t id1, uint32_t id2) {
89 for(;;) {
90 id1 = find(id1);
91 id2 = find(id2);
92
93 if(id1 == id2)
94 return id1;
95
96 uint32_t r1 = rank(id1), r2 = rank(id2);
97
98 if(r1 > r2 || (r1 == r2 && id1 < id2)) {
99 std::swap(r1, r2);
100 std::swap(id1, id2);
101 }
102
103 uint64_t oldEntry = ((uint64_t)r1 << 32) | id1;
104 uint64_t newEntry = ((uint64_t)r1 << 32) | id2;
105
106 if(!mData[id1].compare_exchange_strong(oldEntry, newEntry))
107 continue;
108
109 if(r1 == r2) {
110 oldEntry = ((uint64_t)r2 << 32) | id2;
111 newEntry = ((uint64_t)(r2 + 1) << 32) | id2;
112 /* Try to update the rank (may fail, that's ok) */
113 mData[id2].compare_exchange_weak(oldEntry, newEntry);
114 }
115
116 break;
117 }
118 return id2;
119 }
120
128 bool try_lock(uint32_t &id) {
129 const uint64_t lock_flag = 1ULL << 63;
130 id = find(id);
131 uint64_t value = mData[id];
132 if((value & lock_flag) || (uint32_t)value != id)
133 return false;
134// On IA32/x64, a PAUSE instruction is recommended for CAS busy loops
135#if defined(__i386__) || defined(__amd64__)
136 __asm__ __volatile__("pause\n");
137#endif
138 return mData[id].compare_exchange_strong(value, value | lock_flag);
139 }
140
141 void unlock(uint32_t id) {
142 const uint64_t lock_flag = 1ULL << 63;
143 mData[id] &= ~lock_flag;
144 }
145
150 uint32_t unite_index_locked(uint32_t id1, uint32_t id2) const {
151 uint32_t r1 = rank(id1), r2 = rank(id2);
152 return (r1 > r2 || (r1 == r2 && id1 < id2)) ? id1 : id2;
153 }
154
159 uint32_t unite_unlock(uint32_t id1, uint32_t id2) {
160 uint32_t r1 = rank(id1), r2 = rank(id2);
161
162 if(r1 > r2 || (r1 == r2 && id1 < id2)) {
163 std::swap(r1, r2);
164 std::swap(id1, id2);
165 }
166
167 mData[id1] = ((uint64_t)r1 << 32) | id2;
168 mData[id2] = ((uint64_t)(r2 + ((r1 == r2) ? 1 : 0)) << 32) | id2;
169
170 return id2;
171 }
172
173 uint32_t size() const {
174 return (uint32_t)mData.size();
175 }
176
177 uint32_t rank(uint32_t id) const {
178 return ((uint32_t)(mData[id] >> 32)) & 0x7FFFFFFFu;
179 }
180
181 uint32_t parent(uint32_t id) const {
182 return (uint32_t)mData[id];
183 }
184
185 bool isRoot(uint32_t id) const {
186 return id == parent(id);
187 }
188
189 mutable std::vector<std::atomic<uint64_t>> mData;
190};
bool same(uint32_t id1, uint32_t id2) const
Definition dset.h:77
uint32_t unite(uint32_t id1, uint32_t id2)
Definition dset.h:88
uint32_t find(uint32_t id) const
Definition dset.h:64
void unlock(uint32_t id)
Definition dset.h:141
bool isRoot(uint32_t id) const
Definition dset.h:185
bool try_lock(uint32_t &id)
Definition dset.h:128
uint32_t parent(uint32_t id) const
Definition dset.h:181
uint32_t unite_index_locked(uint32_t id1, uint32_t id2) const
Definition dset.h:150
uint32_t unite_unlock(uint32_t id1, uint32_t id2)
Definition dset.h:159
uint32_t size() const
Definition dset.h:173
uint32_t rank(uint32_t id) const
Definition dset.h:177
DisjointSets(uint32_t size)
Definition dset.h:59
std::vector< std::atomic< uint64_t > > mData
Definition dset.h:189