diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index ea43958999..7c8ea72107 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -58,26 +58,8 @@ fn new_array_from_c_array_no_alloc(len, cap, elm_size int, c_array voidptr) arra return arr } -// Private function. Doubles array capacity if needed -fn (a mut array) ensure_cap(required int) { - if required > a.cap { - mut cap := if a.cap == 0 { 2 } else { a.cap * 2 } - for required > cap { cap *= 2 } - if a.cap == 0 { - a.data = calloc(cap * a.element_size) - } - else { - a.data = C.realloc(a.data, cap * a.element_size) - } - a.cap = cap - } -} - // Private function, used by V (`[0; 100]`) fn array_repeat_old(val voidptr, nr_repeats, elm_size int) array { - if nr_repeats < 0 { - panic('[0; len]: `len` is negative (len == $nr_repeats)') - } arr := array { len: nr_repeats cap: nr_repeats @@ -90,169 +72,149 @@ fn array_repeat_old(val voidptr, nr_repeats, elm_size int) array { return arr } -// array.repeat returns new array with the given array elements -// repeated `nr_repeat` times pub fn (a array) repeat(nr_repeats int) array { - if nr_repeats < 0 { - panic('array.repeat: count is negative (count == $nr_repeats)') - } arr := array { - len: nr_repeats * a.len - cap: nr_repeats * a.len + len: nr_repeats + cap: nr_repeats element_size: a.element_size - data: calloc(nr_repeats * a.len * a.element_size) + data: calloc(nr_repeats * a.element_size) } + val := a.data + 0 //nr_repeats * a.element_size for i := 0; i < nr_repeats; i++ { - C.memcpy(arr.data + i * a.len * a.element_size, a.data, a.len * a.element_size) + C.memcpy(arr.data + i * a.element_size, val, a.element_size) } return arr } -// array.sort sorts array in-place using given `compare` function as comparator pub fn (a mut array) sort_with_compare(compare voidptr) { C.qsort(a.data, a.len, a.element_size, compare) } -// TODO array.insert is broken -// Cannot pass literal or primitive type as it cannot be cast to voidptr. -// In the current state only that would work: -// i := 3 -// a.insert(0, &i) -// ---------------------------- pub fn (a mut array) insert(i int, val voidptr) { - if i < 0 || i > a.len { - panic('array.insert: index out of range (i == $i, a.len == $a.len)') + if i >= a.len { + panic('array.insert: index larger than length') } - a.ensure_cap(a.len + 1) + a.push(val) size := a.element_size C.memmove(a.data + (i + 1) * size, a.data + i * size, (a.len - i) * size) - C.memcpy(a.data + i * size, val, size) - a.len++ + a.set(i, val) } -// TODO array.prepend is broken -// It depends on array.insert -// ----------------------------- pub fn (a mut array) prepend(val voidptr) { a.insert(0, val) } -// array.delete deletes array element at the given index -pub fn (a mut array) delete(i int) { - if i < 0 || i >= a.len { - panic('array.delete: index out of range (i == $i, a.len == $a.len)') - } +pub fn (a mut array) delete(idx int) { size := a.element_size - C.memmove(a.data + i * size, a.data + (i + 1) * size, (a.len - i) * size) + C.memmove(a.data + idx * size, a.data + (idx + 1) * size, (a.len - idx) * size) a.len-- + a.cap-- } -// Private function. Used to implement array[] operator fn (a array) get(i int) voidptr { if i < 0 || i >= a.len { - panic('array.get: index out of range (i == $i, a.len == $a.len)') + panic('array index out of range: $i/$a.len') } return a.data + i * a.element_size } -// array.first gives the first element of the array pub fn (a array) first() voidptr { if a.len == 0 { - panic('array.first: array is empty') + panic('array.first: empty array') } return a.data + 0 } -// array.last gives the last element of the array pub fn (a array) last() voidptr { if a.len == 0 { - panic('array.last: array is empty') + panic('array.last: empty array') } return a.data + (a.len - 1) * a.element_size } -// array.left returns a new array using the same buffer as the given array -// with the first `n` elements of the given array. -pub fn (a array) left(n int) array { - if n < 0 { - panic('array.left: index is negative (n == $n)') +pub fn (s array) left(n int) array { + if n >= s.len { + return s } - if n >= a.len { - return a.slice(0, a.len) - } - return a.slice(0, n) + return s.slice(0, n) } -// array.right returns an array using same buffer as the given array -// but starting with the element of the given array beyond the index `n`. -// If `n` is bigger or equal to the length of the given array, -// returns an empty array of the same type as the given array. -pub fn (a array) right(n int) array { - if n < 0 { - panic('array.right: index is negative (n == $n)') +pub fn (s array) right(n int) array { + if n >= s.len { + return new_array(0, 0, s.element_size) } - if n >= a.len { - return new_array(0, 0, a.element_size) - } - return a.slice(n, a.len) + return s.slice(n, s.len) } // used internally for [2..4] -fn (a array) slice2(start, _end int, end_max bool) array { - end := if end_max { a.len } else { _end } - return a.slice(start, end) +fn (s array) slice2(start, _end int, end_max bool) array { + end := if end_max { s.len } else { _end } + return s.slice(start, end) } -// array.slice returns an array using the same buffer as original array -// but starting from the `start` element and ending with the element before -// the `end` element of the original array with the length and capacity -// set to the number of the elements in the slice. -pub fn (a array) slice(start, _end int) array { +pub fn (s array) slice(start, _end int) array { mut end := _end if start > end { - panic('array.slice: invalid slice index ($start > $end)') + panic('invalid slice index: $start > $end') } - if end > a.len { - panic('array.slice: slice bounds out of range ($end >= $a.len)') + if end > s.len { + panic('runtime error: slice bounds out of range ($end >= $s.len)') } if start < 0 { - panic('array.slice: slice bounds out of range ($start < 0)') + panic('runtime error: slice bounds out of range ($start < 0)') } l := end - start res := array { - element_size: a.element_size - data: a.data + start * a.element_size + element_size: s.element_size + data: s.data + start * s.element_size len: l cap: l + //is_slice: true } return res } -// Private function. Used to implement assigment to the array element. -fn (a mut array) set(i int, val voidptr) { - if i < 0 || i >= a.len { - panic('array.set: index out of range (i == $i, a.len == $a.len)') +fn (a mut array) set(idx int, val voidptr) { + if idx < 0 || idx >= a.len { + panic('array index out of range: $idx / $a.len') } - C.memcpy(a.data + a.element_size * i, val, a.element_size) + C.memcpy(a.data + a.element_size * idx, val, a.element_size) } -// TODO push(val) is the same as push_many(val, 1), can be eliminated -fn (a mut array) push(val voidptr) { - a.ensure_cap(a.len + 1) - C.memcpy(a.data + a.element_size * a.len, val, a.element_size) - a.len++ +fn (arr mut array) push(val voidptr) { + if arr.len >= arr.cap - 1 { + cap := (arr.len + 1) * 2 + // println('_push: realloc, new cap=$cap') + if arr.cap == 0 { + arr.data = calloc(cap * arr.element_size) + } + else { + arr.data = C.realloc(arr.data, cap * arr.element_size) + } + arr.cap = cap + } + C.memcpy(arr.data + arr.element_size * arr.len, val, arr.element_size) + arr.len++ } // `val` is array.data // TODO make private, right now it's used by strings.Builder -pub fn (a mut array) push_many(val voidptr, size int) { - a.ensure_cap(a.len + size) - C.memcpy(a.data + a.element_size * a.len, val, a.element_size * size) - a.len += size +pub fn (arr mut array) push_many(val voidptr, size int) { + if arr.len >= arr.cap - size { + cap := (arr.len + size) * 2 + // println('_push: realloc, new cap=$cap') + if arr.cap == 0 { + arr.data = calloc(cap * arr.element_size) + } + else { + arr.data = C.realloc(arr.data, cap * arr.element_size) + } + arr.cap = cap + } + C.memcpy(arr.data + arr.element_size * arr.len, val, arr.element_size * size) + arr.len += size } -// array.reverse returns a new array with the elements of -// the original array in reverse order. pub fn (a array) reverse() array { arr := array { len: a.len @@ -266,7 +228,6 @@ pub fn (a array) reverse() array { return arr } -// array.clone returns an independent copy of a given array pub fn (a array) clone() array { arr := array { len: a.len @@ -287,7 +248,6 @@ pub fn (a array) free() { C.free(a.data) } -// []string.str returns a string representation of the array of strings // "[ 'a', 'b', 'c' ]" pub fn (a []string) str() string { mut sb := strings.new_builder(a.len * 3) @@ -305,7 +265,6 @@ pub fn (a []string) str() string { return sb.str() } -// []bool.str returns a string representation of the array of bools // "[true, true, false]" pub fn (a []bool) str() string { mut sb := strings.new_builder(a.len * 3) @@ -325,8 +284,6 @@ pub fn (a []bool) str() string { return sb.str() } -// []byte.hex returns a string with the hexadecimal representation -// of the byte elements of the array pub fn (b []byte) hex() string { mut hex := malloc(b.len*2+1) mut ptr := &hex[0] @@ -336,9 +293,6 @@ pub fn (b []byte) hex() string { return string(hex) } -// copy copies the `src` byte array elements to the `dst` byte array. -// The number of the elements copied is the minimum of the length of both arrays. -// Returns the number of elements copied. // TODO: implement for all types pub fn copy(dst, src []byte) int { if dst.len > 0 && src.len > 0 { @@ -349,8 +303,7 @@ pub fn copy(dst, src []byte) int { return 0 } -// Private function. Comparator for int type. -fn compare_ints(a, b int) int { +fn compare_ints(a, b &int) int { if a < b { return -1 } @@ -360,13 +313,12 @@ fn compare_ints(a, b int) int { return 0 } -// []int.sort sorts array of int in place in ascending order. pub fn (a mut []int) sort() { a.sort_with_compare(compare_ints) } -// []string.index returns the index of the first element equal to the given value, -// or -1 if the value is not found in the array. +// Looking for an array index based on value. +// If there is, it will return the index and if not, it will return `-1` pub fn (a []string) index(v string) int { for i := 0; i < a.len; i++ { if a[i] == v { @@ -376,8 +328,6 @@ pub fn (a []string) index(v string) int { return -1 } -// []int.index returns the index of the first element equal to the given value, -// or -1 if the value is not found in the array. pub fn (a []int) index(v int) int { for i := 0; i < a.len; i++ { if a[i] == v { @@ -387,8 +337,6 @@ pub fn (a []int) index(v int) int { return -1 } -// []byte.index returns the index of the first element equal to the given value, -// or -1 if the value is not found in the array. pub fn (a []byte) index(v byte) int { for i := 0; i < a.len; i++ { if a[i] == v { @@ -398,9 +346,6 @@ pub fn (a []byte) index(v byte) int { return -1 } -// []char.index returns the index of the first element equal to the given value, -// or -1 if the value is not found in the array. -// TODO is `char` type yet in the language? pub fn (a []char) index(v char) int { for i := 0; i < a.len; i++ { if a[i] == v { @@ -410,7 +355,7 @@ pub fn (a []char) index(v char) int { return -1 } -// []int.reduce executes a given reducer function on each element of the array, +// Executes a reducer function (that you provide) on each element of the array, // resulting in a single output value. pub fn (a []int) reduce(iter fn (accum, curr int) int, accum_start int) int { mut _accum := 0 @@ -421,7 +366,6 @@ pub fn (a []int) reduce(iter fn (accum, curr int) int, accum_start int) int { return _accum } -// array_eq checks if two arrays contain all the same elements in the same order. // []int == []int (also for: i64, f32, f64, byte, string) fn array_eq(a1, a2 []T) bool { if a1.len != a2.len { @@ -454,3 +398,4 @@ pub fn (a []byte) eq(a2 []byte) bool { pub fn (a []f32) eq(a2 []f32) bool { return array_eq(a, a2) } + diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index cf632f1645..28f8f12320 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -32,10 +32,6 @@ fn test_deleting() { a.delete(1) assert a.str() == '[5, 3, 4]' assert a.len == 3 - - a.delete(a.len - 1) - assert a.str() == '[5, 3]' - assert a.len == 2 } fn test_short() { @@ -84,115 +80,37 @@ fn test_push() { assert a.str() == '[1, 3]' } -// TODO array.insert is broken -// Cannot pass literal or primitive type as it cannot be cast to voidptr. -// In the current state only that would work: -// i := 3 -// a.insert(0, &i) -// ---------------------------- -// fn test_insert() { -// mut a := [1, 2] - -// a.insert(0, 3) -// assert a[0] == 3 -// assert a[2] == 2 -// assert a.len == 3 - -// a.insert(1, 4) -// assert a[1] == 4 -// assert a[2] == 1 -// assert a.len == 4 - -// a.insert(4, 5) -// assert a[4] == 5 -// assert a[3] == 2 -// assert a.len == 5 - -// mut b := []f64 -// assert b.len == 0 -// b.insert(0, f64(1.1)) -// assert b.len == 1 -// assert b[0] == f64(1.1) -// } - -// TODO array.prepend is broken -// It depends on array.insert -// ----------------------------- -// fn test_prepend() { -// mut a := []int -// assert a.len == 0 -// a.prepend(1) -// assert a.len == 1 -// assert a[0] == 1 - -// mut b := []f64 -// assert b.len == 0 -// b.prepend(f64(1.1)) -// assert b.len == 1 -// assert b[0] == f64(1.1) -// } - fn test_strings() { a := ['a', 'b', 'c'] assert a.str() == '["a", "b", "c"]' } -fn test_compare_ints() { - assert compare_ints(1, 2) == -1 - assert compare_ints(2, 1) == 1 - assert compare_ints(0, 0) == 0 - - a := 1 - b := 2 - assert compare_ints(a, b) == -1 - assert compare_ints(b, a) == 1 - assert compare_ints(a, a) == 0 -} - fn test_repeat() { + a := [0].repeat(5) + assert a.len == 5 + assert a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0 && a[4] == 0 + + b := [7].repeat(3) + assert b.len == 3 + assert b[0] == 7 && b[1] == 7 && b[2] == 7 { - a := [0].repeat(5) - assert a.len == 5 - assert a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0 && a[4] == 0 - } - { - a := [1.1].repeat(10) + mut aa := [1.1].repeat(10) // FIXME: assert aa[0] == 1.1 will fail, need fix - assert a[0] == f32(1.1) - assert a[5] == f32(1.1) - assert a[9] == f32(1.1) + assert aa[0] == f32(1.1) + assert aa[5] == f32(1.1) + assert aa[9] == f32(1.1) } { - a := [f32(1.1)].repeat(10) - assert a[0] == f32(1.1) - assert a[5] == f32(1.1) - assert a[9] == f32(1.1) + mut aa := [f32(1.1)].repeat(10) + assert aa[0] == f32(1.1) + assert aa[5] == f32(1.1) + assert aa[9] == f32(1.1) } { - a := [f64(1.1)].repeat(10) - assert a[0] == f64(1.1) - assert a[5] == f64(1.1) - assert a[9] == f64(1.1) - } - { - a := [1, 2].repeat(2) - assert a[0] == 1 - assert a[1] == 2 - assert a[2] == 1 - assert a[3] == 2 - } - { - a := ['1', 'abc'].repeat(2) - assert a[0] == '1' - assert a[1] == 'abc' - assert a[2] == '1' - assert a[3] == 'abc' - } - { - mut a := ['1', 'abc'].repeat(0) - assert a.len == 0 - a << 'abc' - assert a[0] == 'abc' + aa := [f64(1.1)].repeat(10) + assert aa[0] == f64(1.1) + assert aa[5] == f64(1.1) + assert aa[9] == f64(1.1) } } @@ -231,16 +149,12 @@ fn test_left() { b := a.left(2) c := a[0..2] d := a[..2] - e := a.left(4) assert b[0] == 1 assert b[1] == 2 assert c[0] == 1 assert c[1] == 2 assert d[0] == 1 assert d[1] == 2 - assert e[0] == 1 - assert e[2] == 3 - assert e.len == 3 } fn test_slice() {