Skip to content

Commit ae0b0cd

Browse files
committed
splice: Return an iterator
1 parent 087bb92 commit ae0b0cd

File tree

1 file changed

+43
-84
lines changed

1 file changed

+43
-84
lines changed

text/0000-replace-slice.md

Lines changed: 43 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
Add a `splice` method to `Vec<T>` and `String` removes a range of elements,
1010
and replaces it in place with a given sequence of values.
1111
The new sequence does not necessarily have the same length as the range it replaces.
12+
In the `Vec` case, this method returns an iterator of the elements being moved out, like `drain`.
13+
1214

1315
# Motivation
1416
[motivation]: #motivation
@@ -49,78 +51,44 @@ extern crate collections;
4951
use collections::range::RangeArgument;
5052
use std::ptr;
5153

52-
trait ReplaceVecSlice<T> {
53-
fn splice<R, I>(&mut self, range: R, iterable: I)
54-
where R: RangeArgument<usize>, I: IntoIterator<Item=T>, I::IntoIter: ExactSizeIterator;
54+
trait VecSplice<T> {
55+
fn splice<R, I>(&mut self, range: R, iterable: I) -> Splice<I>
56+
where R: RangeArgument<usize>, I: IntoIterator<Item=T>;
5557
}
5658

57-
impl<T> ReplaceVecSlice<T> for Vec<T> {
58-
fn splice<R, I>(&mut self, range: R, iterable: I)
59-
where R: RangeArgument<usize>, I: IntoIterator<Item=T>, I::IntoIter: ExactSizeIterator
59+
impl<T> VecSplice<T> for Vec<T> {
60+
fn splice<R, I>(&mut self, range: R, iterable: I) -> Splice<I>
61+
where R: RangeArgument<usize>, I: IntoIterator<Item=T>
6062
{
61-
let len = self.len();
62-
let range_start = *range.start().unwrap_or(&0);
63-
let range_end = *range.end().unwrap_or(&len);
64-
assert!(range_start <= range_end);
65-
assert!(range_end <= len);
66-
let mut iter = iterable.into_iter();
67-
// Overwrite range
68-
for i in range_start..range_end {
69-
if let Some(new_element) = iter.next() {
70-
unsafe {
71-
*self.get_unchecked_mut(i) = new_element
72-
}
73-
} else {
74-
// Iterator shorter than range
75-
self.drain(i..range_end);
76-
return
77-
}
78-
}
79-
// Insert rest
80-
let iter_len = iter.len();
81-
let elements_after = len - range_end;
82-
let free_space_start = range_end;
83-
let free_space_end = free_space_start + iter_len;
84-
85-
if iter_len > 0 {
86-
// FIXME: merge the reallocating case with the first ptr::copy below?
87-
self.reserve(iter_len);
88-
89-
let p = self.as_mut_ptr();
90-
unsafe {
91-
// In case iter.next() panics, leak some elements rather than risk double-freeing them.
92-
self.set_len(free_space_start);
93-
// Shift everything over to make space (duplicating some elements).
94-
ptr::copy(p.offset(free_space_start as isize),
95-
p.offset(free_space_end as isize),
96-
elements_after);
97-
for i in free_space_start..free_space_end {
98-
if let Some(new_element) = iter.next() {
99-
*self.get_unchecked_mut(i) = new_element
100-
} else {
101-
// Iterator shorter than its ExactSizeIterator::len()
102-
ptr::copy(p.offset(free_space_end as isize),
103-
p.offset(i as isize),
104-
elements_after);
105-
self.set_len(i + elements_after);
106-
return
107-
}
108-
}
109-
self.set_len(free_space_end + elements_after);
110-
}
111-
}
112-
// Iterator longer than its ExactSizeIterator::len(), degenerate to quadratic time
113-
for (new_element, i) in iter.zip(free_space_end..) {
114-
self.insert(i, new_element);
115-
}
63+
unimplemented!() // FIXME: Fill in when exact semantics are decided.
11664
}
11765
}
11866

119-
trait ReplaceStringSlice {
67+
struct Splice<I: IntoIterator> {
68+
vec: &mut Vec<I::Item>,
69+
range: Range<usize>
70+
iter: I::IntoIter,
71+
// FIXME: Fill in when exact semantics are decided.
72+
}
73+
74+
impl<I: IntoIterator> Iterator for Splice<I> {
75+
type Item = I::Item;
76+
fn next(&mut self) -> Option<Self::Item> {
77+
unimplemented!() // FIXME: Fill in when exact semantics are decided.
78+
}
79+
}
80+
81+
impl<I: IntoIterator> Drop for Splice<I> {
82+
fn drop(&mut self) {
83+
unimplemented!() // FIXME: Fill in when exact semantics are decided.
84+
}
85+
}
86+
87+
trait StringSplice {
12088
fn splice<R>(&mut self, range: R, s: &str) where R: RangeArgument<usize>;
12189
}
12290

123-
impl ReplaceStringSlice for String {
91+
impl StringSplice for String {
12492
fn splice<R>(&mut self, range: R, s: &str) where R: RangeArgument<usize> {
12593
if let Some(&start) = range.start() {
12694
assert!(self.is_char_boundary(start));
@@ -154,12 +122,14 @@ fn char_boundary() {
154122
}
155123
```
156124

157-
This implementation defends against `ExactSizeIterator::len()` being incorrect.
158-
If `len()` is too high, it reserves more capacity than necessary
159-
and does more copying than necessary,
160-
but stays in linear time.
161-
If `len()` is too low, the algorithm degenerates to quadratic time
162-
using `Vec::insert` for each additional new element.
125+
The elements of the vector after the range first be moved by an offset of
126+
the lower bound of `Iterator::size_hint` minus the length of the range.
127+
Then, depending on the real length of the iterator:
128+
129+
* If it’s the same as the lower bound, we’re done.
130+
* If it’s lower than the lower bound (which was then incorrect), the elements will be moved once more.
131+
* If it’s higher, the extra iterator items well be collected into a temporary `Vec`
132+
in order to know exactly how many there are, and the elements after will be moved once more.
163133

164134
# Drawbacks
165135
[drawbacks]: #drawbacks
@@ -178,13 +148,8 @@ not every program needs it, and standard library growth has a maintainance cost.
178148
# Unresolved questions
179149
[unresolved]: #unresolved-questions
180150

181-
* Should the `ExactSizeIterator` bound be removed?
182-
The lower bound of `Iterator::size_hint` could be used instead of `ExactSizeIterator::len`,
183-
but the degenerate quadratic time case would become “normal”.
184-
With `ExactSizeIterator` it only happens when `ExactSizeIterator::len` is incorrect
185-
which means that someone is doing something wrong.
186-
187-
* Alternatively, should `splice` panic when `ExactSizeIterator::len` is incorrect?
151+
* Should the input iterator be consumed incrementally at each `Splice::next` call,
152+
or only in `Splice::drop`?
188153

189154
* It would be nice to be able to `Vec::splice` with a slice
190155
without writing `.iter().cloned()` explicitly.
@@ -193,9 +158,9 @@ not every program needs it, and standard library growth has a maintainance cost.
193158
accept iterators of `&T` as well as iterators of `T`:
194159

195160
```rust
196-
impl<'a, T: 'a> ReplaceVecSlice<&'a T> for Vec<T> where T: Copy {
161+
impl<'a, T: 'a> VecSplice<&'a T> for Vec<T> where T: Copy {
197162
fn splice<R, I>(&mut self, range: R, iterable: I)
198-
where R: RangeArgument<usize>, I: IntoIterator<Item=&'a T>, I::IntoIter: ExactSizeIterator
163+
where R: RangeArgument<usize>, I: IntoIterator<Item=&'a T>
199164
{
200165
self.splice(range, iterable.into_iter().cloned())
201166
}
@@ -206,12 +171,6 @@ not every program needs it, and standard library growth has a maintainance cost.
206171
(By the way, what was the motivation for `Extend` being a trait rather than inherent methods,
207172
before RFC 839?)
208173

209-
* The method could return an iterator of the replaced elements.
210-
Nothing would happen when the method is called,
211-
only when the returned iterator is advanced or dropped.
212-
There’s is precedent of this in `Vec::drain`,
213-
though the input iterator being lazily consumed could be surprising.
214-
215174
* If coherence rules and backward-compatibility allow it,
216175
this functionality could be added to `Vec::insert` and `String::insert`
217176
by overloading them / making them more generic.

0 commit comments

Comments
 (0)