Skip to content

Commit bceac22

Browse files
committed
Add range_of to slice/str return a Range, opposite to get
1 parent 2e43d06 commit bceac22

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

library/core/src/slice/mod.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4018,6 +4018,55 @@ impl<T> [T] {
40184018
*self = rem;
40194019
Some(last)
40204020
}
4021+
4022+
/// Gives the `Range` where the `other` slice is located within `self`,
4023+
/// or `None` if it is not a sub-slice.
4024+
///
4025+
/// This method can be thought of as the opposite of [`get`](#method.get),
4026+
/// and they mutually guarantee slice-to-slice roundtrips, as well as
4027+
/// range-to-range roundtrips if `T` is not a Zero-Sized Type.
4028+
///
4029+
/// This means that the resulting [`Range`] can be passed to
4030+
/// [`get`](#method.get) and will always return a slice that is [`ptr::eq`]
4031+
/// to the one passed to this function.
4032+
///
4033+
/// If `T` is a Zero-Sized Type ("ZST"), the resulting [`Range`] will always
4034+
/// start at `0`, and thus range-to-range roundtrips are not guaranteed.
4035+
///
4036+
/// # Examples
4037+
///
4038+
/// ```
4039+
/// #![feature(slice_range_of)]
4040+
///
4041+
/// let slice: &[u8] = &[1, 2, 3, 4, 5];
4042+
/// let subslice = &slice[1..3];
4043+
/// let foreign_slice: &[u8] = &[2, 3];
4044+
///
4045+
/// assert_eq!(slice.range_of(subslice), Some(1..3));
4046+
/// assert_eq!(slice.range_of(foreign_slice), None);
4047+
/// ```
4048+
#[unstable(feature = "slice_range_of", issue = "none")]
4049+
#[inline]
4050+
pub fn range_of(&self, other: &Self) -> Option<Range<usize>> {
4051+
if mem::size_of::<T>() == 0 {
4052+
return if self.as_ptr() == other.as_ptr() && self.len() <= other.len() {
4053+
Some(0..self.len())
4054+
} else {
4055+
None
4056+
};
4057+
}
4058+
4059+
let self_ptr = self.as_ptr_range();
4060+
let other_ptr = other.as_ptr_range();
4061+
if self_ptr.start <= other_ptr.start && other_ptr.end <= self_ptr.end {
4062+
// SAFETY: the bounds checks above uphold the safety contract for `sub_ptr`.
4063+
Some(unsafe {
4064+
other_ptr.start.sub_ptr(self_ptr.start)..other_ptr.end.sub_ptr(self_ptr.start)
4065+
})
4066+
} else {
4067+
None
4068+
}
4069+
}
40214070
}
40224071

40234072
impl<T, const N: usize> [[T; N]] {

library/core/src/str/mod.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
1818

1919
use crate::char::{self, EscapeDebugExtArgs};
2020
use crate::mem;
21+
use crate::ops::Range;
2122
use crate::slice::{self, SliceIndex};
2223

2324
pub mod pattern;
@@ -2555,6 +2556,39 @@ impl str {
25552556
pub fn escape_unicode(&self) -> EscapeUnicode<'_> {
25562557
EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) }
25572558
}
2559+
2560+
/// Gives the `Range` where `substr` is located within `self`, or `None`
2561+
/// if it is not a sub-string.
2562+
///
2563+
/// This method can be thought of as the opposite of [`get`](#method.get),
2564+
/// and they mutually guarantee slice-to-slice roundtrips and
2565+
/// range-to-range roundtrips.
2566+
///
2567+
/// This means that the resulting [`Range`] can be passed to
2568+
/// [`get`](#method.get) and will always return a sub-string that is
2569+
/// [`ptr::eq`](std::ptr::eq) to the one passed to this function.
2570+
///
2571+
/// This is different from using [`find`](#method.find) as it does not do
2572+
/// a search, but rather a pointer comparison. The given `substr` must
2573+
/// point to the same memory location as `self`.
2574+
///
2575+
/// # Examples
2576+
///
2577+
/// ```
2578+
/// #![feature(slice_range_of)]
2579+
///
2580+
/// let containing_str = "abcdefg";
2581+
/// let other_str = "abcdef.h";
2582+
/// let substr = &containing_str[1..3];
2583+
///
2584+
/// assert_eq!(containing_str.range_of(substr), Some(1..3));
2585+
/// assert_eq!(other_str.range_of(substr), None);
2586+
/// ```
2587+
#[unstable(feature = "slice_range_of", issue = "none")]
2588+
#[inline]
2589+
pub fn range_of(&self, substr: &Self) -> Option<Range<usize>> {
2590+
self.as_bytes().range_of(substr.as_bytes())
2591+
}
25582592
}
25592593

25602594
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)