Skip to content

Commit 30dc32b

Browse files
committed
Add (non-public) slice::split_at_unchecked() and split_at_mut_unchecked()
These are unsafe variants of the non-unchecked functions and don't do any bounds checking. For the time being these are not public and only a preparation for the following commit. Making it public and stabilization can follow later and be discussed in rust-lang#76014 .
1 parent 2fe9a33 commit 30dc32b

File tree

1 file changed

+94
-8
lines changed

1 file changed

+94
-8
lines changed

library/core/src/slice/mod.rs

+94-8
Original file line numberDiff line numberDiff line change
@@ -1148,7 +1148,10 @@ impl<T> [T] {
11481148
#[stable(feature = "rust1", since = "1.0.0")]
11491149
#[inline]
11501150
pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
1151-
(&self[..mid], &self[mid..])
1151+
assert!(mid <= self.len());
1152+
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
1153+
// fulfills the requirements of `from_raw_parts_mut`.
1154+
unsafe { self.split_at_unchecked(mid) }
11521155
}
11531156

11541157
/// Divides one mutable slice into two at an index.
@@ -1178,16 +1181,99 @@ impl<T> [T] {
11781181
#[stable(feature = "rust1", since = "1.0.0")]
11791182
#[inline]
11801183
pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
1181-
let len = self.len();
1182-
let ptr = self.as_mut_ptr();
1183-
1184+
assert!(mid <= self.len());
11841185
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
11851186
// fulfills the requirements of `from_raw_parts_mut`.
1186-
unsafe {
1187-
assert!(mid <= len);
1187+
unsafe { self.split_at_mut_unchecked(mid) }
1188+
}
11881189

1189-
(from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid))
1190-
}
1190+
/// Divides one slice into two at an index, without doing bounds checking.
1191+
///
1192+
/// The first will contain all indices from `[0, mid)` (excluding
1193+
/// the index `mid` itself) and the second will contain all
1194+
/// indices from `[mid, len)` (excluding the index `len` itself).
1195+
///
1196+
/// This is generally not recommended, use with caution!
1197+
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
1198+
/// even if the resulting reference is not used.
1199+
/// For a safe alternative see [`split_at`].
1200+
///
1201+
/// [`split_at`]: #method.split_at
1202+
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1203+
///
1204+
/// # Examples
1205+
///
1206+
/// ```compile_fail
1207+
/// #![feature(slice_split_at_unchecked)]
1208+
///
1209+
/// let v = [1, 2, 3, 4, 5, 6];
1210+
///
1211+
/// unsafe {
1212+
/// let (left, right) = v.split_at_unchecked(0);
1213+
/// assert!(left == []);
1214+
/// assert!(right == [1, 2, 3, 4, 5, 6]);
1215+
/// }
1216+
///
1217+
/// unsafe {
1218+
/// let (left, right) = v.split_at_unchecked(2);
1219+
/// assert!(left == [1, 2]);
1220+
/// assert!(right == [3, 4, 5, 6]);
1221+
/// }
1222+
///
1223+
/// unsafe {
1224+
/// let (left, right) = v.split_at_unchecked(6);
1225+
/// assert!(left == [1, 2, 3, 4, 5, 6]);
1226+
/// assert!(right == []);
1227+
/// }
1228+
/// ```
1229+
#[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
1230+
#[inline]
1231+
unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) {
1232+
// SAFETY: Caller has to check that 0 <= mid < self.len()
1233+
unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) }
1234+
}
1235+
1236+
/// Divides one mutable slice into two at an index, without doing bounds checking.
1237+
///
1238+
/// The first will contain all indices from `[0, mid)` (excluding
1239+
/// the index `mid` itself) and the second will contain all
1240+
/// indices from `[mid, len)` (excluding the index `len` itself).
1241+
///
1242+
/// This is generally not recommended, use with caution!
1243+
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
1244+
/// even if the resulting reference is not used.
1245+
/// For a safe alternative see [`split_at_mut`].
1246+
///
1247+
/// [`split_at_mut`]: #method.split_at_mut
1248+
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1249+
///
1250+
/// # Examples
1251+
///
1252+
/// ```compile_fail
1253+
/// #![feature(slice_split_at_unchecked)]
1254+
///
1255+
/// let mut v = [1, 0, 3, 0, 5, 6];
1256+
/// // scoped to restrict the lifetime of the borrows
1257+
/// unsafe {
1258+
/// let (left, right) = v.split_at_mut_unchecked(2);
1259+
/// assert!(left == [1, 0]);
1260+
/// assert!(right == [3, 0, 5, 6]);
1261+
/// left[1] = 2;
1262+
/// right[1] = 4;
1263+
/// }
1264+
/// assert!(v == [1, 2, 3, 4, 5, 6]);
1265+
/// ```
1266+
#[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
1267+
#[inline]
1268+
unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
1269+
let len = self.len();
1270+
let ptr = self.as_mut_ptr();
1271+
1272+
// SAFETY: Caller has to check that 0 <= mid < self.len().
1273+
//
1274+
// [ptr; mid] and [mid; len] are not overlapping, so returning a mutable reference
1275+
// is fine.
1276+
unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
11911277
}
11921278

11931279
/// Returns an iterator over subslices separated by elements that match

0 commit comments

Comments
 (0)