diff --git a/src/ext.rs b/src/ext.rs index eb7fe9d..4ed9f53 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -25,25 +25,62 @@ pub trait FindSliceBounds pub trait SliceInPlace { - fn slice_in_place(&mut self, slice: Range); + #[deprecated = "Slow. Use `drain_inverse`"] + #[inline] + fn slice_in_place>(&mut self, slice: R) + { + self.drain_inverse(slice); + } + fn drain_inverse>(&mut self, slice: R); } impl SliceInPlace for String { - fn slice_in_place(&mut self, slice: Range) { + fn slice_in_place>(&mut self, slice: R) { let mut i=0; self.retain(|_| (slice.contains(&i), i+=1).0); } + + fn drain_inverse>(&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 SliceInPlace for Vec { - fn slice_in_place(&mut self, slice: Range) { + fn slice_in_place>(&mut self, slice: R) { let mut i=0; self.retain(|_| (slice.contains(&i), i+=1).0); } + + fn drain_inverse>(&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> FindSliceBounds for T { type SliceType = str; @@ -72,6 +109,8 @@ impl> 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"); + } } diff --git a/src/format/key/mod.rs b/src/format/key/mod.rs index 17ff2db..2b6021a 100644 --- a/src/format/key/mod.rs +++ b/src/format/key/mod.rs @@ -274,7 +274,7 @@ impl KeyHeader } buffer.slice_bounds(trimmed) }; - buffer.slice_in_place(bounds); + buffer.drain_inverse(bounds); if { let bytes = buffer.as_bytes();