MeshLib C++ Docs
Loading...
Searching...
No Matches
MRUnionFind.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRVector.h"
4#include "MRTimer.h"
5#include <atomic>
6#include <utility>
7
8namespace MR
9{
12
13
20template <typename I>
22{
23public:
25 using SizeType = typename I::ValueType;
26
27 BaseUnionFind() = default;
28 BaseUnionFind( const BaseUnionFind & ) = default;
29 BaseUnionFind( BaseUnionFind && ) noexcept = default;
30 BaseUnionFind & operator =( const BaseUnionFind & ) = default;
31 BaseUnionFind & operator =( BaseUnionFind && ) noexcept = default;
32
34 auto size() const { return parents_.size(); }
35
37 void reset( size_t size )
38 {
40 parents_.clear();
41 parents_.reserve( size );
42 for ( I i{ size_t( 0 ) }; i < size; ++i )
43 parents_.push_back( i );
44 }
45
50 std::pair<I, bool> uniteUnbalanced( I first, I second )
51 {
52 auto firstRoot = updateRoot_( first );
53 auto secondRoot = updateRoot_( second );
54 if ( firstRoot == secondRoot )
55 return { firstRoot, false };
56 parents_[firstRoot] = secondRoot;
57 return { secondRoot, true };
58 }
59
61 bool united( I first, I second )
62 {
63 return updateRoot_( first ) == updateRoot_( second );
64 }
65
67 bool isRoot( I a ) const { return parents_[a] == a; }
68
70 I parent( I a ) const { return parents_[a]; }
71
73 I find( I a ) { return updateRoot_( a ); }
74
77 {
79 }
80
83 {
84 for ( I i{ size_t( 0 ) }; i < parents_.size(); ++i )
86 return parents_;
87 }
88
90 const Vector<I, I> & parents() const { return parents_; }
91
92protected:
95 {
96 I r = parents_[a];
97 for ( I e = a; e != r; r = parents_[e = r] ) {}
98 return r;
99 }
100
102 I updateRoot_( I a, const I r )
103 {
105 while ( a != r )
106 {
107 I b = r;
108 std::swap( parents_[a], b );
109 a = b;
110 }
111 return r;
112 }
113
115 I updateRoot_( I a ) { return updateRoot_( a, findRootNoUpdate_( a ) ); }
116
118 I updateRootInRange_( I a, const I r, I begin, I end )
119 {
120 assert( begin < end );
122 while ( a != r )
123 {
124 if ( a >= begin && a < end )
125 {
126 I b = r;
127 std::swap( parents_[a], b );
128 a = b;
129 }
130 else
131 a = parents_[a];
132 }
133 return r;
134 }
135
138};
139
149template <typename I>
150class UnionFind : public BaseUnionFind<I>
151{
152public:
154 using SizeType = typename I::ValueType;
155
156 UnionFind() = default;
157
159 explicit UnionFind( size_t size ) { reset( size ); }
160
163 explicit UnionFind( BaseUnionFind<I> && base ) : BaseUnionFind<I>( std::move( base ) )
164 {
165 sizes_.resize( this->parents_.size(), SizeType( 0 ) );
166 for ( I i{ size_t( 0 ) }; i < this->parents_.size(); ++i )
167 ++sizes_[ this->findRootNoUpdate_( i ) ];
168 }
169
171 void reset( size_t size )
172 {
174 sizes_.clear();
175 sizes_.resize( size, 1 );
176 }
177
180 std::pair<I,bool> unite( I first, I second )
181 {
182 auto firstRoot = this->updateRoot_( first );
183 auto secondRoot = this->updateRoot_( second );
184 if ( firstRoot == secondRoot )
185 return { firstRoot, false };
187 if ( sizes_[firstRoot] < sizes_[secondRoot] )
188 {
189 this->parents_[firstRoot] = secondRoot;
190 sizes_[secondRoot] += sizes_[firstRoot];
191 return { secondRoot, true };
192 }
193 else
194 {
195 this->parents_[secondRoot] = firstRoot;
196 sizes_[firstRoot] += sizes_[secondRoot];
197 return { firstRoot, true };
198 }
199 }
200
202 SizeType sizeOfComp( I a ) { return sizes_[ this->find( a ) ]; }
203
204private:
206 Vector<SizeType, I> sizes_;
207};
208
216template <typename I>
218{
219public:
220 ParallelUnionFind() = default;
221
223 explicit ParallelUnionFind( size_t size ) { this->reset( size ); }
224
227 void uniteAtomic( I first, I second )
228 {
229 for ( ;; )
230 {
231 first = findAtomic_( first );
232 second = findAtomic_( second );
233 if ( first == second )
234 return;
236 if ( first < second )
237 std::swap( first, second );
239 if ( casStrong_( this->parents_[first], first, second ) )
240 return;
242 }
243 }
244
245private:
249
251 static I loadAtomic_( I& slot )
252 {
253#ifdef __cpp_lib_atomic_ref
254 return I( std::atomic_ref<typename I::ValueType>( slot.get() ).load( std::memory_order_relaxed ) );
255#else
256 return I( __atomic_load_n( &slot.get(), __ATOMIC_RELAXED ) );
257#endif
258 }
259
261 static void casWeak_( I& slot, I expected, I desired )
262 {
263 using T = typename I::ValueType;
264 T exp = expected.get();
265#ifdef __cpp_lib_atomic_ref
266 std::atomic_ref<T>( slot.get() ).compare_exchange_weak( exp, desired.get(), std::memory_order_relaxed );
267#else
268 __atomic_compare_exchange_n( &slot.get(), &exp, desired.get(), true, __ATOMIC_RELAXED, __ATOMIC_RELAXED );
269#endif
270 }
271
273 static bool casStrong_( I& slot, I expected, I desired )
274 {
275 using T = typename I::ValueType;
276 T exp = expected.get();
277#ifdef __cpp_lib_atomic_ref
278 return std::atomic_ref<T>( slot.get() ).compare_exchange_strong( exp, desired.get(), std::memory_order_acq_rel, std::memory_order_relaxed );
279#else
280 return __atomic_compare_exchange_n( &slot.get(), &exp, desired.get(), false, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED );
281#endif
282 }
283
285 I findAtomic_( I a )
286 {
287 for ( ;; )
288 {
289 I p = loadAtomic_( this->parents_[a] );
290 if ( p == a )
291 return a;
292 I gp = loadAtomic_( this->parents_[p] );
293 if ( p == gp )
294 return p;
296 casWeak_( this->parents_[a], p, gp );
297 a = gp;
298 }
299 }
300};
301
302}
#define MR_TIMER
FUNCTION in GCC/Clang returns only short function name without class name and template parameters
Definition MRTimer.h:56
std::vector<T>-like container that requires specific indexing type,
Definition MRVector.h:23
SizeType sizeOfComp(I a)
returns the number of elements in the set containing given element
Definition MRUnionFind.h:202
std::pair< I, bool > unite(I first, I second)
Definition MRUnionFind.h:180
I updateRootInRange_(I a, const I r, I begin, I end)
sets new root
Definition MRUnionFind.h:118
ParallelUnionFind(size_t size)
creates union-find with given number of elements, each element is the only one in its disjoint set
Definition MRUnionFind.h:223
BaseUnionFind(BaseUnionFind &&) noexcept=default
BaseUnionFind()=default
I updateRoot_(I a, const I r)
sets new root
Definition MRUnionFind.h:102
auto size() const
returns the number of elements in union-find
Definition MRUnionFind.h:34
bool isRoot(I a) const
returns true if given element is the root of some set
Definition MRUnionFind.h:67
const Vector< I, I > & parents() const
gets the parents of all elements as is
Definition MRUnionFind.h:90
std::pair< I, bool > uniteUnbalanced(I first, I second)
Definition MRUnionFind.h:50
I updateRoot_(I a)
find the root of given element, and set it as parent for it and other parents
Definition MRUnionFind.h:115
const Vector< I, I > & roots()
sets the root of corresponding set as the parent of each element, then returns the vector
Definition MRUnionFind.h:82
ParallelUnionFind()=default
UnionFind(BaseUnionFind< I > &&base)
Definition MRUnionFind.h:163
UnionFind(size_t size)
creates union-find with given number of elements, each element is the only one in its disjoint set
Definition MRUnionFind.h:159
UnionFind()=default
BaseUnionFind(const BaseUnionFind &)=default
void reset(size_t size)
resets union-find to represent given number of elements, each element is the only one in its disjoint...
Definition MRUnionFind.h:171
class MRMESH_CLASS I
Definition MRMeshFwd.h:141
bool united(I first, I second)
returns true if given two elements are from one set
Definition MRUnionFind.h:61
I find(I a)
finds the root of the set containing given element with optimizing data structure updates
Definition MRUnionFind.h:73
typename I::ValueType SizeType
the type that can hold the number of elements of the maximal set (e.g. int for FaceId and size_t for ...
Definition MRUnionFind.h:25
void uniteAtomic(I first, I second)
Definition MRUnionFind.h:227
I parent(I a) const
return parent element of this element, which is equal to given element only for set's root
Definition MRUnionFind.h:70
typename I::ValueType SizeType
the type that can hold the number of elements of the maximal set (e.g. int for FaceId and size_t for ...
Definition MRUnionFind.h:154
Vector< I, I > parents_
parent element of each element
Definition MRUnionFind.h:137
I findRootNoUpdate_(I a) const
finds the root of the set containing given element without optimizing data structure updates
Definition MRUnionFind.h:94
I findUpdateRange(I a, I begin, I end)
finds the root of the set containing given element with optimizing data structure in the range [begin...
Definition MRUnionFind.h:76
void reset(size_t size)
resets union-find to represent given number of elements, each element is the only one in its disjoint...
Definition MRUnionFind.h:37
auto begin(ViewportMask mask)
Definition MRViewportId.h:122
auto end(ViewportMask)
Definition MRViewportId.h:124
only for bindings generation
Definition MRCameraOrientationPlugin.h:8