builtin,checker: add array.flags. Allow changing it in `unsafe {}` blocks

pull/12341/head
Delyan Angelov 2021-10-30 13:30:14 +03:00
parent 612e742c1f
commit 579d5ae649
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
3 changed files with 21 additions and 8 deletions

View File

@ -5,19 +5,26 @@ module builtin
import strings import strings
// array is a struct used for denoting array types in V // `array` is a struct, used for denoting all array types in V.
// `.data` is a void pointer to the backing heap memory block,
// which avoids using generics and thus without generating extra
// code for every type.
pub struct array { pub struct array {
pub: pub:
element_size int // size in bytes of one element in the array. element_size int // size in bytes of one element in the array.
pub mut: pub mut:
data voidptr data voidptr
offset int // in bytes (should be `usize`) offset int // in bytes (should be `usize`)
len int // length of the array. len int // length of the array in elements.
cap int // capacity of the array. cap int // capacity of the array in elements.
flags ArrayFlags
}
[flag]
pub enum ArrayFlags {
noslices
} }
// array.data uses a void pointer, which allows implementing arrays without generics and without generating
// extra code for every type.
// Internal function, used by V (`nums := []int`) // Internal function, used by V (`nums := []int`)
fn __new_array(mylen int, cap int, elm_size int) array { fn __new_array(mylen int, cap int, elm_size int) array {
cap_ := if cap < mylen { mylen } else { cap } cap_ := if cap < mylen { mylen } else { cap }
@ -104,6 +111,11 @@ fn (mut a array) ensure_cap(required int) {
if a.data != voidptr(0) { if a.data != voidptr(0) {
unsafe { vmemcpy(new_data, a.data, a.len * a.element_size) } unsafe { vmemcpy(new_data, a.data, a.len * a.element_size) }
// TODO: the old data may be leaked when no GC is used (ref-counting?) // TODO: the old data may be leaked when no GC is used (ref-counting?)
if a.flags.has(.noslices) {
unsafe {
free(a.data)
}
}
} }
a.data = new_data a.data = new_data
a.offset = 0 a.offset = 0

View File

@ -510,7 +510,7 @@ pub fn memdup_noscan(src voidptr, sz int) voidptr {
return vcalloc_noscan(1) return vcalloc_noscan(1)
} }
unsafe { unsafe {
mem := vcalloc_noscan(sz) mem := malloc_noscan(sz)
return C.memcpy(mem, src, sz) return C.memcpy(mem, src, sz)
} }
} }

View File

@ -1663,8 +1663,9 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
c.fail_if_immutable(expr.expr) c.fail_if_immutable(expr.expr)
} }
.array, .string { .array, .string {
// This should only happen in `builtin` // should only happen in `builtin` and unsafe blocks
if c.file.mod.name != 'builtin' { inside_builtin := c.file.mod.name == 'builtin'
if !inside_builtin && !c.inside_unsafe {
c.error('`$typ_sym.kind` can not be modified', expr.pos) c.error('`$typ_sym.kind` can not be modified', expr.pos)
return '', expr.pos return '', expr.pos
} }