datasketches 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/ext/datasketches/cpc_wrapper.cpp +8 -9
  4. data/ext/datasketches/fi_wrapper.cpp +4 -5
  5. data/ext/datasketches/hll_wrapper.cpp +9 -10
  6. data/ext/datasketches/kll_wrapper.cpp +13 -12
  7. data/ext/datasketches/theta_wrapper.cpp +11 -13
  8. data/ext/datasketches/vo_wrapper.cpp +1 -2
  9. data/lib/datasketches/version.rb +1 -1
  10. data/vendor/datasketches-cpp/CMakeLists.txt +5 -3
  11. data/vendor/datasketches-cpp/CODE_OF_CONDUCT.md +1 -1
  12. data/vendor/datasketches-cpp/LICENSE +14 -0
  13. data/vendor/datasketches-cpp/README.md +67 -73
  14. data/vendor/datasketches-cpp/benchmarks/CMakeLists.txt +52 -0
  15. data/vendor/datasketches-cpp/benchmarks/benchmark_count_min_sketch.cpp +153 -0
  16. data/vendor/datasketches-cpp/benchmarks/benchmark_count_min_sketch_serialization.cpp +161 -0
  17. data/vendor/datasketches-cpp/common/CMakeLists.txt +1 -0
  18. data/vendor/datasketches-cpp/common/include/binomial_bounds.hpp +2 -2
  19. data/vendor/datasketches-cpp/common/include/fdlibm_log.hpp +101 -0
  20. data/vendor/datasketches-cpp/common/include/serde.hpp +6 -0
  21. data/vendor/datasketches-cpp/common/test/CMakeLists.txt +44 -2
  22. data/vendor/datasketches-cpp/common/test/binomial_bounds_test.cpp +279 -0
  23. data/vendor/datasketches-cpp/common/test/deserialize_hardening_test.cpp +188 -0
  24. data/vendor/datasketches-cpp/count/include/count_min.hpp +17 -4
  25. data/vendor/datasketches-cpp/count/include/count_min_impl.hpp +65 -83
  26. data/vendor/datasketches-cpp/count/test/count_min_test.cpp +63 -7
  27. data/vendor/datasketches-cpp/cpc/include/compression_data.hpp +2 -0
  28. data/vendor/datasketches-cpp/cpc/include/cpc_compressor_impl.hpp +16 -7
  29. data/vendor/datasketches-cpp/cpc/include/cpc_sketch.hpp +1 -0
  30. data/vendor/datasketches-cpp/cpc/include/cpc_sketch_impl.hpp +54 -36
  31. data/vendor/datasketches-cpp/cpc/include/cpc_union_impl.hpp +27 -27
  32. data/vendor/datasketches-cpp/cpc/include/cpc_util.hpp +7 -7
  33. data/vendor/datasketches-cpp/cpc/include/icon_estimator.hpp +5 -5
  34. data/vendor/datasketches-cpp/cpc/include/u32_table_impl.hpp +16 -16
  35. data/vendor/datasketches-cpp/cpc/test/cpc_sketch_test.cpp +35 -0
  36. data/vendor/datasketches-cpp/fi/include/frequent_items_sketch.hpp +28 -3
  37. data/vendor/datasketches-cpp/fi/include/frequent_items_sketch_impl.hpp +41 -25
  38. data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map.hpp +3 -1
  39. data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map_impl.hpp +10 -5
  40. data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_serialize_for_java.cpp +24 -0
  41. data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_test.cpp +116 -0
  42. data/vendor/datasketches-cpp/filters/include/bloom_filter.hpp +1 -1
  43. data/vendor/datasketches-cpp/filters/include/bloom_filter_impl.hpp +32 -12
  44. data/vendor/datasketches-cpp/filters/test/bloom_filter_test.cpp +28 -1
  45. data/vendor/datasketches-cpp/hll/include/CouponHashSet-internal.hpp +1 -2
  46. data/vendor/datasketches-cpp/hll/include/CouponList-internal.hpp +19 -5
  47. data/vendor/datasketches-cpp/hll/include/CubicInterpolation-internal.hpp +4 -4
  48. data/vendor/datasketches-cpp/hll/include/HarmonicNumbers-internal.hpp +2 -1
  49. data/vendor/datasketches-cpp/hll/include/Hll4Array-internal.hpp +4 -4
  50. data/vendor/datasketches-cpp/hll/include/Hll4Array.hpp +1 -1
  51. data/vendor/datasketches-cpp/hll/include/Hll6Array-internal.hpp +3 -3
  52. data/vendor/datasketches-cpp/hll/include/Hll6Array.hpp +1 -1
  53. data/vendor/datasketches-cpp/hll/include/Hll8Array-internal.hpp +6 -3
  54. data/vendor/datasketches-cpp/hll/include/Hll8Array.hpp +1 -1
  55. data/vendor/datasketches-cpp/hll/include/HllArray-internal.hpp +35 -29
  56. data/vendor/datasketches-cpp/hll/include/HllArray.hpp +1 -1
  57. data/vendor/datasketches-cpp/hll/include/HllSketch-internal.hpp +3 -5
  58. data/vendor/datasketches-cpp/hll/include/HllSketchImpl-internal.hpp +5 -11
  59. data/vendor/datasketches-cpp/hll/include/HllSketchImpl.hpp +2 -4
  60. data/vendor/datasketches-cpp/hll/include/HllSketchImplFactory.hpp +11 -10
  61. data/vendor/datasketches-cpp/hll/include/HllUnion-internal.hpp +17 -8
  62. data/vendor/datasketches-cpp/hll/include/HllUtil.hpp +12 -3
  63. data/vendor/datasketches-cpp/hll/include/coupon_iterator-internal.hpp +2 -2
  64. data/vendor/datasketches-cpp/hll/include/coupon_iterator.hpp +3 -0
  65. data/vendor/datasketches-cpp/hll/include/hll.hpp +11 -4
  66. data/vendor/datasketches-cpp/hll/include/hll.private.hpp +19 -0
  67. data/vendor/datasketches-cpp/hll/test/CMakeLists.txt +2 -0
  68. data/vendor/datasketches-cpp/hll/test/CouponListTest.cpp +64 -0
  69. data/vendor/datasketches-cpp/hll/test/HllFullSizeTest.cpp +137 -0
  70. data/vendor/datasketches-cpp/hll/test/HllKxqRebuildTest.cpp +150 -0
  71. data/vendor/datasketches-cpp/hll/test/HllSketchTest.cpp +3 -3
  72. data/vendor/datasketches-cpp/hll/test/HllUnionTest.cpp +71 -1
  73. data/vendor/datasketches-cpp/kll/include/kll_helper_impl.hpp +10 -10
  74. data/vendor/datasketches-cpp/kll/include/kll_sketch.hpp +10 -1
  75. data/vendor/datasketches-cpp/kll/include/kll_sketch_impl.hpp +33 -24
  76. data/vendor/datasketches-cpp/kll/test/kll_sketch_deserialize_from_java_test.cpp +24 -0
  77. data/vendor/datasketches-cpp/kll/test/kll_sketch_serialize_for_java.cpp +10 -0
  78. data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch.hpp +11 -2
  79. data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch_impl.hpp +24 -15
  80. data/vendor/datasketches-cpp/req/include/req_sketch.hpp +9 -0
  81. data/vendor/datasketches-cpp/req/include/req_sketch_impl.hpp +24 -15
  82. data/vendor/datasketches-cpp/req/test/req_sketch_deserialize_from_java_test.cpp +46 -0
  83. data/vendor/datasketches-cpp/req/test/req_sketch_serialize_for_java.cpp +20 -0
  84. data/vendor/datasketches-cpp/req/test/req_sketch_test.cpp +70 -0
  85. data/vendor/datasketches-cpp/sampling/include/ebpps_sample_impl.hpp +17 -8
  86. data/vendor/datasketches-cpp/sampling/include/ebpps_sketch.hpp +13 -0
  87. data/vendor/datasketches-cpp/sampling/include/var_opt_sketch.hpp +10 -1
  88. data/vendor/datasketches-cpp/sampling/include/var_opt_sketch_impl.hpp +6 -7
  89. data/vendor/datasketches-cpp/sampling/include/var_opt_union.hpp +5 -1
  90. data/vendor/datasketches-cpp/sampling/include/var_opt_union_impl.hpp +2 -1
  91. data/vendor/datasketches-cpp/sampling/test/ebpps_allocation_test.cpp +1 -1
  92. data/vendor/datasketches-cpp/sampling/test/ebpps_sketch_test.cpp +2 -2
  93. data/vendor/datasketches-cpp/sampling/test/var_opt_allocation_test.cpp +1 -1
  94. data/vendor/datasketches-cpp/sampling/test/var_opt_sketch_test.cpp +10 -4
  95. data/vendor/datasketches-cpp/sampling/test/var_opt_union_test.cpp +12 -0
  96. data/vendor/datasketches-cpp/tdigest/include/tdigest.hpp +38 -2
  97. data/vendor/datasketches-cpp/tdigest/include/tdigest_impl.hpp +168 -9
  98. data/vendor/datasketches-cpp/tdigest/test/CMakeLists.txt +1 -0
  99. data/vendor/datasketches-cpp/tdigest/test/tdigest_iterator_test.cpp +274 -0
  100. data/vendor/datasketches-cpp/tdigest/test/tdigest_test.cpp +275 -0
  101. data/vendor/datasketches-cpp/theta/include/compact_theta_sketch_parser.hpp +2 -0
  102. data/vendor/datasketches-cpp/theta/include/compact_theta_sketch_parser_impl.hpp +24 -3
  103. data/vendor/datasketches-cpp/theta/include/theta_constants.hpp +4 -2
  104. data/vendor/datasketches-cpp/theta/include/theta_helpers.hpp +32 -0
  105. data/vendor/datasketches-cpp/theta/include/theta_set_difference_base_impl.hpp +4 -2
  106. data/vendor/datasketches-cpp/theta/include/theta_sketch.hpp +22 -4
  107. data/vendor/datasketches-cpp/theta/include/theta_sketch_impl.hpp +60 -38
  108. data/vendor/datasketches-cpp/theta/include/theta_union_base_impl.hpp +2 -6
  109. data/vendor/datasketches-cpp/theta/include/theta_update_sketch_base_impl.hpp +2 -2
  110. data/vendor/datasketches-cpp/theta/test/bit_packing_test.cpp +50 -0
  111. data/vendor/datasketches-cpp/theta/test/theta_a_not_b_test.cpp +22 -0
  112. data/vendor/datasketches-cpp/theta/test/theta_sketch_test.cpp +315 -0
  113. data/vendor/datasketches-cpp/tools/rat-check.sh +68 -0
  114. data/vendor/datasketches-cpp/tuple/include/array_tuple_sketch.hpp +35 -4
  115. data/vendor/datasketches-cpp/tuple/include/array_tuple_sketch_impl.hpp +2 -2
  116. data/vendor/datasketches-cpp/tuple/include/tuple_sketch.hpp +41 -0
  117. data/vendor/datasketches-cpp/tuple/include/tuple_sketch_impl.hpp +5 -4
  118. data/vendor/datasketches-cpp/tuple/test/tuple_sketch_test.cpp +59 -0
  119. data/vendor/datasketches-cpp/version.cfg.in +1 -1
  120. metadata +12 -2
