use core::counter::Counter;
use Histogram;
pub mod quantile;
pub mod linear;
pub mod log;
pub mod recorded;
pub mod all;
pub struct PickMetadata {
quantile_iterated_to: Option<f64>,
value_iterated_to: Option<u64>,
}
impl PickMetadata {
fn new(quantile_iterated_to: Option<f64>, value_iterated_to: Option<u64>) -> PickMetadata {
PickMetadata {
quantile_iterated_to,
value_iterated_to,
}
}
}
pub trait PickyIterator<T: Counter> {
fn pick(
&mut self,
index: usize,
total_count_to_index: u64,
count_at_index: T,
) -> Option<PickMetadata>;
fn more(&mut self, index_to_pick: usize) -> bool;
}
pub struct HistogramIterator<'a, T: 'a + Counter, P: PickyIterator<T>> {
hist: &'a Histogram<T>,
total_count_to_index: u64,
count_since_last_iteration: u64,
count_at_index: T,
current_index: usize,
last_picked_index: usize,
max_value_index: usize,
fresh: bool,
ended: bool,
picker: P,
}
#[derive(Debug, PartialEq)]
pub struct IterationValue<T: Counter> {
value_iterated_to: u64,
quantile: f64,
quantile_iterated_to: f64,
count_at_value: T,
count_since_last_iteration: u64,
}
impl<T: Counter> IterationValue<T> {
pub fn new(
value_iterated_to: u64,
quantile: f64,
quantile_iterated_to: f64,
count_at_value: T,
count_since_last_iteration: u64,
) -> IterationValue<T> {
IterationValue {
value_iterated_to,
quantile,
quantile_iterated_to,
count_at_value,
count_since_last_iteration,
}
}
pub fn value_iterated_to(&self) -> u64 {
self.value_iterated_to
}
pub fn percentile(&self) -> f64 {
self.quantile * 100.0
}
pub fn quantile(&self) -> f64 {
self.quantile
}
pub fn quantile_iterated_to(&self) -> f64 {
self.quantile_iterated_to
}
pub fn count_at_value(&self) -> T {
self.count_at_value
}
pub fn count_since_last_iteration(&self) -> u64 {
self.count_since_last_iteration
}
}
impl<'a, T: Counter, P: PickyIterator<T>> HistogramIterator<'a, T, P> {
fn new(h: &'a Histogram<T>, picker: P) -> HistogramIterator<'a, T, P> {
HistogramIterator {
hist: h,
total_count_to_index: 0,
count_since_last_iteration: 0,
count_at_index: T::zero(),
current_index: 0,
last_picked_index: 0,
max_value_index: h.index_for(h.max()).expect("Either 0 or an existing index"),
picker,
fresh: true,
ended: false,
}
}
}
impl<'a, T: 'a, P> Iterator for HistogramIterator<'a, T, P>
where
T: Counter,
P: PickyIterator<T>,
{
type Item = IterationValue<T>;
fn next(&mut self) -> Option<Self::Item> {
while !self.ended {
if self.current_index == self.hist.distinct_values() {
self.ended = true;
return None;
}
if self.last_picked_index >= self.max_value_index {
if !self.picker.more(self.current_index) {
self.ended = true;
return None;
}
} else {
assert!(self.current_index < self.hist.distinct_values());
if self.fresh {
self.count_at_index = self.hist
.count_at_index(self.current_index)
.expect("Already checked that current_index is < counts len");
self.total_count_to_index = self.total_count_to_index
.saturating_add(self.count_at_index.as_u64());
self.count_since_last_iteration = self.count_since_last_iteration
.saturating_add(self.count_at_index.as_u64());
self.fresh = false;
}
}
if let Some(metadata) = self.picker.pick(
self.current_index,
self.total_count_to_index,
self.count_at_index,
) {
let quantile = self.total_count_to_index as f64 / self.hist.len() as f64;
let val = IterationValue {
value_iterated_to: metadata.value_iterated_to.unwrap_or_else(|| {
self.hist
.highest_equivalent(self.hist.value_for(self.current_index))
}),
quantile,
quantile_iterated_to: metadata.quantile_iterated_to.unwrap_or(quantile),
count_at_value: self.hist
.count_at_index(self.current_index)
.expect("current index cannot exceed counts length"),
count_since_last_iteration: self.count_since_last_iteration,
};
self.count_since_last_iteration = 0;
self.last_picked_index = self.current_index;
return Some(val);
}
self.current_index += 1;
self.fresh = true;
}
None
}
}