@@ -31,15 +31,27 @@ struct MapWindowsInner<I: Iterator, const N: usize> {
3131}
3232
3333// `Buffer` uses two times of space to reduce moves among the iterations.
34+ struct Buffer < T , const N : usize > {
35+ // Invariant: N elements starting from `self.start` must be initialized at
36+ // with all other elements left uninitialized.
37+ buffer : RawBuffer < T , N > ,
38+ // Invariant: `self.start <= N`
39+ start : usize ,
40+ }
41+
42+ /// Internal storage for `Buffer<T, N>`.
43+ ///
44+ /// Has no storage invariants, but has access invariants.
45+ /// See the unsafe method contracts for more information.
46+ ///
47+ /// This type does not implement Drop, it will leak any data stored within.
48+ //
3449// `Buffer<T, N>` is semantically `[MaybeUninit<T>; 2 * N]`. However, due
3550// to limitations of const generics, we use this different type. Note that
3651// it has the same underlying memory layout.
37- struct Buffer < T , const N : usize > {
38- // Invariant: `self.buffer[self.start..self.start + N]` is initialized,
39- // with all other elements being uninitialized. This also
40- // implies that `self.start <= N`.
41- buffer : [ [ MaybeUninit < T > ; N ] ; 2 ] ,
42- start : usize ,
52+ #[ repr( transparent) ]
53+ struct RawBuffer < T , const N : usize > {
54+ data : [ [ MaybeUninit < T > ; N ] ; 2 ] ,
4355}
4456
4557impl < I : Iterator , F , const N : usize > MapWindows < I , F , N > {
@@ -79,7 +91,16 @@ impl<I: Iterator, const N: usize> MapWindowsInner<I, N> {
7991 Some ( item) => buffer. push ( item) ,
8092 } ,
8193 }
82- self . buffer . as_ref ( ) . map ( Buffer :: as_array_ref)
94+ self . buffer . as_ref ( ) . map ( |buf|
95+ // SAFETY:
96+ // - if this was the first time to advance, this is a new well-formed `Buffer`.
97+ //
98+ // - if we already had a buffer, and `iter.next()` was Some;
99+ // `Buffer::push` is responsible for upholding the invariant before we reach this.
100+ //
101+ // - if we already had a buffer, and `iter.next()` was None;
102+ // this closure is unreachable, as the buffer was taken beforehand.
103+ unsafe { buf. buffer . as_array_ref ( buf. start ) } )
83104 }
84105
85106 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
@@ -98,45 +119,32 @@ impl<I: Iterator, const N: usize> MapWindowsInner<I, N> {
98119}
99120
100121impl < T , const N : usize > Buffer < T , N > {
101- fn try_from_iter ( iter : & mut impl Iterator < Item = T > ) -> Option < Self > {
102- let first_half = crate :: array:: iter_next_chunk ( iter) . ok ( ) ?;
103- let buffer =
104- [ MaybeUninit :: new ( first_half) . transpose ( ) , [ const { MaybeUninit :: uninit ( ) } ; N ] ] ;
105- Some ( Self { buffer, start : 0 } )
106- }
107-
108- #[ inline]
109- fn buffer_ptr ( & self ) -> * const MaybeUninit < T > {
110- self . buffer . as_ptr ( ) . cast ( )
111- }
112-
113- #[ inline]
114- fn buffer_mut_ptr ( & mut self ) -> * mut MaybeUninit < T > {
115- self . buffer . as_mut_ptr ( ) . cast ( )
116- }
117-
122+ /// # Safety
123+ ///
124+ /// This type implements `Drop`, and it has invariants that must be upheld:
125+ /// - `start` must be within the bounds `0..=N`.
126+ /// - `raw[start..start + N]` must be initialized.
118127 #[ inline]
119- fn as_array_ref ( & self ) -> & [ T ; N ] {
120- debug_assert ! ( self . start + N <= 2 * N ) ;
121-
122- // SAFETY: our invariant guarantees these elements are initialized.
123- unsafe { & * self . buffer_ptr ( ) . add ( self . start ) . cast ( ) }
128+ unsafe fn new ( raw : RawBuffer < T , N > , start : usize ) -> Self {
129+ Self { buffer : raw, start }
124130 }
125131
126- #[ inline]
127- fn as_uninit_array_mut ( & mut self ) -> & mut MaybeUninit < [ T ; N ] > {
128- debug_assert ! ( self . start + N <= 2 * N ) ;
129-
130- // SAFETY: our invariant guarantees these elements are in bounds.
131- unsafe { & mut * self . buffer_mut_ptr ( ) . add ( self . start ) . cast ( ) }
132+ fn try_from_iter ( iter : & mut impl Iterator < Item = T > ) -> Option < Self > {
133+ let first_half: [ T ; N ] = crate :: array:: iter_next_chunk ( iter) . ok ( ) ?;
134+ let raw = RawBuffer {
135+ data : [ MaybeUninit :: new ( first_half) . transpose ( ) , [ const { MaybeUninit :: uninit ( ) } ; N ] ] ,
136+ } ;
137+ // SAFETY: buffer has the first `first_half.len()` items initialized, which upholds the
138+ // internal invariant for the start offset 0, which is also within bounds.
139+ Some ( unsafe { Self :: new ( raw, 0 ) } )
132140 }
133141
134142 /// Pushes a new item `next` to the back, and pops the front-most one.
135143 ///
136144 /// All the elements will be shifted to the front end when pushing reaches
137145 /// the back end.
138146 fn push ( & mut self , next : T ) {
139- let buffer_mut_ptr = self . buffer_mut_ptr ( ) ;
147+ let buffer_mut_ptr = self . buffer . as_mut_ptr ( ) ;
140148 debug_assert ! ( self . start + N <= 2 * N ) ;
141149
142150 let to_drop = if self . start == N {
@@ -188,18 +196,67 @@ impl<T, const N: usize> Buffer<T, N> {
188196
189197 // SAFETY: the index is valid and this is element `a` in the
190198 // diagram above and has not been dropped yet.
191- unsafe { ptr:: drop_in_place ( to_drop. cast_init ( ) ) } ;
199+ unsafe { to_drop. cast_init ( ) . drop_in_place ( ) } ;
200+ }
201+ }
202+
203+ impl < T , const N : usize > RawBuffer < T , N > {
204+ fn as_ptr ( & self ) -> * const MaybeUninit < T > {
205+ self . data . as_ptr ( ) . cast ( )
206+ }
207+
208+ fn as_mut_ptr ( & mut self ) -> * mut MaybeUninit < T > {
209+ self . data . as_mut_ptr ( ) . cast ( )
210+ }
211+
212+ /// # Safety
213+ ///
214+ /// `self.data` must uphold the internal invariants of `Buffer`:
215+ /// - `start` must be within the bounds `0..=N`
216+ /// - `self.data[start..start + N]` must be initialized.
217+ unsafe fn as_array_ref ( & self , start : usize ) -> & [ T ; N ] {
218+ debug_assert ! ( start + N <= 2 * N ) ;
219+
220+ // SAFETY: caller satisfies that `start` is within bounds.
221+ unsafe { & * self . as_ptr ( ) . add ( start) . cast ( ) }
222+ }
223+
224+ /// # Safety
225+ ///
226+ /// `self.data` must uphold the internal invariants of `Buffer`:
227+ /// - `start` must be within the bounds `0..=N`
228+ /// - `self.data[start..start + N]` must not overlap with the initialized part.
229+ #[ inline]
230+ unsafe fn as_uninit_array_mut ( & mut self , start : usize ) -> & mut MaybeUninit < [ T ; N ] > {
231+ debug_assert ! ( start + N <= 2 * N ) ;
232+
233+ // SAFETY: caller satisfies that `start` is within bounds.
234+ unsafe { & mut * self . as_mut_ptr ( ) . add ( start) . cast ( ) }
192235 }
193236}
194237
195238impl < T : Clone , const N : usize > Clone for Buffer < T , N > {
196239 fn clone ( & self ) -> Self {
197- let mut buffer = Buffer {
198- buffer : [ [ const { MaybeUninit :: uninit ( ) } ; N ] , [ const { MaybeUninit :: uninit ( ) } ; N ] ] ,
199- start : self . start ,
240+ let mut new_raw = RawBuffer {
241+ data : [
242+ [ const { MaybeUninit :: < T > :: uninit ( ) } ; N ] ,
243+ [ const { MaybeUninit :: < T > :: uninit ( ) } ; N ] ,
244+ ] ,
200245 } ;
201- buffer. as_uninit_array_mut ( ) . write ( self . as_array_ref ( ) . clone ( ) ) ;
202- buffer
246+
247+ // SAFETY: invariants of a well-formed `Buffer` guarantee N elements
248+ // starting at `start` are initialized.
249+ let init = unsafe { self . buffer . as_array_ref ( self . start ) } ;
250+ let cloned = init. clone ( ) ;
251+
252+ // SAFETY: new_raw is currently fully uninitialized, which does not
253+ // overlap with any initialized part.
254+ unsafe { new_raw. as_uninit_array_mut ( self . start ) . write ( cloned) } ;
255+
256+ // SAFETY: new_raw has just been initialized above at the offset `self.start`,
257+ // and the invariants of a well-formed `Buffer` guarantee `self.start` is within
258+ // the bounds `0..=N`.
259+ unsafe { Self :: new ( new_raw, self . start ) }
203260 }
204261}
205262
@@ -215,15 +272,12 @@ where
215272
216273impl < T , const N : usize > Drop for Buffer < T , N > {
217274 fn drop ( & mut self ) {
218- // SAFETY: our invariant guarantees that N elements starting from
219- // `self.start` are initialized. We drop them here.
220- unsafe {
221- let initialized_part: * mut [ T ] = crate :: ptr:: slice_from_raw_parts_mut (
222- self . buffer_mut_ptr ( ) . add ( self . start ) . cast ( ) ,
223- N ,
224- ) ;
225- ptr:: drop_in_place ( initialized_part) ;
226- }
275+ // SAFETY: our invariant guarantees that `self.start` is within bounds
276+ let init_ptr = unsafe { self . buffer . as_mut_ptr ( ) . add ( self . start ) . cast_init ( ) } ;
277+
278+ // SAFETY: our invariant guarnatees N elements starting from
279+ // `init_ptr` are initialized. We drop them here.
280+ unsafe { init_ptr. cast_slice ( N ) . drop_in_place ( ) } ;
227281 }
228282}
229283
0 commit comments