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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/ext/datasketches/theta_wrapper.cpp +1 -1
- data/lib/datasketches/version.rb +1 -1
- data/vendor/datasketches-cpp/CMakeLists.txt +5 -3
- data/vendor/datasketches-cpp/CODE_OF_CONDUCT.md +1 -1
- data/vendor/datasketches-cpp/LICENSE +14 -0
- data/vendor/datasketches-cpp/README.md +67 -73
- data/vendor/datasketches-cpp/benchmarks/CMakeLists.txt +52 -0
- data/vendor/datasketches-cpp/benchmarks/benchmark_count_min_sketch.cpp +153 -0
- data/vendor/datasketches-cpp/benchmarks/benchmark_count_min_sketch_serialization.cpp +161 -0
- data/vendor/datasketches-cpp/common/CMakeLists.txt +1 -0
- data/vendor/datasketches-cpp/common/include/binomial_bounds.hpp +2 -2
- data/vendor/datasketches-cpp/common/include/fdlibm_log.hpp +101 -0
- data/vendor/datasketches-cpp/common/include/serde.hpp +6 -0
- data/vendor/datasketches-cpp/common/test/CMakeLists.txt +44 -2
- data/vendor/datasketches-cpp/common/test/binomial_bounds_test.cpp +279 -0
- data/vendor/datasketches-cpp/common/test/deserialize_hardening_test.cpp +188 -0
- data/vendor/datasketches-cpp/count/include/count_min.hpp +17 -4
- data/vendor/datasketches-cpp/count/include/count_min_impl.hpp +65 -83
- data/vendor/datasketches-cpp/count/test/count_min_test.cpp +63 -7
- data/vendor/datasketches-cpp/cpc/include/compression_data.hpp +2 -0
- data/vendor/datasketches-cpp/cpc/include/cpc_compressor_impl.hpp +16 -7
- data/vendor/datasketches-cpp/cpc/include/cpc_sketch.hpp +1 -0
- data/vendor/datasketches-cpp/cpc/include/cpc_sketch_impl.hpp +54 -36
- data/vendor/datasketches-cpp/cpc/include/cpc_union_impl.hpp +27 -27
- data/vendor/datasketches-cpp/cpc/include/cpc_util.hpp +7 -7
- data/vendor/datasketches-cpp/cpc/include/icon_estimator.hpp +5 -5
- data/vendor/datasketches-cpp/cpc/include/u32_table_impl.hpp +16 -16
- data/vendor/datasketches-cpp/cpc/test/cpc_sketch_test.cpp +35 -0
- data/vendor/datasketches-cpp/fi/include/frequent_items_sketch.hpp +28 -3
- data/vendor/datasketches-cpp/fi/include/frequent_items_sketch_impl.hpp +41 -25
- data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map.hpp +3 -1
- data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map_impl.hpp +10 -5
- data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_serialize_for_java.cpp +24 -0
- data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_test.cpp +116 -0
- data/vendor/datasketches-cpp/filters/include/bloom_filter.hpp +1 -1
- data/vendor/datasketches-cpp/filters/include/bloom_filter_impl.hpp +32 -12
- data/vendor/datasketches-cpp/filters/test/bloom_filter_test.cpp +28 -1
- data/vendor/datasketches-cpp/hll/include/CouponHashSet-internal.hpp +1 -2
- data/vendor/datasketches-cpp/hll/include/CouponList-internal.hpp +19 -5
- data/vendor/datasketches-cpp/hll/include/CubicInterpolation-internal.hpp +4 -4
- data/vendor/datasketches-cpp/hll/include/HarmonicNumbers-internal.hpp +2 -1
- data/vendor/datasketches-cpp/hll/include/Hll4Array-internal.hpp +4 -4
- data/vendor/datasketches-cpp/hll/include/Hll4Array.hpp +1 -1
- data/vendor/datasketches-cpp/hll/include/Hll6Array-internal.hpp +3 -3
- data/vendor/datasketches-cpp/hll/include/Hll6Array.hpp +1 -1
- data/vendor/datasketches-cpp/hll/include/Hll8Array-internal.hpp +6 -3
- data/vendor/datasketches-cpp/hll/include/Hll8Array.hpp +1 -1
- data/vendor/datasketches-cpp/hll/include/HllArray-internal.hpp +35 -29
- data/vendor/datasketches-cpp/hll/include/HllArray.hpp +1 -1
- data/vendor/datasketches-cpp/hll/include/HllSketch-internal.hpp +3 -5
- data/vendor/datasketches-cpp/hll/include/HllSketchImpl-internal.hpp +5 -11
- data/vendor/datasketches-cpp/hll/include/HllSketchImpl.hpp +2 -4
- data/vendor/datasketches-cpp/hll/include/HllSketchImplFactory.hpp +11 -10
- data/vendor/datasketches-cpp/hll/include/HllUnion-internal.hpp +17 -8
- data/vendor/datasketches-cpp/hll/include/HllUtil.hpp +12 -3
- data/vendor/datasketches-cpp/hll/include/coupon_iterator-internal.hpp +2 -2
- data/vendor/datasketches-cpp/hll/include/coupon_iterator.hpp +3 -0
- data/vendor/datasketches-cpp/hll/include/hll.hpp +11 -4
- data/vendor/datasketches-cpp/hll/include/hll.private.hpp +19 -0
- data/vendor/datasketches-cpp/hll/test/CMakeLists.txt +2 -0
- data/vendor/datasketches-cpp/hll/test/CouponListTest.cpp +64 -0
- data/vendor/datasketches-cpp/hll/test/HllFullSizeTest.cpp +137 -0
- data/vendor/datasketches-cpp/hll/test/HllKxqRebuildTest.cpp +150 -0
- data/vendor/datasketches-cpp/hll/test/HllSketchTest.cpp +3 -3
- data/vendor/datasketches-cpp/hll/test/HllUnionTest.cpp +71 -1
- data/vendor/datasketches-cpp/kll/include/kll_helper_impl.hpp +10 -10
- data/vendor/datasketches-cpp/kll/include/kll_sketch.hpp +10 -1
- data/vendor/datasketches-cpp/kll/include/kll_sketch_impl.hpp +33 -24
- data/vendor/datasketches-cpp/kll/test/kll_sketch_deserialize_from_java_test.cpp +24 -0
- data/vendor/datasketches-cpp/kll/test/kll_sketch_serialize_for_java.cpp +10 -0
- data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch.hpp +11 -2
- data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch_impl.hpp +24 -15
- data/vendor/datasketches-cpp/req/include/req_sketch.hpp +9 -0
- data/vendor/datasketches-cpp/req/include/req_sketch_impl.hpp +24 -15
- data/vendor/datasketches-cpp/req/test/req_sketch_deserialize_from_java_test.cpp +46 -0
- data/vendor/datasketches-cpp/req/test/req_sketch_serialize_for_java.cpp +20 -0
- data/vendor/datasketches-cpp/req/test/req_sketch_test.cpp +70 -0
- data/vendor/datasketches-cpp/sampling/include/ebpps_sample_impl.hpp +17 -8
- data/vendor/datasketches-cpp/sampling/include/ebpps_sketch.hpp +13 -0
- data/vendor/datasketches-cpp/sampling/include/var_opt_sketch.hpp +10 -1
- data/vendor/datasketches-cpp/sampling/include/var_opt_sketch_impl.hpp +6 -7
- data/vendor/datasketches-cpp/sampling/include/var_opt_union.hpp +5 -1
- data/vendor/datasketches-cpp/sampling/include/var_opt_union_impl.hpp +2 -1
- data/vendor/datasketches-cpp/sampling/test/ebpps_allocation_test.cpp +1 -1
- data/vendor/datasketches-cpp/sampling/test/ebpps_sketch_test.cpp +2 -2
- data/vendor/datasketches-cpp/sampling/test/var_opt_allocation_test.cpp +1 -1
- data/vendor/datasketches-cpp/sampling/test/var_opt_sketch_test.cpp +10 -4
- data/vendor/datasketches-cpp/sampling/test/var_opt_union_test.cpp +12 -0
- data/vendor/datasketches-cpp/tdigest/include/tdigest.hpp +38 -2
- data/vendor/datasketches-cpp/tdigest/include/tdigest_impl.hpp +168 -9
- data/vendor/datasketches-cpp/tdigest/test/CMakeLists.txt +1 -0
- data/vendor/datasketches-cpp/tdigest/test/tdigest_iterator_test.cpp +274 -0
- data/vendor/datasketches-cpp/tdigest/test/tdigest_test.cpp +275 -0
- data/vendor/datasketches-cpp/theta/include/compact_theta_sketch_parser.hpp +2 -0
- data/vendor/datasketches-cpp/theta/include/compact_theta_sketch_parser_impl.hpp +24 -3
- data/vendor/datasketches-cpp/theta/include/theta_constants.hpp +4 -2
- data/vendor/datasketches-cpp/theta/include/theta_helpers.hpp +32 -0
- data/vendor/datasketches-cpp/theta/include/theta_set_difference_base_impl.hpp +4 -2
- data/vendor/datasketches-cpp/theta/include/theta_sketch.hpp +22 -4
- data/vendor/datasketches-cpp/theta/include/theta_sketch_impl.hpp +60 -38
- data/vendor/datasketches-cpp/theta/include/theta_union_base_impl.hpp +2 -6
- data/vendor/datasketches-cpp/theta/include/theta_update_sketch_base_impl.hpp +2 -2
- data/vendor/datasketches-cpp/theta/test/bit_packing_test.cpp +50 -0
- data/vendor/datasketches-cpp/theta/test/theta_a_not_b_test.cpp +22 -0
- data/vendor/datasketches-cpp/theta/test/theta_sketch_test.cpp +315 -0
- data/vendor/datasketches-cpp/tools/rat-check.sh +68 -0
- data/vendor/datasketches-cpp/tuple/include/array_tuple_sketch.hpp +35 -4
- data/vendor/datasketches-cpp/tuple/include/array_tuple_sketch_impl.hpp +2 -2
- data/vendor/datasketches-cpp/tuple/include/tuple_sketch.hpp +41 -0
- data/vendor/datasketches-cpp/tuple/include/tuple_sketch_impl.hpp +5 -4
- data/vendor/datasketches-cpp/tuple/test/tuple_sketch_test.cpp +59 -0
- data/vendor/datasketches-cpp/version.cfg.in +1 -1
- metadata +12 -2
|
@@ -46,6 +46,11 @@ namespace kll_constants {
|
|
|
46
46
|
* and nearly optimal accuracy per retained item.
|
|
47
47
|
* See <a href="https://arxiv.org/abs/1603.05346v2">Optimal Quantile Approximation in Streams</a>.
|
|
48
48
|
*
|
|
49
|
+
* Sketch that may retain string values.
|
|
50
|
+
* For sketches containing strings, cross-language portability depends on
|
|
51
|
+
* using compatible string encodings. This class does not by itself enforce
|
|
52
|
+
* UTF-8 validity for all string inputs.
|
|
53
|
+
*
|
|
49
54
|
* <p>This is a stochastic streaming sketch that enables near real-time analysis of the
|
|
50
55
|
* approximate distribution of items from a very large stream in a single pass, requiring only
|
|
51
56
|
* that the items are comparable.
|
|
@@ -56,7 +61,7 @@ namespace kll_constants {
|
|
|
56
61
|
* <p>As of May 2020, this implementation produces serialized sketches which are binary-compatible
|
|
57
62
|
* with the equivalent Java implementation only when template parameter T = float
|
|
58
63
|
* (32-bit single precision values).
|
|
59
|
-
*
|
|
64
|
+
*
|
|
60
65
|
* <p>Given an input stream of <i>N</i> items, the <i>natural rank</i> of any specific
|
|
61
66
|
* item is defined as its index <i>(1 to N)</i> in inclusive mode
|
|
62
67
|
* or <i>(0 to N-1)</i> in exclusive mode
|
|
@@ -225,6 +230,8 @@ class kll_sketch {
|
|
|
225
230
|
|
|
226
231
|
/**
|
|
227
232
|
* Updates this sketch with the given data item.
|
|
233
|
+
* If cross-language portability is required, callers should ensure that
|
|
234
|
+
* the input string uses a compatible encoding (valid UTF-8).
|
|
228
235
|
* @param item from a stream of items
|
|
229
236
|
*/
|
|
230
237
|
template<typename FwdT>
|
|
@@ -232,6 +239,8 @@ class kll_sketch {
|
|
|
232
239
|
|
|
233
240
|
/**
|
|
234
241
|
* Merges another sketch into this one.
|
|
242
|
+
* If sketches contain strings, callers are responsible for ensuring that
|
|
243
|
+
* both sketches were built using compatible string encodings.
|
|
235
244
|
* @param other sketch to merge into this one
|
|
236
245
|
*/
|
|
237
246
|
template<typename FwdSk>
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
#include <iomanip>
|
|
25
25
|
#include <sstream>
|
|
26
26
|
#include <stdexcept>
|
|
27
|
+
#include <type_traits>
|
|
27
28
|
|
|
28
29
|
#include "conditional_forward.hpp"
|
|
29
30
|
#include "count_zeros.hpp"
|
|
@@ -198,7 +199,7 @@ void kll_sketch<T, C, A>::update_min_max(const T& item) {
|
|
|
198
199
|
|
|
199
200
|
template<typename T, typename C, typename A>
|
|
200
201
|
uint32_t kll_sketch<T, C, A>::internal_update() {
|
|
201
|
-
if (levels_[0] == 0) compress_while_updating();
|
|
202
|
+
if (levels_[0] == 0) { compress_while_updating(); }
|
|
202
203
|
n_++;
|
|
203
204
|
is_level_zero_sorted_ = false;
|
|
204
205
|
return --levels_[0];
|
|
@@ -207,7 +208,7 @@ uint32_t kll_sketch<T, C, A>::internal_update() {
|
|
|
207
208
|
template<typename T, typename C, typename A>
|
|
208
209
|
template<typename FwdSk>
|
|
209
210
|
void kll_sketch<T, C, A>::merge(FwdSk&& other) {
|
|
210
|
-
if (other.is_empty()) return;
|
|
211
|
+
if (other.is_empty()) { return; }
|
|
211
212
|
if (m_ != other.m_) {
|
|
212
213
|
throw std::invalid_argument("incompatible M: " + std::to_string(m_) + " and " + std::to_string(other.m_));
|
|
213
214
|
}
|
|
@@ -223,9 +224,9 @@ void kll_sketch<T, C, A>::merge(FwdSk&& other) {
|
|
|
223
224
|
const uint32_t index = internal_update();
|
|
224
225
|
new (&items_[index]) T(conditional_forward<FwdSk>(other.items_[i]));
|
|
225
226
|
}
|
|
226
|
-
if (other.num_levels_ >= 2) merge_higher_levels(other, final_n);
|
|
227
|
+
if (other.num_levels_ >= 2) { merge_higher_levels(other, final_n); }
|
|
227
228
|
n_ = final_n;
|
|
228
|
-
if (other.is_estimation_mode()) min_k_ = std::min(min_k_, other.min_k_);
|
|
229
|
+
if (other.is_estimation_mode()) { min_k_ = std::min(min_k_, other.min_k_); }
|
|
229
230
|
assert_correct_total_weight();
|
|
230
231
|
reset_sorted_view();
|
|
231
232
|
}
|
|
@@ -257,13 +258,13 @@ bool kll_sketch<T, C, A>::is_estimation_mode() const {
|
|
|
257
258
|
|
|
258
259
|
template<typename T, typename C, typename A>
|
|
259
260
|
T kll_sketch<T, C, A>::get_min_item() const {
|
|
260
|
-
if (is_empty()) throw std::runtime_error("operation is undefined for an empty sketch");
|
|
261
|
+
if (is_empty()) { throw std::runtime_error("operation is undefined for an empty sketch"); }
|
|
261
262
|
return *min_item_;
|
|
262
263
|
}
|
|
263
264
|
|
|
264
265
|
template<typename T, typename C, typename A>
|
|
265
266
|
T kll_sketch<T, C, A>::get_max_item() const {
|
|
266
|
-
if (is_empty()) throw std::runtime_error("operation is undefined for an empty sketch");
|
|
267
|
+
if (is_empty()) { throw std::runtime_error("operation is undefined for an empty sketch"); }
|
|
267
268
|
return *max_item_;
|
|
268
269
|
}
|
|
269
270
|
|
|
@@ -279,28 +280,28 @@ A kll_sketch<T, C, A>::get_allocator() const {
|
|
|
279
280
|
|
|
280
281
|
template<typename T, typename C, typename A>
|
|
281
282
|
double kll_sketch<T, C, A>::get_rank(const T& item, bool inclusive) const {
|
|
282
|
-
if (is_empty()) throw std::runtime_error("operation is undefined for an empty sketch");
|
|
283
|
+
if (is_empty()) { throw std::runtime_error("operation is undefined for an empty sketch"); }
|
|
283
284
|
setup_sorted_view();
|
|
284
285
|
return sorted_view_->get_rank(item, inclusive);
|
|
285
286
|
}
|
|
286
287
|
|
|
287
288
|
template<typename T, typename C, typename A>
|
|
288
289
|
auto kll_sketch<T, C, A>::get_PMF(const T* split_points, uint32_t size, bool inclusive) const -> vector_double {
|
|
289
|
-
if (is_empty()) throw std::runtime_error("operation is undefined for an empty sketch");
|
|
290
|
+
if (is_empty()) { throw std::runtime_error("operation is undefined for an empty sketch"); }
|
|
290
291
|
setup_sorted_view();
|
|
291
292
|
return sorted_view_->get_PMF(split_points, size, inclusive);
|
|
292
293
|
}
|
|
293
294
|
|
|
294
295
|
template<typename T, typename C, typename A>
|
|
295
296
|
auto kll_sketch<T, C, A>::get_CDF(const T* split_points, uint32_t size, bool inclusive) const -> vector_double {
|
|
296
|
-
if (is_empty()) throw std::runtime_error("operation is undefined for an empty sketch");
|
|
297
|
+
if (is_empty()) { throw std::runtime_error("operation is undefined for an empty sketch"); }
|
|
297
298
|
setup_sorted_view();
|
|
298
299
|
return sorted_view_->get_CDF(split_points, size, inclusive);
|
|
299
300
|
}
|
|
300
301
|
|
|
301
302
|
template<typename T, typename C, typename A>
|
|
302
303
|
auto kll_sketch<T, C, A>::get_quantile(double rank, bool inclusive) const -> quantile_return_type {
|
|
303
|
-
if (is_empty()) throw std::runtime_error("operation is undefined for an empty sketch");
|
|
304
|
+
if (is_empty()) { throw std::runtime_error("operation is undefined for an empty sketch"); }
|
|
304
305
|
if ((rank < 0.0) || (rank > 1.0)) {
|
|
305
306
|
throw std::invalid_argument("normalized rank cannot be less than zero or greater than 1.0");
|
|
306
307
|
}
|
|
@@ -481,18 +482,22 @@ kll_sketch<T, C, A> kll_sketch<T, C, A>::deserialize(std::istream& is, const Ser
|
|
|
481
482
|
read(is, levels.data(), sizeof(levels[0]) * num_levels);
|
|
482
483
|
}
|
|
483
484
|
levels[num_levels] = capacity;
|
|
484
|
-
optional<T> tmp; // space to deserialize min and max
|
|
485
485
|
optional<T> min_item;
|
|
486
486
|
optional<T> max_item;
|
|
487
487
|
if (!is_single_item) {
|
|
488
|
-
|
|
488
|
+
// Space to deserialize min and max.
|
|
489
|
+
// serde::deserialize expects allocated but not initialized storage.
|
|
490
|
+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
|
|
491
|
+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
|
|
492
|
+
|
|
493
|
+
sd.deserialize(is, tmp, 1);
|
|
489
494
|
// serde call did not throw, repackage and cleanup
|
|
490
|
-
min_item.emplace(*tmp);
|
|
491
|
-
|
|
492
|
-
sd.deserialize(is,
|
|
495
|
+
min_item.emplace(std::move(*tmp));
|
|
496
|
+
tmp->~T();
|
|
497
|
+
sd.deserialize(is, tmp, 1);
|
|
493
498
|
// serde call did not throw, repackage and cleanup
|
|
494
|
-
max_item.emplace(*tmp);
|
|
495
|
-
|
|
499
|
+
max_item.emplace(std::move(*tmp));
|
|
500
|
+
tmp->~T();
|
|
496
501
|
}
|
|
497
502
|
A alloc(allocator);
|
|
498
503
|
auto items_buffer_deleter = [capacity, &alloc](T* ptr) { alloc.deallocate(ptr, capacity); };
|
|
@@ -565,18 +570,22 @@ kll_sketch<T, C, A> kll_sketch<T, C, A>::deserialize(const void* bytes, size_t s
|
|
|
565
570
|
ptr += copy_from_mem(ptr, levels.data(), sizeof(levels[0]) * num_levels);
|
|
566
571
|
}
|
|
567
572
|
levels[num_levels] = capacity;
|
|
568
|
-
optional<T> tmp; // space to deserialize min and max
|
|
569
573
|
optional<T> min_item;
|
|
570
574
|
optional<T> max_item;
|
|
571
575
|
if (!is_single_item) {
|
|
572
|
-
|
|
576
|
+
// Space to deserialize min and max.
|
|
577
|
+
// serde::deserialize expects allocated but not initialized storage.
|
|
578
|
+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
|
|
579
|
+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
|
|
580
|
+
|
|
581
|
+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
|
|
573
582
|
// serde call did not throw, repackage and cleanup
|
|
574
|
-
min_item.emplace(*tmp);
|
|
575
|
-
|
|
576
|
-
ptr += sd.deserialize(ptr, end_ptr - ptr,
|
|
583
|
+
min_item.emplace(std::move(*tmp));
|
|
584
|
+
tmp->~T();
|
|
585
|
+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
|
|
577
586
|
// serde call did not throw, repackage and cleanup
|
|
578
|
-
max_item.emplace(*tmp);
|
|
579
|
-
|
|
587
|
+
max_item.emplace(std::move(*tmp));
|
|
588
|
+
tmp->~T();
|
|
580
589
|
}
|
|
581
590
|
A alloc(allocator);
|
|
582
591
|
auto items_buffer_deleter = [capacity, &alloc](T* ptr) { alloc.deallocate(ptr, capacity); };
|
|
@@ -100,4 +100,28 @@ TEST_CASE("kll string", "[serde_compat]") {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
TEST_CASE("kll long", "[serde_compat]") {
|
|
104
|
+
const unsigned n_arr[] = {0, 1, 10, 100, 1000, 10000, 100000, 1000000};
|
|
105
|
+
for (const unsigned n: n_arr) {
|
|
106
|
+
std::ifstream is;
|
|
107
|
+
is.exceptions(std::ios::failbit | std::ios::badbit);
|
|
108
|
+
is.open(testBinaryInputPath + "kll_long_n" + std::to_string(n) + "_java.sk", std::ios::binary);
|
|
109
|
+
const auto sketch = kll_sketch<long>::deserialize(is);
|
|
110
|
+
REQUIRE(sketch.is_empty() == (n == 0));
|
|
111
|
+
REQUIRE(sketch.is_estimation_mode() == (n > kll_constants::DEFAULT_K));
|
|
112
|
+
REQUIRE(sketch.get_n() == n);
|
|
113
|
+
if (n > 0) {
|
|
114
|
+
REQUIRE(sketch.get_min_item() == 1);
|
|
115
|
+
REQUIRE(sketch.get_max_item() == static_cast<long>(n));
|
|
116
|
+
uint64_t weight = 0;
|
|
117
|
+
for (const auto pair: sketch) {
|
|
118
|
+
REQUIRE(pair.first >= sketch.get_min_item());
|
|
119
|
+
REQUIRE(pair.first <= sketch.get_max_item());
|
|
120
|
+
weight += pair.second;
|
|
121
|
+
}
|
|
122
|
+
REQUIRE(weight == sketch.get_n());
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
103
127
|
} /* namespace datasketches */
|
|
@@ -43,6 +43,16 @@ TEST_CASE("kll sketch double generate", "[serialize_for_java]") {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
TEST_CASE("kll sketch long generate", "[serialize_for_java]") {
|
|
47
|
+
const unsigned n_arr[] = {0, 1, 10, 100, 1000, 10000, 100000, 1000000};
|
|
48
|
+
for (const unsigned n: n_arr) {
|
|
49
|
+
kll_sketch<long> sketch;
|
|
50
|
+
for (unsigned i = 1; i <= n; ++i) sketch.update(i);
|
|
51
|
+
std::ofstream os("kll_long_n" + std::to_string(n) + "_cpp.sk", std::ios::binary);
|
|
52
|
+
sketch.serialize(os);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
46
56
|
struct compare_as_number {
|
|
47
57
|
bool operator()(const std::string& a, const std::string& b) const {
|
|
48
58
|
return std::stoi(a) < std::stoi(b);
|
|
@@ -47,6 +47,11 @@ namespace quantiles_constants {
|
|
|
47
47
|
* The analysis is obtained using get_rank() and get_quantile() functions,
|
|
48
48
|
* the Probability Mass Function from get_PMF() and the Cumulative Distribution Function from get_CDF().
|
|
49
49
|
*
|
|
50
|
+
* Sketch that may retain string values.
|
|
51
|
+
* For sketches containing strings, cross-language portability depends on
|
|
52
|
+
* using compatible string encodings. This class does not by itself enforce
|
|
53
|
+
* UTF-8 validity for all string inputs.
|
|
54
|
+
*
|
|
50
55
|
* <p>Consider a large stream of one million values such as packet sizes coming into a network node.
|
|
51
56
|
* The natural rank of any specific size value is its index in the hypothetical sorted
|
|
52
57
|
* array of values.
|
|
@@ -206,6 +211,8 @@ public:
|
|
|
206
211
|
|
|
207
212
|
/**
|
|
208
213
|
* Updates this sketch with the given data item.
|
|
214
|
+
* If cross-language portability is required, callers should ensure that
|
|
215
|
+
* the input string uses a compatible encoding (valid UTF-8).
|
|
209
216
|
* @param item from a stream of items
|
|
210
217
|
*/
|
|
211
218
|
template<typename FwdT>
|
|
@@ -213,6 +220,8 @@ public:
|
|
|
213
220
|
|
|
214
221
|
/**
|
|
215
222
|
* Merges another sketch into this one.
|
|
223
|
+
* If sketches contain strings, callers are responsible for ensuring that
|
|
224
|
+
* both sketches were built using compatible string encodings.
|
|
216
225
|
* @param other sketch to merge into this one
|
|
217
226
|
*/
|
|
218
227
|
template<typename FwdSk>
|
|
@@ -537,10 +546,10 @@ private:
|
|
|
537
546
|
static void merge_two_size_k_buffers(Level& arr_in_1, Level& arr_in_2, Level& arr_out, const Comparator& comparator);
|
|
538
547
|
|
|
539
548
|
template<typename SerDe>
|
|
540
|
-
static Level deserialize_array(std::istream& is, uint32_t num_items, uint32_t
|
|
549
|
+
static Level deserialize_array(std::istream& is, uint32_t num_items, uint32_t capacity, const SerDe& serde, const Allocator& allocator);
|
|
541
550
|
|
|
542
551
|
template<typename SerDe>
|
|
543
|
-
static std::pair<Level, size_t> deserialize_array(const void* bytes, size_t size, uint32_t num_items, uint32_t
|
|
552
|
+
static std::pair<Level, size_t> deserialize_array(const void* bytes, size_t size, uint32_t num_items, uint32_t capacity, const SerDe& serde, const Allocator& allocator);
|
|
544
553
|
|
|
545
554
|
static void check_k(uint16_t k);
|
|
546
555
|
static void check_serial_version(uint8_t serial_version);
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
#include <stdexcept>
|
|
26
26
|
#include <iomanip>
|
|
27
27
|
#include <sstream>
|
|
28
|
+
#include <type_traits>
|
|
28
29
|
|
|
29
30
|
#include "count_zeros.hpp"
|
|
30
31
|
#include "conditional_forward.hpp"
|
|
@@ -393,18 +394,22 @@ auto quantiles_sketch<T, C, A>::deserialize(std::istream &is, const SerDe& serde
|
|
|
393
394
|
const bool is_compact = (serial_version == 2) | ((flags_byte & (1 << flags::IS_COMPACT)) > 0);
|
|
394
395
|
const bool is_sorted = (flags_byte & (1 << flags::IS_SORTED)) > 0;
|
|
395
396
|
|
|
396
|
-
optional<T> tmp; // space to deserialize min and max
|
|
397
397
|
optional<T> min_item;
|
|
398
398
|
optional<T> max_item;
|
|
399
399
|
|
|
400
|
-
|
|
400
|
+
// Space to deserialize min and max.
|
|
401
|
+
// serde::deserialize expects allocated but not initialized storage.
|
|
402
|
+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
|
|
403
|
+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
|
|
404
|
+
|
|
405
|
+
serde.deserialize(is, tmp, 1);
|
|
401
406
|
// serde call did not throw, repackage and cleanup
|
|
402
|
-
min_item.emplace(*tmp);
|
|
403
|
-
|
|
404
|
-
serde.deserialize(is,
|
|
407
|
+
min_item.emplace(std::move(*tmp));
|
|
408
|
+
tmp->~T();
|
|
409
|
+
serde.deserialize(is, tmp, 1);
|
|
405
410
|
// serde call did not throw, repackage and cleanup
|
|
406
|
-
max_item.emplace(*tmp);
|
|
407
|
-
|
|
411
|
+
max_item.emplace(std::move(*tmp));
|
|
412
|
+
tmp->~T();
|
|
408
413
|
|
|
409
414
|
if (serial_version == 1) {
|
|
410
415
|
read<uint64_t>(is); // no longer used
|
|
@@ -507,18 +512,22 @@ auto quantiles_sketch<T, C, A>::deserialize(const void* bytes, size_t size, cons
|
|
|
507
512
|
const bool is_compact = (serial_version == 2) | ((flags_byte & (1 << flags::IS_COMPACT)) > 0);
|
|
508
513
|
const bool is_sorted = (flags_byte & (1 << flags::IS_SORTED)) > 0;
|
|
509
514
|
|
|
510
|
-
optional<T> tmp; // space to deserialize min and max
|
|
511
515
|
optional<T> min_item;
|
|
512
516
|
optional<T> max_item;
|
|
513
517
|
|
|
514
|
-
|
|
518
|
+
// Space to deserialize min and max.
|
|
519
|
+
// serde::deserialize expects allocated but not initialized storage.
|
|
520
|
+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
|
|
521
|
+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
|
|
522
|
+
|
|
523
|
+
ptr += serde.deserialize(ptr, end_ptr - ptr, tmp, 1);
|
|
515
524
|
// serde call did not throw, repackage and cleanup
|
|
516
|
-
min_item.emplace(*tmp);
|
|
517
|
-
|
|
518
|
-
ptr += serde.deserialize(ptr, end_ptr - ptr,
|
|
525
|
+
min_item.emplace(std::move(*tmp));
|
|
526
|
+
tmp->~T();
|
|
527
|
+
ptr += serde.deserialize(ptr, end_ptr - ptr, tmp, 1);
|
|
519
528
|
// serde call did not throw, repackage and cleanup
|
|
520
|
-
max_item.emplace(*tmp);
|
|
521
|
-
|
|
529
|
+
max_item.emplace(std::move(*tmp));
|
|
530
|
+
tmp->~T();
|
|
522
531
|
|
|
523
532
|
if (serial_version == 1) {
|
|
524
533
|
uint64_t unused_long;
|
|
@@ -581,7 +590,7 @@ auto quantiles_sketch<T, C, A>::deserialize_array(const void* bytes, size_t size
|
|
|
581
590
|
// serde did not throw, enable destructors
|
|
582
591
|
items.get_deleter().set_destroy(true);
|
|
583
592
|
|
|
584
|
-
//
|
|
593
|
+
// successfully read, now put into a Level
|
|
585
594
|
Level level(allocator);
|
|
586
595
|
level.reserve(capacity);
|
|
587
596
|
level.insert(level.begin(),
|
|
@@ -35,6 +35,11 @@ namespace datasketches {
|
|
|
35
35
|
* "Relative Error Streaming Quantiles" by Graham Cormode, Zohar Karnin, Edo Liberty,
|
|
36
36
|
* Justin Thaler, Pavel Veselý, and loosely derived from a Python prototype written by Pavel Veselý.
|
|
37
37
|
*
|
|
38
|
+
* Sketch that may retain string values.
|
|
39
|
+
* For sketches containing strings, cross-language portability depends on
|
|
40
|
+
* using compatible string encodings. This class does not by itself enforce
|
|
41
|
+
* UTF-8 validity for all string inputs.
|
|
42
|
+
*
|
|
38
43
|
* <p>Reference: https://arxiv.org/abs/2004.01668</p>
|
|
39
44
|
*
|
|
40
45
|
* <p>This implementation differs from the algorithm described in the paper in the following:</p>
|
|
@@ -179,6 +184,8 @@ public:
|
|
|
179
184
|
|
|
180
185
|
/**
|
|
181
186
|
* Updates this sketch with the given data item.
|
|
187
|
+
* If cross-language portability is required, callers should ensure that
|
|
188
|
+
* the input string uses a compatible encoding (valid UTF-8).
|
|
182
189
|
* @param item from a stream of items
|
|
183
190
|
*/
|
|
184
191
|
template<typename FwdT>
|
|
@@ -186,6 +193,8 @@ public:
|
|
|
186
193
|
|
|
187
194
|
/**
|
|
188
195
|
* Merges another sketch into this one.
|
|
196
|
+
* If sketches contain strings, callers are responsible for ensuring that
|
|
197
|
+
* both sketches were built using compatible string encodings.
|
|
189
198
|
* @param other sketch to merge into this one
|
|
190
199
|
*/
|
|
191
200
|
template<typename FwdSk>
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
#include <sstream>
|
|
24
24
|
#include <stdexcept>
|
|
25
|
+
#include <type_traits>
|
|
25
26
|
|
|
26
27
|
namespace datasketches {
|
|
27
28
|
|
|
@@ -292,7 +293,7 @@ double req_sketch<T, C, A>::get_rank_upper_bound(double rank, uint8_t num_std_de
|
|
|
292
293
|
|
|
293
294
|
template<typename T, typename C, typename A>
|
|
294
295
|
double req_sketch<T, C, A>::get_RSE(uint16_t k, double rank, bool hra, uint64_t n) {
|
|
295
|
-
return
|
|
296
|
+
return get_rank_ub(k, 2, rank, 1, n, hra) - rank;
|
|
296
297
|
}
|
|
297
298
|
|
|
298
299
|
template<typename T, typename C, typename A>
|
|
@@ -461,7 +462,6 @@ req_sketch<T, C, A> req_sketch<T, C, A>::deserialize(std::istream& is, const Ser
|
|
|
461
462
|
const bool hra = flags_byte & (1 << flags::IS_HIGH_RANK);
|
|
462
463
|
if (is_empty) return req_sketch(k, hra, comparator, allocator);
|
|
463
464
|
|
|
464
|
-
optional<T> tmp; // space to deserialize min and max
|
|
465
465
|
optional<T> min_item;
|
|
466
466
|
optional<T> max_item;
|
|
467
467
|
|
|
@@ -472,14 +472,19 @@ req_sketch<T, C, A> req_sketch<T, C, A>::deserialize(std::istream& is, const Ser
|
|
|
472
472
|
uint64_t n = 1;
|
|
473
473
|
if (num_levels > 1) {
|
|
474
474
|
n = read<uint64_t>(is);
|
|
475
|
-
|
|
475
|
+
// Space to deserialize min and max.
|
|
476
|
+
// serde::deserialize expects allocated but not initialized storage.
|
|
477
|
+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
|
|
478
|
+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
|
|
479
|
+
|
|
480
|
+
sd.deserialize(is, tmp, 1);
|
|
476
481
|
// serde call did not throw, repackage and cleanup
|
|
477
|
-
min_item.emplace(*tmp);
|
|
478
|
-
|
|
479
|
-
sd.deserialize(is,
|
|
482
|
+
min_item.emplace(std::move(*tmp));
|
|
483
|
+
tmp->~T();
|
|
484
|
+
sd.deserialize(is, tmp, 1);
|
|
480
485
|
// serde call did not throw, repackage and cleanup
|
|
481
|
-
max_item.emplace(*tmp);
|
|
482
|
-
|
|
486
|
+
max_item.emplace(std::move(*tmp));
|
|
487
|
+
tmp->~T();
|
|
483
488
|
}
|
|
484
489
|
|
|
485
490
|
if (raw_items) {
|
|
@@ -537,7 +542,6 @@ req_sketch<T, C, A> req_sketch<T, C, A>::deserialize(const void* bytes, size_t s
|
|
|
537
542
|
const bool hra = flags_byte & (1 << flags::IS_HIGH_RANK);
|
|
538
543
|
if (is_empty) return req_sketch(k, hra, comparator, allocator);
|
|
539
544
|
|
|
540
|
-
optional<T> tmp; // space to deserialize min and max
|
|
541
545
|
optional<T> min_item;
|
|
542
546
|
optional<T> max_item;
|
|
543
547
|
|
|
@@ -549,14 +553,19 @@ req_sketch<T, C, A> req_sketch<T, C, A>::deserialize(const void* bytes, size_t s
|
|
|
549
553
|
if (num_levels > 1) {
|
|
550
554
|
ensure_minimum_memory(end_ptr - ptr, sizeof(n));
|
|
551
555
|
ptr += copy_from_mem(ptr, n);
|
|
552
|
-
|
|
556
|
+
// Space to deserialize min and max.
|
|
557
|
+
// serde::deserialize expects allocated but not initialized storage.
|
|
558
|
+
typename std::aligned_storage<sizeof(T), alignof(T)>::type tmp_storage;
|
|
559
|
+
T* tmp = reinterpret_cast<T*>(&tmp_storage);
|
|
560
|
+
|
|
561
|
+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
|
|
553
562
|
// serde call did not throw, repackage and cleanup
|
|
554
|
-
min_item.emplace(*tmp);
|
|
555
|
-
|
|
556
|
-
ptr += sd.deserialize(ptr, end_ptr - ptr,
|
|
563
|
+
min_item.emplace(std::move(*tmp));
|
|
564
|
+
tmp->~T();
|
|
565
|
+
ptr += sd.deserialize(ptr, end_ptr - ptr, tmp, 1);
|
|
557
566
|
// serde call did not throw, repackage and cleanup
|
|
558
|
-
max_item.emplace(*tmp);
|
|
559
|
-
|
|
567
|
+
max_item.emplace(std::move(*tmp));
|
|
568
|
+
tmp->~T();
|
|
560
569
|
}
|
|
561
570
|
|
|
562
571
|
if (raw_items) {
|
|
@@ -52,4 +52,50 @@ TEST_CASE("req float", "[serde_compat]") {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
TEST_CASE("req float negative", "[serde_compat]") {
|
|
56
|
+
const unsigned n_arr[] = {1, 10};
|
|
57
|
+
for (const unsigned n: n_arr) {
|
|
58
|
+
std::ifstream is;
|
|
59
|
+
is.exceptions(std::ios::failbit | std::ios::badbit);
|
|
60
|
+
is.open(testBinaryInputPath + "req_float_negative_n" + std::to_string(n) + "_java.sk", std::ios::binary);
|
|
61
|
+
const auto sketch = req_sketch<float>::deserialize(is);
|
|
62
|
+
REQUIRE(sketch.is_HRA());
|
|
63
|
+
REQUIRE_FALSE(sketch.is_empty());
|
|
64
|
+
REQUIRE_FALSE(sketch.is_estimation_mode());
|
|
65
|
+
REQUIRE(sketch.get_n() == n);
|
|
66
|
+
REQUIRE(sketch.get_min_item() == -static_cast<float>(n));
|
|
67
|
+
REQUIRE(sketch.get_max_item() == -1.0f);
|
|
68
|
+
uint64_t weight = 0;
|
|
69
|
+
for (const auto pair: sketch) {
|
|
70
|
+
REQUIRE(pair.first >= sketch.get_min_item());
|
|
71
|
+
REQUIRE(pair.first <= sketch.get_max_item());
|
|
72
|
+
weight += pair.second;
|
|
73
|
+
}
|
|
74
|
+
REQUIRE(weight == sketch.get_n());
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
TEST_CASE("req float mixed", "[serde_compat]") {
|
|
79
|
+
const unsigned n_arr[] = {1, 10};
|
|
80
|
+
for (const unsigned n: n_arr) {
|
|
81
|
+
std::ifstream is;
|
|
82
|
+
is.exceptions(std::ios::failbit | std::ios::badbit);
|
|
83
|
+
is.open(testBinaryInputPath + "req_float_mixed_n" + std::to_string(n) + "_java.sk", std::ios::binary);
|
|
84
|
+
const auto sketch = req_sketch<float>::deserialize(is);
|
|
85
|
+
REQUIRE(sketch.is_HRA());
|
|
86
|
+
REQUIRE_FALSE(sketch.is_empty());
|
|
87
|
+
REQUIRE_FALSE(sketch.is_estimation_mode());
|
|
88
|
+
REQUIRE(sketch.get_n() == 2 * n + 1);
|
|
89
|
+
REQUIRE(sketch.get_min_item() == -static_cast<float>(n));
|
|
90
|
+
REQUIRE(sketch.get_max_item() == static_cast<float>(n));
|
|
91
|
+
uint64_t weight = 0;
|
|
92
|
+
for (const auto pair: sketch) {
|
|
93
|
+
REQUIRE(pair.first >= sketch.get_min_item());
|
|
94
|
+
REQUIRE(pair.first <= sketch.get_max_item());
|
|
95
|
+
weight += pair.second;
|
|
96
|
+
}
|
|
97
|
+
REQUIRE(weight == sketch.get_n());
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
55
101
|
} /* namespace datasketches */
|
|
@@ -33,4 +33,24 @@ TEST_CASE("req sketch float generate", "[serialize_for_java]") {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
TEST_CASE("req sketch float negative generate", "[serialize_for_java]") {
|
|
37
|
+
const unsigned n_arr[] = {1, 10};
|
|
38
|
+
for (const unsigned n: n_arr) {
|
|
39
|
+
req_sketch<float> sketch(12);
|
|
40
|
+
for (unsigned i = 1; i <= n; ++i) sketch.update(-static_cast<float>(i));
|
|
41
|
+
std::ofstream os("req_float_negative_n" + std::to_string(n) + "_cpp.sk", std::ios::binary);
|
|
42
|
+
sketch.serialize(os);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
TEST_CASE("req sketch float mixed generate", "[serialize_for_java]") {
|
|
47
|
+
const unsigned n_arr[] = {1, 10};
|
|
48
|
+
for (const unsigned n: n_arr) {
|
|
49
|
+
req_sketch<float> sketch(12);
|
|
50
|
+
for (int i = -static_cast<int>(n); i <= static_cast<int>(n); ++i) sketch.update(static_cast<float>(i));
|
|
51
|
+
std::ofstream os("req_float_mixed_n" + std::to_string(n) + "_cpp.sk", std::ios::binary);
|
|
52
|
+
sketch.serialize(os);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
36
56
|
} /* namespace datasketches */
|
|
@@ -43,6 +43,7 @@ TEST_CASE("req sketch: empty", "[req_sketch]") {
|
|
|
43
43
|
REQUIRE_FALSE(sketch.is_estimation_mode());
|
|
44
44
|
REQUIRE(sketch.get_n() == 0);
|
|
45
45
|
REQUIRE(sketch.get_num_retained() == 0);
|
|
46
|
+
REQUIRE(sketch.get_RSE(sketch.get_k(), 0.5, true, 0) == 0);
|
|
46
47
|
REQUIRE_THROWS_AS(sketch.get_min_item(), std::runtime_error);
|
|
47
48
|
REQUIRE_THROWS_AS(sketch.get_max_item(), std::runtime_error);
|
|
48
49
|
REQUIRE_THROWS_AS(sketch.get_rank(0), std::runtime_error);
|
|
@@ -61,6 +62,7 @@ TEST_CASE("req sketch: single value, lra", "[req_sketch]") {
|
|
|
61
62
|
REQUIRE_FALSE(sketch.is_estimation_mode());
|
|
62
63
|
REQUIRE(sketch.get_n() == 1);
|
|
63
64
|
REQUIRE(sketch.get_num_retained() == 1);
|
|
65
|
+
REQUIRE(sketch.get_RSE(sketch.get_k(), 0.5, false, sketch.get_n()) == 0);
|
|
64
66
|
REQUIRE(sketch.get_rank(1.0f, false) == 0);
|
|
65
67
|
REQUIRE(sketch.get_rank(1.0f) == 1);
|
|
66
68
|
REQUIRE(sketch.get_rank(1.1f, false) == 1);
|
|
@@ -314,6 +316,74 @@ TEST_CASE("req sketch: byte serialize-deserialize estimation mode", "[req_sketch
|
|
|
314
316
|
REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
|
|
315
317
|
}
|
|
316
318
|
|
|
319
|
+
TEST_CASE("req sketch: stream serialize-deserialize negative values", "[req_sketch]") {
|
|
320
|
+
req_sketch<float> sketch(12);
|
|
321
|
+
const size_t n = 50;
|
|
322
|
+
for (size_t i = 1; i <= n; ++i) sketch.update(-static_cast<float>(i));
|
|
323
|
+
|
|
324
|
+
std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
|
|
325
|
+
sketch.serialize(s);
|
|
326
|
+
auto sketch2 = req_sketch<float>::deserialize(s);
|
|
327
|
+
REQUIRE(s.tellg() == s.tellp());
|
|
328
|
+
REQUIRE(sketch2.is_empty() == sketch.is_empty());
|
|
329
|
+
REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
|
|
330
|
+
REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
|
|
331
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
332
|
+
REQUIRE(sketch2.get_min_item() == -static_cast<float>(n));
|
|
333
|
+
REQUIRE(sketch2.get_max_item() == -1.0f);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
TEST_CASE("req sketch: byte serialize-deserialize negative values", "[req_sketch]") {
|
|
337
|
+
req_sketch<float> sketch(12);
|
|
338
|
+
const size_t n = 50;
|
|
339
|
+
for (size_t i = 1; i <= n; ++i) sketch.update(-static_cast<float>(i));
|
|
340
|
+
|
|
341
|
+
auto bytes = sketch.serialize();
|
|
342
|
+
REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
|
|
343
|
+
auto sketch2 = req_sketch<float>::deserialize(bytes.data(), bytes.size());
|
|
344
|
+
REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
|
|
345
|
+
REQUIRE(sketch2.is_empty() == sketch.is_empty());
|
|
346
|
+
REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
|
|
347
|
+
REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
|
|
348
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
349
|
+
REQUIRE(sketch2.get_min_item() == -static_cast<float>(n));
|
|
350
|
+
REQUIRE(sketch2.get_max_item() == -1.0f);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
TEST_CASE("req sketch: stream serialize-deserialize mixed values", "[req_sketch]") {
|
|
354
|
+
req_sketch<float> sketch(12);
|
|
355
|
+
const int half = 25;
|
|
356
|
+
for (int i = -half; i < half; ++i) sketch.update(static_cast<float>(i));
|
|
357
|
+
|
|
358
|
+
std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
|
|
359
|
+
sketch.serialize(s);
|
|
360
|
+
auto sketch2 = req_sketch<float>::deserialize(s);
|
|
361
|
+
REQUIRE(s.tellg() == s.tellp());
|
|
362
|
+
REQUIRE(sketch2.is_empty() == sketch.is_empty());
|
|
363
|
+
REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
|
|
364
|
+
REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
|
|
365
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
366
|
+
REQUIRE(sketch2.get_min_item() == static_cast<float>(-half));
|
|
367
|
+
REQUIRE(sketch2.get_max_item() == static_cast<float>(half - 1));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
TEST_CASE("req sketch: byte serialize-deserialize mixed values", "[req_sketch]") {
|
|
371
|
+
req_sketch<float> sketch(12);
|
|
372
|
+
const int half = 25;
|
|
373
|
+
for (int i = -half; i < half; ++i) sketch.update(static_cast<float>(i));
|
|
374
|
+
|
|
375
|
+
auto bytes = sketch.serialize();
|
|
376
|
+
REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
|
|
377
|
+
auto sketch2 = req_sketch<float>::deserialize(bytes.data(), bytes.size());
|
|
378
|
+
REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
|
|
379
|
+
REQUIRE(sketch2.is_empty() == sketch.is_empty());
|
|
380
|
+
REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
|
|
381
|
+
REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
|
|
382
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
383
|
+
REQUIRE(sketch2.get_min_item() == static_cast<float>(-half));
|
|
384
|
+
REQUIRE(sketch2.get_max_item() == static_cast<float>(half - 1));
|
|
385
|
+
}
|
|
386
|
+
|
|
317
387
|
TEST_CASE("req sketch: serialize deserialize stream and bytes equivalence", "[req_sketch]") {
|
|
318
388
|
req_sketch<float> sketch(12);
|
|
319
389
|
const size_t n = 100000;
|