From 8fe284ac93a8903ca48f2e31bbc053cb12b35361 Mon Sep 17 00:00:00 2001 From: Rusty Conover Date: Wed, 28 Oct 2026 14:06:48 -0400 Subject: [PATCH] fix: count_min_sketch allocated its hash seeds with std::allocator hash_seeds was a std::vector with the default allocator, so every sketch made with a custom allocator also allocated from the global heap, and so did its copies. Rebind the sketch's allocator for it. Co-Authored-By: Claude Opus 5.5 --- count/include/count_min.hpp | 2 +- count/include/count_min_impl.hpp | 3 ++- count/test/count_min_allocation_test.cpp | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/count/include/count_min.hpp b/count/include/count_min.hpp index 08201f75..f78dce1a 100644 --- a/count/include/count_min.hpp +++ b/count/include/count_min.hpp @@ -382,7 +382,7 @@ class count_min_sketch{ std::vector _sketch_array; // the array stored by the sketch uint64_t _seed; W _total_weight; - std::vector hash_seeds; + std::vector::template rebind_alloc> hash_seeds; enum flags {IS_EMPTY}; static const uint8_t PREAMBLE_LONGS_SHORT = 2; // Empty -> need second byte for sketch parameters diff --git a/count/include/count_min_impl.hpp b/count/include/count_min_impl.hpp index dd6e8730..c1c053e3 100644 --- a/count/include/count_min_impl.hpp +++ b/count/include/count_min_impl.hpp @@ -38,7 +38,8 @@ _num_hashes(num_hashes), _num_buckets(num_buckets), _sketch_array((static_cast(num_hashes) * num_buckets < 1<<30) ? static_cast(num_hashes) * num_buckets : 0, 0, _allocator), _seed(seed), -_total_weight(0) { +_total_weight(0), +hash_seeds(_allocator) { if (num_buckets < 3) { throw std::invalid_argument("Using fewer than 3 buckets incurs relative error greater than 1."); } diff --git a/count/test/count_min_allocation_test.cpp b/count/test/count_min_allocation_test.cpp index 2177b515..fc19bd7c 100644 --- a/count/test/count_min_allocation_test.cpp +++ b/count/test/count_min_allocation_test.cpp @@ -152,4 +152,21 @@ TEST_CASE("CountMin sketch test allocator: bytes serialize-deserialize non-empty REQUIRE(test_allocator_net_allocations == 0); } +TEST_CASE("CountMin sketch test allocator: hash seeds use the sketch's allocator", "[cm_sketch_alloc]") { + test_allocator_total_bytes = 0; + test_allocator_net_allocations = 0; + { + const uint8_t n_hashes = 5; + const uint32_t n_buckets = 100; + const long long sketch_bytes = n_hashes * n_buckets * sizeof(uint64_t) + n_hashes * sizeof(uint64_t); + count_min_sketch_test_alloc c(n_hashes, n_buckets, DEFAULT_SEED, alloc(0)); + // the counters and the hash seeds, all through the sketch's allocator + REQUIRE(test_allocator_total_bytes == sketch_bytes); + count_min_sketch_test_alloc copy(c); + REQUIRE(test_allocator_total_bytes == 2 * sketch_bytes); + } + REQUIRE(test_allocator_total_bytes == 0); + REQUIRE(test_allocator_net_allocations == 0); +} + } // namespace datasketches