refactor: strftime last value equality matcher

Allows the StftimeFormatter to perform an equality match against a
timestamp and the last rendered timestamp, potentially after applying
the precision reduction optimisation if appropriate.
pull/24376/head
Dom Dwyer 2023-06-01 13:07:06 +02:00
parent 3b91cc1e15
commit 60cbf53087
No known key found for this signature in database
GPG Key ID: E4C40DBD9157879A
1 changed files with 37 additions and 8 deletions

View File

@ -22,8 +22,8 @@ const YMD_SPEC: &str = "%Y-%m-%d";
struct RingBuffer<const N: usize, T> { struct RingBuffer<const N: usize, T> {
buf: [Option<T>; N], buf: [Option<T>; N],
/// Index into to the next free/to-be-reused slot. /// Index into to the last wrote value.
next_ptr: usize, last_idx: usize,
} }
impl<const N: usize, T> Default for RingBuffer<N, T> impl<const N: usize, T> Default for RingBuffer<N, T>
@ -33,7 +33,7 @@ where
fn default() -> Self { fn default() -> Self {
Self { Self {
buf: [(); N].map(|_| Default::default()), // default init for non-const type buf: [(); N].map(|_| Default::default()), // default init for non-const type
next_ptr: Default::default(), last_idx: N - 1,
} }
} }
} }
@ -50,11 +50,11 @@ where
/// ///
/// This is an O(1) operation. /// This is an O(1) operation.
fn next_slot(&mut self) -> &mut T { fn next_slot(&mut self) -> &mut T {
let v = self.buf[self.next_ptr].get_or_insert_with(Default::default);
// Advance the next slot pointer // Advance the next slot pointer
self.next_ptr += 1; self.last_idx += 1;
self.next_ptr %= N; self.last_idx %= N;
let v = self.buf[self.last_idx].get_or_insert_with(Default::default);
v v
} }
@ -76,6 +76,11 @@ where
} }
None None
} }
/// Return the last wrote value, if any.
fn last(&self) -> Option<&'_ T> {
self.buf[self.last_idx].as_ref()
}
} }
/// A strftime-like formatter of epoch timestamps with nanosecond granularity. /// A strftime-like formatter of epoch timestamps with nanosecond granularity.
@ -231,6 +236,19 @@ impl<'a> StrftimeFormatter<'a> {
} }
timestamp - (timestamp % DAY_NANOSECONDS) timestamp - (timestamp % DAY_NANOSECONDS)
} }
/// Returns true if the output of rendering `timestamp` will match the last
/// rendered timestamp, after optionally applying the precision reduction
/// optimisation.
pub(crate) fn equals_last(&self, timestamp: i64) -> bool {
// Optionally apply the default format reduction optimisation.
let timestamp = self.maybe_reduce(timestamp);
self.values
.last()
.map(|(ts, _)| *ts == timestamp)
.unwrap_or_default()
}
} }
#[cfg(test)] #[cfg(test)]
@ -286,7 +304,18 @@ mod tests {
fmt.values.buf.as_slice(), fmt.values.buf.as_slice(),
[Some((42, _)), Some((12345, _)), None, None, None] [Some((42, _)), Some((12345, _)), None, None, None]
); );
assert_eq!(fmt.values.next_ptr, 2); assert_eq!(fmt.values.last_idx, 1);
}
#[test]
fn test_ring_buffer_equals_last() {
let mut b = RingBuffer::<4, _>::default();
assert!(b.find(|v| *v == 42).is_none());
*b.next_slot() = 42;
assert_eq!(b.last(), Some(&42));
} }
const FORMATTER_SPEC_PARTS: &[&str] = &[ const FORMATTER_SPEC_PARTS: &[&str] = &[