2022-01-04 10:21:08 +01:00
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
2019-06-23 04:21:30 +02:00
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
2019-06-22 20:20:28 +02:00
module builtin
2020-04-26 07:06:33 +02:00
import strings
2019-08-10 23:02:48 +02:00
2022-01-14 16:27:38 +01:00
// array is a struct, used for denoting all array types in V.
2021-10-30 12:30:14 +02:00
// `.data` is a void pointer to the backing heap memory block,
// which avoids using generics and thus without generating extra
// code for every type.
2020-01-12 19:59:57 +01:00
pub struct array {
2019-07-21 12:43:47 +02:00
pub :
2020-12-15 09:31:35 +01:00
element_size int // size in bytes of one element in the array.
2020-04-27 22:53:26 +02:00
pub mut :
2021-05-27 14:50:06 +02:00
data voidptr
2021-09-08 12:09:32 +02:00
offset int // in bytes (should be `usize`)
2021-10-30 12:30:14 +02:00
len int // length of the array in elements.
cap int // capacity of the array in elements.
flags ArrayFlags
}
[ flag ]
pub enum ArrayFlags {
2022-03-24 22:37:13 +01:00
noslices // when <<, `.noslices` will free the old data block immediately (you have to be sure, that there are *no slices* to that specific array). TODO: integrate with reference counting/compiler support for the static cases.
noshrink // when `.noslices` and `.noshrink` are *both set*, .delete(x) will NOT allocate new memory and free the old. It will just move the elements in place, and adjust .len.
2019-06-22 20:20:28 +02:00
}
2020-01-02 20:09:15 +01:00
// Internal function, used by V (`nums := []int`)
2020-04-25 08:42:23 +02:00
fn __new_array ( mylen int , cap int , elm_size int ) array {
2020-05-07 22:41:41 +02:00
cap_ := if cap < mylen { mylen } else { cap }
2019-12-18 18:07:32 +01:00
arr := array {
2020-05-18 17:05:48 +02:00
element_size : elm_size
data : vcalloc ( cap_ * elm_size )
2020-05-18 21:38:06 +02:00
len : mylen
cap : cap_
2019-06-22 20:20:28 +02:00
}
return arr
}
2020-04-15 20:12:06 +02:00
2020-05-16 15:21:37 +02:00
fn __new_array_with_default ( mylen int , cap int , elm_size int , val voidptr ) array {
cap_ := if cap < mylen { mylen } else { cap }
2020-07-03 18:10:10 +02:00
mut arr := array {
2020-05-18 17:05:48 +02:00
element_size : elm_size
2020-05-18 21:38:06 +02:00
len : mylen
cap : cap_
2020-05-16 15:21:37 +02:00
}
2021-10-28 16:18:03 +02:00
if cap_ > 0 && mylen == 0 {
arr . data = unsafe { malloc ( cap_ * elm_size ) }
} else {
arr . data = vcalloc ( cap_ * elm_size )
}
2020-05-16 15:21:37 +02:00
if val != 0 {
2020-10-15 12:32:28 +02:00
for i in 0 .. arr . len {
2020-12-23 19:13:42 +01:00
unsafe { arr . set_unsafe ( i , val ) }
2020-05-16 15:21:37 +02:00
}
}
return arr
}
2020-06-12 01:24:25 +02:00
fn __new_array_with_array_default ( mylen int , cap int , elm_size int , val array ) array {
cap_ := if cap < mylen { mylen } else { cap }
2020-07-03 18:10:10 +02:00
mut arr := array {
2020-06-12 01:24:25 +02:00
element_size : elm_size
2021-10-28 16:18:03 +02:00
data : unsafe { malloc ( cap_ * elm_size ) }
2020-06-12 01:24:25 +02:00
len : mylen
cap : cap_
}
2020-10-15 12:32:28 +02:00
for i in 0 .. arr . len {
2021-07-23 22:25:12 +02:00
val_clone := unsafe { val . clone_to_depth ( 1 ) }
2020-12-23 19:13:42 +01:00
unsafe { arr . set_unsafe ( i , & val_clone ) }
2020-06-12 01:24:25 +02:00
}
return arr
}
2021-12-18 09:07:25 +01:00
fn __new_array_with_map_default ( mylen int , cap int , elm_size int , val map ) array {
cap_ := if cap < mylen { mylen } else { cap }
mut arr := array {
element_size : elm_size
data : unsafe { malloc ( cap_ * elm_size ) }
len : mylen
cap : cap_
}
for i in 0 .. arr . len {
val_clone := unsafe { val . clone ( ) }
unsafe { arr . set_unsafe ( i , & val_clone ) }
}
return arr
}
2019-06-22 20:20:28 +02:00
// Private function, used by V (`nums := [1, 2, 3]`)
2020-10-15 12:32:28 +02:00
fn new_array_from_c_array ( len int , cap int , elm_size int , c_array voidptr ) array {
2020-05-07 22:41:41 +02:00
cap_ := if cap < len { len } else { cap }
2019-12-18 18:07:32 +01:00
arr := array {
2020-05-18 17:05:48 +02:00
element_size : elm_size
2021-10-28 16:33:18 +02:00
data : vcalloc ( cap_ * elm_size )
2020-05-18 21:38:06 +02:00
len : len
cap : cap_
2019-06-22 20:20:28 +02:00
}
// TODO Write all memory functions (like memcpy) in V
2021-08-12 20:46:38 +02:00
unsafe { vmemcpy ( arr . data , c_array , len * elm_size ) }
2019-06-22 20:20:28 +02:00
return arr
}
// Private function, used by V (`nums := [1, 2, 3] !`)
2020-10-15 12:32:28 +02:00
fn new_array_from_c_array_no_alloc ( len int , cap int , elm_size int , c_array voidptr ) array {
2019-12-18 18:07:32 +01:00
arr := array {
2020-05-18 17:05:48 +02:00
element_size : elm_size
data : c_array
2020-05-18 21:38:06 +02:00
len : len
cap : cap
2019-06-22 20:20:28 +02:00
}
return arr
}
2022-01-14 16:27:38 +01:00
// Private function. Increases the `cap` of an array to the
// required value by copying the data to a new memory location
// (creating a clone) unless `a.cap` is already large enough.
2020-05-17 13:51:18 +02:00
fn ( mut a array ) ensure_cap ( required int ) {
2020-01-19 13:11:58 +01:00
if required <= a . cap {
return
2019-10-31 19:50:20 +01:00
}
2020-12-19 20:35:53 +01:00
mut cap := if a . cap > 0 { a . cap } else { 2 }
2020-01-19 13:11:58 +01:00
for required > cap {
cap *= 2
}
2020-12-19 20:35:53 +01:00
new_size := cap * a . element_size
2022-03-20 14:02:15 +01:00
new_data := unsafe { malloc ( new_size ) }
2021-05-27 14:50:06 +02:00
if a . data != voidptr ( 0 ) {
2021-08-12 20:46:38 +02:00
unsafe { vmemcpy ( new_data , a . data , a . len * a . element_size ) }
2021-05-27 14:50:06 +02:00
// TODO: the old data may be leaked when no GC is used (ref-counting?)
2021-10-30 12:30:14 +02:00
if a . flags . has ( . noslices ) {
unsafe {
free ( a . data )
}
}
2020-01-19 13:11:58 +01:00
}
2021-05-27 14:50:06 +02:00
a . data = new_data
a . offset = 0
2020-01-19 13:11:58 +01:00
a . cap = cap
2019-10-31 19:50:20 +01:00
}
2020-11-30 18:51:00 +01:00
// repeat returns a new array with the given array elements repeated given times.
2021-06-08 22:23:28 +02:00
// `cgen` will replace this with an apropriate call to `repeat_to_depth()`
2022-01-14 16:27:38 +01:00
//
2021-06-09 11:52:30 +02:00
// This is a dummy placeholder that will be overridden by `cgen` with an appropriate
// call to `repeat_to_depth()`. However the `checker` needs it here.
2020-02-29 15:25:49 +01:00
pub fn ( a array ) repeat ( count int ) array {
2021-06-08 22:23:28 +02:00
return unsafe { a . repeat_to_depth ( count , 0 ) }
}
2022-01-14 16:27:38 +01:00
// repeat_to_depth is an unsafe version of `repeat()` that handles
// multi-dimensional arrays.
//
// It is `unsafe` to call directly because `depth` is not checked
2021-06-08 22:23:28 +02:00
[ unsafe ]
pub fn ( a array ) repeat_to_depth ( count int , depth int ) array {
2020-02-29 15:25:49 +01:00
if count < 0 {
panic ( ' a r r a y . r e p e a t : c o u n t i s n e g a t i v e : $ count ' )
2019-10-31 19:50:20 +01:00
}
2020-02-29 15:25:49 +01:00
mut size := count * a . len * a . element_size
2019-12-16 20:22:04 +01:00
if size == 0 {
size = a . element_size
}
2019-12-18 18:07:32 +01:00
arr := array {
2020-05-18 17:05:48 +02:00
element_size : a . element_size
data : vcalloc ( size )
2020-05-18 21:38:06 +02:00
len : count * a . len
cap : count * a . len
2019-09-14 22:48:30 +02:00
}
2021-06-09 11:52:30 +02:00
if a . len > 0 {
for i in 0 .. count {
if depth > 0 {
ary_clone := unsafe { a . clone_to_depth ( depth ) }
2022-04-15 12:43:03 +02:00
unsafe { vmemcpy ( arr . get_unsafe ( i * a . len ) , & u8 ( ary_clone . data ) , a . len * a . element_size ) }
2021-06-09 11:52:30 +02:00
} else {
2022-04-15 12:43:03 +02:00
unsafe { vmemcpy ( arr . get_unsafe ( i * a . len ) , & u8 ( a . data ) , a . len * a . element_size ) }
2021-06-09 11:52:30 +02:00
}
2020-06-12 11:42:26 +02:00
}
2019-09-14 22:48:30 +02:00
}
return arr
}
2022-01-14 16:27:38 +01:00
// insert inserts a value in the array at index `i` and increases
// the index of subsequent elements by 1.
//
// This function is type-aware and can insert items of the same
// or lower dimensionality as the original array. That is, if
// the original array is `[]int`, then the insert `val` may be
// `int` or `[]int`. If the original array is `[][]int`, then `val`
// may be `[]int` or `[][]int`. Consider the examples.
//
// Example:
// ```v
// mut a := [1, 2, 4]
// a.insert(2, 3) // a now is [1, 2, 3, 4]
// mut b := [3, 4]
// b.insert(0, [1, 2]) // b now is [1, 2, 3, 4]
// mut c := [[3, 4]]
// c.insert(0, [1, 2]) // c now is [[1, 2], [3, 4]]
// ```
2020-05-17 13:51:18 +02:00
pub fn ( mut a array ) insert ( i int , val voidptr ) {
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2020-02-16 16:13:45 +01:00
if i < 0 || i > a . len {
panic ( ' a r r a y . i n s e r t : i n d e x o u t o f r a n g e ( i = = $ i , a . l e n = = $ a . len ) ' )
}
2019-06-22 20:20:28 +02:00
}
2022-02-02 09:48:15 +01:00
if a . len >= a . cap {
a . ensure_cap ( a . len + 1 )
}
2020-07-03 18:10:10 +02:00
unsafe {
2021-08-12 20:46:38 +02:00
vmemmove ( a . get_unsafe ( i + 1 ) , a . get_unsafe ( i ) , ( a . len - i ) * a . element_size )
2020-07-03 18:10:10 +02:00
a . set_unsafe ( i , val )
}
2019-10-31 19:50:20 +01:00
a . len ++
2019-06-22 20:20:28 +02:00
}
2022-01-14 18:47:17 +01:00
// insert_many is used internally to implement inserting many values
// into an the array beginning at `i`.
2021-02-26 22:55:09 +01:00
[ unsafe ]
2022-01-14 18:47:17 +01:00
fn ( mut a array ) insert_many ( i int , val voidptr , size int ) {
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2020-06-18 12:08:11 +02:00
if i < 0 || i > a . len {
panic ( ' a r r a y . i n s e r t _ m a n y : i n d e x o u t o f r a n g e ( i = = $ i , a . l e n = = $ a . len ) ' )
}
}
a . ensure_cap ( a . len + size )
elem_size := a . element_size
2020-07-03 18:10:10 +02:00
unsafe {
iptr := a . get_unsafe ( i )
2021-08-12 20:46:38 +02:00
vmemmove ( a . get_unsafe ( i + size ) , iptr , ( a . len - i ) * elem_size )
vmemcpy ( iptr , val , size * elem_size )
2020-07-03 18:10:10 +02:00
}
2020-06-18 12:08:11 +02:00
a . len += size
}
2022-01-14 16:27:38 +01:00
// prepend prepends one or more elements to an array.
2022-01-14 18:47:17 +01:00
// It is shorthand for `.insert(0, val)`
2020-05-17 13:51:18 +02:00
pub fn ( mut a array ) prepend ( val voidptr ) {
2019-06-22 20:20:28 +02:00
a . insert ( 0 , val )
}
2020-11-30 18:51:00 +01:00
// prepend_many prepends another array to this array.
2022-01-14 16:27:38 +01:00
// NOTE: `.prepend` is probably all you need.
// NOTE: This code is never called in all of vlib
2021-02-26 22:55:09 +01:00
[ unsafe ]
2022-01-14 18:47:17 +01:00
fn ( mut a array ) prepend_many ( val voidptr , size int ) {
2021-02-26 22:55:09 +01:00
unsafe { a . insert_many ( 0 , val , size ) }
2020-06-18 12:08:11 +02:00
}
2020-11-30 18:51:00 +01:00
// delete deletes array element at index `i`.
2022-01-14 16:27:38 +01:00
// This is exactly the same as calling `.delete_many(i, 1)`.
// NOTE: This function does NOT operate in-place. Internally, it
// creates a copy of the array, skipping over the element at `i`,
// and then points the original variable to the new memory location.
//
// Example:
// ```v
// mut a := ['0', '1', '2', '3', '4', '5']
// a.delete(1) // a is now ['0', '2', '3', '4', '5']
// ```
2020-05-17 13:51:18 +02:00
pub fn ( mut a array ) delete ( i int ) {
2021-07-21 19:55:32 +02:00
a . delete_many ( i , 1 )
}
// delete_many deletes `size` elements beginning with index `i`
2022-01-14 16:27:38 +01:00
// NOTE: This function does NOT operate in-place. Internally, it
// creates a copy of the array, skipping over `size` elements
// starting at `i`, and then points the original variable
// to the new memory location.
//
// Example:
// ```v
// mut a := [1, 2, 3, 4, 5, 6, 7, 8, 9]
// b := a[..9] // creates a `slice` of `a`, not a clone
// a.delete_many(4, 3) // replaces `a` with a modified clone
// dump(a) // a: [1, 2, 3, 4, 8, 9] // `a` is now different
// dump(b) // b: [1, 2, 3, 4, 5, 6, 7, 8, 9] // `b` is still the same
// ```
2021-07-21 19:55:32 +02:00
pub fn ( mut a array ) delete_many ( i int , size int ) {
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2021-07-21 19:55:32 +02:00
if i < 0 || i + size > a . len {
endidx := if size > 1 { ' . . $ { i + size } ' } else { ' ' }
panic ( ' a r r a y . d e l e t e : i n d e x o u t o f r a n g e ( i = = $ i $ endidx , a . l e n = = $ a . len ) ' )
2020-02-16 16:13:45 +01:00
}
2019-10-31 19:50:20 +01:00
}
2022-03-24 22:37:13 +01:00
if a . flags . all ( . noshrink | . noslices ) {
unsafe {
2022-04-15 12:43:03 +02:00
vmemmove ( & u8 ( a . data ) + i * a . element_size , & u8 ( a . data ) + ( i + size ) * a . element_size ,
2022-03-24 22:37:13 +01:00
( a . len - i - size ) * a . element_size )
}
a . len -= size
return
}
2022-03-06 18:01:22 +01:00
// Note: if a is [12,34], a.len = 2, a.delete(0)
2020-05-24 10:10:41 +02:00
// should move (2-0-1) elements = 1 element (the 34) forward
2021-07-21 19:55:32 +02:00
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 )
2021-08-12 20:46:38 +02:00
unsafe { vmemcpy ( a . data , old_data , i * a . element_size ) }
2021-07-21 19:55:32 +02:00
unsafe {
2022-04-15 12:43:03 +02:00
vmemcpy ( & u8 ( a . data ) + i * a . element_size , & u8 ( old_data ) + ( i + size ) * a . element_size ,
2021-07-21 19:55:32 +02:00
( a . len - i - size ) * a . element_size )
}
2021-10-31 11:58:55 +01:00
if a . flags . has ( . noslices ) {
unsafe {
free ( old_data )
}
}
2021-07-21 19:55:32 +02:00
a . len = new_size
a . cap = new_cap
2019-06-22 20:20:28 +02:00
}
2020-11-30 18:51:00 +01:00
// clear clears the array without deallocating the allocated data.
2022-01-14 16:27:38 +01:00
// It does it by setting the array length to `0`
// Example: a.clear() // `a.len` is now 0
2020-05-17 13:51:18 +02:00
pub fn ( mut a array ) clear ( ) {
2020-01-27 22:31:48 +01:00
a . len = 0
}
2022-01-14 16:27:38 +01:00
// trim trims the array length to `index` without modifying the allocated data.
// If `index` is greater than `len` nothing will be changed.
// Example: a.trim(3) // `a.len` is now <= 3
2020-05-17 13:51:18 +02:00
pub fn ( mut a array ) trim ( index int ) {
2020-02-17 20:31:40 +01:00
if index < a . len {
a . len = index
}
}
2022-04-03 16:05:50 +02:00
// drop advances the array past the first `num` elements whilst preserving spare capacity.
// If `num` is greater than `len` the array will be emptied.
// Example:
// ```v
// mut a := [1,2]
// a << 3
// a.drop(2)
// assert a == [3]
// assert a.cap > a.len
// ```
pub fn ( mut a array ) drop ( num int ) {
if num <= 0 {
return
}
n := if num <= a . len { num } else { a . len }
blen := n * a . element_size
2022-04-15 12:43:03 +02:00
a . data = unsafe { & u8 ( a . data ) + blen }
2022-04-03 16:05:50 +02:00
a . offset += blen
a . len -= n
a . cap -= n
}
2020-07-03 18:10:10 +02:00
// we manually inline this for single operations for performance without -prod
2021-03-05 06:17:57 +01:00
[ inline ; unsafe ]
2020-07-03 18:10:10 +02:00
fn ( a array ) get_unsafe ( i int ) voidptr {
unsafe {
2022-04-15 12:43:03 +02:00
return & u8 ( a . data ) + i * a . element_size
2020-07-03 18:10:10 +02:00
}
}
2020-11-30 18:51:00 +01:00
// Private function. Used to implement array[] operator.
2019-10-09 22:38:33 +02:00
fn ( a array ) get ( i int ) voidptr {
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2020-02-16 16:13:45 +01:00
if i < 0 || i >= a . len {
panic ( ' a r r a y . g e t : i n d e x o u t o f r a n g e ( i = = $ i , a . l e n = = $ a . len ) ' )
}
2019-10-09 22:38:33 +02:00
}
2020-07-03 18:10:10 +02:00
unsafe {
2022-04-15 12:43:03 +02:00
return & u8 ( a . data ) + i * a . element_size
2020-07-03 18:10:10 +02:00
}
2019-10-09 22:38:33 +02:00
}
2021-01-19 06:06:57 +01:00
// Private function. Used to implement x = a[i] or { ... }
fn ( a array ) get_with_check ( i int ) voidptr {
if i < 0 || i >= a . len {
return 0
}
unsafe {
2022-04-15 12:43:03 +02:00
return & u8 ( a . data ) + i * a . element_size
2021-01-19 06:06:57 +01:00
}
}
2022-01-14 16:27:38 +01:00
// first returns the first element of the `array`.
// If the `array` is empty, this will panic.
// However, `a[0]` returns an error object
// so it can be handled with an `or` block.
2019-06-27 13:14:59 +02:00
pub fn ( a array ) first ( ) voidptr {
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2020-02-16 16:13:45 +01:00
if a . len == 0 {
panic ( ' a r r a y . f i r s t : a r r a y i s e m p t y ' )
}
2019-06-22 20:20:28 +02:00
}
2020-04-02 15:31:44 +02:00
return a . data
2019-06-22 20:20:28 +02:00
}
2022-01-14 16:27:38 +01:00
// last returns the last element of the `array`.
// If the `array` is empty, this will panic.
2019-06-27 13:14:59 +02:00
pub fn ( a array ) last ( ) voidptr {
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2020-02-16 16:13:45 +01:00
if a . len == 0 {
panic ( ' a r r a y . l a s t : a r r a y i s e m p t y ' )
}
2019-06-22 20:20:28 +02:00
}
2020-07-03 18:10:10 +02:00
unsafe {
2022-04-15 12:43:03 +02:00
return & u8 ( a . data ) + ( a . len - 1 ) * a . element_size
2020-07-03 18:10:10 +02:00
}
2019-06-22 20:20:28 +02:00
}
2020-11-30 18:51:00 +01:00
// pop returns the last element of the array, and removes it.
2022-01-14 16:27:38 +01:00
// If the `array` is empty, this will panic.
// NOTE: this function reduces the length of the given array,
// but arrays sliced from this one will not change. They still
// retain their "view" of the underlying memory.
//
// Example:
// ```v
// mut a := [1, 2, 3, 4, 5, 6, 7, 8, 9]
// b := a[..9] // creates a "view" into the same memory
// c := a.pop() // c == 9
// a[1] = 5
// dump(a) // a: [1, 5, 3, 4, 5, 6, 7, 8]
// dump(b) // b: [1, 5, 3, 4, 5, 6, 7, 8, 9]
// ```
2020-07-14 18:55:44 +02:00
pub fn ( mut a array ) pop ( ) voidptr {
// in a sense, this is the opposite of `a << x`
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2020-07-14 18:55:44 +02:00
if a . len == 0 {
panic ( ' a r r a y . p o p : a r r a y i s e m p t y ' )
}
}
new_len := a . len - 1
2022-04-15 12:43:03 +02:00
last_elem := unsafe { & u8 ( a . data ) + new_len * a . element_size }
2020-07-14 18:55:44 +02:00
a . len = new_len
2022-03-06 18:01:22 +01:00
// Note: a.cap is not changed here *on purpose*, so that
2020-07-14 18:55:44 +02:00
// further << ops on that array will be more efficient.
2022-03-21 22:34:35 +01:00
return last_elem
2020-07-14 18:55:44 +02:00
}
2020-11-30 18:51:00 +01:00
// delete_last efficiently deletes the last element of the array.
2022-01-14 16:27:38 +01:00
// It does it simply by reducing the length of the array by 1.
// If the array is empty, this will panic.
2022-03-21 22:34:35 +01:00
// See also: [trim](#array.trim)
2020-10-23 23:04:22 +02:00
pub fn ( mut a array ) delete_last ( ) {
// copy pasting code for performance
$ if ! no_bounds_checking ? {
if a . len == 0 {
panic ( ' a r r a y . p o p : a r r a y i s e m p t y ' )
}
}
a . len --
}
2020-11-30 18:51:00 +01:00
// slice returns an array using the same buffer as original array
2019-10-31 22:37:24 +01:00
// but starting from the `start` element and ending with the element before
// the `end` element of the original array with the length and capacity
2019-10-31 19:50:20 +01:00
// set to the number of the elements in the slice.
2022-01-14 16:27:38 +01:00
// It will remain tied to the same memory location until the length increases
// (copy on grow) or `.clone()` is called on it.
// If `start` and `end` are invalid this function will panic.
// Alternative: Slices can also be made with [start..end] notation
// Alternative: `.slice_ni()` will always return an array.
2020-10-15 12:32:28 +02:00
fn ( a array ) slice ( start int , _end int ) array {
2019-12-16 23:29:40 +01:00
mut end := _end
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2020-02-16 16:13:45 +01:00
if start > end {
panic ( ' a r r a y . s l i c e : i n v a l i d s l i c e i n d e x ( $ start > $ end ) ' )
}
if end > a . len {
panic ( ' a r r a y . s l i c e : s l i c e b o u n d s o u t o f r a n g e ( $ end > = $ a . len ) ' )
}
if start < 0 {
panic ( ' a r r a y . s l i c e : s l i c e b o u n d s o u t o f r a n g e ( $ start < 0 ) ' )
}
2019-12-16 23:29:40 +01:00
}
2022-03-24 22:37:13 +01:00
// TODO: integrate reference counting
// a.flags.clear(.noslices)
2021-05-27 14:50:06 +02:00
offset := start * a . element_size
2022-04-15 12:43:03 +02:00
data := unsafe { & u8 ( a . data ) + offset }
2019-12-16 23:29:40 +01:00
l := end - start
2019-12-18 18:07:32 +01:00
res := array {
2019-12-16 23:29:40 +01:00
element_size : a . element_size
2020-07-03 18:10:10 +02:00
data : data
2021-05-27 14:50:06 +02:00
offset : a . offset + offset
2019-12-16 23:29:40 +01:00
len : l
cap : l
}
return res
}
2021-12-22 14:34:02 +01:00
// slice_ni 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.
// This function can use negative indexes `a.slice_ni(-3, a.len)`
// that get the last 3 elements of the array otherwise it return an empty array.
// This function always return a valid array.
fn ( a array ) slice_ni ( _start int , _end int ) array {
2022-03-24 22:37:13 +01:00
// a.flags.clear(.noslices)
2021-12-22 14:34:02 +01:00
mut end := _end
mut start := _start
if start < 0 {
start = a . len + start
if start < 0 {
start = 0
}
}
if end < 0 {
end = a . len + end
if end < 0 {
end = 0
}
}
if end >= a . len {
end = a . len
}
if start >= a . len || start > end {
res := array {
element_size : a . element_size
data : a . data
offset : 0
len : 0
cap : 0
}
return res
}
offset := start * a . element_size
2022-04-15 12:43:03 +02:00
data := unsafe { & u8 ( a . data ) + offset }
2021-12-22 14:34:02 +01:00
l := end - start
res := array {
element_size : a . element_size
data : data
offset : a . offset + offset
len : l
cap : l
}
return res
}
2020-01-08 10:19:12 +01:00
// used internally for [2..4]
2020-10-15 12:32:28 +02:00
fn ( a array ) slice2 ( start int , _end int , end_max bool ) array {
2020-01-08 10:19:12 +01:00
end := if end_max { a . len } else { _end }
return a . slice ( start , end )
}
2022-01-14 16:27:38 +01:00
// clone_static_to_depth() returns an independent copy of a given array.
2021-06-09 11:52:30 +02:00
// Unlike `clone_to_depth()` it has a value receiver and is used internally
// for slice-clone expressions like `a[2..4].clone()` and in -autofree generated code.
2021-06-08 22:23:28 +02:00
fn ( a array ) clone_static_to_depth ( depth int ) array {
return unsafe { a . clone_to_depth ( depth ) }
}
2020-11-30 18:51:00 +01:00
// clone returns an independent copy of a given array.
2021-06-08 22:23:28 +02:00
// this will be overwritten by `cgen` with an apropriate call to `.clone_to_depth()`
2021-06-09 11:52:30 +02:00
// However the `checker` needs it here.
2020-03-10 23:21:26 +01:00
pub fn ( a & array ) clone ( ) array {
2021-06-08 22:23:28 +02:00
return unsafe { a . clone_to_depth ( 0 ) }
}
// recursively clone given array - `unsafe` when called directly because depth is not checked
[ unsafe ]
pub fn ( a & array ) clone_to_depth ( depth int ) array {
2020-01-08 10:19:12 +01:00
mut size := a . cap * a . element_size
if size == 0 {
size ++
}
2020-07-03 18:10:10 +02:00
mut arr := array {
2020-05-18 17:05:48 +02:00
element_size : a . element_size
data : vcalloc ( size )
2020-05-18 21:38:06 +02:00
len : a . len
cap : a . cap
2020-01-08 10:19:12 +01:00
}
2020-06-19 13:32:55 +02:00
// Recursively clone-generated elements if array element is array type
2022-03-20 11:57:27 +01:00
if depth > 0 && a . element_size == sizeof ( array ) && a . len >= 0 && a . cap >= a . len {
2020-10-15 12:32:28 +02:00
for i in 0 .. a . len {
2020-06-19 13:32:55 +02:00
ar := array { }
2022-03-20 11:57:27 +01:00
unsafe { vmemcpy ( & ar , a . get_unsafe ( i ) , int ( sizeof ( array ) ) ) }
2021-06-08 22:23:28 +02:00
ar_clone := unsafe { ar . clone_to_depth ( depth - 1 ) }
2022-03-20 11:57:27 +01:00
unsafe { arr . set_unsafe ( i , & ar_clone ) }
2020-06-19 13:32:55 +02:00
}
2021-06-08 22:23:28 +02:00
return arr
} else {
2022-03-20 11:57:27 +01:00
if ! isnil ( a . data ) {
2022-04-15 12:43:03 +02:00
unsafe { vmemcpy ( & u8 ( arr . data ) , a . data , a . cap * a . element_size ) }
2020-12-14 06:34:47 +01:00
}
2021-06-08 22:23:28 +02:00
return arr
2020-06-19 13:32:55 +02:00
}
2019-06-22 20:20:28 +02:00
}
2020-07-03 18:10:10 +02:00
// we manually inline this for single operations for performance without -prod
2021-03-05 06:17:57 +01:00
[ inline ; unsafe ]
2020-07-03 18:10:10 +02:00
fn ( mut a array ) set_unsafe ( i int , val voidptr ) {
2022-04-15 12:43:03 +02:00
unsafe { vmemcpy ( & u8 ( a . data ) + a . element_size * i , val , a . element_size ) }
2020-07-03 18:10:10 +02:00
}
2019-10-31 19:50:20 +01:00
// Private function. Used to implement assigment to the array element.
2020-05-17 13:51:18 +02:00
fn ( mut a array ) set ( i int , val voidptr ) {
2020-10-15 12:32:28 +02:00
$ if ! no_bounds_checking ? {
2020-02-16 16:13:45 +01:00
if i < 0 || i >= a . len {
panic ( ' a r r a y . s e t : i n d e x o u t o f r a n g e ( i = = $ i , a . l e n = = $ a . len ) ' )
}
2019-06-22 20:20:28 +02:00
}
2022-04-15 12:43:03 +02:00
unsafe { vmemcpy ( & u8 ( a . data ) + a . element_size * i , val , a . element_size ) }
2019-06-22 20:20:28 +02:00
}
2020-05-17 13:51:18 +02:00
fn ( mut a array ) push ( val voidptr ) {
2022-03-20 11:57:27 +01:00
if a . len >= a . cap {
a . ensure_cap ( a . len + 1 )
2022-02-02 09:48:15 +01:00
}
2022-04-15 12:43:03 +02:00
unsafe { vmemcpy ( & u8 ( a . data ) + a . element_size * a . len , val , a . element_size ) }
2022-03-20 11:57:27 +01:00
a . len ++
2019-10-09 22:38:33 +02:00
}
2021-02-05 16:51:45 +01:00
// push_many implements the functionality for pushing another array.
// `val` is array.data and user facing usage is `a << [1,2,3]`
2021-02-26 22:55:09 +01:00
[ unsafe ]
2020-05-17 13:51:18 +02:00
pub fn ( mut a3 array ) push_many ( val voidptr , size int ) {
2022-03-20 11:57:27 +01:00
a3 . ensure_cap ( a3 . len + size )
if a3 . data == val && ! isnil ( a3 . data ) {
2020-03-08 22:11:56 +01:00
// handle `arr << arr`
copy := a3 . clone ( )
2020-07-03 18:10:10 +02:00
unsafe {
2022-03-20 11:57:27 +01:00
// vmemcpy(a.data, copy.data, copy.element_size * copy.len)
vmemcpy ( a3 . get_unsafe ( a3 . len ) , copy . data , a3 . element_size * size )
2020-07-03 18:10:10 +02:00
}
2020-01-19 13:11:58 +01:00
} else {
2022-03-20 11:57:27 +01:00
if ! isnil ( a3 . data ) && ! isnil ( val ) {
unsafe { vmemcpy ( a3 . get_unsafe ( a3 . len ) , val , a3 . element_size * size ) }
2020-12-14 06:34:47 +01:00
}
2020-01-19 13:11:58 +01:00
}
2022-03-20 11:57:27 +01:00
a3 . len += size
2019-10-09 22:38:33 +02:00
}
2020-12-15 09:31:35 +01:00
// reverse_in_place reverses existing array data, modifying original array.
2020-07-11 13:17:11 +02:00
pub fn ( mut a array ) reverse_in_place ( ) {
if a . len < 2 {
return
}
unsafe {
mut tmp_value := malloc ( a . element_size )
2020-10-15 12:32:28 +02:00
for i in 0 .. a . len / 2 {
2022-04-15 12:43:03 +02:00
vmemcpy ( tmp_value , & u8 ( a . data ) + i * a . element_size , a . element_size )
vmemcpy ( & u8 ( a . data ) + i * a . element_size , & u8 ( a . data ) +
2021-01-23 09:33:22 +01:00
( a . len - 1 - i ) * a . element_size , a . element_size )
2022-04-15 12:43:03 +02:00
vmemcpy ( & u8 ( a . data ) + ( a . len - 1 - i ) * a . element_size , tmp_value , a . element_size )
2020-07-11 13:17:11 +02:00
}
free ( tmp_value )
}
}
2020-11-30 18:51:00 +01:00
// reverse returns a new array with the elements of the original array in reverse order.
2019-07-17 18:17:07 +02:00
pub fn ( a array ) reverse ( ) array {
2020-02-29 20:44:02 +01:00
if a . len < 2 {
return a
}
2020-07-03 18:10:10 +02:00
mut arr := array {
2020-05-18 17:05:48 +02:00
element_size : a . element_size
data : vcalloc ( a . cap * a . element_size )
2020-05-18 21:38:06 +02:00
len : a . len
cap : a . cap
2019-07-17 18:17:07 +02:00
}
2020-10-15 12:32:28 +02:00
for i in 0 .. a . len {
2020-12-23 19:13:42 +01:00
unsafe { arr . set_unsafe ( i , a . get_unsafe ( a . len - 1 - i ) ) }
2019-07-17 18:17:07 +02:00
}
return arr
}
2020-11-30 18:51:00 +01:00
// free frees all memory occupied by the array.
2020-08-09 11:22:11 +02:00
[ unsafe ]
2020-05-06 18:03:44 +02:00
pub fn ( a & array ) free ( ) {
2020-07-11 13:22:16 +02:00
$ if prealloc {
return
}
2019-12-18 18:07:32 +01:00
// if a.is_slice {
// return
// }
2022-04-15 12:43:03 +02:00
mblock_ptr := & u8 ( u64 ( a . data ) - u64 ( a . offset ) )
2021-11-28 19:35:18 +01:00
unsafe { free ( mblock_ptr ) }
2019-06-22 20:20:28 +02:00
}
2022-01-14 16:27:38 +01:00
// Some of the following functions have no implementation in V and exist here
// to expose them to the array namespace. Their implementation is compiler
// specific because of their use of `it` and `a < b` expressions.
// Therefore, the implementation is left to the backend.
// filter creates a new array with all elements that pass the test.
// Ignore the function signature. `filter` does not take an actual callback. Rather, it
// takes an `it` expression.
//
2022-03-27 13:28:15 +02:00
// Certain array functions (`filter` `any` `all`) support a simplified
// domain-specific-language by the backend compiler to make these operations
// more idiomatic to V. These functions are described here, but their implementation
// is compiler specific.
//
// Each function takes a boolean test expression as its single argument.
// These test expressions may use `it` as a pointer to a single element at a time.
//
// Example: array.filter(it < 5) // create an array of elements less than 5
// Example: array.filter(it % 2 == 1) // create an array of only odd elements
// Example: array.filter(it.name[0] == `A`) // create an array of elements whose `name` field starts with 'A'
2021-08-03 05:25:33 +02:00
pub fn ( a array ) filter ( predicate fn ( voidptr ) bool ) array
2022-01-14 16:27:38 +01:00
// any tests whether at least one element in the array passes the test.
// Ignore the function signature. `any` does not take an actual callback. Rather, it
// takes an `it` expression.
// It returns `true` if it finds an element passing the test. Otherwise,
// it returns `false`. It doesn't modify the array.
//
// Example: array.any(it % 2 == 1) // will return true if any element is odd
2022-03-27 13:28:15 +02:00
// Example: array.any(it.name == 'Bob') // will yield `true` if any element has `.name == 'Bob'`
2021-08-03 05:25:33 +02:00
pub fn ( a array ) any ( predicate fn ( voidptr ) bool ) bool
2022-03-31 18:32:32 +02:00
// all tests whether all elements in the array pass the test.
2022-01-14 16:27:38 +01:00
// Ignore the function signature. `all` does not take an actual callback. Rather, it
// takes an `it` expression.
// It returns `false` if any element fails the test. Otherwise,
// it returns `true`. It doesn't modify the array.
//
// Example: array.all(it % 2 == 1) // will return true if every element is odd
2021-08-03 05:25:33 +02:00
pub fn ( a array ) all ( predicate fn ( voidptr ) bool ) bool
// map creates a new array populated with the results of calling a provided function
2022-03-27 13:28:15 +02:00
// on every element in the calling array.
// It also accepts an `it` expression.
//
// Example:
// ```v
// words := ['hello', 'world']
// r1 := words.map(it.to_upper())
// assert r1 == ['HELLO', 'WORLD']
//
// // map can also accept anonymous functions
// r2 := words.map(fn (w string) string {
// return w.to_upper()
// })
// assert r2 == ['HELLO', 'WORLD']
// ```
2021-08-03 05:25:33 +02:00
pub fn ( a array ) map ( callback fn ( voidptr ) voidptr ) array
2022-03-27 13:28:15 +02:00
// sort sorts the array in place.
2022-01-14 16:27:38 +01:00
// Ignore the function signature. Passing a callback to `.sort` is not supported
// for now. Consider using the `.sort_with_compare` method if you need it.
//
2022-03-27 13:28:15 +02:00
// sort can take a boolean test expression as its single argument.
// The expression uses 2 'magic' variables `a` and `b` as pointers to the two elements
// being compared.
2022-01-14 16:27:38 +01:00
//
// Example: array.sort() // will sort the array in ascending order
// Example: array.sort(b < a) // will sort the array in decending order
// Example: array.sort(b.name < a.name) // will sort descending by the .name field
2021-08-03 05:25:33 +02:00
pub fn ( mut a array ) sort ( callback fn ( voidptr , voidptr ) int )
2022-03-27 13:28:15 +02:00
// sort_with_compare sorts the array in-place using the results of the
2022-01-14 16:27:38 +01:00
// given function to determine sort order.
//
// The function should return one of three values:
// - `-1` when `a` should come before `b` ( `a < b` )
// - `1` when `b` should come before `a` ( `b < a` )
// - `0` when the order cannot be determined ( `a == b` )
//
2022-03-27 13:28:15 +02:00
// Example:
2022-01-14 16:27:38 +01:00
// ```v
// fn main() {
// mut a := ['hi', '1', '5', '3']
// a.sort_with_compare(fn (a &string, b &string) int {
// if a < b {
// return -1
// }
// if a > b {
// return 1
// }
// return 0
// })
// assert a == ['1', '3', '5', 'hi']
// }
// ```
pub fn ( mut a array ) sort_with_compare ( callback fn ( voidptr , voidptr ) int ) {
$ if freestanding {
panic ( ' s o r t d o e s n o t w o r k w i t h - f r e e s t a n d i n g ' )
} $ else {
unsafe { vqsort ( a . data , usize ( a . len ) , usize ( a . element_size ) , callback ) }
}
}
// contains determines whether an array includes a certain value among its elements
// It will return `true` if the array contains an element with this value.
// It is similar to `.any` but does not take an `it` expression.
//
// Example: [1, 2, 3].contains(4) == false
pub fn ( a array ) contains ( value voidptr ) bool
2021-08-03 05:25:33 +02:00
// index returns the first index at which a given element can be found in the array
2022-01-14 16:27:38 +01:00
// or `-1` if the value is not found.
2021-08-03 05:25:33 +02:00
pub fn ( a array ) index ( value voidptr ) int
2021-03-18 20:10:42 +01:00
[ unsafe ]
pub fn ( mut a [ ] string ) free ( ) {
$ if prealloc {
return
}
for s in a {
unsafe { s . free ( ) }
}
2021-11-21 19:53:42 +01:00
unsafe { ( & array ( & a ) ) . free ( ) }
2021-03-18 20:10:42 +01:00
}
2022-01-14 16:27:38 +01:00
// The following functions are type-specific functions that apply
// to arrays of different types in different ways.
// str returns a string representation of an array of strings
// Example: ['a', 'b', 'c'].str() // => "['a', 'b', 'c']".
2021-03-23 21:11:32 +01:00
[ manualfree ]
2019-06-30 13:06:46 +02:00
pub fn ( a [ ] string ) str ( ) string {
2021-10-29 14:49:30 +02:00
mut sb_len := 4 // 2x" + 1x, + 1xspace
if a . len > 0 {
// assume that most strings will be ~large as the first
sb_len += a [ 0 ] . len
sb_len *= a . len
}
sb_len += 2 // 1x[ + 1x]
mut sb := strings . new_builder ( sb_len )
2022-04-15 13:58:56 +02:00
sb . write_u8 ( ` [ ` )
2020-10-15 12:32:28 +02:00
for i in 0 .. a . len {
2019-06-22 20:20:28 +02:00
val := a [ i ]
2022-04-15 13:58:56 +02:00
sb . write_u8 ( ` ' ` )
2021-02-22 12:18:11 +01:00
sb . write_string ( val )
2022-04-15 13:58:56 +02:00
sb . write_u8 ( ` ' ` )
2019-06-22 20:20:28 +02:00
if i < a . len - 1 {
2021-02-22 12:18:11 +01:00
sb . write_string ( ' , ' )
2019-06-22 20:20:28 +02:00
}
}
2022-04-15 13:58:56 +02:00
sb . write_u8 ( ` ] ` )
2021-03-23 21:11:32 +01:00
res := sb . str ( )
unsafe { sb . free ( ) }
return res
2019-06-22 20:20:28 +02:00
}
2020-11-30 18:51:00 +01:00
// hex returns a string with the hexadecimal representation
// of the byte elements of the array.
2022-04-15 14:35:35 +02:00
pub fn ( b [ ] u8 ) hex ( ) string {
2022-03-11 10:07:00 +01:00
mut hex := unsafe { malloc_noscan ( b . len * 2 + 1 ) }
2020-03-11 00:38:11 +01:00
mut dst_i := 0
for i in b {
2020-03-18 16:47:37 +01:00
n0 := i >> 4
2020-07-15 21:56:50 +02:00
unsafe {
2022-04-15 12:43:03 +02:00
hex [ dst_i ] = if n0 < 10 { n0 + ` 0 ` } else { n0 + u8 ( 87 ) }
2021-04-27 00:41:42 +02:00
dst_i ++
2020-07-15 21:56:50 +02:00
}
2020-03-11 00:38:11 +01:00
n1 := i & 0xF
2020-07-15 21:56:50 +02:00
unsafe {
2022-04-15 12:43:03 +02:00
hex [ dst_i ] = if n1 < 10 { n1 + ` 0 ` } else { n1 + u8 ( 87 ) }
2021-04-27 00:41:42 +02:00
dst_i ++
2020-07-15 21:56:50 +02:00
}
}
unsafe {
2021-04-13 10:29:33 +02:00
hex [ dst_i ] = 0
2020-10-15 12:32:28 +02:00
return tos ( hex , dst_i )
2020-03-11 00:38:11 +01:00
}
2019-07-15 17:49:01 +02:00
}
2019-07-28 17:19:59 +02:00
2019-10-31 19:50:20 +01:00
// 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.
2022-01-14 16:27:38 +01:00
// NOTE: This is not an `array` method. It is a function that takes two arrays of bytes.
2022-03-08 08:44:04 +01:00
// See also: `arrays.copy`.
2022-04-15 14:35:35 +02:00
pub fn copy ( mut dst [ ] u8 , src [ ] u8 ) int {
2021-03-02 17:14:42 +01:00
min := if dst . len < src . len { dst . len } else { src . len }
if min > 0 {
2022-04-15 12:43:03 +02:00
unsafe { vmemmove ( & u8 ( dst . data ) , src . data , min ) }
2019-07-28 17:19:59 +02:00
}
2021-03-02 17:14:42 +01:00
return min
2019-07-28 17:19:59 +02:00
}
2019-09-01 19:55:34 +02:00
2020-11-30 18:51:00 +01:00
// reduce executes a given reducer function on each element of the array,
2019-10-11 03:12:40 +02:00
// resulting in a single output value.
2022-03-09 19:04:49 +01:00
// NOTE: It exists as a method on `[]int` types only.
// See also `arrays.fold`.
2020-10-15 12:32:28 +02:00
pub fn ( a [ ] int ) reduce ( iter fn ( int , int ) int , accum_start int ) int {
2020-04-04 14:55:40 +02:00
mut accum_ := accum_start
2020-02-24 17:55:16 +01:00
for i in a {
2020-04-04 14:55:40 +02:00
accum_ = iter ( accum_ , i )
2019-10-11 03:12:40 +02:00
}
2020-04-04 14:55:40 +02:00
return accum_
2019-10-11 03:12:40 +02:00
}
2019-10-29 12:26:00 +01:00
2020-12-16 18:22:26 +01:00
// grow_cap grows the array's capacity by `amount` elements.
2022-01-14 16:27:38 +01:00
// Internally, it does this by copying the entire array to
// a new memory location (creating a clone).
2020-12-16 18:22:26 +01:00
pub fn ( mut a array ) grow_cap ( amount int ) {
a . ensure_cap ( a . cap + amount )
}
// grow_len ensures that an array has a.len + amount of length
2022-01-14 16:27:38 +01:00
// Internally, it does this by copying the entire array to
// a new memory location (creating a clone) unless the array.cap
// is already large enough.
2021-02-26 22:55:09 +01:00
[ unsafe ]
2020-12-16 18:22:26 +01:00
pub fn ( mut a array ) grow_len ( amount int ) {
2020-11-15 21:54:47 +01:00
a . ensure_cap ( a . len + amount )
2020-12-16 18:22:26 +01:00
a . len += amount
2020-11-15 21:54:47 +01:00
}
2020-11-30 18:51:00 +01:00
// pointers returns a new array, where each element
// is the address of the corresponding element in the array.
2021-02-26 22:55:09 +01:00
[ unsafe ]
2020-03-04 20:28:42 +01:00
pub fn ( a array ) pointers ( ) [ ] voidptr {
2020-04-26 09:17:13 +02:00
mut res := [ ] voidptr { }
2020-10-15 12:32:28 +02:00
for i in 0 .. a . len {
2020-12-23 19:13:42 +01:00
unsafe { res << a . get_unsafe ( i ) }
2020-03-04 20:28:42 +01:00
}
return res
}
2020-11-27 17:18:46 +01:00
2022-04-15 14:35:35 +02:00
// vbytes on`voidptr` makes a V []u8 structure from a C style memory buffer.
2022-01-14 16:27:38 +01:00
// NOTE: the data is reused, NOT copied!
2020-11-27 17:18:46 +01:00
[ unsafe ]
2022-04-15 14:35:35 +02:00
pub fn ( data voidptr ) vbytes ( len int ) [ ] u8 {
2020-11-27 17:18:46 +01:00
res := array {
element_size : 1
data : data
len : len
cap : len
}
return res
}
2022-04-15 14:35:35 +02:00
// vbytes on `&byte` makes a V []u8 structure from a C style memory buffer.
2022-01-14 16:27:38 +01:00
// NOTE: the data is reused, NOT copied!
2020-11-27 17:18:46 +01:00
[ unsafe ]
2022-04-15 14:35:35 +02:00
pub fn ( data & byte ) vbytes ( len int ) [ ] u8 {
2020-12-23 19:13:42 +01:00
return unsafe { voidptr ( data ) . vbytes ( len ) }
2020-11-27 17:18:46 +01:00
}