velora_ta/utils/
circular_buffer.rs1use std::ops::Add;
7
8#[derive(Debug, Clone)]
29pub struct CircularBuffer<T> {
30 data: Vec<T>,
31 capacity: usize,
32 head: usize,
33 size: usize,
34}
35
36impl<T: Copy + Default> CircularBuffer<T> {
37 pub fn new(capacity: usize) -> Self {
47 assert!(capacity > 0, "Capacity must be greater than 0");
48 Self {
49 data: vec![T::default(); capacity],
50 capacity,
51 head: 0,
52 size: 0,
53 }
54 }
55
56 pub fn push(&mut self, value: T) {
60 self.data[self.head] = value;
61 self.head = (self.head + 1) % self.capacity;
62 if self.size < self.capacity {
63 self.size += 1;
64 }
65 }
66
67 pub fn get(&self, index: usize) -> Option<T> {
72 if index >= self.size {
73 return None;
74 }
75 let actual_index = (self.head + self.capacity - self.size + index) % self.capacity;
76 Some(self.data[actual_index])
77 }
78
79 pub fn last(&self) -> Option<T> {
81 if self.size == 0 {
82 return None;
83 }
84 let index = (self.head + self.capacity - 1) % self.capacity;
85 Some(self.data[index])
86 }
87
88 pub fn first(&self) -> Option<T> {
90 if self.size == 0 {
91 return None;
92 }
93 self.get(0)
94 }
95
96 pub fn is_full(&self) -> bool {
98 self.size == self.capacity
99 }
100
101 pub fn is_empty(&self) -> bool {
103 self.size == 0
104 }
105
106 pub fn len(&self) -> usize {
108 self.size
109 }
110
111 pub fn capacity(&self) -> usize {
113 self.capacity
114 }
115
116 pub fn clear(&mut self) {
118 self.head = 0;
119 self.size = 0;
120 }
121
122 pub fn iter(&self) -> CircularBufferIter<'_, T> {
124 CircularBufferIter {
125 buffer: self,
126 index: 0,
127 }
128 }
129
130 pub fn as_slice(&self) -> Vec<T> {
135 self.iter().copied().collect()
136 }
137}
138
139impl<T> CircularBuffer<T>
141where
142 T: Copy + Default + Add<Output = T> + PartialOrd,
143{
144 pub fn sum(&self) -> T
146 where
147 T: Add<Output = T> + Default,
148 {
149 self.iter().fold(T::default(), |acc, &x| acc + x)
150 }
151
152 pub fn max(&self) -> Option<T> {
156 if self.is_empty() {
157 return None;
158 }
159 self.iter()
160 .copied()
161 .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
162 }
163
164 pub fn min(&self) -> Option<T> {
168 if self.is_empty() {
169 return None;
170 }
171 self.iter()
172 .copied()
173 .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
174 }
175}
176
177impl CircularBuffer<f64> {
178 pub fn mean(&self) -> Option<f64> {
182 if self.is_empty() {
183 return None;
184 }
185 Some(self.sum() / self.size as f64)
186 }
187
188 pub fn variance(&self) -> Option<f64> {
192 if self.is_empty() {
193 return None;
194 }
195 let mean = self.mean()?;
196 let sum_squared_diff: f64 = self.iter().map(|&x| (x - mean).powi(2)).sum();
197 Some(sum_squared_diff / self.size as f64)
198 }
199
200 pub fn std_dev(&self) -> Option<f64> {
204 self.variance().map(|v| v.sqrt())
205 }
206}
207
208#[derive(Debug)]
210pub struct CircularBufferIter<'a, T> {
211 buffer: &'a CircularBuffer<T>,
212 index: usize,
213}
214
215impl<'a, T: Copy> Iterator for CircularBufferIter<'a, T> {
216 type Item = &'a T;
217
218 fn next(&mut self) -> Option<Self::Item> {
219 if self.index >= self.buffer.size {
220 return None;
221 }
222 let actual_index = (self.buffer.head + self.buffer.capacity - self.buffer.size
223 + self.index)
224 % self.buffer.capacity;
225 self.index += 1;
226 Some(&self.buffer.data[actual_index])
227 }
228
229 fn size_hint(&self) -> (usize, Option<usize>) {
230 let remaining = self.buffer.size - self.index;
231 (remaining, Some(remaining))
232 }
233}
234
235impl<'a, T: Copy> ExactSizeIterator for CircularBufferIter<'a, T> {}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240
241 #[test]
242 fn test_new_buffer() {
243 let buffer: CircularBuffer<f64> = CircularBuffer::new(5);
244 assert_eq!(buffer.capacity(), 5);
245 assert_eq!(buffer.len(), 0);
246 assert!(buffer.is_empty());
247 assert!(!buffer.is_full());
248 }
249
250 #[test]
251 #[should_panic(expected = "Capacity must be greater than 0")]
252 fn test_zero_capacity_panics() {
253 let _buffer: CircularBuffer<f64> = CircularBuffer::new(0);
254 }
255
256 #[test]
257 fn test_push_and_get() {
258 let mut buffer = CircularBuffer::new(3);
259 buffer.push(10.0);
260 buffer.push(20.0);
261 buffer.push(30.0);
262
263 assert_eq!(buffer.len(), 3);
264 assert!(buffer.is_full());
265 assert_eq!(buffer.get(0), Some(10.0));
266 assert_eq!(buffer.get(1), Some(20.0));
267 assert_eq!(buffer.get(2), Some(30.0));
268 assert_eq!(buffer.get(3), None);
269 }
270
271 #[test]
272 fn test_circular_overwrite() {
273 let mut buffer = CircularBuffer::new(3);
274 buffer.push(10.0);
275 buffer.push(20.0);
276 buffer.push(30.0);
277 buffer.push(40.0); assert_eq!(buffer.len(), 3);
280 assert_eq!(buffer.get(0), Some(20.0));
281 assert_eq!(buffer.get(1), Some(30.0));
282 assert_eq!(buffer.get(2), Some(40.0));
283 }
284
285 #[test]
286 fn test_first_and_last() {
287 let mut buffer = CircularBuffer::new(3);
288 assert_eq!(buffer.first(), None);
289 assert_eq!(buffer.last(), None);
290
291 buffer.push(10.0);
292 assert_eq!(buffer.first(), Some(10.0));
293 assert_eq!(buffer.last(), Some(10.0));
294
295 buffer.push(20.0);
296 buffer.push(30.0);
297 assert_eq!(buffer.first(), Some(10.0));
298 assert_eq!(buffer.last(), Some(30.0));
299
300 buffer.push(40.0); assert_eq!(buffer.first(), Some(20.0));
302 assert_eq!(buffer.last(), Some(40.0));
303 }
304
305 #[test]
306 fn test_sum() {
307 let mut buffer = CircularBuffer::new(3);
308 buffer.push(10.0);
309 buffer.push(20.0);
310 buffer.push(30.0);
311
312 assert_eq!(buffer.sum(), 60.0);
313
314 buffer.push(40.0); assert_eq!(buffer.sum(), 90.0);
316 }
317
318 #[test]
319 fn test_mean() {
320 let mut buffer = CircularBuffer::new(3);
321 assert_eq!(buffer.mean(), None);
322
323 buffer.push(10.0);
324 buffer.push(20.0);
325 buffer.push(30.0);
326 assert_eq!(buffer.mean(), Some(20.0));
327
328 buffer.push(40.0); assert_eq!(buffer.mean(), Some(30.0));
330 }
331
332 #[test]
333 fn test_max_min() {
334 let mut buffer = CircularBuffer::new(3);
335 assert_eq!(buffer.max(), None);
336 assert_eq!(buffer.min(), None);
337
338 buffer.push(20.0);
339 buffer.push(10.0);
340 buffer.push(30.0);
341
342 assert_eq!(buffer.max(), Some(30.0));
343 assert_eq!(buffer.min(), Some(10.0));
344 }
345
346 #[test]
347 fn test_variance_std_dev() {
348 let mut buffer = CircularBuffer::new(3);
349 buffer.push(2.0);
350 buffer.push(4.0);
351 buffer.push(6.0);
352
353 let variance = buffer.variance().unwrap();
356 assert!((variance - 2.666666).abs() < 0.001);
357
358 let std_dev = buffer.std_dev().unwrap();
359 assert!((std_dev - 1.632993).abs() < 0.001);
360 }
361
362 #[test]
363 fn test_clear() {
364 let mut buffer = CircularBuffer::new(3);
365 buffer.push(10.0);
366 buffer.push(20.0);
367 buffer.push(30.0);
368
369 assert_eq!(buffer.len(), 3);
370
371 buffer.clear();
372 assert_eq!(buffer.len(), 0);
373 assert!(buffer.is_empty());
374 assert_eq!(buffer.first(), None);
375 assert_eq!(buffer.last(), None);
376 }
377
378 #[test]
379 fn test_iterator() {
380 let mut buffer = CircularBuffer::new(3);
381 buffer.push(10.0);
382 buffer.push(20.0);
383 buffer.push(30.0);
384
385 let values: Vec<f64> = buffer.iter().copied().collect();
386 assert_eq!(values, vec![10.0, 20.0, 30.0]);
387
388 buffer.push(40.0); let values: Vec<f64> = buffer.iter().copied().collect();
390 assert_eq!(values, vec![20.0, 30.0, 40.0]);
391 }
392
393 #[test]
394 fn test_iterator_size_hint() {
395 let mut buffer = CircularBuffer::new(5);
396 buffer.push(1.0);
397 buffer.push(2.0);
398 buffer.push(3.0);
399
400 let iter = buffer.iter();
401 assert_eq!(iter.size_hint(), (3, Some(3)));
402 }
403}