diff --git a/req/include/req_compactor_impl.hpp b/req/include/req_compactor_impl.hpp index bcc276c6..f30a7b6c 100755 --- a/req/include/req_compactor_impl.hpp +++ b/req/include/req_compactor_impl.hpp @@ -301,7 +301,9 @@ template bool req_compactor::ensure_enough_sections() { const float ssr = section_size_raw_ / sqrtf(2); const uint32_t ne = nearest_even(ssr); - if (state_ >= static_cast(1ULL << (num_sections_ - 1)) && ne >= req_constants::MIN_K) { + if (state_ >= static_cast(1ULL << (num_sections_ - 1)) + && section_size_ > req_constants::MIN_K + && ne >= req_constants::MIN_K) { section_size_raw_ = ssr; section_size_ = ne; num_sections_ <<= 1; diff --git a/req/test/req_sketch_test.cpp b/req/test/req_sketch_test.cpp index 99e59140..3db56247 100755 --- a/req/test/req_sketch_test.cpp +++ b/req/test/req_sketch_test.cpp @@ -593,7 +593,6 @@ TEST_CASE("get_rank equivalence") { // sketch.serialize(os); //} - template static void put_value(Bytes& bytes, size_t offset, V value) { std::memcpy(bytes.data() + offset, &value, sizeof(value)); @@ -734,4 +733,34 @@ TEST_CASE("req sketch: deserialize rejects inconsistent compactors", "[req_sketc } } +using req_compactor_float = req_compactor, std::allocator>; + +static req_compactor_float make_compactor_with_state(uint16_t k, uint64_t state) { + std::stringstream s(std::ios::in | std::ios::out | std::ios::binary); + const float section_size_raw = k; // not used by merge + const uint8_t lg_weight = 0; + const uint8_t num_sections = req_constants::INIT_NUM_SECTIONS; + const uint16_t padding = 0; + const uint32_t num_items = 0; + s.write(reinterpret_cast(&state), sizeof(state)); + s.write(reinterpret_cast(§ion_size_raw), sizeof(section_size_raw)); + s.write(reinterpret_cast(&lg_weight), sizeof(lg_weight)); + s.write(reinterpret_cast(&num_sections), sizeof(num_sections)); + s.write(reinterpret_cast(&padding), sizeof(padding)); + s.write(reinterpret_cast(&num_items), sizeof(num_items)); + return req_compactor_float::deserialize(s, serde(), std::less(), std::allocator(), true, true, + k, 0); +} + +TEST_CASE("req compactor: section growth stops at minimum section size", "[req_compactor]") { + const uint16_t ks[] = {6, 12, 14}; + const uint32_t expected_nom_capacities[] = {48, 192, 192}; + for (size_t i = 0; i < 3; ++i) { + req_compactor_float c(true, 0, ks[i], std::less(), std::allocator()); + for (uint8_t lg_state: {2, 5, 11, 23}) c.merge(make_compactor_with_state(ks[i], 1ULL << lg_state)); + INFO("k=" << ks[i]); + CHECK(c.get_nom_capacity() == expected_nom_capacities[i]); + } +} + } /* namespace datasketches */