@@ -191,6 +191,183 @@ 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
+ ///
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
+
194
371
/// Provides a reference to the front element, or None if the `Deque` is empty.
195
372
pub fn front ( & self ) -> Option < & T > {
196
373
if self . is_empty ( ) {
@@ -866,4 +1043,55 @@ mod tests {
866
1043
q. push_back ( 0 ) . unwrap ( ) ;
867
1044
assert_eq ! ( q. len( ) , 1 ) ;
868
1045
}
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
+ }
869
1097
}
0 commit comments