@@ -1289,6 +1289,70 @@ impl<T> RingBuf<T> {
12891289
12901290 return elem;
12911291 }
1292+
1293+ /// Splits the collection into two at the given index.
1294+ ///
1295+ /// Returns a newly allocated `Self`. `self` contains elements `[0, at)`,
1296+ /// and the returned `Self` contains elements `[at, len)`.
1297+ ///
1298+ /// Note that the capacity of `self` does not change.
1299+ ///
1300+ /// # Panics
1301+ ///
1302+ /// Panics if `at > len`
1303+ ///
1304+ /// # Examples
1305+ /// ```rust
1306+ /// let mut buf: RingBuf<_> = vec![1,2,3].into_iter().collect();
1307+ /// let buf2 = buf.split_off(1);
1308+ /// // buf = [1], buf2 = [2, 3]
1309+ /// assert_eq!(buf.len(), 1);
1310+ /// assert_eq!(buf2.len(), 2);
1311+ /// ```
1312+ #[ inline]
1313+ #[ unstable( feature = "collections" ,
1314+ reason = "new API, waiting for dust to settle" ) ]
1315+ pub fn split_off ( & mut self , at : usize ) -> Self {
1316+ let len = self . len ( ) ;
1317+ assert ! ( at <= len, "`at` out of bounds" ) ;
1318+
1319+ let other_len = len - at;
1320+ let mut other = RingBuf :: with_capacity ( other_len) ;
1321+
1322+ unsafe {
1323+ let ( first_half, second_half) = self . as_slices ( ) ;
1324+
1325+ let first_len = first_half. len ( ) ;
1326+ let second_len = second_half. len ( ) ;
1327+ if at < first_len {
1328+ // `at` lies in the first half.
1329+ let amount_in_first = first_len - at;
1330+
1331+ ptr:: copy_nonoverlapping_memory ( other. ptr ,
1332+ first_half. as_ptr ( ) . offset ( at as isize ) ,
1333+ amount_in_first) ;
1334+
1335+ // just take all of the second half.
1336+ ptr:: copy_nonoverlapping_memory ( other. ptr . offset ( amount_in_first as isize ) ,
1337+ second_half. as_ptr ( ) ,
1338+ second_len) ;
1339+ } else {
1340+ // `at` lies in the second half, need to factor in the elements we skipped
1341+ // in the first half.
1342+ let offset = at - first_len;
1343+ let amount_in_second = second_len - offset;
1344+ ptr:: copy_nonoverlapping_memory ( other. ptr ,
1345+ second_half. as_ptr ( ) . offset ( offset as isize ) ,
1346+ amount_in_second) ;
1347+ }
1348+ }
1349+
1350+ // Cleanup where the ends of the buffers are
1351+ self . head = self . wrap_index ( self . head - other_len) ;
1352+ other. head = other. wrap_index ( other_len) ;
1353+
1354+ other
1355+ }
12921356}
12931357
12941358impl < T : Clone > RingBuf < T > {
@@ -2711,4 +2775,42 @@ mod tests {
27112775 assert_eq ! ( ring. len( ) as i32 , cap) ;
27122776 assert_eq ! ( ring. capacity( ) as i32 , cap) ;
27132777 }
2778+
2779+ #[ test]
2780+ fn test_split_off ( ) {
2781+ // This test checks that every single combination of tail position, length, and
2782+ // split position is tested. Capacity 15 should be large enough to cover every case.
2783+
2784+ let mut tester = RingBuf :: with_capacity ( 15 ) ;
2785+ // can't guarantee we got 15, so have to get what we got.
2786+ // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else
2787+ // this test isn't covering what it wants to
2788+ let cap = tester. capacity ( ) ;
2789+
2790+ // len is the length *before* splitting
2791+ for len in 0 ..cap {
2792+ // index to split at
2793+ for at in 0 ..len + 1 {
2794+ // 0, 1, 2, .., at - 1 (may be empty)
2795+ let expected_self = iter:: count ( 0 , 1 ) . take ( at) . collect ( ) ;
2796+ // at, at + 1, .., len - 1 (may be empty)
2797+ let expected_other = iter:: count ( at, 1 ) . take ( len - at) . collect ( ) ;
2798+
2799+ for tail_pos in 0 ..cap {
2800+ tester. tail = tail_pos;
2801+ tester. head = tail_pos;
2802+ for i in 0 ..len {
2803+ tester. push_back ( i) ;
2804+ }
2805+ let result = tester. split_off ( at) ;
2806+ assert ! ( tester. tail < tester. cap) ;
2807+ assert ! ( tester. head < tester. cap) ;
2808+ assert ! ( result. tail < result. cap) ;
2809+ assert ! ( result. head < result. cap) ;
2810+ assert_eq ! ( tester, expected_self) ;
2811+ assert_eq ! ( result, expected_other) ;
2812+ }
2813+ }
2814+ }
2815+ }
27142816}
0 commit comments