datasketches 0.5.2 → 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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/ext/datasketches/theta_wrapper.cpp +1 -1
  4. data/lib/datasketches/version.rb +1 -1
  5. data/vendor/datasketches-cpp/CMakeLists.txt +5 -3
  6. data/vendor/datasketches-cpp/CODE_OF_CONDUCT.md +1 -1
  7. data/vendor/datasketches-cpp/LICENSE +14 -0
  8. data/vendor/datasketches-cpp/README.md +67 -73
  9. data/vendor/datasketches-cpp/benchmarks/CMakeLists.txt +52 -0
  10. data/vendor/datasketches-cpp/benchmarks/benchmark_count_min_sketch.cpp +153 -0
  11. data/vendor/datasketches-cpp/benchmarks/benchmark_count_min_sketch_serialization.cpp +161 -0
  12. data/vendor/datasketches-cpp/common/CMakeLists.txt +1 -0
  13. data/vendor/datasketches-cpp/common/include/binomial_bounds.hpp +2 -2
  14. data/vendor/datasketches-cpp/common/include/fdlibm_log.hpp +101 -0
  15. data/vendor/datasketches-cpp/common/include/serde.hpp +6 -0
  16. data/vendor/datasketches-cpp/common/test/CMakeLists.txt +44 -2
  17. data/vendor/datasketches-cpp/common/test/binomial_bounds_test.cpp +279 -0
  18. data/vendor/datasketches-cpp/common/test/deserialize_hardening_test.cpp +188 -0
  19. data/vendor/datasketches-cpp/count/include/count_min.hpp +17 -4
  20. data/vendor/datasketches-cpp/count/include/count_min_impl.hpp +65 -83
  21. data/vendor/datasketches-cpp/count/test/count_min_test.cpp +63 -7
  22. data/vendor/datasketches-cpp/cpc/include/compression_data.hpp +2 -0
  23. data/vendor/datasketches-cpp/cpc/include/cpc_compressor_impl.hpp +16 -7
  24. data/vendor/datasketches-cpp/cpc/include/cpc_sketch.hpp +1 -0
  25. data/vendor/datasketches-cpp/cpc/include/cpc_sketch_impl.hpp +54 -36
  26. data/vendor/datasketches-cpp/cpc/include/cpc_union_impl.hpp +27 -27
  27. data/vendor/datasketches-cpp/cpc/include/cpc_util.hpp +7 -7
  28. data/vendor/datasketches-cpp/cpc/include/icon_estimator.hpp +5 -5
  29. data/vendor/datasketches-cpp/cpc/include/u32_table_impl.hpp +16 -16
  30. data/vendor/datasketches-cpp/cpc/test/cpc_sketch_test.cpp +35 -0
  31. data/vendor/datasketches-cpp/fi/include/frequent_items_sketch.hpp +28 -3
  32. data/vendor/datasketches-cpp/fi/include/frequent_items_sketch_impl.hpp +41 -25
  33. data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map.hpp +3 -1
  34. data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map_impl.hpp +10 -5
  35. data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_serialize_for_java.cpp +24 -0
  36. data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_test.cpp +116 -0
  37. data/vendor/datasketches-cpp/filters/include/bloom_filter.hpp +1 -1
  38. data/vendor/datasketches-cpp/filters/include/bloom_filter_impl.hpp +32 -12
  39. data/vendor/datasketches-cpp/filters/test/bloom_filter_test.cpp +28 -1
  40. data/vendor/datasketches-cpp/hll/include/CouponHashSet-internal.hpp +1 -2
  41. data/vendor/datasketches-cpp/hll/include/CouponList-internal.hpp +19 -5
  42. data/vendor/datasketches-cpp/hll/include/CubicInterpolation-internal.hpp +4 -4
  43. data/vendor/datasketches-cpp/hll/include/HarmonicNumbers-internal.hpp +2 -1
  44. data/vendor/datasketches-cpp/hll/include/Hll4Array-internal.hpp +4 -4
  45. data/vendor/datasketches-cpp/hll/include/Hll4Array.hpp +1 -1
  46. data/vendor/datasketches-cpp/hll/include/Hll6Array-internal.hpp +3 -3
  47. data/vendor/datasketches-cpp/hll/include/Hll6Array.hpp +1 -1
  48. data/vendor/datasketches-cpp/hll/include/Hll8Array-internal.hpp +6 -3
  49. data/vendor/datasketches-cpp/hll/include/Hll8Array.hpp +1 -1
  50. data/vendor/datasketches-cpp/hll/include/HllArray-internal.hpp +35 -29
  51. data/vendor/datasketches-cpp/hll/include/HllArray.hpp +1 -1
  52. data/vendor/datasketches-cpp/hll/include/HllSketch-internal.hpp +3 -5
  53. data/vendor/datasketches-cpp/hll/include/HllSketchImpl-internal.hpp +5 -11
  54. data/vendor/datasketches-cpp/hll/include/HllSketchImpl.hpp +2 -4
  55. data/vendor/datasketches-cpp/hll/include/HllSketchImplFactory.hpp +11 -10
  56. data/vendor/datasketches-cpp/hll/include/HllUnion-internal.hpp +17 -8
  57. data/vendor/datasketches-cpp/hll/include/HllUtil.hpp +12 -3
  58. data/vendor/datasketches-cpp/hll/include/coupon_iterator-internal.hpp +2 -2
  59. data/vendor/datasketches-cpp/hll/include/coupon_iterator.hpp +3 -0
  60. data/vendor/datasketches-cpp/hll/include/hll.hpp +11 -4
  61. data/vendor/datasketches-cpp/hll/include/hll.private.hpp +19 -0
  62. data/vendor/datasketches-cpp/hll/test/CMakeLists.txt +2 -0
  63. data/vendor/datasketches-cpp/hll/test/CouponListTest.cpp +64 -0
  64. data/vendor/datasketches-cpp/hll/test/HllFullSizeTest.cpp +137 -0
  65. data/vendor/datasketches-cpp/hll/test/HllKxqRebuildTest.cpp +150 -0
  66. data/vendor/datasketches-cpp/hll/test/HllSketchTest.cpp +3 -3
  67. data/vendor/datasketches-cpp/hll/test/HllUnionTest.cpp +71 -1
  68. data/vendor/datasketches-cpp/kll/include/kll_helper_impl.hpp +10 -10
  69. data/vendor/datasketches-cpp/kll/include/kll_sketch.hpp +10 -1
  70. data/vendor/datasketches-cpp/kll/include/kll_sketch_impl.hpp +33 -24
  71. data/vendor/datasketches-cpp/kll/test/kll_sketch_deserialize_from_java_test.cpp +24 -0
  72. data/vendor/datasketches-cpp/kll/test/kll_sketch_serialize_for_java.cpp +10 -0
  73. data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch.hpp +11 -2
  74. data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch_impl.hpp +24 -15
  75. data/vendor/datasketches-cpp/req/include/req_sketch.hpp +9 -0
  76. data/vendor/datasketches-cpp/req/include/req_sketch_impl.hpp +24 -15
  77. data/vendor/datasketches-cpp/req/test/req_sketch_deserialize_from_java_test.cpp +46 -0
  78. data/vendor/datasketches-cpp/req/test/req_sketch_serialize_for_java.cpp +20 -0
  79. data/vendor/datasketches-cpp/req/test/req_sketch_test.cpp +70 -0
  80. data/vendor/datasketches-cpp/sampling/include/ebpps_sample_impl.hpp +17 -8
  81. data/vendor/datasketches-cpp/sampling/include/ebpps_sketch.hpp +13 -0
  82. data/vendor/datasketches-cpp/sampling/include/var_opt_sketch.hpp +10 -1
  83. data/vendor/datasketches-cpp/sampling/include/var_opt_sketch_impl.hpp +6 -7
  84. data/vendor/datasketches-cpp/sampling/include/var_opt_union.hpp +5 -1
  85. data/vendor/datasketches-cpp/sampling/include/var_opt_union_impl.hpp +2 -1
  86. data/vendor/datasketches-cpp/sampling/test/ebpps_allocation_test.cpp +1 -1
  87. data/vendor/datasketches-cpp/sampling/test/ebpps_sketch_test.cpp +2 -2
  88. data/vendor/datasketches-cpp/sampling/test/var_opt_allocation_test.cpp +1 -1
  89. data/vendor/datasketches-cpp/sampling/test/var_opt_sketch_test.cpp +10 -4
  90. data/vendor/datasketches-cpp/sampling/test/var_opt_union_test.cpp +12 -0
  91. data/vendor/datasketches-cpp/tdigest/include/tdigest.hpp +38 -2
  92. data/vendor/datasketches-cpp/tdigest/include/tdigest_impl.hpp +168 -9
  93. data/vendor/datasketches-cpp/tdigest/test/CMakeLists.txt +1 -0
  94. data/vendor/datasketches-cpp/tdigest/test/tdigest_iterator_test.cpp +274 -0
  95. data/vendor/datasketches-cpp/tdigest/test/tdigest_test.cpp +275 -0
  96. data/vendor/datasketches-cpp/theta/include/compact_theta_sketch_parser.hpp +2 -0
  97. data/vendor/datasketches-cpp/theta/include/compact_theta_sketch_parser_impl.hpp +24 -3
  98. data/vendor/datasketches-cpp/theta/include/theta_constants.hpp +4 -2
  99. data/vendor/datasketches-cpp/theta/include/theta_helpers.hpp +32 -0
  100. data/vendor/datasketches-cpp/theta/include/theta_set_difference_base_impl.hpp +4 -2
  101. data/vendor/datasketches-cpp/theta/include/theta_sketch.hpp +22 -4
  102. data/vendor/datasketches-cpp/theta/include/theta_sketch_impl.hpp +60 -38
  103. data/vendor/datasketches-cpp/theta/include/theta_union_base_impl.hpp +2 -6
  104. data/vendor/datasketches-cpp/theta/include/theta_update_sketch_base_impl.hpp +2 -2
  105. data/vendor/datasketches-cpp/theta/test/bit_packing_test.cpp +50 -0
  106. data/vendor/datasketches-cpp/theta/test/theta_a_not_b_test.cpp +22 -0
  107. data/vendor/datasketches-cpp/theta/test/theta_sketch_test.cpp +315 -0
  108. data/vendor/datasketches-cpp/tools/rat-check.sh +68 -0
  109. data/vendor/datasketches-cpp/tuple/include/array_tuple_sketch.hpp +35 -4
  110. data/vendor/datasketches-cpp/tuple/include/array_tuple_sketch_impl.hpp +2 -2
  111. data/vendor/datasketches-cpp/tuple/include/tuple_sketch.hpp +41 -0
  112. data/vendor/datasketches-cpp/tuple/include/tuple_sketch_impl.hpp +5 -4
  113. data/vendor/datasketches-cpp/tuple/test/tuple_sketch_test.cpp +59 -0
  114. data/vendor/datasketches-cpp/version.cfg.in +1 -1
  115. metadata +12 -2
