挿入と削除

スライスから提供されないものに、 insertremove があります。 今度はこれらを実装していきましょう。

挿入では、挿入位置から最後の要素まで、 1 ずつずらす必要があります。 これを行なうために、 ptr::copy を使う必要があります。 C の memmove の、 Rust 版のようなものです。これは、ある場所のメモリを別の場所にコピーします。 そして、2つの場所が重なっていても、正しくコピーされます (今回の場合、 明らかに重なります) 。

インデックス i の位置に挿入する場合、古い len の値を用いて、 [i .. len][i+1 .. len+1] にシフトします。

pub fn insert(&mut self, index: usize, elem: T) {
    // 注意: 全要素の後に挿入しても問題ないため、
    // `<=` としています。これは、プッシュと同等です。

    // 境界外インデックスです
    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): "src から dest まで len 個の要素をコピー"
            ptr::copy(self.ptr.offset(index as isize),
                      self.ptr.offset(index as isize + 1),
                      self.len - index);
        }
        ptr::write(self.ptr.offset(index as isize), elem);
        self.len += 1;
    }
}

削除では真逆の事を行ないます。新しい len を使用して、 [i+1 .. len+1][i .. len] にシフトします。

pub fn remove(&mut self, index: usize) -> T {
    // 注意: 全要素のあとの物を削除することは*有効ではない*ため、 '<' を使用します

    // 境界外インデックスです
    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),
                  self.len - index);
        result
    }
}