[llvm] bf0f94a - New SetOperations and unittesting for all SetOperations

Teresa Johnson via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 17 07:18:45 PST 2023


Author: Teresa Johnson
Date: 2023-02-17T07:18:32-08:00
New Revision: bf0f94a5cf82e62e86c454d96ab8bd29adcb71af

URL: https://github.com/llvm/llvm-project/commit/bf0f94a5cf82e62e86c454d96ab8bd29adcb71af
DIFF: https://github.com/llvm/llvm-project/commit/bf0f94a5cf82e62e86c454d96ab8bd29adcb71af.diff

LOG: New SetOperations and unittesting for all SetOperations

New set operations split out of D140908 as suggested, and I have added
unit testing for all set operations.

This adds a set_intersection, which returns the intersection instead of
updating the first set like set_intersect (using a different name
analogous to set_difference vs set_subtract).

Also adds a variant of set_subtract that updates two additional set
arguments to note which members of the subtrahend were removed from
the minuend and which were not.

Differential Revision: https://reviews.llvm.org/D144220

Added: 
    llvm/unittests/ADT/SetOperationsTest.cpp

Modified: 
    llvm/include/llvm/ADT/SetOperations.h
    llvm/unittests/ADT/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/SetOperations.h b/llvm/include/llvm/ADT/SetOperations.h
index c9462f077dc89..52aced7068931 100644
--- a/llvm/include/llvm/ADT/SetOperations.h
+++ b/llvm/include/llvm/ADT/SetOperations.h
@@ -45,6 +45,25 @@ void set_intersect(S1Ty &S1, const S2Ty &S2) {
    }
 }
 
+template <class S1Ty, class S2Ty>
+S1Ty set_intersection_impl(const S1Ty &S1, const S2Ty &S2) {
+   S1Ty Result;
+   for (typename S1Ty::const_iterator SI = S1.begin(), SE = S1.end(); SI != SE;
+        ++SI)
+     if (S2.count(*SI))
+      Result.insert(*SI);
+   return Result;
+}
+
+/// set_intersection(A, B) - Return A ^ B
+template <class S1Ty, class S2Ty>
+S1Ty set_intersection(const S1Ty &S1, const S2Ty &S2) {
+   if (S1.size() < S2.size())
+     return set_intersection_impl(S1, S2);
+   else
+     return set_intersection_impl(S2, S1);
+}
+
 /// set_
diff erence(A, B) - Return A - B
 ///
 template <class S1Ty, class S2Ty>
@@ -66,6 +85,19 @@ void set_subtract(S1Ty &S1, const S2Ty &S2) {
     S1.erase(*SI);
 }
 
+/// set_subtract(A, B, C, D) - Compute A := A - B, set C to the elements of B
+/// removed from A (A ^ B), and D to the elements of B not found in and removed
+/// from A (B - A).
+template <class S1Ty, class S2Ty>
+void set_subtract(S1Ty &S1, const S2Ty &S2, S1Ty &Removed, S1Ty &Remaining) {
+  for (typename S2Ty::const_iterator SI = S2.begin(), SE = S2.end(); SI != SE;
+       ++SI)
+    if (S1.erase(*SI))
+      Removed.insert(*SI);
+    else
+      Remaining.insert(*SI);
+}
+
 /// set_is_subset(A, B) - Return true iff A in B
 ///
 template <class S1Ty, class S2Ty>