@@ -28,6 +28,7 @@
28
28
  #include <cmath>
29
29
  #include <string>
30
30
  #include <sstream>
31
+ #include <type_traits>
31
32
 
32
33
  namespace datasketches {
33
34
 
@@ -365,11 +366,15 @@ std::pair<ebpps_sample<T, A>, size_t> ebpps_sample<T, A>::deserialize(const uint
365
366
 
366
367
  optional<T> partial_item;
367
368
  if (has_partial) {
368
- optional<T> tmp; // space to deserialize
369
- ptr += sd.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
369
+ // Space to deserialize.
370
+ // serde::deserialize expects allocated but not initialized storage.
371
+ typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
372
+ T* tmp = reinterpret_cast<T*>(&tmp_storage);
373
+
374
+ ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
370
375
  // serde did not throw so place item and clean up
371
- partial_item.emplace(*tmp);
372
- (*tmp).~T();
376
+ partial_item.emplace(std::move(*tmp));
377
+ tmp->~T();
373
378
  }
374
379
 
375
380
  return std::pair<ebpps_sample<T,A>, size_t>(
@@ -400,11 +405,15 @@ ebpps_sample<T, A> ebpps_sample<T, A>::deserialize(std::istream& is, const SerDe
400
405
 
401
406
  optional<T> partial_item;
402
407
  if (has_partial) {
403
- optional<T> tmp; // space to deserialize
404
- sd.deserialize(is, &*tmp, 1);
408
+ // Space to deserialize.
409
+ // serde::deserialize expects allocated but not initialized storage.
410
+ typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
411
+ T* tmp = reinterpret_cast<T*>(&tmp_storage);
412
+
413
+ sd.deserialize(is, tmp, 1);
405
414
  // serde did not throw so place item and clean up
406
- partial_item.emplace(*tmp);
407
- (*tmp).~T();
415
+ partial_item.emplace(std::move(*tmp));
416
+ tmp->~T();
408
417
  }
409
418
 
410
419
  if (!is.good()) throw std::runtime_error("error reading from std::istream");
@@ -50,6 +50,11 @@ namespace ebpps_constants {
50
50
  * The sample may be smaller than k and the resulting size of the sample potentially includes
51
51
  * a probabilistic component, meaning the resulting sample size is not always constant.
52
52
  *
53
+ * Sketch that may retain string values.
54
+ * For sketches containing strings, cross-language portability depends on
55
+ * using compatible string encodings. This class does not by itself enforce
56
+ * UTF-8 validity for all string inputs.
57
+ *
53
58
  * @author Jon Malkin
54
59
  */
55
60
  template<
@@ -71,6 +76,8 @@ class ebpps_sketch {
71
76
  /**
72
77
  * Updates this sketch with the given data item with the given weight.
73
78
  * This method takes an lvalue.
79
+ * If cross-language portability is required, callers should ensure that
80
+ * the input string uses a compatible encoding (valid UTF-8).
74
81
  * @param item an item from a stream of items
75
82
  * @param weight the weight of the item
76
83
  */
@@ -79,6 +86,8 @@ class ebpps_sketch {
79
86
  /**
80
87
  * Updates this sketch with the given data item with the given weight.
81
88
  * This method takes an rvalue.
89
+ * If cross-language portability is required, callers should ensure that
90
+ * the input string uses a compatible encoding (valid UTF-8).
82
91
  * @param item an item from a stream of items
83
92
  * @param weight the weight of the item
84
93
  */
@@ -87,6 +96,8 @@ class ebpps_sketch {
87
96
  /**
88
97
  * Merges the provided sketch into the current one.
89
98
  * This method takes an lvalue.
99
+ * If sketches contain strings, callers are responsible for ensuring that
100
+ * both sketches were built using compatible string encodings.
90
101
  * @param sketch the sketch to merge into the current object
91
102
  */
92
103
  void merge(const ebpps_sketch<T, A>& sketch);
@@ -94,6 +105,8 @@ class ebpps_sketch {
94
105
  /**
95
106
  * Merges the provided sketch into the current one.
96
107
  * This method takes an rvalue.
108
+ * If sketches contain strings, callers are responsible for ensuring that
109
+ * both sketches were built using compatible string encodings.
97
110
  * @param sketch the sketch to merge into the current object
98
111
  */
99
112
  void merge(ebpps_sketch<T, A>&& sketch);
@@ -57,6 +57,11 @@ namespace var_opt_constants {
57
57
  * optimal (varopt) sampling is related to reservoir sampling, with improved error bounds for
58
58
  * subset sum estimation.
59
59
  *
60
+ * Sketch that may retain string values.
61
+ * For sketches containing strings, cross-language portability depends on
62
+ * using compatible string encodings. This class does not by itself enforce
63
+ * UTF-8 validity for all string inputs.
64
+ *
60
65
  * author Kevin Lang
61
66
  * author Jon Malkin
62
67
  */
@@ -111,6 +116,8 @@ class var_opt_sketch {
111
116
  /**
112
117
  * Updates this sketch with the given data item with the given weight.
113
118
  * This method takes an lvalue.
119
+ * If cross-language portability is required, callers should ensure that
120
+ * the input string uses a compatible encoding (valid UTF-8).
114
121
  * @param item an item from a stream of items
115
122
  * @param weight the weight of the item
116
123
  */
@@ -119,6 +126,8 @@ class var_opt_sketch {
119
126
  /**
120
127
  * Updates this sketch with the given data item with the given weight.
121
128
  * This method takes an rvalue.
129
+ * If cross-language portability is required, callers should ensure that
130
+ * the input string uses a compatible encoding (valid UTF-8).
122
131
  * @param item an item from a stream of items
123
132
  * @param weight the weight of the item
124
133
  */
@@ -263,7 +272,7 @@ class var_opt_sketch {
263
272
  typedef typename std::allocator_traits<A>::template rebind_alloc<double> AllocDouble;
264
273
  typedef typename std::allocator_traits<A>::template rebind_alloc<bool> AllocBool;
265
274
 
266
- static const uint32_t MIN_LG_ARR_ITEMS = 3;
275
+ static const uint32_t MIN_LG_ARR_ITEMS = 4;
267
276
 
268
277
  static const uint8_t PREAMBLE_LONGS_EMPTY = 1;
269
278
  static const uint8_t PREAMBLE_LONGS_WARMUP = 3;
@@ -772,12 +772,11 @@ string<A> var_opt_sketch<T, A>::items_to_string(bool print_gap) const {
772
772
  template<typename T, typename A>
773
773
  template<typename O>
774
774
  void var_opt_sketch<T, A>::update(O&& item, double weight, bool mark) {
775
- if (weight < 0.0 || std::isnan(weight) || std::isinf(weight)) {
776
- throw std::invalid_argument("Item weights must be nonnegative and finite. Found: "
775
+ if (weight <= 0.0 || std::isnan(weight) || std::isinf(weight)) {
776
+ throw std::invalid_argument("Item weights must be positive and finite. Found: "
777
777
  + std::to_string(weight));
778
- } else if (weight == 0.0) {
779
- return;
780
778
  }
779
+
781
780
  ++n_;
782
781
 
783
782
  if (r_ == 0) {
@@ -1029,7 +1028,7 @@ void var_opt_sketch<T, A>::transition_from_warmup() {
1029
1028
  total_wt_r_ = weights_[k_]; // only one item, known location
1030
1029
  weights_[k_] = -1.0;
1031
1030
 
1032
- // The two lightest items are ncessarily downsample-able to one item,
1031
+ // The two lightest items are necessarily downsample-able to one item,
1033
1032
  // and are therefore a valid initial candidate set
1034
1033
  grow_candidate_set(weights_[k_ - 1] + total_wt_r_, 2);
1035
1034
  }
@@ -1065,7 +1064,7 @@ void var_opt_sketch<T, A>::restore_towards_leaves(uint32_t slot_in) {
1065
1064
  while (child <= last_slot) {
1066
1065
  uint32_t child2 = child + 1; // might also be invalid
1067
1066
  if ((child2 <= last_slot) && (weights_[child2] < weights_[child])) {
1068
- // siwtch to other child if it's both valid and smaller
1067
+ // switch to other child if it's both valid and smaller
1069
1068
  child = child2;
1070
1069
  }
1071
1070
 
@@ -1221,7 +1220,7 @@ uint32_t var_opt_sketch<T, A>::choose_delete_slot(double wt_cands, uint32_t num_
1221
1220
  if ((wt_cands * next_double_exclude_zero()) < ((num_cands - 1) * wt_m_cand)) {
1222
1221
  return pick_random_slot_in_r(); // keep item in M
1223
1222
  } else {
1224
- return h_; // indext of item in M
1223
+ return h_; // index of item in M
1225
1224
  }
1226
1225
  } else {
1227
1226
  // general case
@@ -65,13 +65,17 @@ public:
65
65
  /**
66
66
  * Updates this union with the given sketch
67
67
  * This method takes an lvalue.
68
+ * If sketches contain strings, callers are responsible for ensuring that
69
+ * both sketches were built using compatible string encodings.
68
70
  * @param sk a sketch to add to the union
69
71
  */
70
72
  void update(const var_opt_sketch<T, A>& sk);
71
-
73
+
72
74
  /**
73
75
  * Updates this union with the given sketch
74
76
  * This method takes an rvalue.
77
+ * If sketches contain strings, callers are responsible for ensuring that
78
+ * both sketches were built using compatible string encodings.
75
79
  * @param sk a sketch to add to the union
76
80
  */
77
81
  void update(var_opt_sketch<T, A>&& sk);
@@ -200,6 +200,7 @@ var_opt_union<T, A> var_opt_union<T, A>::deserialize(const void* bytes, size_t s
200
200
  return var_opt_union(max_k);
201
201
  }
202
202
 
203
+ ensure_minimum_memory(size, PREAMBLE_LONGS_NON_EMPTY << 3);
203
204
  uint64_t items_seen;
204
205
  ptr += copy_from_mem(ptr, items_seen);
205
206
  double outer_tau_numer;
@@ -590,7 +591,7 @@ void var_opt_union<T, A>::migrate_marked_items_by_decreasing_k(var_opt_sketch<T,
590
591
 
591
592
  // if non-full and pseudo-exact, change k so that gcopy is full
592
593
  if ((r_count == 0) && (h_count < k)) {
593
- gcopy.k_ = h_count; // may leve extra space allocated but that's ok
594
+ gcopy.k_ = h_count; // may leave extra space allocated but that's ok
594
595
  }
595
596
 
596
597
  // Now k equals the number of samples, so reducing k will increase tau.
@@ -63,7 +63,7 @@ TEST_CASE( "ebpps merge", "[ebpps_sketch][test_type]") {
63
63
  ebpps_test_sketch sk1(k, 0);
64
64
  ebpps_test_sketch sk2(k, 0);
65
65
 
66
- // move udpates
66
+ // move updates
67
67
  for (int i = 0; i < (int) n; ++i) {
68
68
  sk1.update(i);
69
69
  sk2.update(-i);
@@ -222,7 +222,7 @@ TEST_CASE("ebpps sketch: merge large into small", "[ebpps_sketch]") {
222
222
  sk1 = create_unweighted_sketch(k / 2, 0);
223
223
  sk1.update(-1, k / 4.0);
224
224
  sk1.update(-2, k / 8.0);
225
- // sk2 should have been unchaged
225
+ // sk2 should have been unchanged
226
226
  REQUIRE(sk2.get_n() == k);
227
227
  REQUIRE(sk2.get_c() == Approx(k).margin(EPS));
228
228
 
@@ -250,7 +250,7 @@ TEST_CASE("ebpps sketch: merge small into large", "[ebpps_sketch]") {
250
250
 
251
251
  // rvalue merge
252
252
  sk1 = create_unweighted_sketch(k, 3 * k / 2);
253
- // sk2 should have been unchaged
253
+ // sk2 should have been unchanged
254
254
  REQUIRE(sk2.get_n() == 1);
255
255
  REQUIRE(sk2.get_c() == 1.0);
256
256
  sk2.update(-2, k / 10.0);
@@ -67,7 +67,7 @@ TEST_CASE( "varopt union: move", "[var_opt_union][test_type]") {
67
67
  var_opt_test_sketch sk1(k, var_opt_test_sketch::DEFAULT_RESIZE_FACTOR, 0);
68
68
  var_opt_test_sketch sk2(k, var_opt_test_sketch::DEFAULT_RESIZE_FACTOR, 0);
69
69
 
70
- // move udpates
70
+ // move updates
71
71
  for (int i = 0; i < (int) n; ++i) {
72
72
  sk1.update(i);
73
73
  sk2.update(-i);
@@ -178,11 +178,17 @@ TEST_CASE("varopt sketch: non-empty degenerate sketch", "[var_opt_sketch]") {
178
178
 
179
179
  TEST_CASE("varopt sketch: invalid weight", "[var_opt_sketch]") {
180
180
  var_opt_sketch<std::string> sk(100, resize_factor::X2);
181
- REQUIRE_THROWS_AS(sk.update("invalid_weight", -1.0), std::invalid_argument);
182
181
 
183
- // should not throw but sketch should still be empty
184
- sk.update("zero weight", 0.0);
185
- REQUIRE(sk.is_empty());
182
+ // Negative
183
+ REQUIRE_THROWS_AS(sk.update("invalid_weight", -1.0), std::invalid_argument);
184
+ // Zero
185
+ REQUIRE_THROWS_AS(sk.update("zero_weight", 0.0), std::invalid_argument);
186
+ // NaN
187
+ REQUIRE_THROWS_AS(sk.update("NaN_weight", std::numeric_limits<double>::quiet_NaN()), std::invalid_argument);
188
+ // +Inf
189
+ REQUIRE_THROWS_AS(sk.update("positive_infinity", std::numeric_limits<double>::infinity()), std::invalid_argument);
190
+ // -Inf
191
+ REQUIRE_THROWS_AS(sk.update("negative_infinity", -std::numeric_limits<double>::infinity()), std::invalid_argument);
186
192
  }
187
193
 
188
194
  TEST_CASE("varopt sketch: corrupt serialized weight", "[var_opt_sketch]") {
@@ -305,4 +305,16 @@ TEST_CASE("varopt union: serialize sampling", "[var_opt_union]") {
305
305
  compare_serialization_deserialization(u);
306
306
  }
307
307
 
308
+ TEST_CASE("varopt union: deserialize truncated non-empty preamble", "[var_opt_union]") {
309
+ var_opt_sketch<int> sk(32);
310
+ sk.update(1);
311
+ var_opt_union<int> u(32);
312
+ u.update(sk);
313
+ auto bytes = u.serialize();
314
+ // a non-empty union needs 4 preamble longs
315
+ for (size_t size = 8; size < 32; ++size) {
316
+ REQUIRE_THROWS_AS(var_opt_union<int>::deserialize(bytes.data(), size), std::out_of_range);
317
+ }
318
+ }
319
+
308
320
  }
@@ -108,6 +108,7 @@ public:
108
108
 
109
109
  /**
110
110
  * Update this t-Digest with the given value
111
+ * NaN and infinity values are ignored
111
112
  * @param value to update the t-Digest with
112
113
  */
113
114
  void update(T value);
@@ -153,6 +154,7 @@ public:
153
154
  * Compute approximate normalized rank of the given value.
154
155
  *
155
156
  * <p>If the sketch is empty this throws std::runtime_error.
157
+ * <p>NaN value throw std::invalid_argument.
156
158
  *
157
159
  * @param value to be ranked
158
160
  * @return normalized rank (from 0 to 1 inclusive)
@@ -257,16 +259,29 @@ public:
257
259
  */
258
260
  static tdigest deserialize(const void* bytes, size_t size, const Allocator& allocator = Allocator());
259
261
 
262
+ class const_iterator;
263
+
264
+ /**
265
+ * Iterator pointing to the first centroid in the sketch.
266
+ * If the sketch is empty, the returned iterator must not be dereferenced or incremented.
267
+ * @return iterator pointing to the first centroid in the sketch
268
+ */
269
+ const_iterator begin() const;
270
+
271
+ /**
272
+ * Iterator pointing to the past-the-end centroid in the sketch.
273
+ * It does not point to any centroid, and must not be dereferenced or incremented.
274
+ * @return iterator pointing to the past-the-end centroid in the sketch
275
+ */
276
+ const_iterator end() const;
260
277
  private:
261
278
  bool reverse_merge_;
262
279
  uint16_t k_;
263
- uint16_t internal_k_;
264
280
  T min_;
265
281
  T max_;
266
282
  size_t centroids_capacity_;
267
283
  vector_centroid centroids_;
268
284
  uint64_t centroids_weight_;
269
- size_t buffer_capacity_;
270
285
  vector_t buffer_;
271
286
 
272
287
  static const size_t BUFFER_MULTIPLIER = 4;
@@ -297,6 +312,27 @@ private:
297
312
  static inline void check_split_points(const T* values, uint32_t size);
298
313
  };
299
314
 
315
+ template<typename T, typename A>
316
+ class tdigest<T, A>::const_iterator {
317
+ public:
318
+ using iterator_category = std::input_iterator_tag;
319
+ using value_type = std::pair<T, W>;
320
+ using difference_type = void;
321
+ using pointer = const return_value_holder<value_type>;
322
+ using reference = const value_type;
323
+
324
+ const_iterator& operator++();
325
+ const_iterator& operator++(int);
326
+ bool operator==(const const_iterator& other) const;
327
+ bool operator!=(const const_iterator& other) const;
328
+ reference operator*() const;
329
+ pointer operator->() const;
330
+ private:
331
+ friend class tdigest;
332
+ uint32_t index_;
333
+ vector_centroid centroids_;
334
+ const_iterator(const tdigest& tdigest_, bool is_end);
335
+ };
300
336
  } /* namespace datasketches */
301
337
 
302
338
  #include "tdigest_impl.hpp"