Auto merge of #88540 - ibraheemdev:swap-unchecked, r=kennytm
add `slice::swap_unchecked` An unsafe version of `slice::swap` that does not do bounds checking.
This commit is contained in:
commit
1dafe6d1c3
@ -560,15 +560,52 @@ pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn swap(&mut self, a: usize, b: usize) {
|
||||
// Can't take two mutable loans from one vector, so instead use raw pointers.
|
||||
let pa = ptr::addr_of_mut!(self[a]);
|
||||
let pb = ptr::addr_of_mut!(self[b]);
|
||||
// SAFETY: `pa` and `pb` have been created from safe mutable references and refer
|
||||
// to elements in the slice and therefore are guaranteed to be valid and aligned.
|
||||
// Note that accessing the elements behind `a` and `b` is checked and will
|
||||
// panic when out of bounds.
|
||||
let _ = &self[a];
|
||||
let _ = &self[b];
|
||||
|
||||
// SAFETY: we just checked that both `a` and `b` are in bounds
|
||||
unsafe { self.swap_unchecked(a, b) }
|
||||
}
|
||||
|
||||
/// Swaps two elements in the slice, without doing bounds checking.
|
||||
///
|
||||
/// For a safe alternative see [`swap`].
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * a - The index of the first element
|
||||
/// * b - The index of the second element
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Calling this method with an out-of-bounds index is *[undefined behavior]*.
|
||||
/// The caller has to ensure that `a < self.len()` and `b < self.len()`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_swap_unchecked)]
|
||||
///
|
||||
/// let mut v = ["a", "b", "c", "d"];
|
||||
/// // SAFETY: we know that 1 and 3 are both indices of the slice
|
||||
/// unsafe { v.swap_unchecked(1, 3) };
|
||||
/// assert!(v == ["a", "d", "c", "b"]);
|
||||
/// ```
|
||||
///
|
||||
/// [`swap`]: slice::swap
|
||||
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||
#[unstable(feature = "slice_swap_unchecked", issue = "88539")]
|
||||
pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let _ = &self[a];
|
||||
let _ = &self[b];
|
||||
}
|
||||
|
||||
let ptr = self.as_mut_ptr();
|
||||
// SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()`
|
||||
unsafe {
|
||||
ptr::swap(pa, pb);
|
||||
ptr::swap(ptr.add(a), ptr.add(b));
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,11 +712,7 @@ pub fn reverse(&mut self) {
|
||||
// The resulting pointers `pa` and `pb` are therefore valid and
|
||||
// aligned, and can be read from and written to.
|
||||
unsafe {
|
||||
// Unsafe swap to avoid the bounds check in safe swap.
|
||||
let ptr = self.as_mut_ptr();
|
||||
let pa = ptr.add(i);
|
||||
let pb = ptr.add(ln - i - 1);
|
||||
ptr::swap(pa, pb);
|
||||
self.swap_unchecked(i, ln - i - 1);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
@ -2152,3 +2152,42 @@ fn test_slice_fill_with_uninit() {
|
||||
let mut a = [MaybeUninit::<u8>::uninit(); 10];
|
||||
a.fill(MaybeUninit::uninit());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_swap() {
|
||||
let mut x = ["a", "b", "c", "d"];
|
||||
x.swap(1, 3);
|
||||
assert_eq!(x, ["a", "d", "c", "b"]);
|
||||
x.swap(0, 3);
|
||||
assert_eq!(x, ["b", "d", "c", "a"]);
|
||||
}
|
||||
|
||||
mod swap_panics {
|
||||
#[test]
|
||||
#[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
|
||||
fn index_a_equals_len() {
|
||||
let mut x = ["a", "b", "c", "d"];
|
||||
x.swap(4, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
|
||||
fn index_b_equals_len() {
|
||||
let mut x = ["a", "b", "c", "d"];
|
||||
x.swap(2, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")]
|
||||
fn index_a_greater_than_len() {
|
||||
let mut x = ["a", "b", "c", "d"];
|
||||
x.swap(5, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")]
|
||||
fn index_b_greater_than_len() {
|
||||
let mut x = ["a", "b", "c", "d"];
|
||||
x.swap(2, 5);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user