map: use voidptr-based key equality and meta index methods (#7320)

pull/7324/head weekly.2020.51
Nick Treleaven 2020-12-14 12:57:53 +00:00 committed by GitHub
parent 999fe846e5
commit 89ef316db3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 32 additions and 20 deletions

View File

@ -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