1+ use core:: mem:: MaybeUninit ;
2+ use core:: ptr;
3+ use core:: slice;
4+
15/// A "history buffer", similar to a write-only ring buffer of fixed length.
26///
37/// This buffer keeps a fixed number of elements. On write, the oldest element
48/// is overwritten. Thus, the buffer is useful to keep a history of values with
59/// some desired depth, and for example calculate a rolling average.
610///
7- /// The buffer is always fully initialized; depending on the constructor, the
8- /// initial value is either the default value for the element type or a supplied
9- /// initial value. This simplifies the API and is mostly irrelevant for the
10- /// intended use case.
11- ///
1211/// # Examples
1312/// ```
1413/// use heapless::HistoryBuffer;
1514///
1615/// // Initialize a new buffer with 8 elements, all initially zero.
1716/// let mut buf = HistoryBuffer::<_, 8>::new();
1817///
18+ /// // Starts with no data
19+ /// assert_eq!(buf.recent(), None);
20+ ///
1921/// buf.write(3);
2022/// buf.write(5);
2123/// buf.extend(&[4, 4]);
2224///
2325/// // The most recent written element is a four.
24- /// assert_eq!(buf.recent(), &4 );
26+ /// assert_eq!(buf.recent(), Some(&4) );
2527///
2628/// // To access all elements in an unspecified order, use `as_slice()`.
2729/// for el in buf.as_slice() { println!("{:?}", el); }
2830///
29- /// // Now we can prepare an average of all values, which comes out to 2 .
31+ /// // Now we can prepare an average of all values, which comes out to 4 .
3032/// let avg = buf.as_slice().iter().sum::<usize>() / buf.len();
31- /// assert_eq!(avg, 2 );
33+ /// assert_eq!(avg, 4 );
3234/// ```
33- #[ derive( Clone ) ]
3435pub struct HistoryBuffer < T , const N : usize > {
35- data : [ T ; N ] ,
36+ data : [ MaybeUninit < T > ; N ] ,
3637 write_at : usize ,
38+ filled : bool ,
3739}
3840
39- impl < T , const N : usize > HistoryBuffer < T , N >
40- where
41- T : Default + Copy ,
42- {
43- /// Constructs a new history buffer, where every element is filled with the
44- /// default value of the type `T`.
41+ impl < T , const N : usize > HistoryBuffer < T , N > {
42+ const INIT : MaybeUninit < T > = MaybeUninit :: uninit ( ) ;
43+
44+ /// Constructs a new history buffer.
4545 ///
46- /// `HistoryBuffer` currently cannot be constructed in `const` context .
46+ /// The construction of a `HistoryBuffer` works in `const` contexts .
4747 ///
4848 /// # Examples
4949 ///
5050 /// ```
5151 /// use heapless::HistoryBuffer;
5252 ///
5353 /// // Allocate a 16-element buffer on the stack
54- /// let mut x: HistoryBuffer<u8, 16> = HistoryBuffer::new();
55- /// // All elements are zero
56- /// assert_eq!(x.as_slice(), [0; 16]);
54+ /// let x: HistoryBuffer<u8, 16> = HistoryBuffer::new();
55+ /// assert_eq!(x.len(), 0);
5756 /// ```
58- pub fn new ( ) -> Self {
57+ #[ inline]
58+ pub const fn new ( ) -> Self {
5959 Self {
60- // seems not yet implemented
61- // data: Default::default(),
62- data : [ T :: default ( ) ; N ] ,
60+ data : [ Self :: INIT ; N ] ,
6361 write_at : 0 ,
62+ filled : false ,
6463 }
6564 }
6665
@@ -87,10 +86,12 @@ where
8786 /// // All elements are four
8887 /// assert_eq!(x.as_slice(), [4; 16]);
8988 /// ```
89+ #[ inline]
9090 pub fn new_with ( t : T ) -> Self {
9191 Self {
92- data : [ t ; N ] ,
92+ data : [ MaybeUninit :: new ( t ) ; N ] ,
9393 write_at : 0 ,
94+ filled : true ,
9495 }
9596 }
9697
@@ -101,18 +102,35 @@ where
101102}
102103
103104impl < T , const N : usize > HistoryBuffer < T , N > {
105+ /// Returns the current fill level of the buffer.
106+ #[ inline]
107+ pub fn len ( & self ) -> usize {
108+ if self . filled {
109+ N
110+ } else {
111+ self . write_at
112+ }
113+ }
114+
104115 /// Returns the capacity of the buffer, which is the length of the
105116 /// underlying backing array.
106- pub fn len ( & self ) -> usize {
107- self . data . len ( )
117+ #[ inline]
118+ pub fn capacity ( & self ) -> usize {
119+ N
108120 }
109121
110122 /// Writes an element to the buffer, overwriting the oldest value.
111123 pub fn write ( & mut self , t : T ) {
112- self . data [ self . write_at ] = t;
124+ if self . filled {
125+ // Drop the old before we overwrite it.
126+ unsafe { ptr:: drop_in_place ( self . data [ self . write_at ] . as_mut_ptr ( ) ) }
127+ }
128+ self . data [ self . write_at ] = MaybeUninit :: new ( t) ;
129+
113130 self . write_at += 1 ;
114- if self . write_at == self . len ( ) {
131+ if self . write_at == self . capacity ( ) {
115132 self . write_at = 0 ;
133+ self . filled = true ;
116134 }
117135 }
118136
@@ -139,20 +157,28 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
139157 /// let mut x: HistoryBuffer<u8, 16> = HistoryBuffer::new();
140158 /// x.write(4);
141159 /// x.write(10);
142- /// assert_eq!(x.recent(), &10);
160+ /// assert_eq!(x.recent(), Some( &10) );
143161 /// ```
144- pub fn recent ( & self ) -> & T {
162+ pub fn recent ( & self ) -> Option < & T > {
145163 if self . write_at == 0 {
146- & self . data [ self . len ( ) - 1 ]
164+ if self . filled {
165+ Some ( unsafe { & * self . data [ self . capacity ( ) - 1 ] . as_ptr ( ) } )
166+ } else {
167+ None
168+ }
147169 } else {
148- & self . data [ self . write_at - 1 ]
170+ Some ( unsafe { & * self . data [ self . write_at - 1 ] . as_ptr ( ) } )
149171 }
150172 }
151173
152174 /// Returns the array slice backing the buffer, without keeping track
153175 /// of the write position. Therefore, the element order is unspecified.
154176 pub fn as_slice ( & self ) -> & [ T ] {
155- & self . data
177+ if self . filled {
178+ unsafe { slice:: from_raw_parts ( self . data . as_ptr ( ) as * const _ , self . capacity ( ) ) }
179+ } else {
180+ unsafe { slice:: from_raw_parts ( self . data . as_ptr ( ) as * const _ , self . write_at ) }
181+ }
156182 }
157183}
158184
@@ -179,6 +205,17 @@ where
179205 }
180206}
181207
208+ impl < T , const N : usize > Drop for HistoryBuffer < T , N > {
209+ fn drop ( & mut self ) {
210+ unsafe {
211+ ptr:: drop_in_place ( ptr:: slice_from_raw_parts_mut (
212+ self . data . as_mut_ptr ( ) as * mut T ,
213+ self . len ( ) ,
214+ ) )
215+ }
216+ }
217+ }
218+
182219#[ cfg( test) ]
183220mod tests {
184221 use crate :: HistoryBuffer ;
@@ -190,15 +227,15 @@ mod tests {
190227 assert_eq ! ( x. as_slice( ) , [ 1 ; 4 ] ) ;
191228
192229 let x: HistoryBuffer < u8 , 4 > = HistoryBuffer :: new ( ) ;
193- assert_eq ! ( x. as_slice( ) , [ 0 ; 4 ] ) ;
230+ assert_eq ! ( x. as_slice( ) , [ ] ) ;
194231 }
195232
196233 #[ test]
197234 fn write ( ) {
198235 let mut x: HistoryBuffer < u8 , 4 > = HistoryBuffer :: new ( ) ;
199236 x. write ( 1 ) ;
200237 x. write ( 4 ) ;
201- assert_eq ! ( x. as_slice( ) , [ 1 , 4 , 0 , 0 ] ) ;
238+ assert_eq ! ( x. as_slice( ) , [ 1 , 4 ] ) ;
202239
203240 x. write ( 5 ) ;
204241 x. write ( 6 ) ;
@@ -213,7 +250,7 @@ mod tests {
213250 fn clear ( ) {
214251 let mut x: HistoryBuffer < u8 , 4 > = HistoryBuffer :: new_with ( 1 ) ;
215252 x. clear ( ) ;
216- assert_eq ! ( x. as_slice( ) , [ 0 ; 4 ] ) ;
253+ assert_eq ! ( x. as_slice( ) , [ ] ) ;
217254
218255 let mut x: HistoryBuffer < u8 , 4 > = HistoryBuffer :: new ( ) ;
219256 x. clear_with ( 1 ) ;
@@ -223,16 +260,16 @@ mod tests {
223260 #[ test]
224261 fn recent ( ) {
225262 let mut x: HistoryBuffer < u8 , 4 > = HistoryBuffer :: new ( ) ;
226- assert_eq ! ( x. recent( ) , & 0 ) ;
263+ assert_eq ! ( x. recent( ) , None ) ;
227264
228265 x. write ( 1 ) ;
229266 x. write ( 4 ) ;
230- assert_eq ! ( x. recent( ) , & 4 ) ;
267+ assert_eq ! ( x. recent( ) , Some ( & 4 ) ) ;
231268
232269 x. write ( 5 ) ;
233270 x. write ( 6 ) ;
234271 x. write ( 10 ) ;
235- assert_eq ! ( x. recent( ) , & 10 ) ;
272+ assert_eq ! ( x. recent( ) , Some ( & 10 ) ) ;
236273 }
237274
238275 #[ test]
0 commit comments