From d0d9338bb0bdb189a93e681622a75e26b0611627 Mon Sep 17 00:00:00 2001 From: Rusty Conover Date: Wed, 28 Oct 2026 10:52:44 -0400 Subject: [PATCH] fix: ebpps_sketch::merge(const&) called an unqualified swap The const& overload swapped with swap(*this, sk_copy), which only compiles when argument-dependent lookup finds a swap through the template arguments. With an allocator from an application's namespace it fails to compile. Call std::swap, as merge(&&) already does. Co-Authored-By: Claude Opus 5.5 --- sampling/include/ebpps_sketch_impl.hpp | 2 +- sampling/test/ebpps_allocation_test.cpp | 33 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/sampling/include/ebpps_sketch_impl.hpp b/sampling/include/ebpps_sketch_impl.hpp index 299b7f5c..36a7b926 100644 --- a/sampling/include/ebpps_sketch_impl.hpp +++ b/sampling/include/ebpps_sketch_impl.hpp @@ -202,7 +202,7 @@ void ebpps_sketch::merge(const ebpps_sketch& sk) { // need to swap this with sk to merge, so make a copy, swap, // and use that to merge ebpps_sketch sk_copy(sk); - swap(*this, sk_copy); + std::swap(*this, sk_copy); internal_merge(sk_copy); } else { internal_merge(sk); diff --git a/sampling/test/ebpps_allocation_test.cpp b/sampling/test/ebpps_allocation_test.cpp index e249ac1f..59294997 100644 --- a/sampling/test/ebpps_allocation_test.cpp +++ b/sampling/test/ebpps_allocation_test.cpp @@ -25,6 +25,26 @@ #include +// An allocator outside the datasketches namespace, as an application's would be: argument-dependent +// lookup finds no swap() in its namespace. +namespace ebpps_test_alloc { + +template +struct plain_allocator { + using value_type = T; + plain_allocator() = default; + template + plain_allocator(const plain_allocator&) {} + T* allocate(std::size_t n) { return static_cast(::operator new(n * sizeof(T))); } + void deallocate(T* p, std::size_t) { ::operator delete(p); } +}; +template +bool operator==(const plain_allocator&, const plain_allocator&) { return true; } +template +bool operator!=(const plain_allocator&, const plain_allocator&) { return false; } + +} // namespace ebpps_test_alloc + namespace datasketches { using ebpps_test_sketch = ebpps_sketch>; @@ -93,4 +113,17 @@ TEST_CASE( "ebpps merge", "[ebpps_sketch][test_type]") { REQUIRE(test_allocator_net_allocations == 0); } +TEST_CASE("ebpps merge heavier sketch by const reference with an application allocator", "[ebpps_sketch]") { + using sketch = ebpps_sketch>; + sketch light(5); + sketch heavy(5); + for (int i = 0; i < 10; ++i) light.update(i); + for (int i = 0; i < 100; ++i) heavy.update(i, 2.0); + const sketch& heavy_ref = heavy; + light.merge(heavy_ref); + REQUIRE(light.get_n() == 110); + REQUIRE(light.get_cumulative_weight() == Approx(210.0)); + REQUIRE(heavy.get_n() == 100); } + +} // namespace datasketches