builtin: make `array.delete()` reallocate, provide `.delete_many()` (#10889)

pull/10878/head^2
Uwe Krüger 2021-07-21 19:55:32 +02:00 committed by GitHub
parent be7c3965a9
commit 41982053f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 4 deletions

View File

@ -862,6 +862,9 @@ There are further built in methods for arrays:
* `a.prepend(arr)` insert elements of array `arr` at beginning
* `a.trim(new_len)` truncate the length (if `new_length < a.len`, otherwise do nothing)
* `a.clear()` empty the array (without changing `cap`, equivalent to `a.trim(0)`)
* `a.delete_many(start, size)` removes `size` consecutive elements beginning with index `start`
&ndash; triggers reallocation
* `a.delete(index)` equivalent to `a.delete_many(index, 1)`
* `v := a.first()` equivalent to `v := a[0]`
* `v := a.last()` equivalent to `v := a[a.len - 1]`
* `v := a.pop()` get last element and remove it from array

View File

@ -200,15 +200,30 @@ pub fn (mut a array) prepend_many(val voidptr, size int) {
// delete deletes array element at index `i`.
pub fn (mut a array) delete(i int) {
a.delete_many(i, 1)
}
// delete_many deletes `size` elements beginning with index `i`
pub fn (mut a array) delete_many(i int, size int) {
$if !no_bounds_checking ? {
if i < 0 || i >= a.len {
panic('array.delete: index out of range (i == $i, a.len == $a.len)')
if i < 0 || i + size > a.len {
endidx := if size > 1 { '..${i + size}' } else { '' }
panic('array.delete: index out of range (i == $i$endidx, a.len == $a.len)')
}
}
// NB: if a is [12,34], a.len = 2, a.delete(0)
// should move (2-0-1) elements = 1 element (the 34) forward
unsafe { C.memmove(a.get_unsafe(i), a.get_unsafe(i + 1), (a.len - i - 1) * a.element_size) }
a.len--
old_data := a.data
new_size := a.len - size
new_cap := if new_size == 0 { 1 } else { new_size }
a.data = vcalloc(new_cap * a.element_size)
unsafe { C.memcpy(a.data, old_data, i * a.element_size) }
unsafe {
C.memcpy(&byte(a.data) + i * a.element_size, &byte(old_data) + (i + size) * a.element_size,
(a.len - i - size) * a.element_size)
}
a.len = new_size
a.cap = new_cap
}
// clear clears the array without deallocating the allocated data.

View File

@ -65,6 +65,34 @@ fn test_deleting() {
assert a.len == 2
}
fn test_slice_delete() {
mut a := [1.5, 2.5, 3.25, 4.5, 5.75]
b := a[2..4]
a.delete(0)
assert a == [2.5, 3.25, 4.5, 5.75]
assert b == [3.25, 4.5]
a = [3.75, 4.25, -1.5, 2.25, 6.0]
c := a[..3]
a.delete(2)
assert a == [3.75, 4.25, 2.25, 6.0]
assert c == [3.75, 4.25, -1.5]
}
fn test_delete_many() {
mut a := [1, 2, 3, 4, 5, 6, 7, 8, 9]
b := a[2..6]
a.delete_many(4, 3)
assert a == [1, 2, 3, 4, 8, 9]
assert b == [3, 4, 5, 6]
c := a[..a.len]
a.delete_many(2, 0) // this should just clone
a[1] = 17
assert a == [1, 17, 3, 4, 8, 9]
assert c == [1, 2, 3, 4, 8, 9]
a.delete_many(0, a.len)
assert a == []int{}
}
fn test_short() {
a := [1, 2, 3]
assert a.len == 3