datasketches 0.1.2 → 0.2.0

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 (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/ext/datasketches/cpc_wrapper.cpp +12 -13
  4. data/ext/datasketches/ext.cpp +1 -1
  5. data/ext/datasketches/ext.h +4 -0
  6. data/ext/datasketches/extconf.rb +1 -1
  7. data/ext/datasketches/fi_wrapper.cpp +6 -8
  8. data/ext/datasketches/hll_wrapper.cpp +13 -14
  9. data/ext/datasketches/kll_wrapper.cpp +28 -76
  10. data/ext/datasketches/theta_wrapper.cpp +27 -41
  11. data/ext/datasketches/vo_wrapper.cpp +4 -6
  12. data/lib/datasketches/version.rb +1 -1
  13. data/vendor/datasketches-cpp/CMakeLists.txt +1 -0
  14. data/vendor/datasketches-cpp/README.md +4 -4
  15. data/vendor/datasketches-cpp/common/include/MurmurHash3.h +7 -0
  16. data/vendor/datasketches-cpp/common/include/memory_operations.hpp +12 -0
  17. data/vendor/datasketches-cpp/common/test/CMakeLists.txt +24 -0
  18. data/vendor/datasketches-cpp/common/test/integration_test.cpp +77 -0
  19. data/vendor/datasketches-cpp/common/test/test_allocator.hpp +9 -1
  20. data/vendor/datasketches-cpp/cpc/include/cpc_common.hpp +3 -0
  21. data/vendor/datasketches-cpp/cpc/include/cpc_compressor.hpp +2 -2
  22. data/vendor/datasketches-cpp/cpc/include/cpc_compressor_impl.hpp +28 -19
  23. data/vendor/datasketches-cpp/cpc/include/cpc_sketch.hpp +8 -5
  24. data/vendor/datasketches-cpp/cpc/include/cpc_sketch_impl.hpp +19 -14
  25. data/vendor/datasketches-cpp/cpc/include/cpc_union.hpp +2 -2
  26. data/vendor/datasketches-cpp/cpc/include/cpc_union_impl.hpp +6 -6
  27. data/vendor/datasketches-cpp/cpc/include/cpc_util.hpp +0 -6
  28. data/vendor/datasketches-cpp/cpc/include/icon_estimator.hpp +3 -3
  29. data/vendor/datasketches-cpp/cpc/include/u32_table.hpp +3 -3
  30. data/vendor/datasketches-cpp/cpc/include/u32_table_impl.hpp +9 -9
  31. data/vendor/datasketches-cpp/cpc/test/CMakeLists.txt +1 -0
  32. data/vendor/datasketches-cpp/cpc/test/cpc_sketch_allocation_test.cpp +237 -0
  33. data/vendor/datasketches-cpp/fi/include/frequent_items_sketch.hpp +15 -10
  34. data/vendor/datasketches-cpp/fi/include/frequent_items_sketch_impl.hpp +40 -28
  35. data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map.hpp +19 -13
  36. data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map_impl.hpp +140 -124
  37. data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_custom_type_test.cpp +15 -12
  38. data/vendor/datasketches-cpp/fi/test/reverse_purge_hash_map_test.cpp +3 -3
  39. data/vendor/datasketches-cpp/hll/CMakeLists.txt +3 -0
  40. data/vendor/datasketches-cpp/hll/include/AuxHashMap-internal.hpp +32 -57
  41. data/vendor/datasketches-cpp/hll/include/AuxHashMap.hpp +9 -8
  42. data/vendor/datasketches-cpp/hll/include/CompositeInterpolationXTable.hpp +2 -2
  43. data/vendor/datasketches-cpp/hll/include/CouponHashSet-internal.hpp +34 -48
  44. data/vendor/datasketches-cpp/hll/include/CouponHashSet.hpp +10 -10
  45. data/vendor/datasketches-cpp/hll/include/CouponList-internal.hpp +45 -77
  46. data/vendor/datasketches-cpp/hll/include/CouponList.hpp +11 -12
  47. data/vendor/datasketches-cpp/hll/include/CubicInterpolation.hpp +2 -2
  48. data/vendor/datasketches-cpp/hll/include/HarmonicNumbers.hpp +2 -2
  49. data/vendor/datasketches-cpp/hll/include/Hll4Array-internal.hpp +15 -14
  50. data/vendor/datasketches-cpp/hll/include/Hll4Array.hpp +1 -1
  51. data/vendor/datasketches-cpp/hll/include/Hll6Array-internal.hpp +10 -21
  52. data/vendor/datasketches-cpp/hll/include/Hll6Array.hpp +2 -3
  53. data/vendor/datasketches-cpp/hll/include/Hll8Array-internal.hpp +10 -21
  54. data/vendor/datasketches-cpp/hll/include/Hll8Array.hpp +2 -3
  55. data/vendor/datasketches-cpp/hll/include/HllArray-internal.hpp +28 -55
  56. data/vendor/datasketches-cpp/hll/include/HllArray.hpp +8 -8
  57. data/vendor/datasketches-cpp/hll/include/HllSketch-internal.hpp +9 -11
  58. data/vendor/datasketches-cpp/hll/include/HllSketchImpl.hpp +2 -1
  59. data/vendor/datasketches-cpp/hll/include/HllSketchImplFactory.hpp +34 -31
  60. data/vendor/datasketches-cpp/hll/include/HllUnion-internal.hpp +3 -28
  61. data/vendor/datasketches-cpp/hll/include/HllUtil.hpp +1 -1
  62. data/vendor/datasketches-cpp/hll/include/RelativeErrorTables.hpp +1 -1
  63. data/vendor/datasketches-cpp/hll/include/hll.hpp +6 -34
  64. data/vendor/datasketches-cpp/hll/test/AuxHashMapTest.cpp +7 -7
  65. data/vendor/datasketches-cpp/hll/test/CouponHashSetTest.cpp +2 -2
  66. data/vendor/datasketches-cpp/hll/test/CouponListTest.cpp +3 -3
  67. data/vendor/datasketches-cpp/hll/test/HllArrayTest.cpp +2 -2
  68. data/vendor/datasketches-cpp/hll/test/HllSketchTest.cpp +46 -50
  69. data/vendor/datasketches-cpp/kll/include/kll_quantile_calculator.hpp +1 -1
  70. data/vendor/datasketches-cpp/kll/include/kll_quantile_calculator_impl.hpp +3 -3
  71. data/vendor/datasketches-cpp/kll/include/kll_sketch.hpp +10 -3
  72. data/vendor/datasketches-cpp/kll/include/kll_sketch_impl.hpp +93 -75
  73. data/vendor/datasketches-cpp/kll/test/kll_sketch_custom_type_test.cpp +11 -10
  74. data/vendor/datasketches-cpp/kll/test/kll_sketch_test.cpp +45 -42
  75. data/vendor/datasketches-cpp/python/CMakeLists.txt +2 -0
  76. data/vendor/datasketches-cpp/python/README.md +6 -3
  77. data/vendor/datasketches-cpp/python/src/datasketches.cpp +2 -0
  78. data/vendor/datasketches-cpp/python/src/hll_wrapper.cpp +0 -2
  79. data/vendor/datasketches-cpp/python/src/kll_wrapper.cpp +3 -1
  80. data/vendor/datasketches-cpp/python/src/req_wrapper.cpp +246 -0
  81. data/vendor/datasketches-cpp/python/src/theta_wrapper.cpp +36 -26
  82. data/vendor/datasketches-cpp/python/tests/hll_test.py +0 -1
  83. data/vendor/datasketches-cpp/python/tests/kll_test.py +3 -3
  84. data/vendor/datasketches-cpp/python/tests/req_test.py +126 -0
  85. data/vendor/datasketches-cpp/python/tests/theta_test.py +28 -3
  86. data/vendor/datasketches-cpp/req/CMakeLists.txt +60 -0
  87. data/vendor/datasketches-cpp/{tuple/include/theta_a_not_b_experimental_impl.hpp → req/include/req_common.hpp} +17 -8
  88. data/vendor/datasketches-cpp/req/include/req_compactor.hpp +137 -0
  89. data/vendor/datasketches-cpp/req/include/req_compactor_impl.hpp +501 -0
  90. data/vendor/datasketches-cpp/req/include/req_quantile_calculator.hpp +69 -0
  91. data/vendor/datasketches-cpp/req/include/req_quantile_calculator_impl.hpp +60 -0
  92. data/vendor/datasketches-cpp/req/include/req_sketch.hpp +395 -0
  93. data/vendor/datasketches-cpp/req/include/req_sketch_impl.hpp +810 -0
  94. data/vendor/datasketches-cpp/req/test/CMakeLists.txt +43 -0
  95. data/vendor/datasketches-cpp/req/test/req_float_empty_from_java.sk +0 -0
  96. data/vendor/datasketches-cpp/req/test/req_float_estimation_from_java.sk +0 -0
  97. data/vendor/datasketches-cpp/req/test/req_float_exact_from_java.sk +0 -0
  98. data/vendor/datasketches-cpp/req/test/req_float_raw_items_from_java.sk +0 -0
  99. data/vendor/datasketches-cpp/req/test/req_float_single_item_from_java.sk +0 -0
  100. data/vendor/datasketches-cpp/req/test/req_sketch_custom_type_test.cpp +128 -0
  101. data/vendor/datasketches-cpp/req/test/req_sketch_test.cpp +494 -0
  102. data/vendor/datasketches-cpp/sampling/include/var_opt_sketch.hpp +10 -9
  103. data/vendor/datasketches-cpp/sampling/include/var_opt_sketch_impl.hpp +82 -70
  104. data/vendor/datasketches-cpp/sampling/include/var_opt_union.hpp +5 -5
  105. data/vendor/datasketches-cpp/sampling/include/var_opt_union_impl.hpp +7 -7
  106. data/vendor/datasketches-cpp/sampling/test/CMakeLists.txt +1 -0
  107. data/vendor/datasketches-cpp/sampling/test/var_opt_allocation_test.cpp +96 -0
  108. data/vendor/datasketches-cpp/sampling/test/var_opt_union_test.cpp +0 -31
  109. data/vendor/datasketches-cpp/setup.py +5 -3
  110. data/vendor/datasketches-cpp/theta/CMakeLists.txt +30 -3
  111. data/vendor/datasketches-cpp/{tuple → theta}/include/bounds_on_ratios_in_sampled_sets.hpp +2 -1
  112. data/vendor/datasketches-cpp/{tuple → theta}/include/bounds_on_ratios_in_theta_sketched_sets.hpp +1 -1
  113. data/vendor/datasketches-cpp/theta/include/theta_a_not_b.hpp +12 -29
  114. data/vendor/datasketches-cpp/theta/include/theta_a_not_b_impl.hpp +5 -46
  115. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_comparators.hpp +0 -0
  116. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_constants.hpp +2 -0
  117. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_helpers.hpp +0 -0
  118. data/vendor/datasketches-cpp/theta/include/theta_intersection.hpp +22 -29
  119. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_intersection_base.hpp +0 -0
  120. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_intersection_base_impl.hpp +0 -0
  121. data/vendor/datasketches-cpp/theta/include/theta_intersection_impl.hpp +8 -90
  122. data/vendor/datasketches-cpp/{tuple/test/theta_union_experimental_test.cpp → theta/include/theta_jaccard_similarity.hpp} +11 -18
  123. data/vendor/datasketches-cpp/{tuple/include/jaccard_similarity.hpp → theta/include/theta_jaccard_similarity_base.hpp} +6 -22
  124. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_set_difference_base.hpp +0 -0
  125. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_set_difference_base_impl.hpp +5 -0
  126. data/vendor/datasketches-cpp/theta/include/theta_sketch.hpp +132 -266
  127. data/vendor/datasketches-cpp/theta/include/theta_sketch_impl.hpp +200 -650
  128. data/vendor/datasketches-cpp/theta/include/theta_union.hpp +27 -60
  129. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_union_base.hpp +1 -1
  130. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_union_base_impl.hpp +5 -0
  131. data/vendor/datasketches-cpp/theta/include/theta_union_impl.hpp +13 -69
  132. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_update_sketch_base.hpp +3 -19
  133. data/vendor/datasketches-cpp/{tuple → theta}/include/theta_update_sketch_base_impl.hpp +6 -1
  134. data/vendor/datasketches-cpp/theta/test/CMakeLists.txt +1 -0
  135. data/vendor/datasketches-cpp/{tuple → theta}/test/theta_jaccard_similarity_test.cpp +2 -3
  136. data/vendor/datasketches-cpp/theta/test/theta_sketch_test.cpp +37 -234
  137. data/vendor/datasketches-cpp/tuple/CMakeLists.txt +3 -35
  138. data/vendor/datasketches-cpp/tuple/include/tuple_jaccard_similarity.hpp +38 -0
  139. data/vendor/datasketches-cpp/tuple/include/tuple_sketch.hpp +28 -13
  140. data/vendor/datasketches-cpp/tuple/include/tuple_sketch_impl.hpp +6 -6
  141. data/vendor/datasketches-cpp/tuple/test/CMakeLists.txt +1 -6
  142. data/vendor/datasketches-cpp/tuple/test/tuple_a_not_b_test.cpp +1 -4
  143. data/vendor/datasketches-cpp/tuple/test/tuple_intersection_test.cpp +1 -4
  144. data/vendor/datasketches-cpp/tuple/test/tuple_jaccard_similarity_test.cpp +2 -1
  145. data/vendor/datasketches-cpp/tuple/test/tuple_sketch_allocation_test.cpp +2 -2
  146. data/vendor/datasketches-cpp/tuple/test/tuple_union_test.cpp +1 -4
  147. metadata +43 -34
  148. data/vendor/datasketches-cpp/tuple/include/theta_a_not_b_experimental.hpp +0 -53
  149. data/vendor/datasketches-cpp/tuple/include/theta_intersection_experimental.hpp +0 -78
  150. data/vendor/datasketches-cpp/tuple/include/theta_intersection_experimental_impl.hpp +0 -43
  151. data/vendor/datasketches-cpp/tuple/include/theta_sketch_experimental.hpp +0 -393
  152. data/vendor/datasketches-cpp/tuple/include/theta_sketch_experimental_impl.hpp +0 -481
  153. data/vendor/datasketches-cpp/tuple/include/theta_union_experimental.hpp +0 -88
  154. data/vendor/datasketches-cpp/tuple/include/theta_union_experimental_impl.hpp +0 -47
  155. data/vendor/datasketches-cpp/tuple/test/theta_a_not_b_experimental_test.cpp +0 -250
  156. data/vendor/datasketches-cpp/tuple/test/theta_compact_empty_from_java.sk +0 -0
  157. data/vendor/datasketches-cpp/tuple/test/theta_compact_estimation_from_java.sk +0 -0
  158. data/vendor/datasketches-cpp/tuple/test/theta_compact_single_item_from_java.sk +0 -0
  159. data/vendor/datasketches-cpp/tuple/test/theta_intersection_experimental_test.cpp +0 -224
  160. data/vendor/datasketches-cpp/tuple/test/theta_sketch_experimental_test.cpp +0 -247
@@ -28,7 +28,7 @@ template <typename T, typename C, typename A>
28
28
  class kll_quantile_calculator {
29
29
  public:
30
30
  // assumes that all levels are sorted including level 0
31
- kll_quantile_calculator(const T* items, const uint32_t* levels, uint8_t num_levels, uint64_t n);
31
+ kll_quantile_calculator(const T* items, const uint32_t* levels, uint8_t num_levels, uint64_t n, const A& allocator);
32
32
  T get_quantile(double fraction) const;
33
33
 
34
34
  private:
@@ -29,8 +29,8 @@
29
29
  namespace datasketches {
30
30
 
31
31
  template <typename T, typename C, typename A>
32
- kll_quantile_calculator<T, C, A>::kll_quantile_calculator(const T* items, const uint32_t* levels, uint8_t num_levels, uint64_t n):
33
- n_(n), levels_(num_levels + 1)
32
+ kll_quantile_calculator<T, C, A>::kll_quantile_calculator(const T* items, const uint32_t* levels, uint8_t num_levels, uint64_t n, const A& allocator):
33
+ n_(n), levels_(num_levels + 1, 0, allocator), entries_(allocator)
34
34
  {
35
35
  const uint32_t num_items = levels[num_levels] - levels[0];
36
36
  entries_.reserve(num_items);
@@ -116,7 +116,7 @@ uint32_t kll_quantile_calculator<T, C, A>::search_for_chunk_containing_pos(uint6
116
116
  template <typename T, typename C, typename A>
117
117
  void kll_quantile_calculator<T, C, A>::merge_sorted_blocks(Container& entries, const uint32_t* levels, uint8_t num_levels, uint32_t num_items) {
118
118
  if (num_levels == 1) return;
119
- Container temporary;
119
+ Container temporary(entries.get_allocator());
120
120
  temporary.reserve(num_items);
121
121
  merge_sorted_blocks_direct(entries, temporary, levels, 0, num_levels);
122
122
  }
@@ -161,7 +161,7 @@ class kll_sketch {
161
161
  static const uint16_t MIN_K = DEFAULT_M;
162
162
  static const uint16_t MAX_K = (1 << 16) - 1;
163
163
 
164
- explicit kll_sketch(uint16_t k = DEFAULT_K);
164
+ explicit kll_sketch(uint16_t k = DEFAULT_K, const A& allocator = A());
165
165
  kll_sketch(const kll_sketch& other);
166
166
  kll_sketch(kll_sketch&& other) noexcept;
167
167
  ~kll_sketch();
@@ -202,6 +202,12 @@ class kll_sketch {
202
202
  */
203
203
  bool is_empty() const;
204
204
 
205
+ /**
206
+ * Returns configured parameter k
207
+ * @return parameter k
208
+ */
209
+ uint16_t get_k() const;
210
+
205
211
  /**
206
212
  * Returns the length of the input stream.
207
213
  * @return stream length
@@ -401,7 +407,7 @@ class kll_sketch {
401
407
  * @param is input stream
402
408
  * @return an instance of a sketch
403
409
  */
404
- static kll_sketch deserialize(std::istream& is);
410
+ static kll_sketch<T, C, S, A> deserialize(std::istream& is, const A& allocator = A());
405
411
 
406
412
  /**
407
413
  * This method deserializes a sketch from a given array of bytes.
@@ -409,7 +415,7 @@ class kll_sketch {
409
415
  * @param size the size of the array
410
416
  * @return an instance of a sketch
411
417
  */
412
- static kll_sketch deserialize(const void* bytes, size_t size);
418
+ static kll_sketch<T, C, S, A> deserialize(const void* bytes, size_t size, const A& allocator = A());
413
419
 
414
420
  /*
415
421
  * Gets the normalized rank error given k and pmf.
@@ -461,6 +467,7 @@ class kll_sketch {
461
467
  static const uint8_t PREAMBLE_INTS_SHORT = 2; // for empty and single item
462
468
  static const uint8_t PREAMBLE_INTS_FULL = 5;
463
469
 
470
+ A allocator_;
464
471
  uint16_t k_;
465
472
  uint8_t m_; // minimum buffer "width"
466
473
  uint16_t min_k_; // for error estimation after merging with different k
@@ -30,13 +30,14 @@
30
30
  namespace datasketches {
31
31
 
32
32
  template<typename T, typename C, typename S, typename A>
33
- kll_sketch<T, C, S, A>::kll_sketch(uint16_t k):
33
+ kll_sketch<T, C, S, A>::kll_sketch(uint16_t k, const A& allocator):
34
+ allocator_(allocator),
34
35
  k_(k),
35
36
  m_(DEFAULT_M),
36
37
  min_k_(k),
37
38
  n_(0),
38
39
  num_levels_(1),
39
- levels_(2),
40
+ levels_(2, 0, allocator),
40
41
  items_(nullptr),
41
42
  items_size_(k_),
42
43
  min_value_(nullptr),
@@ -47,11 +48,12 @@ is_level_zero_sorted_(false)
47
48
  throw std::invalid_argument("K must be >= " + std::to_string(MIN_K) + " and <= " + std::to_string(MAX_K) + ": " + std::to_string(k));
48
49
  }
49
50
  levels_[0] = levels_[1] = k;
50
- items_ = A().allocate(items_size_);
51
+ items_ = allocator_.allocate(items_size_);
51
52
  }
52
53
 
53
54
  template<typename T, typename C, typename S, typename A>
54
55
  kll_sketch<T, C, S, A>::kll_sketch(const kll_sketch& other):
56
+ allocator_(other.allocator_),
55
57
  k_(other.k_),
56
58
  m_(other.m_),
57
59
  min_k_(other.min_k_),
@@ -64,14 +66,15 @@ min_value_(nullptr),
64
66
  max_value_(nullptr),
65
67
  is_level_zero_sorted_(other.is_level_zero_sorted_)
66
68
  {
67
- items_ = A().allocate(items_size_);
69
+ items_ = allocator_.allocate(items_size_);
68
70
  std::copy(&other.items_[levels_[0]], &other.items_[levels_[num_levels_]], &items_[levels_[0]]);
69
- if (other.min_value_ != nullptr) min_value_ = new (A().allocate(1)) T(*other.min_value_);
70
- if (other.max_value_ != nullptr) max_value_ = new (A().allocate(1)) T(*other.max_value_);
71
+ if (other.min_value_ != nullptr) min_value_ = new (allocator_.allocate(1)) T(*other.min_value_);
72
+ if (other.max_value_ != nullptr) max_value_ = new (allocator_.allocate(1)) T(*other.max_value_);
71
73
  }
72
74
 
73
75
  template<typename T, typename C, typename S, typename A>
74
76
  kll_sketch<T, C, S, A>::kll_sketch(kll_sketch&& other) noexcept:
77
+ allocator_(std::move(other.allocator_)),
75
78
  k_(other.k_),
76
79
  m_(other.m_),
77
80
  min_k_(other.min_k_),
@@ -91,7 +94,8 @@ is_level_zero_sorted_(other.is_level_zero_sorted_)
91
94
 
92
95
  template<typename T, typename C, typename S, typename A>
93
96
  kll_sketch<T, C, S, A>& kll_sketch<T, C, S, A>::operator=(const kll_sketch& other) {
94
- kll_sketch copy(other);
97
+ kll_sketch<T, C, S, A> copy(other);
98
+ std::swap(allocator_, copy.allocator_);
95
99
  std::swap(k_, copy.k_);
96
100
  std::swap(m_, copy.m_);
97
101
  std::swap(min_k_, copy.min_k_);
@@ -108,6 +112,7 @@ kll_sketch<T, C, S, A>& kll_sketch<T, C, S, A>::operator=(const kll_sketch& othe
108
112
 
109
113
  template<typename T, typename C, typename S, typename A>
110
114
  kll_sketch<T, C, S, A>& kll_sketch<T, C, S, A>::operator=(kll_sketch&& other) {
115
+ std::swap(allocator_, other.allocator_);
111
116
  std::swap(k_, other.k_);
112
117
  std::swap(m_, other.m_);
113
118
  std::swap(min_k_, other.min_k_);
@@ -128,15 +133,15 @@ kll_sketch<T, C, S, A>::~kll_sketch() {
128
133
  const uint32_t begin = levels_[0];
129
134
  const uint32_t end = levels_[num_levels_];
130
135
  for (uint32_t i = begin; i < end; i++) items_[i].~T();
131
- A().deallocate(items_, items_size_);
136
+ allocator_.deallocate(items_, items_size_);
132
137
  }
133
138
  if (min_value_ != nullptr) {
134
139
  min_value_->~T();
135
- A().deallocate(min_value_, 1);
140
+ allocator_.deallocate(min_value_, 1);
136
141
  }
137
142
  if (max_value_ != nullptr) {
138
143
  max_value_->~T();
139
- A().deallocate(max_value_, 1);
144
+ allocator_.deallocate(max_value_, 1);
140
145
  }
141
146
  }
142
147
 
@@ -159,8 +164,8 @@ void kll_sketch<T, C, S, A>::update(T&& value) {
159
164
  template<typename T, typename C, typename S, typename A>
160
165
  void kll_sketch<T, C, S, A>::update_min_max(const T& value) {
161
166
  if (is_empty()) {
162
- min_value_ = new (A().allocate(1)) T(value);
163
- max_value_ = new (A().allocate(1)) T(value);
167
+ min_value_ = new (allocator_.allocate(1)) T(value);
168
+ max_value_ = new (allocator_.allocate(1)) T(value);
164
169
  } else {
165
170
  if (C()(value, *min_value_)) *min_value_ = value;
166
171
  if (C()(*max_value_, value)) *max_value_ = value;
@@ -182,8 +187,8 @@ void kll_sketch<T, C, S, A>::merge(const kll_sketch& other) {
182
187
  throw std::invalid_argument("incompatible M: " + std::to_string(m_) + " and " + std::to_string(other.m_));
183
188
  }
184
189
  if (is_empty()) {
185
- min_value_ = new (A().allocate(1)) T(*other.min_value_);
186
- max_value_ = new (A().allocate(1)) T(*other.max_value_);
190
+ min_value_ = new (allocator_.allocate(1)) T(*other.min_value_);
191
+ max_value_ = new (allocator_.allocate(1)) T(*other.max_value_);
187
192
  } else {
188
193
  if (C()(*other.min_value_, *min_value_)) *min_value_ = *other.min_value_;
189
194
  if (C()(*max_value_, *other.max_value_)) *max_value_ = *other.max_value_;
@@ -206,8 +211,8 @@ void kll_sketch<T, C, S, A>::merge(kll_sketch&& other) {
206
211
  throw std::invalid_argument("incompatible M: " + std::to_string(m_) + " and " + std::to_string(other.m_));
207
212
  }
208
213
  if (is_empty()) {
209
- min_value_ = new (A().allocate(1)) T(std::move(*other.min_value_));
210
- max_value_ = new (A().allocate(1)) T(std::move(*other.max_value_));
214
+ min_value_ = new (allocator_.allocate(1)) T(std::move(*other.min_value_));
215
+ max_value_ = new (allocator_.allocate(1)) T(std::move(*other.max_value_));
211
216
  } else {
212
217
  if (C()(*other.min_value_, *min_value_)) *min_value_ = std::move(*other.min_value_);
213
218
  if (C()(*max_value_, *other.max_value_)) *max_value_ = std::move(*other.max_value_);
@@ -228,6 +233,11 @@ bool kll_sketch<T, C, S, A>::is_empty() const {
228
233
  return n_ == 0;
229
234
  }
230
235
 
236
+ template<typename T, typename C, typename S, typename A>
237
+ uint16_t kll_sketch<T, C, S, A>::get_k() const {
238
+ return k_;
239
+ }
240
+
231
241
  template<typename T, typename C, typename S, typename A>
232
242
  uint64_t kll_sketch<T, C, S, A>::get_n() const {
233
243
  return n_;
@@ -270,8 +280,7 @@ T kll_sketch<T, C, S, A>::get_quantile(double fraction) const {
270
280
 
271
281
  template<typename T, typename C, typename S, typename A>
272
282
  std::vector<T, A> kll_sketch<T, C, S, A>::get_quantiles(const double* fractions, uint32_t size) const {
273
- std::vector<T, A> quantiles;
274
- quantiles.reserve(size);
283
+ std::vector<T, A> quantiles(allocator_);
275
284
  if (is_empty()) return quantiles;
276
285
  std::unique_ptr<kll_quantile_calculator<T, C, A>, std::function<void(kll_quantile_calculator<T, C, A>*)>> quantile_calculator;
277
286
  quantiles.reserve(size);
@@ -295,11 +304,11 @@ std::vector<T, A> kll_sketch<T, C, S, A>::get_quantiles(const double* fractions,
295
304
 
296
305
  template<typename T, typename C, typename S, typename A>
297
306
  std::vector<T, A> kll_sketch<T, C, S, A>::get_quantiles(size_t num) const {
298
- if (is_empty()) return std::vector<T, A>();
307
+ if (is_empty()) return std::vector<T, A>(allocator_);
299
308
  if (num == 0) {
300
309
  throw std::invalid_argument("num must be > 0");
301
310
  }
302
- std::vector<double> fractions(num);
311
+ vector_d<A> fractions(num, 0, allocator_);
303
312
  fractions[0] = 0.0;
304
313
  for (size_t i = 1; i < num; i++) {
305
314
  fractions[i] = static_cast<double>(i) / (num - 1);
@@ -411,7 +420,7 @@ template<typename T, typename C, typename S, typename A>
411
420
  vector_u8<A> kll_sketch<T, C, S, A>::serialize(unsigned header_size_bytes) const {
412
421
  const bool is_single_item = n_ == 1;
413
422
  const size_t size = header_size_bytes + get_serialized_size_bytes();
414
- vector_u8<A> bytes(size);
423
+ vector_u8<A> bytes(size, 0, allocator_);
415
424
  uint8_t* ptr = bytes.data() + header_size_bytes;
416
425
  const uint8_t* end_ptr = ptr + size;
417
426
  const uint8_t preamble_ints(is_empty() || is_single_item ? PREAMBLE_INTS_SHORT : PREAMBLE_INTS_FULL);
@@ -449,7 +458,7 @@ vector_u8<A> kll_sketch<T, C, S, A>::serialize(unsigned header_size_bytes) const
449
458
  }
450
459
 
451
460
  template<typename T, typename C, typename S, typename A>
452
- kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is) {
461
+ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is, const A& allocator) {
453
462
  uint8_t preamble_ints;
454
463
  is.read((char*)&preamble_ints, sizeof(preamble_ints));
455
464
  uint8_t serial_version;
@@ -472,7 +481,7 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is) {
472
481
 
473
482
  if (!is.good()) throw std::runtime_error("error reading from std::istream");
474
483
  const bool is_empty(flags_byte & (1 << flags::IS_EMPTY));
475
- if (is_empty) return kll_sketch(k);
484
+ if (is_empty) return kll_sketch(k, allocator);
476
485
 
477
486
  uint64_t n;
478
487
  uint16_t min_k;
@@ -488,7 +497,7 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is) {
488
497
  is.read((char*)&num_levels, sizeof(num_levels));
489
498
  is.read((char*)&unused, sizeof(unused));
490
499
  }
491
- vector_u32<A> levels(num_levels + 1);
500
+ vector_u32<A> levels(num_levels + 1, 0, allocator);
492
501
  const uint32_t capacity(kll_helper::compute_total_capacity(k, m, num_levels));
493
502
  if (is_single_item) {
494
503
  levels[0] = capacity - 1;
@@ -497,41 +506,43 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is) {
497
506
  is.read((char*)levels.data(), sizeof(levels[0]) * num_levels);
498
507
  }
499
508
  levels[num_levels] = capacity;
500
- auto item_buffer_deleter = [](T* ptr) { A().deallocate(ptr, 1); };
501
- std::unique_ptr<T, decltype(item_buffer_deleter)> min_value_buffer(A().allocate(1), item_buffer_deleter);
502
- std::unique_ptr<T, decltype(item_buffer_deleter)> max_value_buffer(A().allocate(1), item_buffer_deleter);
503
- std::unique_ptr<T, item_deleter> min_value;
504
- std::unique_ptr<T, item_deleter> max_value;
509
+ A alloc(allocator);
510
+ auto item_buffer_deleter = [&alloc](T* ptr) { alloc.deallocate(ptr, 1); };
511
+ std::unique_ptr<T, decltype(item_buffer_deleter)> min_value_buffer(alloc.allocate(1), item_buffer_deleter);
512
+ std::unique_ptr<T, decltype(item_buffer_deleter)> max_value_buffer(alloc.allocate(1), item_buffer_deleter);
513
+ std::unique_ptr<T, item_deleter> min_value(nullptr, item_deleter(allocator));
514
+ std::unique_ptr<T, item_deleter> max_value(nullptr, item_deleter(allocator));
505
515
  if (!is_single_item) {
506
516
  S().deserialize(is, min_value_buffer.get(), 1);
507
517
  // serde call did not throw, repackage with destrtuctor
508
- min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter());
518
+ min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter(allocator));
509
519
  S().deserialize(is, max_value_buffer.get(), 1);
510
520
  // serde call did not throw, repackage with destrtuctor
511
- max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter());
521
+ max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter(allocator));
512
522
  }
513
- auto items_buffer_deleter = [capacity](T* ptr) { A().deallocate(ptr, capacity); };
514
- std::unique_ptr<T, decltype(items_buffer_deleter)> items_buffer(A().allocate(capacity), items_buffer_deleter);
523
+ auto items_buffer_deleter = [capacity, &alloc](T* ptr) { alloc.deallocate(ptr, capacity); };
524
+ std::unique_ptr<T, decltype(items_buffer_deleter)> items_buffer(alloc.allocate(capacity), items_buffer_deleter);
515
525
  const auto num_items = levels[num_levels] - levels[0];
516
526
  S().deserialize(is, &items_buffer.get()[levels[0]], num_items);
517
527
  // serde call did not throw, repackage with destrtuctors
518
- std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity));
528
+ std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity, allocator));
519
529
  const bool is_level_zero_sorted = (flags_byte & (1 << flags::IS_LEVEL_ZERO_SORTED)) > 0;
520
530
  if (is_single_item) {
521
531
  new (min_value_buffer.get()) T(items.get()[levels[0]]);
522
532
  // copy did not throw, repackage with destrtuctor
523
- min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter());
533
+ min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter(allocator));
524
534
  new (max_value_buffer.get()) T(items.get()[levels[0]]);
525
535
  // copy did not throw, repackage with destrtuctor
526
- max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter());
536
+ max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter(allocator));
527
537
  }
528
- if (!is.good()) throw std::runtime_error("error reading from std::istream");
538
+ if (!is.good())
539
+ throw std::runtime_error("error reading from std::istream");
529
540
  return kll_sketch(k, min_k, n, num_levels, std::move(levels), std::move(items), capacity,
530
541
  std::move(min_value), std::move(max_value), is_level_zero_sorted);
531
542
  }
532
543
 
533
544
  template<typename T, typename C, typename S, typename A>
534
- kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, size_t size) {
545
+ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, size_t size, const A& allocator) {
535
546
  ensure_minimum_memory(size, 8);
536
547
  const char* ptr = static_cast<const char*>(bytes);
537
548
  uint8_t preamble_ints;
@@ -555,7 +566,7 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, si
555
566
  ensure_minimum_memory(size, 1 << preamble_ints);
556
567
 
557
568
  const bool is_empty(flags_byte & (1 << flags::IS_EMPTY));
558
- if (is_empty) return kll_sketch<T, C, S, A>(k);
569
+ if (is_empty) return kll_sketch<T, C, S, A>(k, allocator);
559
570
 
560
571
  uint64_t n;
561
572
  uint16_t min_k;
@@ -572,7 +583,7 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, si
572
583
  ptr += copy_from_mem(ptr, &num_levels, sizeof(num_levels));
573
584
  ptr++; // skip unused byte
574
585
  }
575
- vector_u32<A> levels(num_levels + 1);
586
+ vector_u32<A> levels(num_levels + 1, 0, allocator);
576
587
  const uint32_t capacity(kll_helper::compute_total_capacity(k, m, num_levels));
577
588
  if (is_single_item) {
578
589
  levels[0] = capacity - 1;
@@ -581,35 +592,36 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, si
581
592
  ptr += copy_from_mem(ptr, levels.data(), sizeof(levels[0]) * num_levels);
582
593
  }
583
594
  levels[num_levels] = capacity;
584
- auto item_buffer_deleter = [](T* ptr) { A().deallocate(ptr, 1); };
585
- std::unique_ptr<T, decltype(item_buffer_deleter)> min_value_buffer(A().allocate(1), item_buffer_deleter);
586
- std::unique_ptr<T, decltype(item_buffer_deleter)> max_value_buffer(A().allocate(1), item_buffer_deleter);
587
- std::unique_ptr<T, item_deleter> min_value;
588
- std::unique_ptr<T, item_deleter> max_value;
595
+ A alloc(allocator);
596
+ auto item_buffer_deleter = [&alloc](T* ptr) { alloc.deallocate(ptr, 1); };
597
+ std::unique_ptr<T, decltype(item_buffer_deleter)> min_value_buffer(alloc.allocate(1), item_buffer_deleter);
598
+ std::unique_ptr<T, decltype(item_buffer_deleter)> max_value_buffer(alloc.allocate(1), item_buffer_deleter);
599
+ std::unique_ptr<T, item_deleter> min_value(nullptr, item_deleter(allocator));
600
+ std::unique_ptr<T, item_deleter> max_value(nullptr, item_deleter(allocator));
589
601
  if (!is_single_item) {
590
602
  ptr += S().deserialize(ptr, end_ptr - ptr, min_value_buffer.get(), 1);
591
603
  // serde call did not throw, repackage with destrtuctor
592
- min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter());
604
+ min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter(allocator));
593
605
  ptr += S().deserialize(ptr, end_ptr - ptr, max_value_buffer.get(), 1);
594
606
  // serde call did not throw, repackage with destrtuctor
595
- max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter());
607
+ max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter(allocator));
596
608
  }
597
- auto items_buffer_deleter = [capacity](T* ptr) { A().deallocate(ptr, capacity); };
598
- std::unique_ptr<T, decltype(items_buffer_deleter)> items_buffer(A().allocate(capacity), items_buffer_deleter);
609
+ auto items_buffer_deleter = [capacity, &alloc](T* ptr) { alloc.deallocate(ptr, capacity); };
610
+ std::unique_ptr<T, decltype(items_buffer_deleter)> items_buffer(alloc.allocate(capacity), items_buffer_deleter);
599
611
  const auto num_items = levels[num_levels] - levels[0];
600
612
  ptr += S().deserialize(ptr, end_ptr - ptr, &items_buffer.get()[levels[0]], num_items);
601
613
  // serde call did not throw, repackage with destrtuctors
602
- std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity));
614
+ std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity, allocator));
603
615
  const size_t delta = ptr - static_cast<const char*>(bytes);
604
616
  if (delta != size) throw std::logic_error("deserialized size mismatch: " + std::to_string(delta) + " != " + std::to_string(size));
605
617
  const bool is_level_zero_sorted = (flags_byte & (1 << flags::IS_LEVEL_ZERO_SORTED)) > 0;
606
618
  if (is_single_item) {
607
619
  new (min_value_buffer.get()) T(items.get()[levels[0]]);
608
620
  // copy did not throw, repackage with destrtuctor
609
- min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter());
621
+ min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter(allocator));
610
622
  new (max_value_buffer.get()) T(items.get()[levels[0]]);
611
623
  // copy did not throw, repackage with destrtuctor
612
- max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter());
624
+ max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter(allocator));
613
625
  }
614
626
  return kll_sketch(k, min_k, n, num_levels, std::move(levels), std::move(items), capacity,
615
627
  std::move(min_value), std::move(max_value), is_level_zero_sorted);
@@ -634,6 +646,7 @@ template<typename T, typename C, typename S, typename A>
634
646
  kll_sketch<T, C, S, A>::kll_sketch(uint16_t k, uint16_t min_k, uint64_t n, uint8_t num_levels, vector_u32<A>&& levels,
635
647
  std::unique_ptr<T, items_deleter> items, uint32_t items_size, std::unique_ptr<T, item_deleter> min_value,
636
648
  std::unique_ptr<T, item_deleter> max_value, bool is_level_zero_sorted):
649
+ allocator_(levels.get_allocator()),
637
650
  k_(k),
638
651
  m_(DEFAULT_M),
639
652
  min_k_(min_k),
@@ -735,9 +748,9 @@ void kll_sketch<T, C, S, A>::add_empty_top_level_to_completely_full_sketch() {
735
748
  const uint32_t new_total_cap = cur_total_cap + delta_cap;
736
749
 
737
750
  // move (and shift) the current data into the new buffer
738
- T* new_buf = A().allocate(new_total_cap);
751
+ T* new_buf = allocator_.allocate(new_total_cap);
739
752
  kll_helper::move_construct<T>(items_, 0, cur_total_cap, new_buf, delta_cap, true);
740
- A().deallocate(items_, items_size_);
753
+ allocator_.deallocate(items_, items_size_);
741
754
  items_ = new_buf;
742
755
  items_size_ = new_total_cap;
743
756
 
@@ -763,19 +776,20 @@ void kll_sketch<T, C, S, A>::sort_level_zero() {
763
776
  template<typename T, typename C, typename S, typename A>
764
777
  std::unique_ptr<kll_quantile_calculator<T, C, A>, std::function<void(kll_quantile_calculator<T, C, A>*)>> kll_sketch<T, C, S, A>::get_quantile_calculator() {
765
778
  sort_level_zero();
766
- typedef typename std::allocator_traits<A>::template rebind_alloc<kll_quantile_calculator<T, C, A>> AllocCalc;
779
+ using AllocCalc = typename std::allocator_traits<A>::template rebind_alloc<kll_quantile_calculator<T, C, A>>;
780
+ AllocCalc alloc(allocator_);
767
781
  std::unique_ptr<kll_quantile_calculator<T, C, A>, std::function<void(kll_quantile_calculator<T, C, A>*)>> quantile_calculator(
768
- new (AllocCalc().allocate(1)) kll_quantile_calculator<T, C, A>(items_, levels_.data(), num_levels_, n_),
769
- [](kll_quantile_calculator<T, C, A>* ptr){ ptr->~kll_quantile_calculator<T, C, A>(); AllocCalc().deallocate(ptr, 1); }
782
+ new (alloc.allocate(1)) kll_quantile_calculator<T, C, A>(items_, levels_.data(), num_levels_, n_, allocator_),
783
+ [&alloc](kll_quantile_calculator<T, C, A>* ptr){ ptr->~kll_quantile_calculator<T, C, A>(); alloc.deallocate(ptr, 1); }
770
784
  );
771
785
  return quantile_calculator;
772
786
  }
773
787
 
774
788
  template<typename T, typename C, typename S, typename A>
775
789
  vector_d<A> kll_sketch<T, C, S, A>::get_PMF_or_CDF(const T* split_points, uint32_t size, bool is_CDF) const {
776
- if (is_empty()) return vector_d<A>();
790
+ if (is_empty()) return vector_d<A>(allocator_);
777
791
  kll_helper::validate_values<T, C>(split_points, size);
778
- vector_d<A> buckets(size + 1, 0);
792
+ vector_d<A> buckets(size + 1, 0, allocator_);
779
793
  uint8_t level = 0;
780
794
  uint64_t weight = 1;
781
795
  while (level < num_levels_) {
@@ -845,12 +859,13 @@ template<typename T, typename C, typename S, typename A>
845
859
  template<typename O>
846
860
  void kll_sketch<T, C, S, A>::merge_higher_levels(O&& other, uint64_t final_n) {
847
861
  const uint32_t tmp_num_items = get_num_retained() + other.get_num_retained_above_level_zero();
848
- auto tmp_items_deleter = [tmp_num_items](T* ptr) { A().deallocate(ptr, tmp_num_items); }; // no destructor needed
849
- const std::unique_ptr<T, decltype(tmp_items_deleter)> workbuf(A().allocate(tmp_num_items), tmp_items_deleter);
862
+ A alloc(allocator_);
863
+ auto tmp_items_deleter = [tmp_num_items, &alloc](T* ptr) { alloc.deallocate(ptr, tmp_num_items); }; // no destructor needed
864
+ const std::unique_ptr<T, decltype(tmp_items_deleter)> workbuf(allocator_.allocate(tmp_num_items), tmp_items_deleter);
850
865
  const uint8_t ub = kll_helper::ub_on_num_levels(final_n);
851
866
  const size_t work_levels_size = ub + 2; // ub+1 does not work
852
- vector_u32<A> worklevels(work_levels_size);
853
- vector_u32<A> outlevels(work_levels_size);
867
+ vector_u32<A> worklevels(work_levels_size, 0, allocator_);
868
+ vector_u32<A> outlevels(work_levels_size, 0, allocator_);
854
869
 
855
870
  const uint8_t provisional_num_levels = std::max(num_levels_, other.num_levels_);
856
871
 
@@ -864,9 +879,9 @@ void kll_sketch<T, C, S, A>::merge_higher_levels(O&& other, uint64_t final_n) {
864
879
 
865
880
  // now we need to transfer the results back into "this" sketch
866
881
  if (result.final_capacity != items_size_) {
867
- A().deallocate(items_, items_size_);
882
+ allocator_.deallocate(items_, items_size_);
868
883
  items_size_ = result.final_capacity;
869
- items_ = A().allocate(items_size_);
884
+ items_ = allocator_.allocate(items_size_);
870
885
  }
871
886
  const uint32_t free_space_at_bottom = result.final_capacity - result.final_num_items;
872
887
  kll_helper::move_construct<T>(workbuf.get(), outlevels[0], outlevels[0] + result.final_num_items, items_, free_space_at_bottom, true);
@@ -1101,29 +1116,32 @@ const std::pair<const T&, const uint64_t> kll_sketch<T, C, S, A>::const_iterator
1101
1116
  template<typename T, typename C, typename S, typename A>
1102
1117
  class kll_sketch<T, C, S, A>::item_deleter {
1103
1118
  public:
1104
- void operator() (T* ptr) const {
1119
+ item_deleter(const A& allocator): allocator_(allocator) {}
1120
+ void operator() (T* ptr) {
1105
1121
  if (ptr != nullptr) {
1106
1122
  ptr->~T();
1107
- A().deallocate(ptr, 1);
1123
+ allocator_.deallocate(ptr, 1);
1108
1124
  }
1109
1125
  }
1126
+ private:
1127
+ A allocator_;
1110
1128
  };
1111
1129
 
1112
1130
  template<typename T, typename C, typename S, typename A>
1113
1131
  class kll_sketch<T, C, S, A>::items_deleter {
1114
1132
  public:
1115
- items_deleter(uint32_t start, uint32_t num): start(start), num(num) {}
1116
- void operator() (T* ptr) const {
1133
+ items_deleter(uint32_t start, uint32_t num, const A& allocator):
1134
+ allocator_(allocator), start_(start), num_(num) {}
1135
+ void operator() (T* ptr) {
1117
1136
  if (ptr != nullptr) {
1118
- for (uint32_t i = start; i < num; ++i) {
1119
- ptr[i].~T();
1120
- }
1121
- A().deallocate(ptr, num);
1137
+ for (uint32_t i = start_; i < num_; ++i) ptr[i].~T();
1138
+ allocator_.deallocate(ptr, num_);
1122
1139
  }
1123
1140
  }
1124
1141
  private:
1125
- uint32_t start;
1126
- uint32_t num;
1142
+ A allocator_;
1143
+ uint32_t start_;
1144
+ uint32_t num_;
1127
1145
  };
1128
1146
 
1129
1147
  } /* namespace datasketches */