Skip to content

Commit 866f6d0

Browse files
MaheshGPaiMahesh Pai
authored andcommitted
Introduced const_iterator for tdigest
1 parent 82630e5 commit 866f6d0

3 files changed

Lines changed: 110 additions & 10 deletions

File tree

tdigest/include/tdigest.hpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,6 @@ class tdigest {
143143
*/
144144
uint64_t get_total_weight() const;
145145

146-
/**
147-
* @return centroids
148-
*/
149-
vector_centroid get_centroids() const;
150-
151146
/**
152147
* Returns an instance of the allocator for this t-Digest.
153148
* @return allocator
@@ -262,6 +257,21 @@ class tdigest {
262257
*/
263258
static tdigest deserialize(const void* bytes, size_t size, const Allocator& allocator = Allocator());
264259

260+
class const_iterator;
261+
262+
/**
263+
* Iterator pointing to the first centroid in the sketch.
264+
* If the sketch is empty, the returned iterator must not be dereferenced or incremented.
265+
* @return iterator pointing to the first centroid in the sketch
266+
*/
267+
const_iterator begin() const;
268+
269+
/**
270+
* Iterator pointing to the past-the-end centroid in the sketch.
271+
* It does not point to any centroid, and must not be dereferenced or incremented.
272+
* @return iterator pointing to the past-the-end centroid in the sketch
273+
*/
274+
const_iterator end() const;
265275
private:
266276
bool reverse_merge_;
267277
uint16_t k_;
@@ -302,6 +312,28 @@ class tdigest {
302312
static inline void check_split_points(const T* values, uint32_t size);
303313
};
304314

315+
template<typename T, typename A>
316+
class tdigest<T, A>::const_iterator {
317+
public:
318+
using iterator_category = std::input_iterator_tag;
319+
using value_type = std::pair<const T&, const W>;
320+
using difference_type = void;
321+
using pointer = const return_value_holder<value_type>;
322+
using reference = const value_type;
323+
324+
const_iterator(const tdigest<T, A> &tdigest_, bool is_end);
325+
326+
const_iterator& operator++();
327+
const_iterator& operator++(int);
328+
bool operator==(const const_iterator& other) const;
329+
bool operator!=(const const_iterator& other) const;
330+
reference operator*() const;
331+
pointer operator->() const;
332+
private:
333+
friend class tdigest<T, A>;
334+
uint32_t index_;
335+
vector_centroid centroids_;
336+
};
305337
} /* namespace datasketches */
306338

307339
#include "tdigest_impl.hpp"

tdigest/include/tdigest_impl.hpp

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,6 @@ uint64_t tdigest<T, A>::get_total_weight() const {
8585
return centroids_weight_ + buffer_.size();
8686
}
8787

88-
template<typename T, typename A>
89-
auto tdigest<T, A>::get_centroids() const -> vector_centroid{
90-
return centroids_;
91-
}
92-
9388
template<typename T, typename A>
9489
A tdigest<T, A>::get_allocator() const {
9590
return buffer_.get_allocator();
@@ -632,6 +627,65 @@ void tdigest<T, A>::check_split_points(const T* values, uint32_t size) {
632627
}
633628
}
634629

630+
template <typename T, typename A>
631+
typename tdigest<T, A>::const_iterator tdigest<T, A>::begin() const {
632+
return tdigest<T, A>::const_iterator(*this, false);
633+
}
634+
635+
template <typename T, typename A>
636+
typename tdigest<T, A>::const_iterator tdigest<T, A>::end() const {
637+
return tdigest::const_iterator(*this, true);
638+
}
639+
640+
template<typename T, typename A>
641+
tdigest<T, A>::const_iterator::const_iterator(const tdigest& tdigest_, const bool is_end):
642+
centroids_()
643+
{
644+
// Create a copy of the tdigest to generate the centroids after processing the buffered values
645+
tdigest tmp(tdigest_);
646+
tmp.compress();
647+
centroids_.insert(centroids_.end(), tmp.centroids_.begin(), tmp.centroids_.end());
648+
649+
if (is_end) {
650+
index_ = centroids_.size();
651+
} else {
652+
index_ = 0;
653+
}
654+
}
655+
656+
template<typename T, typename A>
657+
typename tdigest<T, A>::const_iterator& tdigest<T, A>::const_iterator::operator++() {
658+
++index_;
659+
return *this;
660+
}
661+
662+
template<typename T, typename A>
663+
typename tdigest<T, A>::const_iterator& tdigest<T, A>::const_iterator::operator++(int) {
664+
const_iterator tmp(*this);
665+
operator++();
666+
return tmp;
667+
}
668+
669+
template<typename T, typename A>
670+
bool tdigest<T, A>::const_iterator::operator==(const const_iterator& other) const {
671+
return index_ == other.index_;
672+
}
673+
674+
template<typename T, typename A>
675+
bool tdigest<T, A>::const_iterator::operator!=(const const_iterator& other) const {
676+
return !operator==(other);
677+
}
678+
679+
template<typename T, typename A>
680+
auto tdigest<T, A>::const_iterator::operator*() const -> reference {
681+
return value_type(centroids_[index_].get_mean(), centroids_[index_].get_weight());
682+
}
683+
684+
template<typename T, typename A>
685+
auto tdigest<T, A>::const_iterator::operator->() const -> pointer {
686+
return **this;
687+
}
688+
635689
} /* namespace datasketches */
636690

637691
#endif // _TDIGEST_IMPL_HPP_

tdigest/test/tdigest_test.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,4 +453,18 @@ TEST_CASE("deserialize from reference implementation bytes float", "[tdigest]")
453453
REQUIRE(td.get_rank(n) == 1);
454454
}
455455

456+
TEST_CASE("iterate centroids", "[tdigest]") {
457+
tdigest_double td(100);
458+
for (int i = 0; i < 10; i++) {
459+
td.update(i);
460+
}
461+
462+
auto centroid_count = 0;
463+
for (const auto &centroid: td) {
464+
centroid_count++;
465+
}
466+
// Ensure that centroids are retrieved for a case where there is buffered values
467+
REQUIRE(centroid_count == 10);
468+
}
469+
456470
} /* namespace datasketches */

0 commit comments

Comments
 (0)