use std::ops::Index; use super::prefix_sums; #[derive(Debug, Clone)] pub(super) enum ReferenceMatchedValues { Identical, Owned(Vec), } impl ReferenceMatchedValues { pub(super) fn push(&mut self, value: f64, reference: &[f64], capacity: usize) { let previous_len = reference.len().checked_sub(1).expect("reference row is missing"); match self { Self::Identical if value.to_bits() == reference[previous_len].to_bits() => {} Self::Identical => { let mut values = Vec::with_capacity(capacity); values.extend_from_slice(&reference[..previous_len]); values.push(value); *self = Self::Owned(values); } Self::Owned(values) => { debug_assert_eq!(values.len(), previous_len); values.push(value); } } } pub(super) fn values<'a>(&'a self, reference: &'a [f64]) -> &'a [f64] { match self { Self::Identical => reference, Self::Owned(values) => { debug_assert_eq!(values.len(), reference.len()); values } } } pub(super) fn set(&mut self, index: usize, value: f64, reference: &[f64]) { assert!(index < reference.len(), "series index out of bounds"); match self { Self::Owned(values) => values[index] = value, Self::Identical if value.to_bits() == reference[index].to_bits() => {} Self::Identical => { let mut values = reference.to_vec(); values[index] = value; *self = Self::Owned(values); } } } pub(super) fn prefix(&self) -> Self { match self { Self::Identical => Self::Identical, Self::Owned(values) => Self::Owned(prefix_sums(values)), } } } #[derive(Debug, Clone)] pub(super) struct RepeatedValues { repeated: T, values: Option>, len: usize, } impl RepeatedValues { pub(super) fn new() -> Self { Self { repeated: T::default(), values: None, len: 0 } } pub(super) fn push(&mut self, value: &T, capacity: usize) { if let Some(values) = &mut self.values { values.push(value.clone()); } else if self.len == 0 { self.repeated = value.clone(); } else if *value != self.repeated { let mut values = Vec::with_capacity(capacity); values.resize(self.len, std::mem::take(&mut self.repeated)); values.push(value.clone()); self.values = Some(values); } self.len += 1; } pub(super) fn set(&mut self, index: usize, value: T) { assert!(index < self.len, "series index out of bounds"); if let Some(values) = &mut self.values { values[index] = value; } else if value != self.repeated { let mut values = vec![std::mem::take(&mut self.repeated); self.len]; values[index] = value; self.values = Some(values); } } } impl Index for RepeatedValues { type Output = T; fn index(&self, index: usize) -> &T { assert!(index < self.len, "series index out of bounds"); match &self.values { Some(values) => &values[index], None => &self.repeated, } } } #[cfg(test)] mod tests { use super::*; fn bits(values: &[f64]) -> Vec { values.iter().map(|value| value.to_bits()).collect() } #[test] fn identical_prices_share_only_after_exact_bit_comparison() { let reference = [10., -0., f64::from_bits(0x7ff8_0000_0000_0042), f64::INFINITY]; let mut column = ReferenceMatchedValues::Identical; for (index, value) in reference.iter().copied().enumerate() { column.push(value, &reference[..=index], reference.len()); } assert!(matches!(column, ReferenceMatchedValues::Identical)); assert_eq!(column.values(&reference).as_ptr(), reference.as_ptr()); let prefix = prefix_sums(&reference); assert_eq!(bits(column.prefix().values(&prefix)), bits(&prefix)); let original = column.clone(); column.set(1, 0., &reference); assert!(matches!(column, ReferenceMatchedValues::Owned(_))); assert_eq!(column.values(&reference)[1].to_bits(), 0_f64.to_bits()); assert_eq!(bits(original.values(&reference)), bits(&reference)); assert_eq!(bits(column.prefix().values(&prefix)), bits(&prefix_sums(column.values(&reference)))); } #[test] fn differing_prices_preserve_zero_nan_payloads_and_prior_rows() { let reference = [10., 11., f64::from_bits(0x7ff8_0000_0000_0042), 13.]; for actual in [ [10., 0., reference[2], 13.], [10., 11., f64::from_bits(0x7ff8_0000_0000_0043), 13.], ] { let mut column = ReferenceMatchedValues::Identical; for (index, value) in actual.iter().copied().enumerate() { column.push(value, &reference[..=index], actual.len()); } assert!(matches!(column, ReferenceMatchedValues::Owned(_))); assert_eq!(bits(column.values(&reference)), bits(&actual)); } } #[test] fn repeated_values_preserve_nonzero_values_and_copy_on_change() { let mut column = RepeatedValues::new(); for _ in 0..128 { column.push(&7_u64, 128); } assert!(column.values.is_none()); assert_eq!(column[127], 7); column.set(0, 7); assert!(column.values.is_none()); let mut changed = column.clone(); changed.set(64, 9); assert_eq!(changed[64], 9); assert_eq!(changed[63], 7); assert_eq!(column[64], 7); } #[test] fn optional_values_keep_none_distinct_from_empty_and_repeated_text() { for repeated in [None, Some(String::new()), Some("continuous".to_string())] { let mut column = RepeatedValues::new(); for _ in 0..12 { column.push(&repeated, 16); } assert!(column.values.is_none()); assert_eq!(column[0], repeated); column.push(&Some("closing".to_string()), 16); assert_eq!(column[11], repeated); assert_eq!(column[12].as_deref(), Some("closing")); column.set(5, None); assert_eq!(column[5], None); assert_eq!(column[4], repeated); } } #[test] #[should_panic(expected = "series index out of bounds")] fn repeated_values_reject_out_of_range_access() { let column = RepeatedValues::::new(); let _ = column[0]; } }