Skip to content

Commit 27ca483

Browse files
cxy-1993fhahn
andauthored
[EquivalenceClasses] Introduce erase member function (#134660)
Introduce 'erase(const ElemTy &V)' member function to allow the deletion of a certain value from EquivClasses. This is essential for certain scenarios that require modifying the contents of EquivClasses. --------- Co-authored-by: Florian Hahn <[email protected]>
1 parent 02f923f commit 27ca483

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

llvm/include/llvm/ADT/EquivalenceClasses.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define LLVM_ADT_EQUIVALENCECLASSES_H
1717

1818
#include "llvm/ADT/DenseMap.h"
19+
#include "llvm/ADT/STLExtras.h"
1920
#include "llvm/ADT/SmallVector.h"
2021
#include "llvm/ADT/iterator_range.h"
2122
#include "llvm/Support/Allocator.h"
@@ -220,6 +221,57 @@ template <class ElemTy> class EquivalenceClasses {
220221
return *ECV;
221222
}
222223

224+
/// erase - Erase a value from the union/find set, return "true" if erase
225+
/// succeeded, or "false" when the value was not found.
226+
bool erase(const ElemTy &V) {
227+
if (!TheMapping.contains(V))
228+
return false;
229+
const ECValue *Cur = TheMapping[V];
230+
const ECValue *Next = Cur->getNext();
231+
// If the current element is the leader and has a successor element,
232+
// update the successor element's 'Leader' field to be the last element,
233+
// set the successor element's stolen bit, and set the 'Leader' field of
234+
// all other elements in same class to be the successor element.
235+
if (Cur->isLeader() && Next) {
236+
Next->Leader = Cur->Leader;
237+
Next->Next = reinterpret_cast<const ECValue *>(
238+
reinterpret_cast<intptr_t>(Next->Next) | static_cast<intptr_t>(1));
239+
240+
const ECValue *NewLeader = Next;
241+
while ((Next = Next->getNext())) {
242+
Next->Leader = NewLeader;
243+
}
244+
} else if (!Cur->isLeader()) {
245+
const ECValue *Leader = findLeader(V).Node;
246+
const ECValue *Pre = Leader;
247+
while (Pre->getNext() != Cur) {
248+
Pre = Pre->getNext();
249+
}
250+
if (!Next) {
251+
// If the current element is the last element(not leader), set the
252+
// successor of the current element's predecessor to null, and set
253+
// the 'Leader' field of the class leader to the predecessor element.
254+
Pre->Next = nullptr;
255+
Leader->Leader = Pre;
256+
} else {
257+
// If the current element is in the middle of class, then simply
258+
// connect the predecessor element and the successor element.
259+
Pre->Next = reinterpret_cast<const ECValue *>(
260+
reinterpret_cast<intptr_t>(Next) |
261+
static_cast<intptr_t>(Pre->isLeader()));
262+
Next->Leader = Pre;
263+
}
264+
}
265+
266+
// Update 'TheMapping' and 'Members'.
267+
assert(TheMapping.contains(V) && "Can't find input in TheMapping!");
268+
TheMapping.erase(V);
269+
auto I = find(Members, Cur);
270+
assert(I != Members.end() && "Can't find input in members!");
271+
Members.erase(I);
272+
return true;
273+
}
274+
223275
/// findLeader - Given a value in the set, return a member iterator for the
224276
/// equivalence class it is in. This does the path-compression part that
225277
/// makes union-find "union findy". This returns an end iterator if the value

llvm/unittests/ADT/EquivalenceClassesTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,55 @@ TEST(EquivalenceClassesTest, SimpleMerge2) {
5959
EXPECT_TRUE(EqClasses.isEquivalent(i, j));
6060
}
6161

62+
TEST(EquivalenceClassesTest, SimpleErase1) {
63+
EquivalenceClasses<int> EqClasses;
64+
// Check that erase head success.
65+
// After erase A from (A, B ,C, D), <B, C, D> belong to one set.
66+
EqClasses.unionSets(0, 1);
67+
EqClasses.unionSets(2, 3);
68+
EqClasses.unionSets(0, 2);
69+
EXPECT_TRUE(EqClasses.erase(0));
70+
for (int i = 1; i < 4; ++i)
71+
for (int j = 1; j < 4; ++j)
72+
EXPECT_TRUE(EqClasses.isEquivalent(i, j));
73+
}
74+
75+
TEST(EquivalenceClassesTest, SimpleErase2) {
76+
EquivalenceClasses<int> EqClasses;
77+
// Check that erase tail success.
78+
// After erase D from (A, B ,C, D), <A, B, C> belong to one set.
79+
EqClasses.unionSets(0, 1);
80+
EqClasses.unionSets(2, 3);
81+
EqClasses.unionSets(0, 2);
82+
EXPECT_TRUE(EqClasses.erase(3));
83+
for (int i = 0; i < 3; ++i)
84+
for (int j = 0; j < 3; ++j)
85+
EXPECT_TRUE(EqClasses.isEquivalent(i, j));
86+
}
87+
88+
TEST(EquivalenceClassesTest, SimpleErase3) {
89+
EquivalenceClasses<int> EqClasses;
90+
// Check that erase a value in the middle success.
91+
// After erase B from (A, B ,C, D), <A, C, D> belong to one set.
92+
EqClasses.unionSets(0, 1);
93+
EqClasses.unionSets(2, 3);
94+
EqClasses.unionSets(0, 2);
95+
EXPECT_TRUE(EqClasses.erase(1));
96+
for (int i = 0; i < 3; ++i)
97+
for (int j = 0; j < 3; ++j)
98+
EXPECT_TRUE(EqClasses.isEquivalent(i, j) ^ ((i == 1) ^ (j == 1)));
99+
}
100+
101+
TEST(EquivalenceClassesTest, SimpleErase4) {
102+
EquivalenceClasses<int> EqClasses;
103+
// Check that erase a single class success.
104+
EqClasses.insert(0);
105+
EXPECT_TRUE(EqClasses.getNumClasses() == 1);
106+
EXPECT_TRUE(EqClasses.erase(0));
107+
EXPECT_TRUE(EqClasses.getNumClasses() == 0);
108+
EXPECT_FALSE(EqClasses.erase(1));
109+
}
110+
62111
TEST(EquivalenceClassesTest, TwoSets) {
63112
EquivalenceClasses<int> EqClasses;
64113
// Form sets of odd and even numbers, check that we split them into these

0 commit comments

Comments
 (0)