[libcxx-commits] [libcxx] [libc++] Add test coverage for unordered containers comparison (PR #66692)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Sep 19 08:57:25 PDT 2023


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/66692

>From d0b99a2a7c23d7f04583ec6fcf4238b729edbb7f Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 18 Sep 2023 15:48:39 -0400
Subject: [PATCH] [libc++] Add test coverage for unordered containers
 comparison

This patch is a melting pot of changes picked up from https://llvm.org/D61878.
It adds a few tests checking corner cases of unordered containers comparison
and adds benchmarks for a few unordered_set operations.
---
 libcxx/benchmarks/ContainerBenchmarks.h       | 31 ++++++++++++++++
 .../unordered_set_operations.bench.cpp        | 19 ++++++++++
 .../unord/unord.multimap/eq.pass.cpp          | 27 +++++++++++++-
 .../unord/unord.multiset/eq.pass.cpp          | 35 ++++++++++++++++++-
 4 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/libcxx/benchmarks/ContainerBenchmarks.h b/libcxx/benchmarks/ContainerBenchmarks.h
index 5ab6f619b85a8d0..071e46c2a1c6546 100644
--- a/libcxx/benchmarks/ContainerBenchmarks.h
+++ b/libcxx/benchmarks/ContainerBenchmarks.h
@@ -179,6 +179,37 @@ static void BM_Rehash(benchmark::State& st, Container c, GenInputs gen) {
   }
 }
 
+template <class Container, class GenInputs>
+static void BM_Compare_same_container(benchmark::State& st, Container, GenInputs gen) {
+  auto in = gen(st.range(0));
+  Container c1(in.begin(), in.end());
+  Container c2 = c1;
+
+  benchmark::DoNotOptimize(&(*c1.begin()));
+  benchmark::DoNotOptimize(&(*c2.begin()));
+  while (st.KeepRunning()) {
+    bool res = c1 == c2;
+    benchmark::DoNotOptimize(&res);
+    benchmark::ClobberMemory();
+  }
+}
+
+template <class Container, class GenInputs>
+static void BM_Compare_different_containers(benchmark::State& st, Container, GenInputs gen) {
+  auto in1 = gen(st.range(0));
+  auto in2 = gen(st.range(0));
+  Container c1(in1.begin(), in1.end());
+  Container c2(in2.begin(), in2.end());
+
+  benchmark::DoNotOptimize(&(*c1.begin()));
+  benchmark::DoNotOptimize(&(*c2.begin()));
+  while (st.KeepRunning()) {
+    bool res = c1 == c2;
+    benchmark::DoNotOptimize(&res);
+    benchmark::ClobberMemory();
+  }
+}
+
 } // end namespace ContainerBenchmarks
 
 #endif // BENCHMARK_CONTAINER_BENCHMARKS_H
diff --git a/libcxx/benchmarks/unordered_set_operations.bench.cpp b/libcxx/benchmarks/unordered_set_operations.bench.cpp
index 96aa2e0dfea3be0..d49de576ec9778d 100644
--- a/libcxx/benchmarks/unordered_set_operations.bench.cpp
+++ b/libcxx/benchmarks/unordered_set_operations.bench.cpp
@@ -290,6 +290,25 @@ BENCHMARK_CAPTURE(BM_Rehash,
 BENCHMARK_CAPTURE(BM_Rehash, unordered_set_int_arg, std::unordered_set<int>{}, getRandomIntegerInputs<int>)
     ->Arg(TestNumInputs);
 
+//----------------------------------------------------------------------------//
+//                         BM_Compare
+// ---------------------------------------------------------------------------//
+
+BENCHMARK_CAPTURE(
+    BM_Compare_same_container, unordered_set_string, std::unordered_set<std::string>{}, getRandomStringInputs)
+    ->Arg(TestNumInputs);
+
+BENCHMARK_CAPTURE(BM_Compare_same_container, unordered_set_int, std::unordered_set<int>{}, getRandomIntegerInputs<int>)
+    ->Arg(TestNumInputs);
+
+BENCHMARK_CAPTURE(
+    BM_Compare_different_containers, unordered_set_string, std::unordered_set<std::string>{}, getRandomStringInputs)
+    ->Arg(TestNumInputs);
+
+BENCHMARK_CAPTURE(
+    BM_Compare_different_containers, unordered_set_int, std::unordered_set<int>{}, getRandomIntegerInputs<int>)
+    ->Arg(TestNumInputs);
+
 ///////////////////////////////////////////////////////////////////////////////
 BENCHMARK_CAPTURE(BM_InsertDuplicate, unordered_set_int, std::unordered_set<int>{}, getRandomIntegerInputs<int>)
     ->Arg(TestNumInputs);
diff --git a/libcxx/test/std/containers/unord/unord.multimap/eq.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/eq.pass.cpp
index d0e578e190c0a18..083fff13b3812fb 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/eq.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/eq.pass.cpp
@@ -221,5 +221,30 @@ int main(int, char**)
     }
 #endif
 
