This is an automated email from the ASF dual-hosted git repository.

alsay pushed a commit to branch kll_no_default_construction
in repository https://gitbox.apache.org/repos/asf/incubator-datasketches-cpp.git


The following commit(s) were added to refs/heads/kll_no_default_construction by 
this push:
     new 7f96aa1  use allocator and no default construction of T in quantiles 
calculator
7f96aa1 is described below

commit 7f96aa1b6d82fd9e4866eba4adf9e5f0c1713836
Author: AlexanderSaydakov <[email protected]>
AuthorDate: Tue Jul 23 15:29:49 2019 -0700

    use allocator and no default construction of T in quantiles calculator
---
 kll/include/kll_helper.hpp              |  5 +--
 kll/include/kll_quantile_calculator.hpp | 59 ++++++++++++++++++++-------------
 kll/include/kll_sketch.hpp              | 48 +++++++++++++--------------
 3 files changed, 62 insertions(+), 50 deletions(-)

diff --git a/kll/include/kll_helper.hpp b/kll/include/kll_helper.hpp
index e39cb7a..67925b1 100644
--- a/kll/include/kll_helper.hpp
+++ b/kll/include/kll_helper.hpp
@@ -349,10 +349,11 @@ class kll_helper {
     }
 
     template<typename T>
-    static void move_construct(T* src, size_t src_first, size_t src_last, T* 
dst, size_t dst_first) {
+    static void move_construct(T* src, size_t src_first, size_t src_last, T* 
dst, size_t dst_first, bool destroy) {
       while (src_first != src_last) {
         new (&dst[dst_first++]) T(std::move(src[src_first]));
-        src[src_first++].~T();
+        if (destroy) src[src_first].~T();
+        src_first++;
       }
     }
 
diff --git a/kll/include/kll_quantile_calculator.hpp 
b/kll/include/kll_quantile_calculator.hpp
index 54801f3..91c906b 100644
--- a/kll/include/kll_quantile_calculator.hpp
+++ b/kll/include/kll_quantile_calculator.hpp
@@ -24,27 +24,34 @@
 #include <cmath>
 #include <assert.h>
 
+#include "kll_helper.hpp"
+
 namespace datasketches {
 
-template <typename T, typename C>
+template <typename T, typename C, typename A>
 class kll_quantile_calculator {
+  typedef typename std::allocator_traits<A>::template rebind_alloc<uint32_t> 
AllocU32;
+  typedef typename std::allocator_traits<A>::template rebind_alloc<uint64_t> 
AllocU64;
   public:
     // assumes that all levels are sorted including level 0
     kll_quantile_calculator(const T* items, const uint32_t* levels, uint8_t 
num_levels, uint64_t n) {
       n_ = n;
-      const uint32_t num_items(levels[num_levels] - levels[0]);
-      items_ = new T[num_items];
-      weights_ = new uint64_t[num_items + 1]; // one more is intentional
-      levels_ = new uint32_t[num_levels + 1];
+      const uint32_t num_items = levels[num_levels] - levels[0];
+      items_ = A().allocate(num_items);
+      weights_ = AllocU64().allocate(num_items + 1); // one more is intentional
+      levels_size_ = num_levels + 1;
+      levels_ = AllocU32().allocate(levels_size_);
       populate_from_sketch(items, num_items, levels, num_levels);
       blocky_tandem_merge_sort(items_, weights_, num_items, levels_, 
num_levels_);
       convert_to_preceding_cummulative(weights_, num_items + 1);
     }
 
     ~kll_quantile_calculator() {
-      delete [] items_;
-      delete [] weights_;
-      delete [] levels_;
+      const uint32_t num_items = levels_[num_levels_] - levels_[0];
+      for (uint32_t i = 0; i < num_items; i++) items_[i].~T();
+      A().deallocate(items_, num_items);
+      AllocU64().deallocate(weights_, num_items + 1);
+      AllocU32().deallocate(levels_, levels_size_);
     }
 
     T get_quantile(double fraction) const {
@@ -56,14 +63,15 @@ class kll_quantile_calculator {
     T* items_;
     uint64_t* weights_;
     uint32_t* levels_;
+    uint8_t levels_size_;
     uint8_t num_levels_;
 
     void populate_from_sketch(const T* items, uint32_t num_items, const 
uint32_t* levels, uint8_t num_levels) {
-      std::copy(&items[levels[0]], &items[levels[num_levels]], items_);
-      uint8_t src_level(0);
-      uint8_t dst_level(0);
-      uint64_t weight(1);
-      uint32_t offset(levels[0]);
+      kll_helper::copy_construct<T>(items, levels[0], levels[num_levels], 
items_, 0);
+      uint8_t src_level = 0;
+      uint8_t dst_level = 0;
+      uint64_t weight = 1;
+      uint32_t offset = levels[0];
       while (src_level < num_levels) {
         const uint32_t from_index(levels[src_level] - offset);
         const uint32_t to_index(levels[src_level + 1] - offset); // exclusive
@@ -123,12 +131,17 @@ class kll_quantile_calculator {
     static void blocky_tandem_merge_sort(T* items, uint64_t* weights, uint32_t 
num_items, const uint32_t* levels, uint8_t num_levels) {
       if (num_levels == 1) return;
 
-      // duplicate the input in preparation for the "ping-pong" copy reduction 
strategy
-      std::unique_ptr<T[]> items_tmp(new T[num_items]);
-      std::copy(items, &items[num_items], items_tmp.get());
-      std::unique_ptr<uint64_t[]> weights_tmp(new uint64_t[num_items]); // 
don't need the extra one here
-      std::copy(weights, &weights[num_items], weights_tmp.get());
-      blocky_tandem_merge_sort_recursion(items_tmp.get(), weights_tmp.get(), 
items, weights, levels, 0, num_levels);
+      // move the input in preparation for the "ping-pong" reduction strategy
+      auto tmp_items_deleter = [num_items](T* ptr) {
+        for (uint32_t i = 0; i < num_items; i++) ptr[i].~T();
+        A().deallocate(ptr, num_items);
+      };
+      std::unique_ptr<T, decltype(tmp_items_deleter)> 
tmp_items(A().allocate(num_items), tmp_items_deleter);
+      kll_helper::move_construct<T>(items, 0, num_items, tmp_items.get(), 0, 
false); // do not destroy since the items will be moved back
+      auto tmp_weights_deleter = [num_items](uint64_t* ptr) { 
AllocU64().deallocate(ptr, num_items); };
+      std::unique_ptr<uint64_t[], decltype(tmp_weights_deleter)> 
tmp_weights(AllocU64().allocate(num_items), tmp_weights_deleter); // don't need 
the extra one here
+      std::copy(weights, &weights[num_items], tmp_weights.get());
+      blocky_tandem_merge_sort_recursion(tmp_items.get(), tmp_weights.get(), 
items, weights, levels, 0, num_levels);
     }
 
     static void blocky_tandem_merge_sort_recursion(T* items_src, uint64_t* 
weights_src, T* items_dst, uint64_t* weights_dst, const uint32_t* levels, 
uint8_t starting_level, uint8_t num_levels) {
@@ -156,21 +169,21 @@ class kll_quantile_calculator {
 
       while ((i_src_1 < to_index_1) and (i_src_2 < to_index_2)) {
         if (C()(items_src[i_src_1], items_src[i_src_2])) {
-          items_dst[i_dst] = items_src[i_src_1];
+          items_dst[i_dst] = std::move(items_src[i_src_1]);
           weights_dst[i_dst] = weights_src[i_src_1];
           i_src_1++;
         } else {
-          items_dst[i_dst] = items_src[i_src_2];
+          items_dst[i_dst] = std::move(items_src[i_src_2]);
           weights_dst[i_dst] = weights_src[i_src_2];
           i_src_2++;
         }
         i_dst++;
       }
       if (i_src_1 < to_index_1) {
-        std::copy(&items_src[i_src_1], &items_src[to_index_1], 
&items_dst[i_dst]);
+        std::move(&items_src[i_src_1], &items_src[to_index_1], 
&items_dst[i_dst]);
         std::copy(&weights_src[i_src_1], &weights_src[to_index_1], 
&weights_dst[i_dst]);
       } else if (i_src_2 < to_index_2) {
-        std::copy(&items_src[i_src_2], &items_src[to_index_2], 
&items_dst[i_dst]);
+        std::move(&items_src[i_src_2], &items_src[to_index_2], 
&items_dst[i_dst]);
         std::copy(&weights_src[i_src_2], &weights_src[to_index_2], 
&weights_dst[i_dst]);
       }
     }
diff --git a/kll/include/kll_sketch.hpp b/kll/include/kll_sketch.hpp
index 350c00b..13fd1e5 100644
--- a/kll/include/kll_sketch.hpp
+++ b/kll/include/kll_sketch.hpp
@@ -290,7 +290,7 @@ class kll_sketch {
     uint8_t find_level_to_compact() const;
     void add_empty_top_level_to_completely_full_sketch();
     void sort_level_zero();
-    std::unique_ptr<kll_quantile_calculator<T, C>> get_quantile_calculator();
+    std::unique_ptr<kll_quantile_calculator<T, C, A>> 
get_quantile_calculator();
     std::unique_ptr<double[]> get_PMF_or_CDF(const T* split_points, uint32_t 
size, bool is_CDF) const;
     void increment_buckets_unsorted_level(uint32_t from_index, uint32_t 
to_index, uint64_t weight,
         const T* split_points, uint32_t size, double* buckets) const;
@@ -306,6 +306,19 @@ class kll_sketch {
     static void check_preamble_ints(uint8_t preamble_ints, uint8_t flags_byte);
     static void check_serial_version(uint8_t serial_version);
     static void check_family_id(uint8_t family_id);
+
+    // implementation for floating point types
+    template<typename TT = T, typename 
std::enable_if<std::is_floating_point<TT>::value, int>::type = 0>
+    static TT get_invalid_value() {
+      return std::numeric_limits<TT>::quiet_NaN();
+    }
+
+    // implementation for all other types
+    template<typename TT = T, typename 
std::enable_if<!std::is_floating_point<TT>::value, int>::type = 0>
+    static TT get_invalid_value() {
+      throw std::runtime_error("getting quantiles from empty sketch is not 
supported for this type of values");
+    }
+
 };
 
 template<typename T, typename C, typename S, typename A>
@@ -475,34 +488,19 @@ bool kll_sketch<T, C, S, A>::is_estimation_mode() const {
 
 template<typename T, typename C, typename S, typename A>
 T kll_sketch<T, C, S, A>::get_min_value() const {
-  if (is_empty()) {
-    if (std::is_floating_point<T>::value) {
-      return std::numeric_limits<T>::quiet_NaN();
-    }
-    throw std::runtime_error("getting quantiles from empty sketch is not 
supported for this type of values");
-  }
+  if (is_empty()) return get_invalid_value();
   return *min_value_;
 }
 
 template<typename T, typename C, typename S, typename A>
 T kll_sketch<T, C, S, A>::get_max_value() const {
-  if (is_empty()) {
-    if (std::is_floating_point<T>::value) {
-      return std::numeric_limits<T>::quiet_NaN();
-    }
-    throw std::runtime_error("getting quantiles from empty sketch is not 
supported for this type of values");
-  }
+  if (is_empty()) return get_invalid_value();
   return *max_value_;
 }
 
 template<typename T, typename C, typename S, typename A>
 T kll_sketch<T, C, S, A>::get_quantile(double fraction) const {
-  if (is_empty()) {
-    if (std::is_floating_point<T>::value) {
-      return std::numeric_limits<T>::quiet_NaN();
-    }
-    throw std::runtime_error("getting quantiles from empty sketch is not 
supported for this type of values");
-  }
+  if (is_empty()) return get_invalid_value();
   if (fraction == 0.0) return *min_value_;
   if (fraction == 1.0) return *max_value_;
   if ((fraction < 0.0) or (fraction > 1.0)) {
@@ -516,7 +514,7 @@ T kll_sketch<T, C, S, A>::get_quantile(double fraction) 
const {
 template<typename T, typename C, typename S, typename A>
 std::unique_ptr<T[]> kll_sketch<T, C, S, A>::get_quantiles(const double* 
fractions, uint32_t size) const {
   if (is_empty()) { return nullptr; }
-  std::unique_ptr<kll_quantile_calculator<T, C>> quantile_calculator;
+  std::unique_ptr<kll_quantile_calculator<T, C, A>> quantile_calculator;
   std::unique_ptr<T[]> quantiles(new T[size]);
   for (uint32_t i = 0; i < size; i++) {
     const double fraction = fractions[i];
@@ -931,9 +929,9 @@ void kll_sketch<T, C, S, A>::sort_level_zero() {
 }
 
 template<typename T, typename C, typename S, typename A>
-std::unique_ptr<kll_quantile_calculator<T, C>> kll_sketch<T, C, S, 
A>::get_quantile_calculator() {
+std::unique_ptr<kll_quantile_calculator<T, C, A>> kll_sketch<T, C, S, 
A>::get_quantile_calculator() {
   sort_level_zero();
-  std::unique_ptr<kll_quantile_calculator<T, C>> quantile_calculator(new 
kll_quantile_calculator<T, C>(items_, levels_, num_levels_, n_));
+  std::unique_ptr<kll_quantile_calculator<T, C, A>> quantile_calculator(new 
kll_quantile_calculator<T, C, A>(items_, levels_, num_levels_, n_));
   return std::move(quantile_calculator);
 }
 
@@ -1037,7 +1035,7 @@ void kll_sketch<T, C, S, A>::merge_higher_levels(const 
kll_sketch& other, uint64
     items_ = A().allocate(items_size_);
   }
   const uint32_t free_space_at_bottom = result.final_capacity - 
result.final_num_items;
-  kll_helper::move_construct<T>(workbuf.get(), outlevels[0], outlevels[0] + 
result.final_num_items, items_, free_space_at_bottom);
+  kll_helper::move_construct<T>(workbuf.get(), outlevels[0], outlevels[0] + 
result.final_num_items, items_, free_space_at_bottom, true);
 
   if (levels_size_ < (result.final_num_levels + 1)) {
     AllocU32().deallocate(levels_, levels_size_);
@@ -1057,7 +1055,7 @@ void kll_sketch<T, C, S, A>::populate_work_arrays(const 
kll_sketch& other, T* wo
   worklevels[0] = 0;
 
   // the level zero data from "other" was already inserted into "this"
-  kll_helper::move_construct<T>(items_, levels_[0], levels_[1], workbuf, 0);
+  kll_helper::move_construct<T>(items_, levels_[0], levels_[1], workbuf, 0, 
true);
   worklevels[1] = safe_level_size(0);
 
   for (uint8_t lvl = 1; lvl < provisional_num_levels; lvl++) {
@@ -1066,7 +1064,7 @@ void kll_sketch<T, C, S, A>::populate_work_arrays(const 
kll_sketch& other, T* wo
     worklevels[lvl + 1] = worklevels[lvl] + self_pop + other_pop;
 
     if ((self_pop > 0) and (other_pop == 0)) {
-      kll_helper::move_construct<T>(items_, levels_[lvl], levels_[lvl] + 
self_pop, workbuf, worklevels[lvl]);
+      kll_helper::move_construct<T>(items_, levels_[lvl], levels_[lvl] + 
self_pop, workbuf, worklevels[lvl], true);
     } else if ((self_pop == 0) and (other_pop > 0)) {
       kll_helper::copy_construct<T>(other.items_, other.levels_[lvl], 
other.levels_[lvl] + other_pop, workbuf, worklevels[lvl]);
     } else if ((self_pop > 0) and (other_pop > 0)) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to