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