|
|
|
@ -25,25 +25,62 @@ pub trait FindSliceBounds
|
|
|
|
|
|
|
|
|
|
pub trait SliceInPlace
|
|
|
|
|
{
|
|
|
|
|
fn slice_in_place(&mut self, slice: Range<usize>);
|
|
|
|
|
#[deprecated = "Slow. Use `drain_inverse`"]
|
|
|
|
|
#[inline]
|
|
|
|
|
fn slice_in_place<R: std::ops::RangeBounds<usize>>(&mut self, slice: R)
|
|
|
|
|
{
|
|
|
|
|
self.drain_inverse(slice);
|
|
|
|
|
}
|
|
|
|
|
fn drain_inverse<R: std::ops::RangeBounds<usize>>(&mut self, slice: R);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SliceInPlace for String
|
|
|
|
|
{
|
|
|
|
|
fn slice_in_place(&mut self, slice: Range<usize>) {
|
|
|
|
|
fn slice_in_place<R: std::ops::RangeBounds<usize>>(&mut self, slice: R) {
|
|
|
|
|
let mut i=0;
|
|
|
|
|
self.retain(|_| (slice.contains(&i), i+=1).0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn drain_inverse<R: std::ops::RangeBounds<usize>>(&mut self, slice: R)
|
|
|
|
|
{
|
|
|
|
|
use std::ops::Bound;
|
|
|
|
|
match slice.end_bound() {
|
|
|
|
|
Bound::Excluded(&ex) => drop(self.drain(ex..)),
|
|
|
|
|
Bound::Included(&inc) => drop(self.drain(inc+1..)),
|
|
|
|
|
_ => (),
|
|
|
|
|
};
|
|
|
|
|
match slice.start_bound() {
|
|
|
|
|
Bound::Included(&ex) => drop(self.drain(..ex)),
|
|
|
|
|
Bound::Excluded(&ex) => drop(..ex+1),
|
|
|
|
|
_ => ()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> SliceInPlace for Vec<T>
|
|
|
|
|
{
|
|
|
|
|
fn slice_in_place(&mut self, slice: Range<usize>) {
|
|
|
|
|
fn slice_in_place<R: std::ops::RangeBounds<usize>>(&mut self, slice: R) {
|
|
|
|
|
let mut i=0;
|
|
|
|
|
self.retain(|_| (slice.contains(&i), i+=1).0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn drain_inverse<R: std::ops::RangeBounds<usize>>(&mut self, slice: R)
|
|
|
|
|
{
|
|
|
|
|
use std::ops::Bound;
|
|
|
|
|
match slice.end_bound() {
|
|
|
|
|
Bound::Excluded(&ex) => drop(self.drain(ex..)),
|
|
|
|
|
Bound::Included(&inc) => drop(self.drain(inc+1..)),
|
|
|
|
|
_ => (),
|
|
|
|
|
};
|
|
|
|
|
match slice.start_bound() {
|
|
|
|
|
Bound::Included(&ex) => drop(self.drain(..ex)),
|
|
|
|
|
Bound::Excluded(&ex) => drop(..ex+1),
|
|
|
|
|
_ => ()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<T: ?Sized + AsRef<str>> FindSliceBounds for T
|
|
|
|
|
{
|
|
|
|
|
type SliceType = str;
|
|
|
|
@ -72,6 +109,8 @@ impl<T: ?Sized + AsRef<str>> FindSliceBounds for T
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test_slice_in_place
|
|
|
|
|
{
|
|
|
|
|
use test::{Bencher, black_box};
|
|
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
#[test]
|
|
|
|
|
fn slice_in_place_str()
|
|
|
|
@ -85,6 +124,36 @@ mod test_slice_in_place
|
|
|
|
|
assert_eq!(&string[string.slice_bounds(string.trim())], string.trim());
|
|
|
|
|
assert_eq!(&string[string.slice_bounds(string.trim())], "hello world");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
|
fn bench_slice_in_place(b: &mut Bencher)
|
|
|
|
|
{
|
|
|
|
|
let mut string = String::from("hello ONE TWO world");
|
|
|
|
|
b.iter(|| {
|
|
|
|
|
black_box(string.slice_in_place(7..16));
|
|
|
|
|
string.push_str("ONE TWO");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
|
fn bench_drain_inverse(b: &mut Bencher)
|
|
|
|
|
{
|
|
|
|
|
let mut string = String::from("hello ONE TWO world");
|
|
|
|
|
b.iter(|| {
|
|
|
|
|
black_box(string.drain_inverse(7..16));
|
|
|
|
|
string.push_str("ONE TWO");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn drain_inverse()
|
|
|
|
|
{
|
|
|
|
|
let mut string = String::from("123hello world5678");
|
|
|
|
|
string.drain_inverse(3..=13);
|
|
|
|
|
assert_eq!(&string[..], "hello world");
|
|
|
|
|
string.drain_inverse(6..);
|
|
|
|
|
assert_eq!(&string[..], "world");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|