@@ -191,6 +191,183 @@ impl<T, const N: usize> Deque<T, N> {
191191 }
192192 }
193193
194+ #[ inline]
195+ fn is_contiguous ( & self ) -> bool {
196+ self . front <= N - self . len ( )
197+ }
198+
199+ /// Rearranges the internal storage of the [`Deque`] to make it into a contiguous slice,
200+ /// which is returned.
201+ ///
202+ /// This does **not** change the order of the elements in the deque.
203+ /// The returned slice can then be used to perform contiguous slice operations on the deque.
204+ ///
205+ /// After calling this method, subsequent [`as_slices`] and [`as_mut_slices`] calls will return
206+ /// a single contiguous slice.
207+ ///
208+ /// [`as_slices`]: Deque::as_slices
209+ /// [`as_mut_slices`]: Deque::as_mut_slices
210+ ///
211+ /// # Examples
212+ /// Sorting a deque:
213+ /// ```
214+ /// use heapless::Deque;
215+ ///
216+ /// let mut buf = Deque::<_, 4>::new();
217+ /// buf.push_back(2).unwrap();
218+ /// buf.push_back(1).unwrap();
219+ /// buf.push_back(3).unwrap();
220+ ///
221+ /// // Sort the deque
222+ /// buf.make_contiguous().sort();
223+ /// assert_eq!(buf.as_slices(), (&[1, 2, 3][..], &[][..]));
224+ ///
225+ /// // Sort the deque in reverse
226+ /// buf.make_contiguous().sort_by(|a, b| b.cmp(a));
227+ /// assert_eq!(buf.as_slices(), (&[3, 2, 1][..], &[][..]));
228+ /// ```
229+ pub fn make_contiguous ( & mut self ) -> & mut [ T ] {
230+ if self . is_contiguous ( ) {
231+ return unsafe {
232+ slice:: from_raw_parts_mut (
233+ self . buffer . as_mut_ptr ( ) . add ( self . front ) . cast ( ) ,
234+ self . len ( ) ,
235+ )
236+ } ;
237+ }
238+
239+ let buffer_ptr: * mut T = self . buffer . as_mut_ptr ( ) . cast ( ) ;
240+
241+ let len = self . len ( ) ;
242+
243+ let free = N - len;
244+ let front_len = N - self . front ;
245+ let back = len - front_len;
246+ let back_len = back;
247+
248+ if free >= front_len {
249+ // there is enough free space to copy the head in one go,
250+ // this means that we first shift the tail backwards, and then
251+ // copy the head to the correct position.
252+ //
253+ // from: DEFGH....ABC
254+ // to: ABCDEFGH....
255+ unsafe {
256+ ptr:: copy ( buffer_ptr, buffer_ptr. add ( front_len) , back_len) ;
257+ // ...DEFGH.ABC
258+ ptr:: copy_nonoverlapping ( buffer_ptr. add ( self . front ) , buffer_ptr, front_len) ;
259+ // ABCDEFGH....
260+ }
261+
262+ self . front = 0 ;
263+ self . back = len;
264+ } else if free >= back_len {
265+ // there is enough free space to copy the tail in one go,
266+ // this means that we first shift the head forwards, and then
267+ // copy the tail to the correct position.
268+ //
269+ // from: FGH....ABCDE
270+ // to: ...ABCDEFGH.
271+ unsafe {
272+ ptr:: copy (
273+ buffer_ptr. add ( self . front ) ,
274+ buffer_ptr. add ( self . back ) ,
275+ front_len,
276+ ) ;
277+ // FGHABCDE....
278+ ptr:: copy_nonoverlapping (
279+ buffer_ptr,
280+ buffer_ptr. add ( self . back + front_len) ,
281+ back_len,
282+ ) ;
283+ // ...ABCDEFGH.
284+ }
285+
286+ self . front = back;
287+ self . back = 0 ;
288+ } else {
289+ // `free` is smaller than both `head_len` and `tail_len`.
290+ // the general algorithm for this first moves the slices
291+ // right next to each other and then uses `slice::rotate`
292+ // to rotate them into place:
293+ //
294+ // initially: HIJK..ABCDEFG
295+ // step 1: ..HIJKABCDEFG
296+ // step 2: ..ABCDEFGHIJK
297+ //
298+ // or:
299+ //
300+ // initially: FGHIJK..ABCDE
301+ // step 1: FGHIJKABCDE..
302+ // step 2: ABCDEFGHIJK..
303+
304+ // pick the shorter of the 2 slices to reduce the amount
305+ // of memory that needs to be moved around.
306+ if front_len > back_len {
307+ // tail is shorter, so:
308+ // 1. copy tail forwards
309+ // 2. rotate used part of the buffer
310+ // 3. update head to point to the new beginning (which is just `free`)
311+ unsafe {
312+ // if there is no free space in the buffer, then the slices are already
313+ // right next to each other and we don't need to move any memory.
314+ if free != 0 {
315+ // because we only move the tail forward as much as there's free space
316+ // behind it, we don't overwrite any elements of the head slice, and
317+ // the slices end up right next to each other.
318+ ptr:: copy ( buffer_ptr, buffer_ptr. add ( free) , back_len) ;
319+ }
320+
321+ // We just copied the tail right next to the head slice,
322+ // so all of the elements in the range are initialized
323+ let slice: & mut [ T ] = slice:: from_raw_parts_mut ( buffer_ptr. add ( free) , N - free) ;
324+
325+ // because the deque wasn't contiguous, we know that `tail_len < self.len == slice.len()`,
326+ // so this will never panic.
327+ slice. rotate_left ( back_len) ;
328+
329+ // the used part of the buffer now is `free..self.capacity()`, so set
330+ // `head` to the beginning of that range.
331+ self . front = free;
332+ self . back = 0 ;
333+ }
334+ } else {
335+ // head is shorter so:
336+ // 1. copy head backwards
337+ // 2. rotate used part of the buffer
338+ // 3. update head to point to the new beginning (which is the beginning of the buffer)
339+
340+ unsafe {
341+ // if there is no free space in the buffer, then the slices are already
342+ // right next to each other and we don't need to move any memory.
343+ if free != 0 {
344+ // copy the head slice to lie right behind the tail slice.
345+ ptr:: copy (
346+ buffer_ptr. add ( self . front ) ,
347+ buffer_ptr. add ( back_len) ,
348+ front_len,
349+ ) ;
350+ }
351+
352+ // because we copied the head slice so that both slices lie right
353+ // next to each other, all the elements in the range are initialized.
354+ let slice: & mut [ T ] = slice:: from_raw_parts_mut ( buffer_ptr, len) ;
355+
356+ // because the deque wasn't contiguous, we know that `head_len < self.len == slice.len()`
357+ // so this will never panic.
358+ slice. rotate_right ( front_len) ;
359+
360+ // the used part of the buffer now is `0..self.len`, so set
361+ // `head` to the beginning of that range.
362+ self . front = 0 ;
363+ self . back = len;
364+ }
365+ }
366+ }
367+
368+ unsafe { slice:: from_raw_parts_mut ( buffer_ptr. add ( self . front ) , len) }
369+ }
370+
194371 /// Provides a reference to the front element, or None if the `Deque` is empty.
195372 pub fn front ( & self ) -> Option < & T > {
196373 if self . is_empty ( ) {
@@ -866,4 +1043,55 @@ mod tests {
8661043 q. push_back ( 0 ) . unwrap ( ) ;
8671044 assert_eq ! ( q. len( ) , 1 ) ;
8681045 }
1046+
1047+ #[ test]
1048+ fn make_contiguous ( ) {
1049+ let mut q: Deque < i32 , 4 > = Deque :: new ( ) ;
1050+ assert_eq ! ( q. len( ) , 0 ) ;
1051+
1052+ q. push_back ( 0 ) . unwrap ( ) ;
1053+ q. push_back ( 1 ) . unwrap ( ) ;
1054+ q. push_back ( 2 ) . unwrap ( ) ;
1055+ q. push_back ( 3 ) . unwrap ( ) ;
1056+
1057+ // Deque contains: 0, 1, 2, 3
1058+ assert_eq ! ( q. pop_front( ) , Some ( 0 ) ) ;
1059+ assert_eq ! ( q. pop_front( ) , Some ( 1 ) ) ;
1060+
1061+ // Deque contains: ., ., 2, 3
1062+ q. push_back ( 4 ) . unwrap ( ) ;
1063+
1064+ // Deque contains: 4, ., 2, 3
1065+ assert_eq ! ( q. as_slices( ) , ( [ 2 , 3 ] . as_slice( ) , [ 4 ] . as_slice( ) ) ) ;
1066+
1067+ assert_eq ! ( q. make_contiguous( ) , & [ 2 , 3 , 4 ] ) ;
1068+
1069+ // Deque contains: ., 2, 3, 4
1070+ assert_eq ! ( q. as_slices( ) , ( [ 2 , 3 , 4 ] . as_slice( ) , [ ] . as_slice( ) ) ) ;
1071+
1072+ assert_eq ! ( q. pop_front( ) , Some ( 2 ) ) ;
1073+ assert_eq ! ( q. pop_front( ) , Some ( 3 ) ) ;
1074+ q. push_back ( 5 ) . unwrap ( ) ;
1075+ q. push_back ( 6 ) . unwrap ( ) ;
1076+
1077+ // Deque contains: 5, 6, ., 4
1078+ assert_eq ! ( q. as_slices( ) , ( [ 4 ] . as_slice( ) , [ 5 , 6 ] . as_slice( ) ) ) ;
1079+
1080+ assert_eq ! ( q. make_contiguous( ) , & [ 4 , 5 , 6 ] ) ;
1081+
1082+ // Deque contains: 4, 5, 6, .
1083+ assert_eq ! ( q. as_slices( ) , ( [ 4 , 5 , 6 ] . as_slice( ) , [ ] . as_slice( ) ) ) ;
1084+
1085+ assert_eq ! ( q. pop_front( ) , Some ( 4 ) ) ;
1086+ q. push_back ( 7 ) . unwrap ( ) ;
1087+ q. push_back ( 8 ) . unwrap ( ) ;
1088+
1089+ // Deque contains: 8, 5, 6, 7
1090+ assert_eq ! ( q. as_slices( ) , ( [ 5 , 6 , 7 ] . as_slice( ) , [ 8 ] . as_slice( ) ) ) ;
1091+
1092+ assert_eq ! ( q. make_contiguous( ) , & [ 5 , 6 , 7 , 8 ] ) ;
1093+
1094+ // Deque contains: 5, 6, 7, 8
1095+ assert_eq ! ( q. as_slices( ) , ( [ 5 , 6 , 7 , 8 ] . as_slice( ) , [ ] . as_slice( ) ) ) ;
1096+ }
8691097}
0 commit comments