@@ -191,6 +191,178 @@ impl<T, const N: usize> Deque<T, N> {
191
191
}
192
192
}
193
193
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
+
194
366
/// Provides a reference to the front element, or None if the `Deque` is empty.
195
367
pub fn front ( & self ) -> Option < & T > {
196
368
if self . is_empty ( ) {
@@ -866,4 +1038,55 @@ mod tests {
866
1038
q. push_back ( 0 ) . unwrap ( ) ;
867
1039
assert_eq ! ( q. len( ) , 1 ) ;
868
1040
}
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
+ }
869
1092
}
0 commit comments