hdrhistogram/iterators/
log.rs

1use crate::core::counter::Counter;
2use crate::iterators::{HistogramIterator, PickMetadata, PickyIterator};
3use crate::Histogram;
4
5/// An iterator that will yield at log-size steps through the histogram's value range.
6pub struct Iter<'a, T: 'a + Counter> {
7    hist: &'a Histogram<T>,
8
9    // > 1.0
10    next_value_reporting_level: f64,
11    // > 1.0
12    log_base: f64,
13
14    current_step_lowest_value_reporting_level: u64,
15    current_step_highest_value_reporting_level: u64,
16}
17
18impl<'a, T: 'a + Counter> Iter<'a, T> {
19    /// Construct a new logarithmic iterator. See `Histogram::iter_log` for details.
20    pub fn new(
21        hist: &'a Histogram<T>,
22        value_units_in_first_bucket: u64,
23        log_base: f64,
24    ) -> HistogramIterator<'a, T, Iter<'a, T>> {
25        assert!(
26            value_units_in_first_bucket > 0,
27            "value_units_per_bucket must be > 0"
28        );
29        assert!(log_base > 1.0, "log_base must be > 1.0");
30
31        let new_lowest = hist.lowest_equivalent(value_units_in_first_bucket - 1);
32        HistogramIterator::new(
33            hist,
34            Iter {
35                hist,
36                log_base,
37                next_value_reporting_level: value_units_in_first_bucket as f64,
38                current_step_highest_value_reporting_level: value_units_in_first_bucket - 1,
39                current_step_lowest_value_reporting_level: new_lowest,
40            },
41        )
42    }
43}
44
45impl<'a, T: 'a + Counter> PickyIterator<T> for Iter<'a, T> {
46    fn pick(&mut self, index: usize, _: u64, _: T) -> Option<PickMetadata> {
47        let val = self.hist.value_for(index);
48        if val >= self.current_step_lowest_value_reporting_level || index == self.hist.last_index()
49        {
50            let metadata =
51                PickMetadata::new(None, Some(self.current_step_highest_value_reporting_level));
52            // implies log_base must be > 1.0
53            self.next_value_reporting_level *= self.log_base;
54            // won't underflow since next_value_reporting_level starts > 0 and only grows
55            self.current_step_highest_value_reporting_level =
56                self.next_value_reporting_level as u64 - 1;
57            self.current_step_lowest_value_reporting_level = self
58                .hist
59                .lowest_equivalent(self.current_step_highest_value_reporting_level);
60            Some(metadata)
61        } else {
62            None
63        }
64    }
65
66    fn more(&mut self, index_to_pick: usize) -> bool {
67        // If the next iterate will not move to the next sub bucket index (which is empty if if we
68        // reached this point), then we are not yet done iterating (we want to iterate until we are
69        // no longer on a value that has a count, rather than util we first reach the last value
70        // that has a count. The difference is subtle but important)...
71        self.hist
72            .lowest_equivalent(self.next_value_reporting_level as u64)
73            < self.hist.value_for(index_to_pick)
74    }
75}