1 | use core::fmt; |
2 | use core::mem::MaybeUninit; |
3 | use core::ops::Deref; |
4 | use core::ptr; |
5 | use core::slice; |
6 | |
7 | /// A "history buffer", similar to a write-only ring buffer of fixed length. |
8 | /// |
9 | /// This buffer keeps a fixed number of elements. On write, the oldest element |
10 | /// is overwritten. Thus, the buffer is useful to keep a history of values with |
11 | /// some desired depth, and for example calculate a rolling average. |
12 | /// |
13 | /// # Examples |
14 | /// ``` |
15 | /// use heapless::HistoryBuffer; |
16 | /// |
17 | /// // Initialize a new buffer with 8 elements. |
18 | /// let mut buf = HistoryBuffer::<_, 8>::new(); |
19 | /// |
20 | /// // Starts with no data |
21 | /// assert_eq!(buf.recent(), None); |
22 | /// |
23 | /// buf.write(3); |
24 | /// buf.write(5); |
25 | /// buf.extend(&[4, 4]); |
26 | /// |
27 | /// // The most recent written element is a four. |
28 | /// assert_eq!(buf.recent(), Some(&4)); |
29 | /// |
30 | /// // To access all elements in an unspecified order, use `as_slice()`. |
31 | /// for el in buf.as_slice() { println!("{:?}" , el); } |
32 | /// |
33 | /// // Now we can prepare an average of all values, which comes out to 4. |
34 | /// let avg = buf.as_slice().iter().sum::<usize>() / buf.len(); |
35 | /// assert_eq!(avg, 4); |
36 | /// ``` |
37 | pub struct HistoryBuffer<T, const N: usize> { |
38 | data: [MaybeUninit<T>; N], |
39 | write_at: usize, |
40 | filled: bool, |
41 | } |
42 | |
43 | impl<T, const N: usize> HistoryBuffer<T, N> { |
44 | const INIT: MaybeUninit<T> = MaybeUninit::uninit(); |
45 | |
46 | /// Constructs a new history buffer. |
47 | /// |
48 | /// The construction of a `HistoryBuffer` works in `const` contexts. |
49 | /// |
50 | /// # Examples |
51 | /// |
52 | /// ``` |
53 | /// use heapless::HistoryBuffer; |
54 | /// |
55 | /// // Allocate a 16-element buffer on the stack |
56 | /// let x: HistoryBuffer<u8, 16> = HistoryBuffer::new(); |
57 | /// assert_eq!(x.len(), 0); |
58 | /// ``` |
59 | #[inline ] |
60 | pub const fn new() -> Self { |
61 | // Const assert |
62 | crate::sealed::greater_than_0::<N>(); |
63 | |
64 | Self { |
65 | data: [Self::INIT; N], |
66 | write_at: 0, |
67 | filled: false, |
68 | } |
69 | } |
70 | |
71 | /// Clears the buffer, replacing every element with the default value of |
72 | /// type `T`. |
73 | pub fn clear(&mut self) { |
74 | *self = Self::new(); |
75 | } |
76 | } |
77 | |
78 | impl<T, const N: usize> HistoryBuffer<T, N> |
79 | where |
80 | T: Copy + Clone, |
81 | { |
82 | /// Constructs a new history buffer, where every element is the given value. |
83 | /// |
84 | /// # Examples |
85 | /// |
86 | /// ``` |
87 | /// use heapless::HistoryBuffer; |
88 | /// |
89 | /// // Allocate a 16-element buffer on the stack |
90 | /// let mut x: HistoryBuffer<u8, 16> = HistoryBuffer::new_with(4); |
91 | /// // All elements are four |
92 | /// assert_eq!(x.as_slice(), [4; 16]); |
93 | /// ``` |
94 | #[inline ] |
95 | pub fn new_with(t: T) -> Self { |
96 | Self { |
97 | data: [MaybeUninit::new(t); N], |
98 | write_at: 0, |
99 | filled: true, |
100 | } |
101 | } |
102 | |
103 | /// Clears the buffer, replacing every element with the given value. |
104 | pub fn clear_with(&mut self, t: T) { |
105 | *self = Self::new_with(t); |
106 | } |
107 | } |
108 | |
109 | impl<T, const N: usize> HistoryBuffer<T, N> { |
110 | /// Returns the current fill level of the buffer. |
111 | #[inline ] |
112 | pub fn len(&self) -> usize { |
113 | if self.filled { |
114 | N |
115 | } else { |
116 | self.write_at |
117 | } |
118 | } |
119 | |
120 | /// Returns the capacity of the buffer, which is the length of the |
121 | /// underlying backing array. |
122 | #[inline ] |
123 | pub fn capacity(&self) -> usize { |
124 | N |
125 | } |
126 | |
127 | /// Writes an element to the buffer, overwriting the oldest value. |
128 | pub fn write(&mut self, t: T) { |
129 | if self.filled { |
130 | // Drop the old before we overwrite it. |
131 | unsafe { ptr::drop_in_place(self.data[self.write_at].as_mut_ptr()) } |
132 | } |
133 | self.data[self.write_at] = MaybeUninit::new(t); |
134 | |
135 | self.write_at += 1; |
136 | if self.write_at == self.capacity() { |
137 | self.write_at = 0; |
138 | self.filled = true; |
139 | } |
140 | } |
141 | |
142 | /// Clones and writes all elements in a slice to the buffer. |
143 | /// |
144 | /// If the slice is longer than the buffer, only the last `self.len()` |
145 | /// elements will actually be stored. |
146 | pub fn extend_from_slice(&mut self, other: &[T]) |
147 | where |
148 | T: Clone, |
149 | { |
150 | for item in other { |
151 | self.write(item.clone()); |
152 | } |
153 | } |
154 | |
155 | /// Returns a reference to the most recently written value. |
156 | /// |
157 | /// # Examples |
158 | /// |
159 | /// ``` |
160 | /// use heapless::HistoryBuffer; |
161 | /// |
162 | /// let mut x: HistoryBuffer<u8, 16> = HistoryBuffer::new(); |
163 | /// x.write(4); |
164 | /// x.write(10); |
165 | /// assert_eq!(x.recent(), Some(&10)); |
166 | /// ``` |
167 | pub fn recent(&self) -> Option<&T> { |
168 | if self.write_at == 0 { |
169 | if self.filled { |
170 | Some(unsafe { &*self.data[self.capacity() - 1].as_ptr() }) |
171 | } else { |
172 | None |
173 | } |
174 | } else { |
175 | Some(unsafe { &*self.data[self.write_at - 1].as_ptr() }) |
176 | } |
177 | } |
178 | |
179 | /// Returns the array slice backing the buffer, without keeping track |
180 | /// of the write position. Therefore, the element order is unspecified. |
181 | pub fn as_slice(&self) -> &[T] { |
182 | unsafe { slice::from_raw_parts(self.data.as_ptr() as *const _, self.len()) } |
183 | } |
184 | |
185 | /// Returns a pair of slices which contain, in order, the contents of the buffer. |
186 | /// |
187 | /// # Examples |
188 | /// |
189 | /// ``` |
190 | /// use heapless::HistoryBuffer; |
191 | /// |
192 | /// let mut buffer: HistoryBuffer<u8, 6> = HistoryBuffer::new(); |
193 | /// buffer.extend([0, 0, 0]); |
194 | /// buffer.extend([1, 2, 3, 4, 5, 6]); |
195 | /// assert_eq!(buffer.as_slices(), (&[1, 2, 3][..], &[4, 5, 6][..])); |
196 | /// ``` |
197 | pub fn as_slices(&self) -> (&[T], &[T]) { |
198 | let buffer = self.as_slice(); |
199 | |
200 | if !self.filled { |
201 | (buffer, &[]) |
202 | } else { |
203 | (&buffer[self.write_at..], &buffer[..self.write_at]) |
204 | } |
205 | } |
206 | |
207 | /// Returns an iterator for iterating over the buffer from oldest to newest. |
208 | /// |
209 | /// # Examples |
210 | /// |
211 | /// ``` |
212 | /// use heapless::HistoryBuffer; |
213 | /// |
214 | /// let mut buffer: HistoryBuffer<u8, 6> = HistoryBuffer::new(); |
215 | /// buffer.extend([0, 0, 0, 1, 2, 3, 4, 5, 6]); |
216 | /// let expected = [1, 2, 3, 4, 5, 6]; |
217 | /// for (x, y) in buffer.oldest_ordered().zip(expected.iter()) { |
218 | /// assert_eq!(x, y) |
219 | /// } |
220 | /// |
221 | /// ``` |
222 | pub fn oldest_ordered<'a>(&'a self) -> OldestOrdered<'a, T, N> { |
223 | if self.filled { |
224 | OldestOrdered { |
225 | buf: self, |
226 | cur: self.write_at, |
227 | wrapped: false, |
228 | } |
229 | } else { |
230 | // special case: act like we wrapped already to handle empty buffer. |
231 | OldestOrdered { |
232 | buf: self, |
233 | cur: 0, |
234 | wrapped: true, |
235 | } |
236 | } |
237 | } |
238 | } |
239 | |
240 | impl<T, const N: usize> Extend<T> for HistoryBuffer<T, N> { |
241 | fn extend<I>(&mut self, iter: I) |
242 | where |
243 | I: IntoIterator<Item = T>, |
244 | { |
245 | for item: T in iter.into_iter() { |
246 | self.write(item); |
247 | } |
248 | } |
249 | } |
250 | |
251 | impl<'a, T, const N: usize> Extend<&'a T> for HistoryBuffer<T, N> |
252 | where |
253 | T: 'a + Clone, |
254 | { |
255 | fn extend<I>(&mut self, iter: I) |
256 | where |
257 | I: IntoIterator<Item = &'a T>, |
258 | { |
259 | self.extend(iter.into_iter().cloned()) |
260 | } |
261 | } |
262 | |
263 | impl<T, const N: usize> Clone for HistoryBuffer<T, N> |
264 | where |
265 | T: Clone, |
266 | { |
267 | fn clone(&self) -> Self { |
268 | let mut ret: HistoryBuffer = Self::new(); |
269 | for (new: &mut MaybeUninit, old: &T) in ret.data.iter_mut().zip(self.as_slice()) { |
270 | new.write(val:old.clone()); |
271 | } |
272 | ret.filled = self.filled; |
273 | ret.write_at = self.write_at; |
274 | ret |
275 | } |
276 | } |
277 | |
278 | impl<T, const N: usize> Drop for HistoryBuffer<T, N> { |
279 | fn drop(&mut self) { |
280 | unsafe { |
281 | ptr::drop_in_place(to_drop:ptr::slice_from_raw_parts_mut( |
282 | self.data.as_mut_ptr() as *mut T, |
283 | self.len(), |
284 | )) |
285 | } |
286 | } |
287 | } |
288 | |
289 | impl<T, const N: usize> Deref for HistoryBuffer<T, N> { |
290 | type Target = [T]; |
291 | |
292 | fn deref(&self) -> &[T] { |
293 | self.as_slice() |
294 | } |
295 | } |
296 | |
297 | impl<T, const N: usize> AsRef<[T]> for HistoryBuffer<T, N> { |
298 | #[inline ] |
299 | fn as_ref(&self) -> &[T] { |
300 | self |
301 | } |
302 | } |
303 | |
304 | impl<T, const N: usize> fmt::Debug for HistoryBuffer<T, N> |
305 | where |
306 | T: fmt::Debug, |
307 | { |
308 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
309 | <[T] as fmt::Debug>::fmt(self, f) |
310 | } |
311 | } |
312 | |
313 | impl<T, const N: usize> Default for HistoryBuffer<T, N> { |
314 | fn default() -> Self { |
315 | Self::new() |
316 | } |
317 | } |
318 | |
319 | impl<T, const N: usize> PartialEq for HistoryBuffer<T, N> |
320 | where |
321 | T: PartialEq, |
322 | { |
323 | fn eq(&self, other: &Self) -> bool { |
324 | self.oldest_ordered().eq(other.oldest_ordered()) |
325 | } |
326 | } |
327 | |
328 | /// An iterator on the underlying buffer ordered from oldest data to newest |
329 | #[derive (Clone)] |
330 | pub struct OldestOrdered<'a, T, const N: usize> { |
331 | buf: &'a HistoryBuffer<T, N>, |
332 | cur: usize, |
333 | wrapped: bool, |
334 | } |
335 | |
336 | impl<'a, T, const N: usize> Iterator for OldestOrdered<'a, T, N> { |
337 | type Item = &'a T; |
338 | |
339 | fn next(&mut self) -> Option<&'a T> { |
340 | if self.cur == self.buf.len() && self.buf.filled { |
341 | // roll-over |
342 | self.cur = 0; |
343 | self.wrapped = true; |
344 | } |
345 | |
346 | if self.cur == self.buf.write_at && self.wrapped { |
347 | return None; |
348 | } |
349 | |
350 | let item: &T = &self.buf[self.cur]; |
351 | self.cur += 1; |
352 | Some(item) |
353 | } |
354 | } |
355 | |
356 | #[cfg (test)] |
357 | mod tests { |
358 | use crate::HistoryBuffer; |
359 | use core::fmt::Debug; |
360 | use core::sync::atomic::{AtomicUsize, Ordering}; |
361 | |
362 | #[test ] |
363 | fn new() { |
364 | let x: HistoryBuffer<u8, 4> = HistoryBuffer::new_with(1); |
365 | assert_eq!(x.len(), 4); |
366 | assert_eq!(x.as_slice(), [1; 4]); |
367 | assert_eq!(*x, [1; 4]); |
368 | |
369 | let x: HistoryBuffer<u8, 4> = HistoryBuffer::new(); |
370 | assert_eq!(x.as_slice(), []); |
371 | } |
372 | |
373 | #[test ] |
374 | fn write() { |
375 | let mut x: HistoryBuffer<u8, 4> = HistoryBuffer::new(); |
376 | x.write(1); |
377 | x.write(4); |
378 | assert_eq!(x.as_slice(), [1, 4]); |
379 | |
380 | x.write(5); |
381 | x.write(6); |
382 | x.write(10); |
383 | assert_eq!(x.as_slice(), [10, 4, 5, 6]); |
384 | |
385 | x.extend([11, 12].iter()); |
386 | assert_eq!(x.as_slice(), [10, 11, 12, 6]); |
387 | } |
388 | |
389 | #[test ] |
390 | fn clear() { |
391 | let mut x: HistoryBuffer<u8, 4> = HistoryBuffer::new_with(1); |
392 | x.clear(); |
393 | assert_eq!(x.as_slice(), []); |
394 | |
395 | let mut x: HistoryBuffer<u8, 4> = HistoryBuffer::new(); |
396 | x.clear_with(1); |
397 | assert_eq!(x.as_slice(), [1; 4]); |
398 | } |
399 | |
400 | #[test ] |
401 | fn clone() { |
402 | let mut x: HistoryBuffer<u8, 3> = HistoryBuffer::new(); |
403 | for i in 0..10 { |
404 | assert_eq!(x.as_slice(), x.clone().as_slice()); |
405 | x.write(i); |
406 | } |
407 | |
408 | // Records number of clones locally and globally. |
409 | static GLOBAL: AtomicUsize = AtomicUsize::new(0); |
410 | #[derive (Default, PartialEq, Debug)] |
411 | struct InstrumentedClone(usize); |
412 | |
413 | impl Clone for InstrumentedClone { |
414 | fn clone(&self) -> Self { |
415 | GLOBAL.fetch_add(1, Ordering::Relaxed); |
416 | Self(self.0 + 1) |
417 | } |
418 | } |
419 | |
420 | let mut y: HistoryBuffer<InstrumentedClone, 2> = HistoryBuffer::new(); |
421 | let _ = y.clone(); |
422 | assert_eq!(GLOBAL.load(Ordering::Relaxed), 0); |
423 | y.write(InstrumentedClone(0)); |
424 | assert_eq!(GLOBAL.load(Ordering::Relaxed), 0); |
425 | assert_eq!(y.clone().as_slice(), [InstrumentedClone(1)]); |
426 | assert_eq!(GLOBAL.load(Ordering::Relaxed), 1); |
427 | y.write(InstrumentedClone(0)); |
428 | assert_eq!(GLOBAL.load(Ordering::Relaxed), 1); |
429 | assert_eq!( |
430 | y.clone().as_slice(), |
431 | [InstrumentedClone(1), InstrumentedClone(1)] |
432 | ); |
433 | assert_eq!(GLOBAL.load(Ordering::Relaxed), 3); |
434 | assert_eq!( |
435 | y.clone().clone().clone().as_slice(), |
436 | [InstrumentedClone(3), InstrumentedClone(3)] |
437 | ); |
438 | assert_eq!(GLOBAL.load(Ordering::Relaxed), 9); |
439 | } |
440 | |
441 | #[test ] |
442 | fn recent() { |
443 | let mut x: HistoryBuffer<u8, 4> = HistoryBuffer::new(); |
444 | assert_eq!(x.recent(), None); |
445 | |
446 | x.write(1); |
447 | x.write(4); |
448 | assert_eq!(x.recent(), Some(&4)); |
449 | |
450 | x.write(5); |
451 | x.write(6); |
452 | x.write(10); |
453 | assert_eq!(x.recent(), Some(&10)); |
454 | } |
455 | |
456 | #[test ] |
457 | fn as_slice() { |
458 | let mut x: HistoryBuffer<u8, 4> = HistoryBuffer::new(); |
459 | |
460 | assert_eq!(x.as_slice(), []); |
461 | |
462 | x.extend([1, 2, 3, 4, 5].iter()); |
463 | |
464 | assert_eq!(x.as_slice(), [5, 2, 3, 4]); |
465 | } |
466 | |
467 | /// Test whether .as_slices() behaves as expected. |
468 | #[test ] |
469 | fn as_slices() { |
470 | let mut buffer: HistoryBuffer<u8, 4> = HistoryBuffer::new(); |
471 | let mut extend_then_assert = |extend: &[u8], assert: (&[u8], &[u8])| { |
472 | buffer.extend(extend); |
473 | assert_eq!(buffer.as_slices(), assert); |
474 | }; |
475 | |
476 | extend_then_assert(b"a" , (b"a" , b"" )); |
477 | extend_then_assert(b"bcd" , (b"abcd" , b"" )); |
478 | extend_then_assert(b"efg" , (b"d" , b"efg" )); |
479 | extend_then_assert(b"h" , (b"efgh" , b"" )); |
480 | extend_then_assert(b"123456" , (b"34" , b"56" )); |
481 | } |
482 | |
483 | /// Test whether .as_slices() and .oldest_ordered() produce elements in the same order. |
484 | #[test ] |
485 | fn as_slices_equals_ordered() { |
486 | let mut buffer: HistoryBuffer<u8, 6> = HistoryBuffer::new(); |
487 | |
488 | for n in 0..20 { |
489 | buffer.write(n); |
490 | let (head, tail) = buffer.as_slices(); |
491 | assert_eq_iter( |
492 | [head, tail].iter().copied().flatten(), |
493 | buffer.oldest_ordered(), |
494 | ) |
495 | } |
496 | } |
497 | |
498 | #[test ] |
499 | fn ordered() { |
500 | // test on an empty buffer |
501 | let buffer: HistoryBuffer<u8, 6> = HistoryBuffer::new(); |
502 | let mut iter = buffer.oldest_ordered(); |
503 | assert_eq!(iter.next(), None); |
504 | assert_eq!(iter.next(), None); |
505 | |
506 | // test on a un-filled buffer |
507 | let mut buffer: HistoryBuffer<u8, 6> = HistoryBuffer::new(); |
508 | buffer.extend([1, 2, 3]); |
509 | assert_eq!(buffer.len(), 3); |
510 | assert_eq_iter(buffer.oldest_ordered(), &[1, 2, 3]); |
511 | |
512 | // test on a filled buffer |
513 | let mut buffer: HistoryBuffer<u8, 6> = HistoryBuffer::new(); |
514 | buffer.extend([0, 0, 0, 1, 2, 3, 4, 5, 6]); |
515 | assert_eq!(buffer.len(), 6); |
516 | assert_eq_iter(buffer.oldest_ordered(), &[1, 2, 3, 4, 5, 6]); |
517 | |
518 | // comprehensive test all cases |
519 | for n in 0..50 { |
520 | const N: usize = 7; |
521 | let mut buffer: HistoryBuffer<u8, N> = HistoryBuffer::new(); |
522 | buffer.extend(0..n); |
523 | assert_eq_iter( |
524 | buffer.oldest_ordered().copied(), |
525 | n.saturating_sub(N as u8)..n, |
526 | ); |
527 | } |
528 | } |
529 | |
530 | /// Compares two iterators item by item, making sure they stop at the same time. |
531 | fn assert_eq_iter<I: Eq + Debug>( |
532 | a: impl IntoIterator<Item = I>, |
533 | b: impl IntoIterator<Item = I>, |
534 | ) { |
535 | let mut a = a.into_iter(); |
536 | let mut b = b.into_iter(); |
537 | |
538 | let mut i = 0; |
539 | loop { |
540 | let a_item = a.next(); |
541 | let b_item = b.next(); |
542 | |
543 | assert_eq!(a_item, b_item, "{}" , i); |
544 | |
545 | i += 1; |
546 | |
547 | if b_item.is_none() { |
548 | break; |
549 | } |
550 | } |
551 | } |
552 | |
553 | #[test ] |
554 | fn partial_eq() { |
555 | let mut x: HistoryBuffer<u8, 3> = HistoryBuffer::new(); |
556 | let mut y: HistoryBuffer<u8, 3> = HistoryBuffer::new(); |
557 | assert_eq!(x, y); |
558 | x.write(1); |
559 | assert_ne!(x, y); |
560 | y.write(1); |
561 | assert_eq!(x, y); |
562 | for _ in 0..4 { |
563 | x.write(2); |
564 | assert_ne!(x, y); |
565 | for i in 0..5 { |
566 | x.write(i); |
567 | y.write(i); |
568 | } |
569 | assert_eq!( |
570 | x, |
571 | y, |
572 | "{:?} {:?}" , |
573 | x.iter().collect::<Vec<_>>(), |
574 | y.iter().collect::<Vec<_>>() |
575 | ); |
576 | } |
577 | } |
578 | } |
579 | |