diff  --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt
index f20bc2eb7dccb..900294d4216ee 100644
--- a/llvm/unittests/ADT/CMakeLists.txt
+++ b/llvm/unittests/ADT/CMakeLists.txt
@@ -62,6 +62,7 @@ add_llvm_unittest(ADTTests
   STLForwardCompatTest.cpp
   ScopeExitTest.cpp
   SequenceTest.cpp
+  SetOperationsTest.cpp
   SetVectorTest.cpp
   SimpleIListTest.cpp
   SmallPtrSetTest.cpp

diff  --git a/llvm/unittests/ADT/SetOperationsTest.cpp b/llvm/unittests/ADT/SetOperationsTest.cpp
new file mode 100644
index 0000000000000..982ea819fd809
--- /dev/null
+++ b/llvm/unittests/ADT/SetOperationsTest.cpp
@@ -0,0 +1,266 @@
+//===- SetOperations.cpp - Unit tests for set operations ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SetOperations.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include <set>
+
+using namespace llvm;
+
+using testing::IsEmpty;
+
+namespace {
+
+TEST(SetOperationsTest, SetUnion) {
+  std::set<int> Set1 = {1, 2, 3, 4};
+  std::set<int> Set2 = {5, 6, 7, 8};
+  // Set1 should be the union of input sets Set1 and Set2.
+  std::set<int> ExpectedSet1 = {1, 2, 3, 4, 5, 6, 7, 8};
+  // Set2 should not be touched.
+  std::set<int> ExpectedSet2 = Set2;
+
+  set_union(Set1, Set2);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+
+  Set1.clear();
+  Set2 = {1, 2};
+  // Set1 should be the union of input sets Set1 and Set2, which in this case
+  // will be Set2.
+  ExpectedSet1 = Set2;
+  // Set2 should not be touched.
+  ExpectedSet2 = Set2;
+
+  set_union(Set1, Set2);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+}
+
+TEST(SetOperationsTest, SetIntersect) {
+  std::set<int> Set1 = {1, 2, 3, 4};
+  std::set<int> Set2 = {3, 4, 5, 6};
+  // Set1 should be the intersection of sets Set1 and Set2.
+  std::set<int> ExpectedSet1 = {3, 4};
+  // Set2 should not be touched.
+  std::set<int> ExpectedSet2 = Set2;
+
+  set_intersect(Set1, Set2);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {5, 6};
+  // Set2 should not be touched.
+  ExpectedSet2 = Set2;
+
+  set_intersect(Set1, Set2);
+  // Set1 should be the intersection of sets Set1 and Set2, which
+  // is empty as they are non-overlapping.
+  EXPECT_THAT(Set1, IsEmpty());
+  EXPECT_EQ(ExpectedSet2, Set2);
+}
+
+TEST(SetOperationsTest, SetIntersection) {
+  std::set<int> Set1 = {1, 2, 3, 4};
+  std::set<int> Set2 = {3, 4, 5, 6};
+  std::set<int> Result;
+  // Result should be the intersection of sets Set1 and Set2.
+  std::set<int> ExpectedResult = {3, 4};
+  // Set1 and Set2 should not be touched.
+  std::set<int> ExpectedSet1 = Set1;
+  std::set<int> ExpectedSet2 = Set2;
+
+  Result = set_intersection(Set1, Set2);
+  EXPECT_EQ(ExpectedResult, Result);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {5, 6};
+  // Set1 and Set2 should not be touched.
+  ExpectedSet1 = Set1;
+  ExpectedSet2 = Set2;
+
+  Result = set_intersection(Set1, Set2);
+  // Result should be the intersection of sets Set1 and Set2, which
+  // is empty as they are non-overlapping.
+  EXPECT_THAT(Result, IsEmpty());
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+
+  Set1 = {5, 6};
+  Set2 = {1, 2, 3, 4};
+  // Set1 and Set2 should not be touched.
+  ExpectedSet1 = Set1;
+  ExpectedSet2 = Set2;
+
+  Result = set_intersection(Set1, Set2);
+  // Result should be the intersection of sets Set1 and Set2, which
+  // is empty as they are non-overlapping. Test this again with the input sets
+  // reversed, since the code takes a 
diff erent path depending on which input
+  // set is smaller.
+  EXPECT_THAT(Result, IsEmpty());
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+}
+
+TEST(SetOperationsTest, SetDifference) {
+  std::set<int> Set1 = {1, 2, 3, 4};
+  std::set<int> Set2 = {3, 4, 5, 6};
+  std::set<int> Result;
+  // Result should be Set1 - Set2, leaving only {1, 2}.
+  std::set<int> ExpectedResult = {1, 2};
+  // Set1 and Set2 should not be touched.
+  std::set<int> ExpectedSet1 = Set1;
+  std::set<int> ExpectedSet2 = Set2;
+
+  Result = set_
diff erence(Set1, Set2);
+  EXPECT_EQ(ExpectedResult, Result);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {1, 2, 3, 4};
+  // Set1 and Set2 should not be touched.
+  ExpectedSet1 = Set1;
+  ExpectedSet2 = Set2;
+
+  Result = set_
diff erence(Set1, Set2);
+  // Result should be Set1 - Set2, which should be empty.
+  EXPECT_THAT(Result, IsEmpty());
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {5, 6};
+  // Result should be Set1 - Set2, which should be Set1 as they are
+  // non-overlapping.
+  ExpectedResult = Set1;
+  // Set1 and Set2 should not be touched.
+  ExpectedSet1 = Set1;
+  ExpectedSet2 = Set2;
+
+  Result = set_
diff erence(Set1, Set2);
+  EXPECT_EQ(ExpectedResult, Result);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+}
+
+TEST(SetOperationsTest, SetSubtract) {
+  std::set<int> Set1 = {1, 2, 3, 4};
+  std::set<int> Set2 = {3, 4, 5, 6};
+  // Set1 should get Set1 - Set2, leaving only {1, 2}.
+  std::set<int> ExpectedSet1 = {1, 2};
+  // Set2 should not be touched.
+  std::set<int> ExpectedSet2 = Set2;
+
+  set_subtract(Set1, Set2);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {1, 2, 3, 4};
+  // Set2 should not be touched.
+  ExpectedSet2 = Set2;
+
+  set_subtract(Set1, Set2);
+  // Set1 should get Set1 - Set2, which should be empty.
+  EXPECT_THAT(Set1, IsEmpty());
+  EXPECT_EQ(ExpectedSet2, Set2);
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {5, 6};
+  // Set1 should get Set1 - Set2, which should be Set1 as they are
+  // non-overlapping.
+  ExpectedSet1 = Set1;
+  // Set2 should not be touched.
+  ExpectedSet2 = Set2;
+
+  set_subtract(Set1, Set2);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+}
+
+TEST(SetOperationsTest, SetSubtractRemovedRemaining) {
+  std::set<int> Removed, Remaining;
+
+  std::set<int> Set1 = {1, 2, 3, 4};
+  std::set<int> Set2 = {3, 4, 5, 6};
+  // Set1 should get Set1 - Set2, leaving only {1, 2}.
+  std::set<int> ExpectedSet1 = {1, 2};
+  // Set2 should not be touched.
+  std::set<int> ExpectedSet2 = Set2;
+  // We should get back that {3, 4} from Set2 were removed from Set1, and {5, 6}
+  // were not removed from Set1.
+  std::set<int> ExpectedRemoved = {3, 4};
+  std::set<int> ExpectedRemaining = {5, 6};
+
+  set_subtract(Set1, Set2, Removed, Remaining);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+  EXPECT_EQ(ExpectedRemoved, Removed);
+  EXPECT_EQ(ExpectedRemaining, Remaining);
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {1, 2, 3, 4};
+  Removed.clear();
+  Remaining.clear();
+  // Set2 should not be touched.
+  ExpectedSet2 = Set2;
+  // Set should get back that all of Set2 was removed from Set1, and nothing
+  // left in Set2 was not removed from Set1.
+  ExpectedRemoved = Set2;
+
+  set_subtract(Set1, Set2, Removed, Remaining);
+  // Set1 should get Set1 - Set2, which should be empty.
+  EXPECT_THAT(Set1, IsEmpty());
+  EXPECT_EQ(ExpectedSet2, Set2);
+  EXPECT_EQ(ExpectedRemoved, Removed);
+  EXPECT_THAT(Remaining, IsEmpty());
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {5, 6};
+  Removed.clear();
+  Remaining.clear();
+  // Set1 should get Set1 - Set2, which should be Set1 as they are
+  // non-overlapping.
+  ExpectedSet1 = {1, 2, 3, 4};
+  // Set2 should not be touched.
+  ExpectedSet2 = Set2;
+  // Set should get back that none of Set2 was removed from Set1, and all
+  // of Set2 was not removed from Set1.
+  ExpectedRemaining = Set2;
+
+  set_subtract(Set1, Set2, Removed, Remaining);
+  EXPECT_EQ(ExpectedSet1, Set1);
+  EXPECT_EQ(ExpectedSet2, Set2);
+  EXPECT_THAT(Removed, IsEmpty());
+  EXPECT_EQ(ExpectedRemaining, Remaining);
+}
+
+TEST(SetOperationsTest, SetIsSubset) {
+  std::set<int> Set1 = {1, 2, 3, 4};
+  std::set<int> Set2 = {3, 4};
+  EXPECT_FALSE(set_is_subset(Set1, Set2));
+
+  Set1 = {1, 2, 3, 4};
+  Set2 = {1, 2, 3, 4};
+  EXPECT_TRUE(set_is_subset(Set1, Set2));
+
+  Set1 = {1, 2};
+  Set2 = {1, 2, 3, 4};
+  EXPECT_TRUE(set_is_subset(Set1, Set2));
+
+  Set1 = {1, 2};
+  Set2 = {3, 4};
+  EXPECT_FALSE(set_is_subset(Set1, Set2));
+}
+
+} // namespace


        


More information about the llvm-commits mailing list