9
9
Add a ` splice ` method to ` Vec<T> ` and ` String ` removes a range of elements,
10
10
and replaces it in place with a given sequence of values.
11
11
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
+
12
14
13
15
# Motivation
14
16
[ motivation ] : #motivation
@@ -49,78 +51,44 @@ extern crate collections;
49
51
use collections :: range :: RangeArgument ;
50
52
use std :: ptr;
51
53
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 >;
55
57
}
56
58
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 >
60
62
{
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.
116
64
}
117
65
}
118
66
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 {
120
88
fn splice <R >(& mut self , range : R , s : & str ) where R : RangeArgument <usize >;
121
89
}
122
90
123
- impl ReplaceStringSlice for String {
91
+ impl StringSplice for String {
124
92
fn splice <R >(& mut self , range : R , s : & str ) where R : RangeArgument <usize > {
125
93
if let Some (& start ) = range . start () {
126
94
assert! (self . is_char_boundary (start ));
@@ -154,12 +122,14 @@ fn char_boundary() {
154
122
}
155
123
```
156
124
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.
163
133
164
134
# Drawbacks
165
135
[ drawbacks ] : #drawbacks
@@ -178,13 +148,8 @@ not every program needs it, and standard library growth has a maintainance cost.
178
148
# Unresolved questions
179
149
[ unresolved ] : #unresolved-questions
180
150
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 ` ?
188
153
189
154
* It would be nice to be able to ` Vec::splice ` with a slice
190
155
without writing ` .iter().cloned() ` explicitly.
@@ -193,9 +158,9 @@ not every program needs it, and standard library growth has a maintainance cost.
193
158
accept iterators of ` &T ` as well as iterators of ` T ` :
194
159
195
160
``` 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 {
197
162
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 >
199
164
{
200
165
self . splice (range , iterable . into_iter (). cloned ())
201
166
}
@@ -206,12 +171,6 @@ not every program needs it, and standard library growth has a maintainance cost.
206
171
(By the way, what was the motivation for ` Extend ` being a trait rather than inherent methods,
207
172
before RFC 839?)
208
173
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
-
215
174
* If coherence rules and backward-compatibility allow it,
216
175
this functionality could be added to ` Vec::insert ` and ` String::insert `
217
176
by overloading them / making them more generic.
0 commit comments