From 89ef316db3a6c46d82337ae93705c4c30dcd1fd6 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 14 Dec 2020 12:57:53 +0000 Subject: [PATCH] map: use voidptr-based key equality and meta index methods (#7320) --- vlib/builtin/map.v | 52 ++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 54e3114dad7b06..d8de89e4c78c11 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -194,6 +194,8 @@ fn (mut d DenseArray) zeros_to_end() { } pub struct map { + // Number of bytes of a key + key_bytes int // Number of bytes of a value value_bytes int mut: @@ -219,12 +221,14 @@ pub mut: fn new_map_1(value_bytes int) map { metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) + key_bytes := int(sizeof(string)) return map{ + key_bytes: key_bytes value_bytes: value_bytes cap: init_cap cached_hashbits: max_cached_hashbits shift: init_log_capicity - key_values: new_dense_array(int(sizeof(string)), value_bytes) + key_values: new_dense_array(key_bytes, value_bytes) metas: &u32(vcalloc(metasize)) extra_metas: extra_metas_inc len: 0 @@ -240,7 +244,14 @@ fn new_map_init(n int, value_bytes int, keys &string, values voidptr) map { } [inline] -fn (m &map) key_to_index(key string) (u32, u32) { +fn (m &map) keys_eq(a voidptr, b voidptr) bool { + // assume string for now + return fast_string_eq(*&string(a), *&string(b)) +} + +[inline] +fn (m &map) key_to_index(pkey voidptr) (u32, u32) { + key := *&string(pkey) hash := hash.wyhash_c(key.str, u64(key.len), 0) index := hash & m.cap meta := ((hash >> m.shift) & hash_mask) | probe_inc @@ -311,15 +322,15 @@ fn (mut m map) set(k string, value voidptr) { if load_factor > max_load_factor { m.expand() } - mut index, mut meta := m.key_to_index(key) + mut index, mut meta := m.key_to_index(&key) index, meta = m.meta_less(index, meta) // While we might have a match for meta == unsafe {m.metas[index]} { kv_index := int(unsafe {m.metas[index + 1]}) - pkey := unsafe {&string(m.key_values.key(kv_index))} - if fast_string_eq(key, *pkey) { + pkey := unsafe {m.key_values.key(kv_index)} + if m.keys_eq(&key, pkey) { unsafe { - pval := pkey + 1 // skip string + pval := byteptr(pkey) + m.key_bytes C.memcpy(pval, value, m.value_bytes) } return @@ -327,7 +338,7 @@ fn (mut m map) set(k string, value voidptr) { index += 2 meta += probe_inc } - kv_index := m.key_values.push(key, value) + kv_index := m.key_values.push(&key, value) m.meta_greater(index, meta, u32(kv_index)) m.len++ } @@ -363,8 +374,8 @@ fn (mut m map) rehash() { if !m.key_values.has_index(i) { continue } - pkey := unsafe {&string(m.key_values.key(i))} - mut index, mut meta := m.key_to_index(*pkey) + pkey := unsafe {m.key_values.key(i)} + mut index, mut meta := m.key_to_index(pkey) index, meta = m.meta_less(index, meta) m.meta_greater(index, meta, u32(i)) } @@ -398,12 +409,12 @@ fn (mut m map) cached_rehash(old_cap u32) { // If the key exists, its respective value is returned. fn (mut m map) get_and_set(key string, zero voidptr) voidptr { for { - mut index, mut meta := m.key_to_index(key) + mut index, mut meta := m.key_to_index(&key) for { if meta == unsafe {m.metas[index]} { kv_index := int(unsafe {m.metas[index + 1]}) - pkey := unsafe {&string(m.key_values.key(kv_index))} - if fast_string_eq(key, *pkey) { + pkey := unsafe {m.key_values.key(kv_index)} + if m.keys_eq(&key, pkey) { return unsafe {byteptr(pkey) + m.key_values.key_bytes} } } @@ -424,12 +435,12 @@ fn (mut m map) get_and_set(key string, zero voidptr) voidptr { // the method returns a reference to its mapped value. // If not, a zero/default value is returned. fn (m map) get(key string, zero voidptr) voidptr { - mut index, mut meta := m.key_to_index(key) + mut index, mut meta := m.key_to_index(&key) for { if meta == unsafe {m.metas[index]} { kv_index := int(unsafe {m.metas[index + 1]}) - pkey := unsafe {&string(m.key_values.key(kv_index))} - if fast_string_eq(key, *pkey) { + pkey := unsafe {m.key_values.key(kv_index)} + if m.keys_eq(&key, pkey) { return unsafe {byteptr(pkey) + m.key_values.key_bytes} } } @@ -444,12 +455,12 @@ fn (m map) get(key string, zero voidptr) voidptr { // Checks whether a particular key exists in the map. fn (m map) exists(key string) bool { - mut index, mut meta := m.key_to_index(key) + mut index, mut meta := m.key_to_index(&key) for { if meta == unsafe {m.metas[index]} { kv_index := int(unsafe {m.metas[index + 1]}) - pkey := unsafe {&string(m.key_values.key(kv_index))} - if fast_string_eq(key, *pkey) { + pkey := unsafe {m.key_values.key(kv_index)} + if m.keys_eq(&key, pkey) { return true } } @@ -464,13 +475,13 @@ fn (m map) exists(key string) bool { // Removes the mapping of a particular key from the map. pub fn (mut m map) delete(key string) { - mut index, mut meta := m.key_to_index(key) + mut index, mut meta := m.key_to_index(&key) index, meta = m.meta_less(index, meta) // Perform backwards shifting for meta == unsafe {m.metas[index]} { kv_index := int(unsafe {m.metas[index + 1]}) pkey := unsafe {&string(m.key_values.key(kv_index))} - if fast_string_eq(key, *pkey) { + if m.keys_eq(&key, pkey) { for (unsafe {m.metas[index + 2]} >> hashbits) > 1 { unsafe { m.metas[index] = m.metas[index + 2] - probe_inc @@ -554,6 +565,7 @@ pub fn (d DenseArray) clone() DenseArray { pub fn (m map) clone() map { metasize := int(sizeof(u32) * (m.cap + 2 + m.extra_metas)) res := map{ + key_bytes: m.key_bytes value_bytes: m.value_bytes cap: m.cap cached_hashbits: m.cached_hashbits