-  return 0;
+    // Make sure we take into account the number of times that a key repeats into equality.
+    {
+        typedef std::pair<int, char> P;
+        P a[] = {P(1, 'a'), P(1, 'b'),            P(1, 'd'), P(2, 'b')};
+        P b[] = {P(1, 'a'), P(1, 'b'), P(1, 'b'), P(1, 'd'), P(2, 'b')};
+
+        std::unordered_multimap<int, char> c1(std::begin(a), std::end(a));
+        std::unordered_multimap<int, char> c2(std::begin(b), std::end(b));
+        assert(testEquality(c1, c2, false));
+    }
+
+    // Make sure we incorporate the values into the equality of the maps.
+    // If we were to compare only the keys (including how many time each key repeats),
+    // the following test would fail cause only the values differ.
+    {
+        typedef std::pair<int, char> P;
+        P a[] = {P(1, 'a'), P(1, 'b'), P(1, 'd'), P(2, 'b')};
+        P b[] = {P(1, 'a'), P(1, 'b'), P(1, 'E'), P(2, 'b')};
+        //                                   ^ different here
+
+        std::unordered_multimap<int, char> c1(std::begin(a), std::end(a));
+        std::unordered_multimap<int, char> c2(std::begin(b), std::end(b));
+        assert(testEquality(c1, c2, false));
+    }
+
+    return 0;
 }
diff --git a/libcxx/test/std/containers/unord/unord.multiset/eq.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/eq.pass.cpp
index 22d3207d0ff74a0..7c4cfd63c7bb613 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/eq.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/eq.pass.cpp
@@ -20,10 +20,13 @@
 
 #include <unordered_set>
 #include <cassert>
+#include <cstddef>
 
 #include "test_macros.h"
 #include "min_allocator.h"
 
+#include "test_comparisons.h"
+
 int main(int, char**)
 {
     {
@@ -178,5 +181,35 @@ int main(int, char**)
     }
 #endif
 
-  return 0;
+    // Make sure we take into account the number of times that a key repeats into equality.
+    {
+        int a[] = {1, 1, 1, 2};
+        int b[] = {1, 1, 1, 1, 2};
+
+        std::unordered_multiset<int> c1(std::begin(a), std::end(a));
+        std::unordered_multiset<int> c2(std::begin(b), std::end(b));
+        assert(testEquality(c1, c2, false));
+    }
+
+    // Make sure we behave properly when a custom key predicate is provided.
+    {
+        int a[] = {1, 3};
+        int b[] = {1, 1};
+        // A very poor hash
+        struct HashModuloOddness {
+            std::size_t operator()(int x) const { return std::hash<int>()(x % 2); }
+        };
+        // A very poor hash
+        struct CompareModuloOddness {
+            bool operator()(int x, int y) const { return (x % 2) == (y % 2); }
+        };
+
+        using Set = std::unordered_multiset<int, HashModuloOddness, CompareModuloOddness>;
+        Set c1(std::begin(a), std::end(a));
+        Set c2(std::begin(b), std::end(b));
+
+        assert(testEquality(c1, c2, false));
+    }
+
+    return 0;
 }



More information about the libcxx-commits mailing list