This is an automated email from the ASF dual-hosted git repository. alsay pushed a commit to branch kll_allocator in repository https://gitbox.apache.org/repos/asf/datasketches-cpp.git
commit 9b008b981e779bdfb3a3888784bc221a21530790 Author: AlexanderSaydakov <[email protected]> AuthorDate: Tue Jan 12 14:50:30 2021 -0800 support allocator instance --- kll/include/kll_quantile_calculator.hpp | 2 +- kll/include/kll_quantile_calculator_impl.hpp | 6 +- kll/include/kll_sketch.hpp | 7 +- kll/include/kll_sketch_impl.hpp | 159 +++++++++++++++------------ 4 files changed, 94 insertions(+), 80 deletions(-) diff --git a/kll/include/kll_quantile_calculator.hpp b/kll/include/kll_quantile_calculator.hpp index bc60f26..5114399 100644 --- a/kll/include/kll_quantile_calculator.hpp +++ b/kll/include/kll_quantile_calculator.hpp @@ -28,7 +28,7 @@ template <typename T, typename C, typename A> class kll_quantile_calculator { 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); + kll_quantile_calculator(const T* items, const uint32_t* levels, uint8_t num_levels, uint64_t n, const A& allocator); T get_quantile(double fraction) const; private: diff --git a/kll/include/kll_quantile_calculator_impl.hpp b/kll/include/kll_quantile_calculator_impl.hpp index f580819..23efa4d 100644 --- a/kll/include/kll_quantile_calculator_impl.hpp +++ b/kll/include/kll_quantile_calculator_impl.hpp @@ -29,8 +29,8 @@ namespace datasketches { template <typename T, typename C, typename A> -kll_quantile_calculator<T, C, A>::kll_quantile_calculator(const T* items, const uint32_t* levels, uint8_t num_levels, uint64_t n): -n_(n), levels_(num_levels + 1) +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): +n_(n), levels_(num_levels + 1, 0, allocator), entries_(allocator) { const uint32_t num_items = levels[num_levels] - levels[0]; entries_.reserve(num_items); @@ -116,7 +116,7 @@ uint32_t kll_quantile_calculator<T, C, A>::search_for_chunk_containing_pos(uint6 template <typename T, typename C, typename A> void kll_quantile_calculator<T, C, A>::merge_sorted_blocks(Container& entries, const uint32_t* levels, uint8_t num_levels, uint32_t num_items) { if (num_levels == 1) return; - Container temporary; + Container temporary(entries.get_allocator()); temporary.reserve(num_items); merge_sorted_blocks_direct(entries, temporary, levels, 0, num_levels); } diff --git a/kll/include/kll_sketch.hpp b/kll/include/kll_sketch.hpp index a4530c9..af36ceb 100644 --- a/kll/include/kll_sketch.hpp +++ b/kll/include/kll_sketch.hpp @@ -161,7 +161,7 @@ class kll_sketch { static const uint16_t MIN_K = DEFAULT_M; static const uint16_t MAX_K = (1 << 16) - 1; - explicit kll_sketch(uint16_t k = DEFAULT_K); + explicit kll_sketch(uint16_t k = DEFAULT_K, const A& allocator = A()); kll_sketch(const kll_sketch& other); kll_sketch(kll_sketch&& other) noexcept; ~kll_sketch(); @@ -401,7 +401,7 @@ class kll_sketch { * @param is input stream * @return an instance of a sketch */ - static kll_sketch deserialize(std::istream& is); + static kll_sketch<T, C, S, A> deserialize(std::istream& is, const A& allocator = A()); /** * This method deserializes a sketch from a given array of bytes. @@ -409,7 +409,7 @@ class kll_sketch { * @param size the size of the array * @return an instance of a sketch */ - static kll_sketch deserialize(const void* bytes, size_t size); + static kll_sketch<T, C, S, A> deserialize(const void* bytes, size_t size, const A& allocator = A()); /* * Gets the normalized rank error given k and pmf. @@ -461,6 +461,7 @@ class kll_sketch { static const uint8_t PREAMBLE_INTS_SHORT = 2; // for empty and single item static const uint8_t PREAMBLE_INTS_FULL = 5; + A allocator_; uint16_t k_; uint8_t m_; // minimum buffer "width" uint16_t min_k_; // for error estimation after merging with different k diff --git a/kll/include/kll_sketch_impl.hpp b/kll/include/kll_sketch_impl.hpp index f0c5ff3..c1e620a 100644 --- a/kll/include/kll_sketch_impl.hpp +++ b/kll/include/kll_sketch_impl.hpp @@ -30,13 +30,14 @@ namespace datasketches { template<typename T, typename C, typename S, typename A> -kll_sketch<T, C, S, A>::kll_sketch(uint16_t k): +kll_sketch<T, C, S, A>::kll_sketch(uint16_t k, const A& allocator): +allocator_(allocator), k_(k), m_(DEFAULT_M), min_k_(k), n_(0), num_levels_(1), -levels_(2), +levels_(2, 0, allocator), items_(nullptr), items_size_(k_), min_value_(nullptr), @@ -47,11 +48,12 @@ is_level_zero_sorted_(false) throw std::invalid_argument("K must be >= " + std::to_string(MIN_K) + " and <= " + std::to_string(MAX_K) + ": " + std::to_string(k)); } levels_[0] = levels_[1] = k; - items_ = A().allocate(items_size_); + items_ = allocator_.allocate(items_size_); } template<typename T, typename C, typename S, typename A> kll_sketch<T, C, S, A>::kll_sketch(const kll_sketch& other): +allocator_(other.allocator_), k_(other.k_), m_(other.m_), min_k_(other.min_k_), @@ -64,14 +66,15 @@ min_value_(nullptr), max_value_(nullptr), is_level_zero_sorted_(other.is_level_zero_sorted_) { - items_ = A().allocate(items_size_); + items_ = allocator_.allocate(items_size_); std::copy(&other.items_[levels_[0]], &other.items_[levels_[num_levels_]], &items_[levels_[0]]); - if (other.min_value_ != nullptr) min_value_ = new (A().allocate(1)) T(*other.min_value_); - if (other.max_value_ != nullptr) max_value_ = new (A().allocate(1)) T(*other.max_value_); + if (other.min_value_ != nullptr) min_value_ = new (allocator_.allocate(1)) T(*other.min_value_); + if (other.max_value_ != nullptr) max_value_ = new (allocator_.allocate(1)) T(*other.max_value_); } template<typename T, typename C, typename S, typename A> kll_sketch<T, C, S, A>::kll_sketch(kll_sketch&& other) noexcept: +allocator_(std::move(other.allocator_)), k_(other.k_), m_(other.m_), min_k_(other.min_k_), @@ -91,7 +94,8 @@ is_level_zero_sorted_(other.is_level_zero_sorted_) template<typename T, typename C, typename S, typename A> kll_sketch<T, C, S, A>& kll_sketch<T, C, S, A>::operator=(const kll_sketch& other) { - kll_sketch copy(other); + kll_sketch<T, C, S, A> copy(other); + std::swap(allocator_, copy.allocator_); std::swap(k_, copy.k_); std::swap(m_, copy.m_); 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 template<typename T, typename C, typename S, typename A> kll_sketch<T, C, S, A>& kll_sketch<T, C, S, A>::operator=(kll_sketch&& other) { + std::swap(allocator_, other.allocator_); std::swap(k_, other.k_); std::swap(m_, other.m_); std::swap(min_k_, other.min_k_); @@ -128,15 +133,15 @@ kll_sketch<T, C, S, A>::~kll_sketch() { const uint32_t begin = levels_[0]; const uint32_t end = levels_[num_levels_]; for (uint32_t i = begin; i < end; i++) items_[i].~T(); - A().deallocate(items_, items_size_); + allocator_.deallocate(items_, items_size_); } if (min_value_ != nullptr) { min_value_->~T(); - A().deallocate(min_value_, 1); + allocator_.deallocate(min_value_, 1); } if (max_value_ != nullptr) { max_value_->~T(); - A().deallocate(max_value_, 1); + allocator_.deallocate(max_value_, 1); } } @@ -159,8 +164,8 @@ void kll_sketch<T, C, S, A>::update(T&& value) { template<typename T, typename C, typename S, typename A> void kll_sketch<T, C, S, A>::update_min_max(const T& value) { if (is_empty()) { - min_value_ = new (A().allocate(1)) T(value); - max_value_ = new (A().allocate(1)) T(value); + min_value_ = new (allocator_.allocate(1)) T(value); + max_value_ = new (allocator_.allocate(1)) T(value); } else { if (C()(value, *min_value_)) *min_value_ = value; if (C()(*max_value_, value)) *max_value_ = value; @@ -182,8 +187,8 @@ void kll_sketch<T, C, S, A>::merge(const kll_sketch& other) { throw std::invalid_argument("incompatible M: " + std::to_string(m_) + " and " + std::to_string(other.m_)); } if (is_empty()) { - min_value_ = new (A().allocate(1)) T(*other.min_value_); - max_value_ = new (A().allocate(1)) T(*other.max_value_); + min_value_ = new (allocator_.allocate(1)) T(*other.min_value_); + max_value_ = new (allocator_.allocate(1)) T(*other.max_value_); } else { if (C()(*other.min_value_, *min_value_)) *min_value_ = *other.min_value_; 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) { throw std::invalid_argument("incompatible M: " + std::to_string(m_) + " and " + std::to_string(other.m_)); } if (is_empty()) { - min_value_ = new (A().allocate(1)) T(std::move(*other.min_value_)); - max_value_ = new (A().allocate(1)) T(std::move(*other.max_value_)); + min_value_ = new (allocator_.allocate(1)) T(std::move(*other.min_value_)); + max_value_ = new (allocator_.allocate(1)) T(std::move(*other.max_value_)); } else { if (C()(*other.min_value_, *min_value_)) *min_value_ = std::move(*other.min_value_); if (C()(*max_value_, *other.max_value_)) *max_value_ = std::move(*other.max_value_); @@ -270,8 +275,7 @@ T kll_sketch<T, C, S, A>::get_quantile(double fraction) const { template<typename T, typename C, typename S, typename A> std::vector<T, A> kll_sketch<T, C, S, A>::get_quantiles(const double* fractions, uint32_t size) const { - std::vector<T, A> quantiles; - quantiles.reserve(size); + std::vector<T, A> quantiles(allocator_); if (is_empty()) return quantiles; std::unique_ptr<kll_quantile_calculator<T, C, A>, std::function<void(kll_quantile_calculator<T, C, A>*)>> quantile_calculator; quantiles.reserve(size); @@ -295,11 +299,11 @@ std::vector<T, A> kll_sketch<T, C, S, A>::get_quantiles(const double* fractions, template<typename T, typename C, typename S, typename A> std::vector<T, A> kll_sketch<T, C, S, A>::get_quantiles(size_t num) const { - if (is_empty()) return std::vector<T, A>(); + if (is_empty()) return std::vector<T, A>(allocator_); if (num == 0) { throw std::invalid_argument("num must be > 0"); } - std::vector<double> fractions(num); + vector_d<A> fractions(num, 0, allocator_); fractions[0] = 0.0; for (size_t i = 1; i < num; i++) { fractions[i] = static_cast<double>(i) / (num - 1); @@ -411,7 +415,7 @@ template<typename T, typename C, typename S, typename A> vector_u8<A> kll_sketch<T, C, S, A>::serialize(unsigned header_size_bytes) const { const bool is_single_item = n_ == 1; const size_t size = header_size_bytes + get_serialized_size_bytes(); - vector_u8<A> bytes(size); + vector_u8<A> bytes(size, 0, allocator_); uint8_t* ptr = bytes.data() + header_size_bytes; const uint8_t* end_ptr = ptr + size; const uint8_t preamble_ints(is_empty() || is_single_item ? PREAMBLE_INTS_SHORT : PREAMBLE_INTS_FULL); @@ -449,7 +453,7 @@ vector_u8<A> kll_sketch<T, C, S, A>::serialize(unsigned header_size_bytes) const } template<typename T, typename C, typename S, typename A> -kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is) { +kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is, const A& allocator) { uint8_t preamble_ints; is.read((char*)&preamble_ints, sizeof(preamble_ints)); uint8_t serial_version; @@ -472,7 +476,7 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is) { if (!is.good()) throw std::runtime_error("error reading from std::istream"); const bool is_empty(flags_byte & (1 << flags::IS_EMPTY)); - if (is_empty) return kll_sketch(k); + if (is_empty) return kll_sketch(k, allocator); uint64_t n; uint16_t min_k; @@ -488,7 +492,7 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is) { is.read((char*)&num_levels, sizeof(num_levels)); is.read((char*)&unused, sizeof(unused)); } - vector_u32<A> levels(num_levels + 1); + vector_u32<A> levels(num_levels + 1, 0, allocator); const uint32_t capacity(kll_helper::compute_total_capacity(k, m, num_levels)); if (is_single_item) { levels[0] = capacity - 1; @@ -497,41 +501,43 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(std::istream& is) { is.read((char*)levels.data(), sizeof(levels[0]) * num_levels); } levels[num_levels] = capacity; - auto item_buffer_deleter = [](T* ptr) { A().deallocate(ptr, 1); }; - std::unique_ptr<T, decltype(item_buffer_deleter)> min_value_buffer(A().allocate(1), item_buffer_deleter); - std::unique_ptr<T, decltype(item_buffer_deleter)> max_value_buffer(A().allocate(1), item_buffer_deleter); - std::unique_ptr<T, item_deleter> min_value; - std::unique_ptr<T, item_deleter> max_value; + A alloc(allocator); + auto item_buffer_deleter = [&alloc](T* ptr) { alloc.deallocate(ptr, 1); }; + std::unique_ptr<T, decltype(item_buffer_deleter)> min_value_buffer(alloc.allocate(1), item_buffer_deleter); + std::unique_ptr<T, decltype(item_buffer_deleter)> max_value_buffer(alloc.allocate(1), item_buffer_deleter); + std::unique_ptr<T, item_deleter> min_value(nullptr, item_deleter(allocator)); + std::unique_ptr<T, item_deleter> max_value(nullptr, item_deleter(allocator)); if (!is_single_item) { S().deserialize(is, min_value_buffer.get(), 1); // serde call did not throw, repackage with destrtuctor - min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter()); + min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter(allocator)); S().deserialize(is, max_value_buffer.get(), 1); // serde call did not throw, repackage with destrtuctor - max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter()); + max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter(allocator)); } auto items_buffer_deleter = [capacity](T* ptr) { A().deallocate(ptr, capacity); }; std::unique_ptr<T, decltype(items_buffer_deleter)> items_buffer(A().allocate(capacity), items_buffer_deleter); const auto num_items = levels[num_levels] - levels[0]; S().deserialize(is, &items_buffer.get()[levels[0]], num_items); // serde call did not throw, repackage with destrtuctors - std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity)); + std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity, allocator)); const bool is_level_zero_sorted = (flags_byte & (1 << flags::IS_LEVEL_ZERO_SORTED)) > 0; if (is_single_item) { new (min_value_buffer.get()) T(items.get()[levels[0]]); // copy did not throw, repackage with destrtuctor - min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter()); + min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter(allocator)); new (max_value_buffer.get()) T(items.get()[levels[0]]); // copy did not throw, repackage with destrtuctor - max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter()); + max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter(allocator)); } - if (!is.good()) throw std::runtime_error("error reading from std::istream"); + if (!is.good()) + throw std::runtime_error("error reading from std::istream"); return kll_sketch(k, min_k, n, num_levels, std::move(levels), std::move(items), capacity, std::move(min_value), std::move(max_value), is_level_zero_sorted); } template<typename T, typename C, typename S, typename A> -kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, size_t size) { +kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, size_t size, const A& allocator) { ensure_minimum_memory(size, 8); const char* ptr = static_cast<const char*>(bytes); uint8_t preamble_ints; @@ -555,7 +561,7 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, si ensure_minimum_memory(size, 1 << preamble_ints); const bool is_empty(flags_byte & (1 << flags::IS_EMPTY)); - if (is_empty) return kll_sketch<T, C, S, A>(k); + if (is_empty) return kll_sketch<T, C, S, A>(k, allocator); uint64_t n; uint16_t min_k; @@ -572,7 +578,7 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, si ptr += copy_from_mem(ptr, &num_levels, sizeof(num_levels)); ptr++; // skip unused byte } - vector_u32<A> levels(num_levels + 1); + vector_u32<A> levels(num_levels + 1, 0, allocator); const uint32_t capacity(kll_helper::compute_total_capacity(k, m, num_levels)); if (is_single_item) { levels[0] = capacity - 1; @@ -581,35 +587,36 @@ kll_sketch<T, C, S, A> kll_sketch<T, C, S, A>::deserialize(const void* bytes, si ptr += copy_from_mem(ptr, levels.data(), sizeof(levels[0]) * num_levels); } levels[num_levels] = capacity; - auto item_buffer_deleter = [](T* ptr) { A().deallocate(ptr, 1); }; - std::unique_ptr<T, decltype(item_buffer_deleter)> min_value_buffer(A().allocate(1), item_buffer_deleter); - std::unique_ptr<T, decltype(item_buffer_deleter)> max_value_buffer(A().allocate(1), item_buffer_deleter); - std::unique_ptr<T, item_deleter> min_value; - std::unique_ptr<T, item_deleter> max_value; + A alloc(allocator); + auto item_buffer_deleter = [&alloc](T* ptr) { alloc.deallocate(ptr, 1); }; + std::unique_ptr<T, decltype(item_buffer_deleter)> min_value_buffer(alloc.allocate(1), item_buffer_deleter); + std::unique_ptr<T, decltype(item_buffer_deleter)> max_value_buffer(alloc.allocate(1), item_buffer_deleter); + std::unique_ptr<T, item_deleter> min_value(nullptr, item_deleter(allocator)); + std::unique_ptr<T, item_deleter> max_value(nullptr, item_deleter(allocator)); if (!is_single_item) { ptr += S().deserialize(ptr, end_ptr - ptr, min_value_buffer.get(), 1); // serde call did not throw, repackage with destrtuctor - min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter()); + min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter(allocator)); ptr += S().deserialize(ptr, end_ptr - ptr, max_value_buffer.get(), 1); // serde call did not throw, repackage with destrtuctor - max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter()); + max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter(allocator)); } - auto items_buffer_deleter = [capacity](T* ptr) { A().deallocate(ptr, capacity); }; - std::unique_ptr<T, decltype(items_buffer_deleter)> items_buffer(A().allocate(capacity), items_buffer_deleter); + auto items_buffer_deleter = [capacity, &alloc](T* ptr) { alloc.deallocate(ptr, capacity); }; + std::unique_ptr<T, decltype(items_buffer_deleter)> items_buffer(alloc.allocate(capacity), items_buffer_deleter); const auto num_items = levels[num_levels] - levels[0]; ptr += S().deserialize(ptr, end_ptr - ptr, &items_buffer.get()[levels[0]], num_items); // serde call did not throw, repackage with destrtuctors - std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity)); + std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity, allocator)); const size_t delta = ptr - static_cast<const char*>(bytes); if (delta != size) throw std::logic_error("deserialized size mismatch: " + std::to_string(delta) + " != " + std::to_string(size)); const bool is_level_zero_sorted = (flags_byte & (1 << flags::IS_LEVEL_ZERO_SORTED)) > 0; if (is_single_item) { new (min_value_buffer.get()) T(items.get()[levels[0]]); // copy did not throw, repackage with destrtuctor - min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter()); + min_value = std::unique_ptr<T, item_deleter>(min_value_buffer.release(), item_deleter(allocator)); new (max_value_buffer.get()) T(items.get()[levels[0]]); // copy did not throw, repackage with destrtuctor - max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter()); + max_value = std::unique_ptr<T, item_deleter>(max_value_buffer.release(), item_deleter(allocator)); } return kll_sketch(k, min_k, n, num_levels, std::move(levels), std::move(items), capacity, std::move(min_value), std::move(max_value), is_level_zero_sorted); @@ -634,6 +641,7 @@ template<typename T, typename C, typename S, typename A> 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, std::unique_ptr<T, items_deleter> items, uint32_t items_size, std::unique_ptr<T, item_deleter> min_value, std::unique_ptr<T, item_deleter> max_value, bool is_level_zero_sorted): +allocator_(levels.get_allocator()), k_(k), m_(DEFAULT_M), min_k_(min_k), @@ -735,9 +743,9 @@ void kll_sketch<T, C, S, A>::add_empty_top_level_to_completely_full_sketch() { const uint32_t new_total_cap = cur_total_cap + delta_cap; // move (and shift) the current data into the new buffer - T* new_buf = A().allocate(new_total_cap); + T* new_buf = allocator_.allocate(new_total_cap); kll_helper::move_construct<T>(items_, 0, cur_total_cap, new_buf, delta_cap, true); - A().deallocate(items_, items_size_); + allocator_.deallocate(items_, items_size_); items_ = new_buf; items_size_ = new_total_cap; @@ -763,19 +771,20 @@ 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, A>, std::function<void(kll_quantile_calculator<T, C, A>*)>> kll_sketch<T, C, S, A>::get_quantile_calculator() { sort_level_zero(); - typedef typename std::allocator_traits<A>::template rebind_alloc<kll_quantile_calculator<T, C, A>> AllocCalc; + using AllocCalc = typename std::allocator_traits<A>::template rebind_alloc<kll_quantile_calculator<T, C, A>>; + AllocCalc alloc(allocator_); std::unique_ptr<kll_quantile_calculator<T, C, A>, std::function<void(kll_quantile_calculator<T, C, A>*)>> quantile_calculator( - new (AllocCalc().allocate(1)) kll_quantile_calculator<T, C, A>(items_, levels_.data(), num_levels_, n_), - [](kll_quantile_calculator<T, C, A>* ptr){ ptr->~kll_quantile_calculator<T, C, A>(); AllocCalc().deallocate(ptr, 1); } + new (alloc.allocate(1)) kll_quantile_calculator<T, C, A>(items_, levels_.data(), num_levels_, n_, allocator_), + [&alloc](kll_quantile_calculator<T, C, A>* ptr){ ptr->~kll_quantile_calculator<T, C, A>(); alloc.deallocate(ptr, 1); } ); return quantile_calculator; } template<typename T, typename C, typename S, typename A> vector_d<A> kll_sketch<T, C, S, A>::get_PMF_or_CDF(const T* split_points, uint32_t size, bool is_CDF) const { - if (is_empty()) return vector_d<A>(); + if (is_empty()) return vector_d<A>(allocator_); kll_helper::validate_values<T, C>(split_points, size); - vector_d<A> buckets(size + 1, 0); + vector_d<A> buckets(size + 1, 0, allocator_); uint8_t level = 0; uint64_t weight = 1; while (level < num_levels_) { @@ -845,12 +854,13 @@ template<typename T, typename C, typename S, typename A> template<typename O> void kll_sketch<T, C, S, A>::merge_higher_levels(O&& other, uint64_t final_n) { const uint32_t tmp_num_items = get_num_retained() + other.get_num_retained_above_level_zero(); - auto tmp_items_deleter = [tmp_num_items](T* ptr) { A().deallocate(ptr, tmp_num_items); }; // no destructor needed - const std::unique_ptr<T, decltype(tmp_items_deleter)> workbuf(A().allocate(tmp_num_items), tmp_items_deleter); + A alloc(allocator_); + auto tmp_items_deleter = [tmp_num_items, &alloc](T* ptr) { alloc.deallocate(ptr, tmp_num_items); }; // no destructor needed + const std::unique_ptr<T, decltype(tmp_items_deleter)> workbuf(allocator_.allocate(tmp_num_items), tmp_items_deleter); const uint8_t ub = kll_helper::ub_on_num_levels(final_n); const size_t work_levels_size = ub + 2; // ub+1 does not work - vector_u32<A> worklevels(work_levels_size); - vector_u32<A> outlevels(work_levels_size); + vector_u32<A> worklevels(work_levels_size, 0, allocator_); + vector_u32<A> outlevels(work_levels_size, 0, allocator_); const uint8_t provisional_num_levels = std::max(num_levels_, other.num_levels_); @@ -864,9 +874,9 @@ void kll_sketch<T, C, S, A>::merge_higher_levels(O&& other, uint64_t final_n) { // now we need to transfer the results back into "this" sketch if (result.final_capacity != items_size_) { - A().deallocate(items_, items_size_); + allocator_.deallocate(items_, items_size_); items_size_ = result.final_capacity; - items_ = A().allocate(items_size_); + items_ = allocator_.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, true); @@ -1101,29 +1111,32 @@ const std::pair<const T&, const uint64_t> kll_sketch<T, C, S, A>::const_iterator template<typename T, typename C, typename S, typename A> class kll_sketch<T, C, S, A>::item_deleter { public: - void operator() (T* ptr) const { + item_deleter(const A& allocator): allocator_(allocator) {} + void operator() (T* ptr) { if (ptr != nullptr) { ptr->~T(); - A().deallocate(ptr, 1); + allocator_.deallocate(ptr, 1); } } + private: + A allocator_; }; template<typename T, typename C, typename S, typename A> class kll_sketch<T, C, S, A>::items_deleter { public: - items_deleter(uint32_t start, uint32_t num): start(start), num(num) {} - void operator() (T* ptr) const { + items_deleter(uint32_t start, uint32_t num, const A& allocator): + allocator_(allocator), start_(start), num_(num) {} + void operator() (T* ptr) { if (ptr != nullptr) { - for (uint32_t i = start; i < num; ++i) { - ptr[i].~T(); - } - A().deallocate(ptr, num); + for (uint32_t i = start_; i < num_; ++i) ptr[i].~T(); + allocator_.deallocate(ptr, num_); } } private: - uint32_t start; - uint32_t num; + A allocator_; + uint32_t start_; + uint32_t num_; }; } /* namespace datasketches */ --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
