diff --git a/doc/docs.md b/doc/docs.md index 1b0153ad12..d84613dbf4 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -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` + – 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 diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index 4bd6aa7fea..1457a1950f 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -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. diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index 9b723b3c37..d7699ca954 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -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