rust/src/doc/tarpl/vec-insert-remove.md

52 lines
1.7 KiB
Markdown
Raw Normal View History

2015-07-06 18:36:16 -07:00
% Insert and Remove
2015-07-20 11:31:29 -07:00
Something *not* provided by slice is `insert` and `remove`, so let's do those
next.
2015-07-06 18:36:16 -07:00
Insert needs to shift all the elements at the target index to the right by one.
To do this we need to use `ptr::copy`, which is our version of C's `memmove`.
2015-07-20 11:31:29 -07:00
This copies some chunk of memory from one location to another, correctly
handling the case where the source and destination overlap (which will
definitely happen here).
2015-07-06 18:36:16 -07:00
If we insert at index `i`, we want to shift the `[i .. len]` to `[i+1 .. len+1]`
using the *old* len.
2015-07-14 11:07:00 -07:00
```rust,ignore
2015-07-06 18:36:16 -07:00
pub fn insert(&mut self, index: usize, elem: T) {
// Note: `<=` because it's valid to insert after everything
// which would be equivalent to push.
assert!(index <= self.len, "index out of bounds");
if self.cap == self.len { self.grow(); }
unsafe {
if index < self.len {
// ptr::copy(src, dest, len): "copy from source to dest len elems"
ptr::copy(self.ptr.offset(index as isize),
self.ptr.offset(index as isize + 1),
len - index);
}
ptr::write(self.ptr.offset(index as isize), elem);
self.len += 1;
}
}
```
Remove behaves in the opposite manner. We need to shift all the elements from
`[i+1 .. len + 1]` to `[i .. len]` using the *new* len.
2015-07-14 11:07:00 -07:00
```rust,ignore
2015-07-06 18:36:16 -07:00
pub fn remove(&mut self, index: usize) -> T {
// Note: `<` because it's *not* valid to remove after everything
assert!(index < self.len, "index out of bounds");
unsafe {
self.len -= 1;
let result = ptr::read(self.ptr.offset(index as isize));
ptr::copy(self.ptr.offset(index as isize + 1),
self.ptr.offset(index as isize),
len - index);
result
}
}
2015-07-14 11:07:00 -07:00
```