-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add methods to String which can remove multiple elements at once #570
Conversation
CC @aturon This makes sense to me, although adding ever-more methods for this sort of thing is unfortunate. Especially because I forsee someone saying they want this API in iterator form, or just "returns a Vec/String" form. Perhaps this could be generalized to a |
You can implement these methods outside of libstd using based on Rather than take a pair of impl Vec {
pub fn remove<R>(&mut self, R) where R: RemoveFromVec {
R.remove_from(self)
}
}
pub trait RemoveFromVec {
fn remove_from(&self, &mut Vec);
}
// Usage: v.remove(i), same as currently
impl RemoveFromVec for usize { /* ... */ }
// Usage: v.remove(i..j)
impl RemoveFromVec for Range<usize> { /* ... */ }
// Usage: v.remove(i..), same as v.truncate(i) (which could be removed?)
impl RemoveFromVec for RangeFrom<usize> { /* ... */ }
// Usage: v.remove(..i)
impl RemoveFromVec for RangeTo<usize> { /* ... */ }
// Usage: v.remove(..), same as v.clear() (which could be removed?)
impl RemoveFromVec for FullRange { /* ... */ } |
|
Also note that |
An associated type for the return value could work, but might be "too much magic". So maybe |
We could theoretically fold CC @cgaebel thoughts? |
#![feature(unsafe_destructor, slicing_syntax)]
use std::{ptr, mem};
use std::ops::{Range, RangeFrom, RangeTo, FullRange};
pub struct DrainRangeIter<'a, T: 'a> {
vec: &'a mut Vec<T>,
next: *mut T,
next_back: *mut T,
range_end: *mut T,
rest: usize,
}
impl<'a, T> Iterator for DrainRangeIter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
unsafe {
if self.next == self.next_back {
None
} else {
if mem::size_of::<T>() == 0 {
let ret = ptr::read(1u as *mut T);
self.next = (self.next as usize + 1) as *mut T;
Some(ret)
} else {
let ret = ptr::read(self.next);
self.next = self.next.offset(1);
Some(ret)
}
}
}
}
fn size_hint(&self) -> (uint, Option<uint>) {
let diff = (self.next_back as uint) - (self.next as uint);
let size = mem::size_of::<T>();
let exact = diff / (if size == 0 {1} else {size});
(exact, Some(exact))
}
}
impl<'a, T> DoubleEndedIterator for DrainRangeIter<'a, T> {
fn next_back(&mut self) -> Option<T> {
unsafe {
if self.next == self.next_back {
None
} else {
if mem::size_of::<T>() == 0 {
self.next_back = (self.next_back as usize - 1) as *mut T;
Some(ptr::read(1u as *mut T))
} else {
self.next_back = self.next_back.offset(-1);
Some(ptr::read(self.next))
}
}
}
}
}
#[unsafe_destructor]
impl<'a, T> Drop for DrainRangeIter<'a, T> {
fn drop(&mut self) {
for _x in *self { }
let ptr = self.vec.as_mut_ptr();
let len = self.vec.len();
unsafe {
let dest = ptr.offset(len as isize);
ptr::copy_memory(dest, self.range_end, self.rest);
self.vec.set_len(len + self.rest);
}
}
}
pub trait DrainFromVec {
fn drain_from<'a, T>(&self, vec: &'a mut Vec<T>) -> DrainRangeIter<'a, T>;
}
impl DrainFromVec for Range<usize> {
fn drain_from<'a, T>(&self, vec: &'a mut Vec<T>) -> DrainRangeIter<'a, T> {
assert!(self.start <= self.end);
assert!(self.end <= vec.len());
let ptr = vec.as_mut_ptr();
let len = vec.len();
unsafe {
vec.set_len(self.start);
let (next, range_end) = if mem::size_of::<T>() == 0 {
((ptr as usize + self.start) as *mut T, (ptr as usize + self.end) as *mut T)
} else {
(ptr.offset(self.start as isize), ptr.offset(self.end as isize))
};
DrainRangeIter {
vec: vec,
next: next,
next_back: range_end,
range_end: range_end,
rest: len - self.end,
}
}
}
}
impl DrainFromVec for RangeFrom<usize> {
fn drain_from<'a, T>(&self, vec: &'a mut Vec<T>) -> DrainRangeIter<'a, T> {
(self.start..vec.len()).drain_from(vec)
}
}
impl DrainFromVec for RangeTo<usize> {
fn drain_from<'a, T>(&self, vec: &'a mut Vec<T>) -> DrainRangeIter<'a, T> {
(0..self.end).drain_from(vec)
}
}
impl DrainFromVec for FullRange {
fn drain_from<'a, T>(&self, vec: &'a mut Vec<T>) -> DrainRangeIter<'a, T> {
(0..vec.len()).drain_from(vec)
}
}
pub trait DrainRange<T> {
fn drain_range<'a, R>(&'a mut self,
r: R) -> DrainRangeIter<'a, T> where R: DrainFromVec;
}
impl<T> DrainRange<T> for Vec<T> {
fn drain_range<'a, R>(&'a mut self,
r: R) -> DrainRangeIter<'a, T> where R: DrainFromVec {
r.drain_from(self)
}
}
fn main() {
let mut s = b"abcdefghijklm".to_vec();
for b in s.drain_range(..5) {
println!("{}", b as char);
}
println!("{:?}", s);
} Naturally this doesn't work for String. |
The vector part has been moved to #574. |
Closing in favor of the RFCs. |
Add a method to
String
that allows the user to remove more thanone characterat a time while preserving the order of the remaining
characters.
Rendered