From acbd93b54ca27b4638cc7aa83cd3928d16c7f705 Mon Sep 17 00:00:00 2001 From: l-m Date: Wed, 14 Dec 2022 18:44:14 +1100 Subject: [PATCH] builtin: add `.nogrow` and `.nofree` flags to `array` (#16661) --- vlib/builtin/array.v | 8 ++++ ...ay_shrinkage_test.v => array_flags_test.v} | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+) rename vlib/builtin/{array_shrinkage_test.v => array_flags_test.v} (70%) diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index c6474709b3..2d9d7e5538 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -24,6 +24,8 @@ pub mut: pub enum ArrayFlags { 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. + nogrow // the array will never be allowed to grow past `.cap`. set `.nogrow` and `.noshrink` for a truly fixed heap array + nofree // `.data` will never be freed } // Internal function, used by V (`nums := []int`) @@ -133,6 +135,9 @@ fn (mut a array) ensure_cap(required int) { if required <= a.cap { return } + if a.flags.has(.nogrow) { + panic('array.ensure_cap: array with the flag `.nogrow` cannot grow in size, array required new size: ${required}') + } mut cap := if a.cap > 0 { a.cap } else { 2 } for required > cap { cap *= 2 @@ -698,6 +703,9 @@ pub fn (a &array) free() { // if a.is_slice { // return // } + if a.flags.has(.nofree) { + return + } mblock_ptr := &u8(u64(a.data) - u64(a.offset)) unsafe { free(mblock_ptr) } } diff --git a/vlib/builtin/array_shrinkage_test.v b/vlib/builtin/array_flags_test.v similarity index 70% rename from vlib/builtin/array_shrinkage_test.v rename to vlib/builtin/array_flags_test.v index b9919ccdd8..396b2d066f 100644 --- a/vlib/builtin/array_shrinkage_test.v +++ b/vlib/builtin/array_flags_test.v @@ -55,3 +55,40 @@ fn test_array_cap_shrinkage_after_deletion() { assert a.len == 12 assert a.cap == 20 } + +fn fixed_array_on_the_heap(len int, size int) []u8 { + data := vcalloc(size) + println(ptr_str(data)) + return unsafe { + array{ + element_size: 1 + len: len + cap: size + data: data + flags: .noshrink | .nogrow | .nofree + } + } +} + +fn test_array_fixed_growth() { + mut x := fixed_array_on_the_heap(0, 10) + println(ptr_str(x.data)) + x << 5 + x << 10 + x << 15 + x << 20 + dump(x) + dump(x.flags) + assert x[2] == 15 + assert x.flags == .noshrink | .nogrow | .nofree +} + +fn test_array_fixed() { + mut x := fixed_array_on_the_heap(10, 10) + println(ptr_str(x.data)) + x[2] = 5 + dump(x) + dump(x.flags) + assert x[2] == 5 + assert x.flags == .noshrink | .nogrow | .nofree +}