From ae460a2208a7651415f8ca62840d8ec8585eabb6 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sun, 13 Dec 2020 01:05:56 +0000 Subject: [PATCH] map: make DenseArray.has_index not assume string keys (#7284) --- vlib/builtin/map.v | 40 ++++++++++++++++++++++++++++++---------- vlib/builtin/map_test.v | 2 +- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 0794a8746c..37a7abf5a7 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -100,7 +100,10 @@ mut: cap int len int deletes u32 // count - data byteptr // array of interspersed key data and value data + // array allocated (with `cap` bytes) on first deletion + // has non-zero element when key deleted + all_deleted &byte + data byteptr // array of interleaved key data and value data } [inline] @@ -115,7 +118,8 @@ fn new_dense_array(key_bytes int, value_bytes int) DenseArray { cap: cap len: 0 deletes: 0 - data: malloc(cap * slot_bytes) + all_deleted: 0 + data: malloc(cap * slot_bytes) } } @@ -132,9 +136,7 @@ fn (d &DenseArray) value(i int) voidptr { [inline] fn (d &DenseArray) has_index(i int) bool { - // assume string keys for now - pkey := unsafe {&string(d.key(i))} - return pkey.str != 0 + return d.deletes == 0 || unsafe {d.all_deleted[i]} == 0 } // Push element to array and return index @@ -145,10 +147,17 @@ fn (mut d DenseArray) push(key voidptr, value voidptr) int { d.cap += d.cap >> 3 unsafe { d.data = v_realloc(d.data, d.slot_bytes * d.cap) + if d.deletes != 0 { + d.all_deleted = v_realloc(d.all_deleted, d.cap) + C.memset(d.all_deleted + d.len, 0, d.cap - d.len) + } } } push_index := d.len unsafe { + if d.deletes != 0 { + d.all_deleted[push_index] = 0 + } ptr := d.key(push_index) C.memcpy(ptr, key, d.key_bytes) C.memcpy(byteptr(ptr) + d.key_bytes, value, d.value_bytes) @@ -175,6 +184,8 @@ fn (mut d DenseArray) zeros_to_end() { } free(tmp_buf) d.deletes = 0 + // TODO: reallocate instead as more deletes are likely + free(d.all_deleted) d.len = count d.cap = if count < 8 { 8 } else { count } unsafe { @@ -468,12 +479,14 @@ pub fn (mut m map) delete(key string) { index += 2 } m.len-- - unsafe { - m.metas[index] = 0 + if m.key_values.deletes == 0 { + m.key_values.all_deleted = C.calloc(1, m.cap) // sets to 0 } m.key_values.deletes++ - // Mark key as deleted unsafe { + m.key_values.all_deleted[kv_index] = 1 + m.metas[index] = 0 + // Mark key as deleted (*pkey).free() C.memset(pkey, 0, sizeof(string)) } @@ -484,7 +497,6 @@ pub fn (mut m map) delete(key string) { if m.key_values.deletes >= (m.key_values.len >> 1) { m.key_values.zeros_to_end() m.rehash() - m.key_values.deletes = 0 } return } @@ -525,7 +537,14 @@ pub fn (d DenseArray) clone() DenseArray { cap: d.cap len: d.len deletes: d.deletes - data: unsafe {memdup(d.data, d.cap * d.slot_bytes)} + all_deleted: 0 + data: 0 + } + unsafe { + if d.deletes != 0 { + res.all_deleted = memdup(d.all_deleted, d.cap) + } + res.data = memdup(d.data, d.cap * d.slot_bytes) } // FIXME clone each key return res @@ -568,6 +587,7 @@ pub fn (m &map) free() { (*pkey).free() } } + unsafe {free(m.key_values.all_deleted)} } unsafe {free(m.key_values.data)} } diff --git a/vlib/builtin/map_test.v b/vlib/builtin/map_test.v index f88b58c07e..f1b3395ce9 100644 --- a/vlib/builtin/map_test.v +++ b/vlib/builtin/map_test.v @@ -5,7 +5,7 @@ const ( ) fn unique_strings(arr_len int, str_len int) []string { - mut arr := []string{} + mut arr := []string{cap: arr_len} for arr.len < arr_len { str := rand.string(str_len) if str !in arr {