@@ -33,7 +33,7 @@ namespace datasketches {
33
33
 
34
34
  template<typename A>
35
35
  CouponList<A>::CouponList(uint8_t lgConfigK, target_hll_type tgtHllType, hll_mode mode, const A& allocator):
36
- HllSketchImpl<A>(lgConfigK, tgtHllType, mode, false),
36
+ HllSketchImpl<A>(lgConfigK, tgtHllType, mode),
37
37
  couponCount_(0),
38
38
  oooFlag_(false),
39
39
  coupons_(1ULL << (mode == hll_mode::LIST ? hll_constants::LG_INIT_LIST_SIZE : hll_constants::LG_INIT_SET_SIZE), 0, allocator)
@@ -41,7 +41,7 @@ coupons_(1ULL << (mode == hll_mode::LIST ? hll_constants::LG_INIT_LIST_SIZE : hl
41
41
 
42
42
  template<typename A>
43
43
  CouponList<A>::CouponList(const CouponList& that, const target_hll_type tgtHllType):
44
- HllSketchImpl<A>(that.lgConfigK_, tgtHllType, that.mode_, false),
44
+ HllSketchImpl<A>(that.lgConfigK_, tgtHllType, that.mode_),
45
45
  couponCount_(that.couponCount_),
46
46
  oooFlag_(that.oooFlag_),
47
47
  coupons_(that.coupons_)
@@ -99,6 +99,13 @@ CouponList<A>* CouponList<A>::newList(const void* bytes, size_t len, const A& al
99
99
  const bool emptyFlag = ((data[hll_constants::FLAGS_BYTE] & hll_constants::EMPTY_FLAG_MASK) ? true : false);
100
100
 
101
101
  const uint32_t couponCount = data[hll_constants::LIST_COUNT_BYTE];
102
+ // Reject LIST counts at or above the fixed LIST capacity.
103
+ const uint32_t listCapacity = 1u << hll_constants::LG_INIT_LIST_SIZE;
104
+ if (couponCount >= listCapacity) {
105
+ throw std::invalid_argument("Attempt to deserialize invalid CouponList with couponCount >= capacity. Found couponCount: "
106
+ + std::to_string(couponCount)
107
+ + ", capacity: " + std::to_string(listCapacity));
108
+ }
102
109
  const uint32_t couponsInArray = (compact ? couponCount : (1 << HllUtil<A>::computeLgArrInts(LIST, couponCount, lgK)));
103
110
  const size_t expectedLength = hll_constants::LIST_INT_ARR_START + (couponsInArray * sizeof(uint32_t));
104
111
  if (len < expectedLength) {
@@ -146,11 +153,19 @@ CouponList<A>* CouponList<A>::newList(std::istream& is, const A& allocator) {
146
153
  const bool oooFlag = ((listHeader[hll_constants::FLAGS_BYTE] & hll_constants::OUT_OF_ORDER_FLAG_MASK) ? true : false);
147
154
  const bool emptyFlag = ((listHeader[hll_constants::FLAGS_BYTE] & hll_constants::EMPTY_FLAG_MASK) ? true : false);
148
155
 
156
+ const uint32_t couponCount = listHeader[hll_constants::LIST_COUNT_BYTE];
157
+ // Reject LIST counts at or above the fixed LIST capacity.
158
+ const uint32_t listCapacity = 1u << hll_constants::LG_INIT_LIST_SIZE;
159
+ if (couponCount >= listCapacity) {
160
+ throw std::invalid_argument("Attempt to deserialize invalid CouponList with couponCount >= capacity. Found couponCount: "
161
+ + std::to_string(couponCount)
162
+ + ", capacity: " + std::to_string(listCapacity));
163
+ }
164
+
149
165
  ClAlloc cla(allocator);
150
166
  CouponList<A>* sketch = new (cla.allocate(1)) CouponList<A>(lgK, tgtHllType, mode, allocator);
151
167
  using coupon_list_ptr = std::unique_ptr<CouponList<A>, std::function<void(HllSketchImpl<A>*)>>;
152
168
  coupon_list_ptr ptr(sketch, sketch->get_deleter());
153
- const uint32_t couponCount = listHeader[hll_constants::LIST_COUNT_BYTE];
154
169
  sketch->couponCount_ = couponCount;
155
170
  sketch->putOutOfOrderFlag(oooFlag); // should always be false for LIST
156
171
 
@@ -162,8 +177,7 @@ CouponList<A>* CouponList<A>::newList(std::istream& is, const A& allocator) {
162
177
  read(is, sketch->coupons_.data(), numToRead * sizeof(uint32_t));
163
178
  }
164
179
 
165
- if (!is.good())
166
- throw std::runtime_error("error reading from std::istream");
180
+ if (!is.good()) { throw std::runtime_error("error reading from std::istream"); }
167
181
 
168
182
  return ptr.release();
169
183
  }
@@ -165,10 +165,10 @@ static int recursiveFindStraddle(const double xArr[], const int l, const int r,
165
165
  throw std::logic_error("target value invariant violated in search");
166
166
  }
167
167
 
168
- if (l+1 == r) return (l);
168
+ if (l+1 == r) { return (l); }
169
169
  m = l + ((r-l)/2);
170
- if (xArr[m] <= x) return (recursiveFindStraddle<A>(xArr, m, r, x));
171
- else return (recursiveFindStraddle<A>(xArr, l, m, x));
170
+ if (xArr[m] <= x) { return (recursiveFindStraddle<A>(xArr, m, r, x)); }
171
+ else { return (recursiveFindStraddle<A>(xArr, l, m, x)); }
172
172
  }
173
173
 
174
174
 
@@ -191,7 +191,7 @@ double CubicInterpolation<A>::usingXArrAndYStride(const double xArr[], const int
191
191
  const int xArrLenM1 = xArrLen - 1;
192
192
 
193
193
  if ((xArrLen < 4) || (x < xArr[0]) || (x > xArr[xArrLenM1])) {
194
- throw std::logic_error("impossible values during interpolaiton");
194
+ throw std::logic_error("impossible values during interpolation");
195
195
  }
196
196
 
197
197
  if (x == xArr[xArrLenM1]) { /* corner case */
@@ -21,6 +21,7 @@
21
21
  #define _HARMONICNUMBERS_INTERNAL_HPP_
22
22
 
23
23
  #include "HarmonicNumbers.hpp"
24
+ #include "fdlibm_log.hpp"
24
25
 
25
26
  #include <cmath>
26
27
 
@@ -70,7 +71,7 @@ double HarmonicNumbers<A>::harmonicNumber(const uint64_t x_i) {
70
71
  } else {
71
72
  double x = static_cast<double>(x_i);
72
73
  double invSq = 1.0 / (x * x);
73
- double sum = log(x) + EULER_MASCHERONI_CONSTANT + (1.0 / (2.0 * x));
74
+ double sum = fdlibm::log(x) + EULER_MASCHERONI_CONSTANT + (1.0 / (2.0 * x));
74
75
  /* note: the number of terms included from this series expansion is appropriate
75
76
  for the size of the exact table (25) and the precision of doubles */
76
77
  double pow = invSq; // now n^-2
@@ -30,8 +30,8 @@
30
30
  namespace datasketches {
31
31
 
32
32
  template<typename A>
33
- Hll4Array<A>::Hll4Array(uint8_t lgConfigK, bool startFullSize, const A& allocator):
34
- HllArray<A>(lgConfigK, target_hll_type::HLL_4, startFullSize, allocator),
33
+ Hll4Array<A>::Hll4Array(uint8_t lgConfigK, const A& allocator):
34
+ HllArray<A>(lgConfigK, target_hll_type::HLL_4, allocator),
35
35
  auxHashMap_(nullptr)
36
36
  {
37
37
  const uint32_t numBytes = this->hll4ArrBytes(lgConfigK);
@@ -53,7 +53,7 @@ Hll4Array<A>::Hll4Array(const Hll4Array<A>& that) :
53
53
 
54
54
  template<typename A>
55
55
  Hll4Array<A>::Hll4Array(const HllArray<A>& other) :
56
- HllArray<A>(other.getLgConfigK(), target_hll_type::HLL_4, other.isStartFullSize(), other.getAllocator()),
56
+ HllArray<A>(other.getLgConfigK(), target_hll_type::HLL_4, other.getAllocator()),
57
57
  auxHashMap_(nullptr)
58
58
  {
59
59
  const int numBytes = this->hll4ArrBytes(this->lgConfigK_);
@@ -131,7 +131,7 @@ uint8_t Hll4Array<A>::getSlot(uint32_t slotNo) const {
131
131
 
132
132
  template<typename A>
133
133
  uint8_t Hll4Array<A>::adjustRawValue(uint32_t slot, uint8_t value) const {
134
- if (value != hll_constants::AUX_TOKEN) return value + this->curMin_;
134
+ if (value != hll_constants::AUX_TOKEN) { return value + this->curMin_; }
135
135
  return auxHashMap_->mustFindValueFor(slot);
136
136
  }
137
137
 
@@ -28,7 +28,7 @@ namespace datasketches {
28
28
  template<typename A>
29
29
  class Hll4Array final : public HllArray<A> {
30
30
  public:
31
- explicit Hll4Array(uint8_t lgConfigK, bool startFullSize, const A& allocator);
31
+ explicit Hll4Array(uint8_t lgConfigK, const A& allocator);
32
32
  explicit Hll4Array(const Hll4Array<A>& that);
33
33
  explicit Hll4Array(const HllArray<A>& that);
34
34
 
@@ -27,8 +27,8 @@
27
27
  namespace datasketches {
28
28
 
29
29
  template<typename A>
30
- Hll6Array<A>::Hll6Array(uint8_t lgConfigK, bool startFullSize, const A& allocator):
31
- HllArray<A>(lgConfigK, target_hll_type::HLL_6, startFullSize, allocator)
30
+ Hll6Array<A>::Hll6Array(uint8_t lgConfigK, const A& allocator):
31
+ HllArray<A>(lgConfigK, target_hll_type::HLL_6, allocator)
32
32
  {
33
33
  const int numBytes = this->hll6ArrBytes(lgConfigK);
34
34
  this->hllByteArr_.resize(numBytes, 0);
@@ -36,7 +36,7 @@ HllArray<A>(lgConfigK, target_hll_type::HLL_6, startFullSize, allocator)
36
36
 
37
37
  template<typename A>
38
38
  Hll6Array<A>::Hll6Array(const HllArray<A>& other) :
39
- HllArray<A>(other.getLgConfigK(), target_hll_type::HLL_6, other.isStartFullSize(), other.getAllocator())
39
+ HllArray<A>(other.getLgConfigK(), target_hll_type::HLL_6, other.getAllocator())
40
40
  {
41
41
  const int numBytes = this->hll6ArrBytes(this->lgConfigK_);
42
42
  this->hllByteArr_.resize(numBytes, 0);
@@ -30,7 +30,7 @@ class Hll6Iterator;
30
30
  template<typename A>
31
31
  class Hll6Array final : public HllArray<A> {
32
32
  public:
33
- Hll6Array(uint8_t lgConfigK, bool startFullSize, const A& allocator);
33
+ Hll6Array(uint8_t lgConfigK, const A& allocator);
34
34
  explicit Hll6Array(const HllArray<A>& that);
35
35
 
36
36
  virtual ~Hll6Array() = default;
@@ -25,8 +25,8 @@
25
25
  namespace datasketches {
26
26
 
27
27
  template<typename A>
28
- Hll8Array<A>::Hll8Array(uint8_t lgConfigK, bool startFullSize, const A& allocator):
29
- HllArray<A>(lgConfigK, target_hll_type::HLL_8, startFullSize, allocator)
28
+ Hll8Array<A>::Hll8Array(uint8_t lgConfigK, const A& allocator):
29
+ HllArray<A>(lgConfigK, target_hll_type::HLL_8, allocator)
30
30
  {
31
31
  const int numBytes = this->hll8ArrBytes(lgConfigK);
32
32
  this->hllByteArr_.resize(numBytes, 0);
@@ -34,7 +34,7 @@ HllArray<A>(lgConfigK, target_hll_type::HLL_8, startFullSize, allocator)
34
34
 
35
35
  template<typename A>
36
36
  Hll8Array<A>::Hll8Array(const HllArray<A>& other):
37
- HllArray<A>(other.getLgConfigK(), target_hll_type::HLL_8, other.isStartFullSize(), other.getAllocator())
37
+ HllArray<A>(other.getLgConfigK(), target_hll_type::HLL_8, other.getAllocator())
38
38
  {
39
39
  const int numBytes = this->hll8ArrBytes(this->lgConfigK_);
40
40
  this->hllByteArr_.resize(numBytes, 0);
@@ -98,6 +98,9 @@ void Hll8Array<A>::internalCouponUpdate(uint32_t coupon) {
98
98
 
99
99
  const uint8_t curVal = this->hllByteArr_[slotNo];
100
100
  if (newVal > curVal) {
101
+ // A prior HLL merge may have left the estimator state stale. Rebuild it before applying
102
+ // an incremental update for a changed register.
103
+ this->check_rebuild_kxq_cur_min();
101
104
  this->hllByteArr_[slotNo] = newVal;
102
105
  this->hipAndKxQIncrementalUpdate(curVal, newVal);
103
106
  this->numAtCurMin_ -= curVal == 0; // interpret numAtCurMin as num zeros
@@ -30,7 +30,7 @@ class Hll8Iterator;
30
30
  template<typename A>
31
31
  class Hll8Array final : public HllArray<A> {
32
32
  public:
33
- Hll8Array(uint8_t lgConfigK, bool startFullSize, const A& allocator);
33
+ Hll8Array(uint8_t lgConfigK, const A& allocator);
34
34
  explicit Hll8Array(const HllArray<A>& that);
35
35
 
36
36
  virtual ~Hll8Array() = default;
@@ -21,6 +21,7 @@
21
21
  #define _HLLARRAY_INTERNAL_HPP_
22
22
 
23
23
  #include "HllArray.hpp"
24
+ #include "fdlibm_log.hpp"
24
25
  #include "HllUtil.hpp"
25
26
  #include "HarmonicNumbers.hpp"
26
27
  #include "CubicInterpolation.hpp"
@@ -35,8 +36,8 @@
35
36
  namespace datasketches {
36
37
 
37
38
  template<typename A>
38
- HllArray<A>::HllArray(uint8_t lgConfigK, target_hll_type tgtHllType, bool startFullSize, const A& allocator):
39
- HllSketchImpl<A>(lgConfigK, tgtHllType, hll_mode::HLL, startFullSize),
39
+ HllArray<A>::HllArray(uint8_t lgConfigK, target_hll_type tgtHllType, const A& allocator):
40
+ HllSketchImpl<A>(lgConfigK, tgtHllType, hll_mode::HLL),
40
41
  hipAccum_(0.0),
41
42
  kxq0_(1 << lgConfigK),
42
43
  kxq1_(0.0),
@@ -49,7 +50,7 @@ rebuild_kxq_curmin_(false)
49
50
 
50
51
  template<typename A>
51
52
  HllArray<A>::HllArray(const HllArray& other, target_hll_type tgtHllType) :
52
- HllSketchImpl<A>(other.getLgConfigK(), tgtHllType, hll_mode::HLL, other.isStartFullSize()),
53
+ HllSketchImpl<A>(other.getLgConfigK(), tgtHllType, hll_mode::HLL),
53
54
  // remaining fields are initialized to empty sketch defaults
54
55
  // and left to subclass constructor to populate
55
56
  hipAccum_(0.0),
@@ -109,7 +110,6 @@ HllArray<A>* HllArray<A>::newHll(const void* bytes, size_t len, const A& allocat
109
110
  const target_hll_type tgtHllType = HllSketchImpl<A>::extractTgtHllType(data[hll_constants::MODE_BYTE]);
110
111
  const bool oooFlag = ((data[hll_constants::FLAGS_BYTE] & hll_constants::OUT_OF_ORDER_FLAG_MASK) ? true : false);
111
112
  const bool comapctFlag = ((data[hll_constants::FLAGS_BYTE] & hll_constants::COMPACT_FLAG_MASK) ? true : false);
112
- const bool startFullSizeFlag = ((data[hll_constants::FLAGS_BYTE] & hll_constants::FULL_SIZE_FLAG_MASK) ? true : false);
113
113
 
114
114
  const uint8_t lgK = data[hll_constants::LG_K_BYTE];
115
115
  const uint8_t curMin = data[hll_constants::HLL_CUR_MIN_BYTE];
@@ -139,18 +139,19 @@ HllArray<A>* HllArray<A>::newHll(const void* bytes, size_t len, const A& allocat
139
139
  aux_ptr = aux_hash_map_ptr(auxHashMap, auxHashMap->make_deleter());
140
140
  }
141
141
 
142
- HllArray<A>* sketch = HllSketchImplFactory<A>::newHll(lgK, tgtHllType, startFullSizeFlag, allocator);
142
+ HllArray<A>* sketch = HllSketchImplFactory<A>::newHll(lgK, tgtHllType, allocator);
143
143
  sketch->putCurMin(curMin);
144
144
  sketch->putOutOfOrderFlag(oooFlag);
145
- if (!oooFlag) sketch->putHipAccum(hip);
145
+ if (!oooFlag) { sketch->putHipAccum(hip); }
146
146
  sketch->putKxQ0(kxq0);
147
147
  sketch->putKxQ1(kxq1);
148
148
  sketch->putNumAtCurMin(numAtCurMin);
149
149
 
150
150
  std::memcpy(sketch->hllByteArr_.data(), data + hll_constants::HLL_BYTE_ARR_START, arrayBytes);
151
151
 
152
- if (auxHashMap != nullptr)
152
+ if (auxHashMap != nullptr) {
153
153
  ((Hll4Array<A>*)sketch)->putAuxHashMap(auxHashMap);
154
+ }
154
155
 
155
156
  aux_ptr.release();
156
157
  return sketch;
@@ -173,18 +174,17 @@ HllArray<A>* HllArray<A>::newHll(std::istream& is, const A& allocator) {
173
174
 
174
175
  hll_mode mode = HllSketchImpl<A>::extractCurMode(listHeader[hll_constants::MODE_BYTE]);
175
176
  if (mode != HLL) {
176
- throw std::invalid_argument("Calling HLL construtor with non-HLL mode data");
177
+ throw std::invalid_argument("Calling HLL constructor with non-HLL mode data");
177
178
  }
178
179
 
179
180
  const target_hll_type tgtHllType = HllSketchImpl<A>::extractTgtHllType(listHeader[hll_constants::MODE_BYTE]);
180
181
  const bool oooFlag = ((listHeader[hll_constants::FLAGS_BYTE] & hll_constants::OUT_OF_ORDER_FLAG_MASK) ? true : false);
181
182
  const bool comapctFlag = ((listHeader[hll_constants::FLAGS_BYTE] & hll_constants::COMPACT_FLAG_MASK) ? true : false);
182
- const bool startFullSizeFlag = ((listHeader[hll_constants::FLAGS_BYTE] & hll_constants::FULL_SIZE_FLAG_MASK) ? true : false);
183
183
 
184
184
  const uint8_t lgK = listHeader[hll_constants::LG_K_BYTE];
185
185
  const uint8_t curMin = listHeader[hll_constants::HLL_CUR_MIN_BYTE];
186
186
 
187
- HllArray* sketch = HllSketchImplFactory<A>::newHll(lgK, tgtHllType, startFullSizeFlag, allocator);
187
+ HllArray* sketch = HllSketchImplFactory<A>::newHll(lgK, tgtHllType, allocator);
188
188
  typedef std::unique_ptr<HllArray<A>, std::function<void(HllSketchImpl<A>*)>> hll_array_ptr;
189
189
  hll_array_ptr sketch_ptr(sketch, sketch->get_deleter());
190
190
  sketch->putCurMin(curMin);
@@ -193,7 +193,7 @@ HllArray<A>* HllArray<A>::newHll(std::istream& is, const A& allocator) {
193
193
  const auto hip = read<double>(is);
194
194
  const auto kxq0 = read<double>(is);
195
195
  const auto kxq1 = read<double>(is);
196
- if (!oooFlag) sketch->putHipAccum(hip);
196
+ if (!oooFlag) { sketch->putHipAccum(hip); }
197
197
  sketch->putKxQ0(kxq0);
198
198
  sketch->putKxQ1(kxq1);
199
199
 
@@ -209,8 +209,7 @@ HllArray<A>* HllArray<A>::newHll(std::istream& is, const A& allocator) {
209
209
  ((Hll4Array<A>*)sketch)->putAuxHashMap(auxHashMap);
210
210
  }
211
211
 
212
- if (!is.good())
213
- throw std::runtime_error("error reading from std::istream");
212
+ if (!is.good()) { throw std::runtime_error("error reading from std::istream"); }
214
213
 
215
214
  return sketch_ptr.release();
216
215
  }
@@ -465,6 +464,10 @@ bool HllArray<A>::isCompact() const {
465
464
 
466
465
  template<typename A>
467
466
  bool HllArray<A>::isEmpty() const {
467
+ // mergeHll() is only called with non-empty sketches and sets this flag after updating the
468
+ // register array. The cached curMin_/numAtCurMin_ may still have their empty-sketch values,
469
+ // but a pending rebuild therefore proves that this array is not empty.
470
+ if (rebuild_kxq_curmin_) return false;
468
471
  const uint32_t configK = 1 << this->lgConfigK_;
469
472
  return (curMin_ == 0) && (numAtCurMin_ == configK);
470
473
  }
@@ -545,7 +548,7 @@ template<typename A>
545
548
  void HllArray<A>::hipAndKxQIncrementalUpdate(uint8_t oldValue, uint8_t newValue) {
546
549
  const uint32_t configK = 1 << this->getLgConfigK();
547
550
  // update hip BEFORE updating kxq
548
- if (!oooFlag_) hipAccum_ += configK / (kxq0_ + kxq1_);
551
+ if (!oooFlag_) { hipAccum_ += configK / (kxq0_ + kxq1_); }
549
552
  // update kxq0 and kxq1; subtract first, then add
550
553
  if (oldValue < 32) { kxq0_ -= INVERSE_POWERS_OF_2[oldValue]; }
551
554
  else { kxq1_ -= INVERSE_POWERS_OF_2[oldValue]; }
@@ -566,7 +569,7 @@ double HllArray<A>::getHllBitMapEstimate() const {
566
569
 
567
570
  //This will eventually go away.
568
571
  if (numUnhitBuckets == 0) {
569
- return configK * log(configK / 0.5);
572
+ return configK * fdlibm::log(configK / 0.5);
570
573
  }
571
574
 
572
575
  const uint32_t numHitBuckets = configK - numUnhitBuckets;
@@ -599,34 +602,37 @@ bool HllArray<A>::isRebuildKxqCurminFlag() const {
599
602
  template<typename A>
600
603
  void HllArray<A>::check_rebuild_kxq_cur_min() {
601
604
  if (!rebuild_kxq_curmin_) { return; }
605
+ // the deferred rebuild is only ever set on an HLL_8 union gadget. Guarding here also keeps
606
+ // this from ever rewriting curMin_ on an HLL_4 array, whose nibbles are stored relative to it.
607
+ if (this->getCurMode() != hll_mode::HLL || this->getTgtHllType() != target_hll_type::HLL_8) {
608
+ rebuild_kxq_curmin_ = false;
609
+ return;
610
+ }
602
611
 
603
- uint8_t cur_min = 64;
604
- uint32_t num_at_cur_min = 0;
612
+ uint32_t num_zeros = 0;
605
613
  double kxq0 = 1 << this->lgConfigK_;
606
614
  double kxq1 = 0;
607
615
 
608
- auto it = this->begin(true); // want all points to adjust cur_min
616
+ auto it = this->begin(true); // want all slots, including the empty ones
609
617
  const auto end = this->end();
610
618
  while (it != end) {
611
619
  uint8_t v = HllUtil<A>::getValue(*it);
612
620
  if (v > 0) {
613
621
  if (v < 32) { kxq0 += INVERSE_POWERS_OF_2[v] - 1.0; }
614
622
  else { kxq1 += INVERSE_POWERS_OF_2[v] - 1.0; }
615
- }
616
- if (v > cur_min) { ++it; continue; }
617
- if (v < cur_min) {
618
- cur_min = v;
619
- num_at_cur_min = 1;
620
623
  } else {
621
- ++num_at_cur_min;
622
- }
624
+ ++num_zeros;
625
+ }
623
626
  ++it;
624
627
  }
625
628
 
626
629
  kxq0_ = kxq0;
627
630
  kxq1_ = kxq1;
628
- curMin_ = cur_min;
629
- numAtCurMin_ = num_at_cur_min;
631
+ // HLL_8 convention: curMin is always 0 and numAtCurMin is the number of zero registers.
632
+ // That is the representation the incremental update path maintains, so the rebuilt state is
633
+ // indistinguishable from it and the timing of this rebuild is not observable in the image.
634
+ curMin_ = 0;
635
+ numAtCurMin_ = num_zeros;
630
636
  rebuild_kxq_curmin_ = false;
631
637
  // HipAccum is not affected
632
638
 
@@ -648,7 +654,7 @@ array_(array), array_size_(array_size), index_(index), hll_type_(hll_type), exce
648
654
  {
649
655
  while (index_ < array_size_) {
650
656
  value_ = get_value(array_, index_, hll_type_, exceptions_, offset_);
651
- if (all_ || value_ != hll_constants::EMPTY) break;
657
+ if (all_ || value_ != hll_constants::EMPTY) { break; }
652
658
  ++index_;
653
659
  }
654
660
  }
@@ -657,7 +663,7 @@ template<typename A>
657
663
  typename HllArray<A>::const_iterator& HllArray<A>::const_iterator::operator++() {
658
664
  while (++index_ < array_size_) {
659
665
  value_ = get_value(array_, index_, hll_type_, exceptions_, offset_);
660
- if (all_ || value_ != hll_constants::EMPTY) break;
666
+ if (all_ || value_ != hll_constants::EMPTY) { break; }
661
667
  }
662
668
  return *this;
663
669
  }
@@ -33,7 +33,7 @@ class HllArray : public HllSketchImpl<A> {
33
33
  public:
34
34
  using vector_bytes = std::vector<uint8_t, typename std::allocator_traits<A>::template rebind_alloc<uint8_t>>;
35
35
 
36
- HllArray(uint8_t lgConfigK, target_hll_type tgtHllType, bool startFullSize, const A& allocator);
36
+ HllArray(uint8_t lgConfigK, target_hll_type tgtHllType, const A& allocator);
37
37
  explicit HllArray(const HllArray& other, target_hll_type tgtHllType);
38
38
 
39
39
  static HllArray* newHll(const void* bytes, size_t len, const A& allocator);
@@ -45,7 +45,7 @@ template<typename A>
45
45
  hll_sketch_alloc<A>::hll_sketch_alloc(uint8_t lg_config_k, target_hll_type tgt_type, bool start_full_size, const A& allocator) {
46
46
  HllUtil<A>::checkLgK(lg_config_k);
47
47
  if (start_full_size) {
48
- sketch_impl = HllSketchImplFactory<A>::newHll(lg_config_k, tgt_type, start_full_size, allocator);
48
+ sketch_impl = HllSketchImplFactory<A>::newHll(lg_config_k, tgt_type, allocator);
49
49
  } else {
50
50
  typedef typename std::allocator_traits<A>::template rebind_alloc<CouponList<A>> clAlloc;
51
51
  sketch_impl = new (clAlloc(allocator).allocate(1)) CouponList<A>(lg_config_k, tgt_type, hll_mode::LIST, allocator);
@@ -107,10 +107,8 @@ hll_sketch_alloc<A>& hll_sketch_alloc<A>::operator=(hll_sketch_alloc<A>&& other)
107
107
  }
108
108
 
109
109
  template<typename A>
110
- void hll_sketch_alloc<A>::reset() {
111
- // TODO: need to allow starting from a full-sized sketch
112
- // (either here or in other implementation)
113
- sketch_impl = sketch_impl->reset();
110
+ void hll_sketch_alloc<A>::reset(bool full_size) {
111
+ sketch_impl = sketch_impl->reset(full_size);
114
112
  }
115
113
 
116
114
  template<typename A>
@@ -29,11 +29,10 @@ namespace datasketches {
29
29
 
30
30
  template<typename A>
31
31
  HllSketchImpl<A>::HllSketchImpl(uint8_t lgConfigK, target_hll_type tgtHllType,
32
- hll_mode mode, bool startFullSize)
32
+ hll_mode mode)
33
33
  : lgConfigK_(lgConfigK),
34
34
  tgtHllType_(tgtHllType),
35
- mode_(mode),
36
- startFullSize_(startFullSize)
35
+ mode_(mode)
37
36
  {
38
37
  }
39
38
 
@@ -75,7 +74,7 @@ uint8_t HllSketchImpl<A>::makeFlagsByte(bool compact) const {
75
74
  flags |= (isEmpty() ? hll_constants::EMPTY_FLAG_MASK : 0);
76
75
  flags |= (compact ? hll_constants::COMPACT_FLAG_MASK : 0);
77
76
  flags |= (isOutOfOrderFlag() ? hll_constants::OUT_OF_ORDER_FLAG_MASK : 0);
78
- flags |= (startFullSize_ ? hll_constants::FULL_SIZE_FLAG_MASK : 0);
77
+ // bit 32 is reserved: see RESERVED_FLAG_MASK_32 in HllUtil.hpp
79
78
  return flags;
80
79
  }
81
80
 
@@ -122,8 +121,8 @@ uint8_t HllSketchImpl<A>::makeModeByte() const {
122
121
  }
123
122
 
124
123
  template<typename A>
125
- HllSketchImpl<A>* HllSketchImpl<A>::reset() {
126
- return HllSketchImplFactory<A>::reset(this, startFullSize_);
124
+ HllSketchImpl<A>* HllSketchImpl<A>::reset(bool full_size) {
125
+ return HllSketchImplFactory<A>::reset(this, full_size);
127
126
  }
128
127
 
129
128
  template<typename A>
@@ -141,11 +140,6 @@ hll_mode HllSketchImpl<A>::getCurMode() const {
141
140
  return mode_;
142
141
  }
143
142
 
144
- template<typename A>
145
- bool HllSketchImpl<A>::isStartFullSize() const {
146
- return startFullSize_;
147
- }
148
-
149
143
  }
150
144
 
151
145
  #endif // _HLLSKETCHIMPL_INTERNAL_HPP_
@@ -32,7 +32,7 @@ class HllSketchImpl {
32
32
  public:
33
33
  using vector_bytes = std::vector<uint8_t, typename std::allocator_traits<A>::template rebind_alloc<uint8_t>>;
34
34
 
35
- HllSketchImpl(uint8_t lgConfigK, target_hll_type tgtHllType, hll_mode mode, bool startFullSize);
35
+ HllSketchImpl(uint8_t lgConfigK, target_hll_type tgtHllType, hll_mode mode);
36
36
  virtual ~HllSketchImpl();
37
37
 
38
38
  virtual void serialize(std::ostream& os, bool compact) const = 0;
@@ -40,7 +40,7 @@ class HllSketchImpl {
40
40
 
41
41
  virtual HllSketchImpl* copy() const = 0;
42
42
  virtual HllSketchImpl* copyAs(target_hll_type tgtHllType) const = 0;
43
- HllSketchImpl<A>* reset();
43
+ HllSketchImpl<A>* reset(bool full_size);
44
44
 
45
45
  virtual std::function<void(HllSketchImpl<A>*)> get_deleter() const = 0;
46
46
 
@@ -69,7 +69,6 @@ class HllSketchImpl {
69
69
  virtual bool isOutOfOrderFlag() const = 0;
70
70
  virtual void putOutOfOrderFlag(bool oooFlag) = 0;
71
71
  virtual A getAllocator() const = 0;
72
- bool isStartFullSize() const;
73
72
 
74
73
  protected:
75
74
  static target_hll_type extractTgtHllType(uint8_t modeByte);
@@ -80,7 +79,6 @@ class HllSketchImpl {
80
79
  const uint8_t lgConfigK_;
81
80
  const target_hll_type tgtHllType_;
82
81
  const hll_mode mode_;
83
- const bool startFullSize_;
84
82
  };
85
83
 
86
84
  }
@@ -41,10 +41,11 @@ public:
41
41
 
42
42
  static CouponHashSet<A>* promoteListToSet(const CouponList<A>& list);
43
43
  static HllArray<A>* promoteListOrSetToHll(const CouponList<A>& list);
44
- static HllArray<A>* newHll(uint8_t lgConfigK, target_hll_type tgtHllType, bool startFullSize, const A& allocator);
44
+ static HllArray<A>* newHll(uint8_t lgConfigK, target_hll_type tgtHllType, const A& allocator);
45
45
 
46
46
  // resets the input impl, deleting the input pointer and returning a new pointer
47
- static HllSketchImpl<A>* reset(HllSketchImpl<A>* impl, bool startFullSize);
47
+ // full_size selects the state to reset to: an empty HLL array, or LIST (coupon) mode
48
+ static HllSketchImpl<A>* reset(HllSketchImpl<A>* impl, bool full_size);
48
49
 
49
50
  static Hll4Array<A>* convertToHll4(const HllArray<A>& srcHllArr);
50
51
  static Hll6Array<A>* convertToHll6(const HllArray<A>& srcHllArr);
@@ -63,7 +64,7 @@ CouponHashSet<A>* HllSketchImplFactory<A>::promoteListToSet(const CouponList<A>&
63
64
 
64
65
  template<typename A>
65
66
  HllArray<A>* HllSketchImplFactory<A>::promoteListOrSetToHll(const CouponList<A>& src) {
66
- HllArray<A>* tgtHllArr = HllSketchImplFactory<A>::newHll(src.getLgConfigK(), src.getTgtHllType(), false, src.getAllocator());
67
+ HllArray<A>* tgtHllArr = HllSketchImplFactory<A>::newHll(src.getLgConfigK(), src.getTgtHllType(), src.getAllocator());
67
68
  tgtHllArr->putKxQ0(1 << src.getLgConfigK());
68
69
  for (const auto coupon: src) {
69
70
  tgtHllArr->couponUpdate(coupon);
@@ -105,25 +106,25 @@ HllSketchImpl<A>* HllSketchImplFactory<A>::deserialize(const void* bytes, size_t
105
106
  }
106
107
 
107
108
  template<typename A>
108
- HllArray<A>* HllSketchImplFactory<A>::newHll(uint8_t lgConfigK, target_hll_type tgtHllType, bool startFullSize, const A& allocator) {
109
+ HllArray<A>* HllSketchImplFactory<A>::newHll(uint8_t lgConfigK, target_hll_type tgtHllType, const A& allocator) {
109
110
  switch (tgtHllType) {
110
111
  case HLL_8:
111
112
  using Hll8Alloc = typename std::allocator_traits<A>::template rebind_alloc<Hll8Array<A>>;
112
- return new (Hll8Alloc(allocator).allocate(1)) Hll8Array<A>(lgConfigK, startFullSize, allocator);
113
+ return new (Hll8Alloc(allocator).allocate(1)) Hll8Array<A>(lgConfigK, allocator);
113
114
  case HLL_6:
114
115
  using Hll6Alloc = typename std::allocator_traits<A>::template rebind_alloc<Hll6Array<A>>;
115
- return new (Hll6Alloc(allocator).allocate(1)) Hll6Array<A>(lgConfigK, startFullSize, allocator);
116
+ return new (Hll6Alloc(allocator).allocate(1)) Hll6Array<A>(lgConfigK, allocator);
116
117
  case HLL_4:
117
118
  using Hll4Alloc = typename std::allocator_traits<A>::template rebind_alloc<Hll4Array<A>>;
118
- return new (Hll4Alloc(allocator).allocate(1)) Hll4Array<A>(lgConfigK, startFullSize, allocator);
119
+ return new (Hll4Alloc(allocator).allocate(1)) Hll4Array<A>(lgConfigK, allocator);
119
120
  }
120
121
  throw std::logic_error("Invalid target_hll_type");
121
122
  }
122
123
 
123
124
  template<typename A>
124
- HllSketchImpl<A>* HllSketchImplFactory<A>::reset(HllSketchImpl<A>* impl, bool startFullSize) {
125
- if (startFullSize) {
126
- HllArray<A>* hll = newHll(impl->getLgConfigK(), impl->getTgtHllType(), startFullSize, impl->getAllocator());
125
+ HllSketchImpl<A>* HllSketchImplFactory<A>::reset(HllSketchImpl<A>* impl, bool full_size) {
126
+ if (full_size) {
127
+ HllArray<A>* hll = newHll(impl->getLgConfigK(), impl->getTgtHllType(), impl->getAllocator());
127
128
  impl->get_deleter()(impl);
128
129
  return hll;
129
130
  } else {
@@ -39,18 +39,21 @@ hll_union_alloc<A>::hll_union_alloc(uint8_t lg_max_k, const A& allocator):
39
39
 
40
40
  template<typename A>
41
41
  hll_sketch_alloc<A> hll_union_alloc<A>::get_result(target_hll_type target_type) const {
42
+ if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL) {
43
+ static_cast<HllArray<A>*>(gadget_.sketch_impl)->check_rebuild_kxq_cur_min();
44
+ }
42
45
  return hll_sketch_alloc<A>(gadget_, target_type);
43
46
  }
44
47
 
45
48
  template<typename A>
46
49
  void hll_union_alloc<A>::update(const hll_sketch_alloc<A>& sketch) {
47
- if (sketch.is_empty()) return;
50
+ if (sketch.is_empty()) { return; }
48
51
  union_impl(sketch, lg_max_k_);
49
52
  }
50
53
 
51
54
  template<typename A>
52
55
  void hll_union_alloc<A>::update(hll_sketch_alloc<A>&& sketch) {
53
- if (sketch.is_empty()) return;
56
+ if (sketch.is_empty()) { return; }
54
57
  if (gadget_.is_empty() && sketch.get_target_type() == HLL_8 && sketch.get_lg_config_k() <= lg_max_k_) {
55
58
  if (sketch.get_current_mode() == HLL || sketch.get_lg_config_k() == lg_max_k_) {
56
59
  gadget_ = std::move(sketch);
@@ -131,29 +134,33 @@ void hll_union_alloc<A>::coupon_update(uint32_t coupon) {
131
134
 
132
135
  template<typename A>
133
136
  double hll_union_alloc<A>::get_estimate() const {
134
- if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL)
137
+ if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL) {
135
138
  static_cast<HllArray<A>*>(gadget_.sketch_impl)->check_rebuild_kxq_cur_min();
139
+ }
136
140
  return gadget_.get_estimate();
137
141
  }
138
142
 
139
143
  template<typename A>
140
144
  double hll_union_alloc<A>::get_composite_estimate() const {
141
- if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL)
145
+ if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL) {
142
146
  static_cast<HllArray<A>*>(gadget_.sketch_impl)->check_rebuild_kxq_cur_min();
147
+ }
143
148
  return gadget_.get_composite_estimate();
144
149
  }
145
150
 
146
151
  template<typename A>
147
152
  double hll_union_alloc<A>::get_lower_bound(uint8_t num_std_dev) const {
148
- if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL)
153
+ if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL) {
149
154
  static_cast<HllArray<A>*>(gadget_.sketch_impl)->check_rebuild_kxq_cur_min();
155
+ }
150
156
  return gadget_.get_lower_bound(num_std_dev);
151
157
  }
152
158
 
153
159
  template<typename A>
154
160
  double hll_union_alloc<A>::get_upper_bound(uint8_t num_std_dev) const {
155
- if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL)
161
+ if (gadget_.sketch_impl->getCurMode() == hll_mode::HLL) {
156
162
  static_cast<HllArray<A>*>(gadget_.sketch_impl)->check_rebuild_kxq_cur_min();
163
+ }
157
164
  return gadget_.get_upper_bound(num_std_dev);
158
165
  }
159
166
 
@@ -164,7 +171,9 @@ uint8_t hll_union_alloc<A>::get_lg_config_k() const {
164
171
 
165
172
  template<typename A>
166
173
  void hll_union_alloc<A>::reset() {
167
- gadget_.reset();
174
+ // always coupon collection mode: the gadget is an internal detail and must not
175
+ // inherit a full-size state from whatever sketches happen to have been unioned in
176
+ gadget_.reset(false);
168
177
  }
169
178
 
170
179
  template<typename A>
@@ -209,7 +218,7 @@ HllSketchImpl<A>* hll_union_alloc<A>::copy_or_downsample(const HllSketchImpl<A>*
209
218
  return src->copyAs(HLL_8);
210
219
  }
211
220
  typedef typename std::allocator_traits<A>::template rebind_alloc<Hll8Array<A>> hll8Alloc;
212
- Hll8Array<A>* tgtHllArr = new (hll8Alloc(src->getAllocator()).allocate(1)) Hll8Array<A>(tgt_lg_k, false, src->getAllocator());
221
+ Hll8Array<A>* tgtHllArr = new (hll8Alloc(src->getAllocator()).allocate(1)) Hll8Array<A>(tgt_lg_k, src->getAllocator());
213
222
  tgtHllArr->mergeHll(*src);
214
223
  //both of these are required for isomorphism
215
224
  tgtHllArr->putHipAccum(src->getHipAccum());