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 { pub struct map {
// Number of bytes of a key
key_bytes int
// Number of bytes of a value // Number of bytes of a value
value_bytes int value_bytes int
mut: mut:
@ -219,12 +221,14 @@ pub mut:
fn new_map_1(value_bytes int) map { fn new_map_1(value_bytes int) map {
metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc))
key_bytes := int(sizeof(string))
return map{ return map{
key_bytes: key_bytes
value_bytes: value_bytes value_bytes: value_bytes
cap: init_cap cap: init_cap
cached_hashbits: max_cached_hashbits cached_hashbits: max_cached_hashbits
shift: init_log_capicity 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)) metas: &u32(vcalloc(metasize))
extra_metas: extra_metas_inc extra_metas: extra_metas_inc
len: 0 len: 0
@ -240,7 +244,14 @@ fn new_map_init(n int, value_bytes int, keys &string, values voidptr) map {
} }
[inline] [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) hash := hash.wyhash_c(key.str, u64(key.len), 0)
index := hash & m.cap index := hash & m.cap
meta := ((hash >> m.shift) & hash_mask) | probe_inc 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 { if load_factor > max_load_factor {
m.expand() 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) index, meta = m.meta_less(index, meta)
// While we might have a match // While we might have a match
for meta == unsafe {m.metas[index]} { for meta == unsafe {m.metas[index]} {
kv_index := int(unsafe {m.metas[index + 1]}) kv_index := int(unsafe {m.metas[index + 1]})
pkey := unsafe {&string(m.key_values.key(kv_index))} pkey := unsafe {m.key_values.key(kv_index)}
if fast_string_eq(key, *pkey) { if m.keys_eq(&key, pkey) {
unsafe { unsafe {
pval := pkey + 1 // skip string pval := byteptr(pkey) + m.key_bytes
C.memcpy(pval, value, m.value_bytes) C.memcpy(pval, value, m.value_bytes)
} }
return return
@ -327,7 +338,7 @@ fn (mut m map) set(k string, value voidptr) {
index += 2 index += 2
meta += probe_inc 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.meta_greater(index, meta, u32(kv_index))
m.len++ m.len++
} }
@ -363,8 +374,8 @@ fn (mut m map) rehash() {
if !m.key_values.has_index(i) { if !m.key_values.has_index(i) {
continue continue
} }
pkey := unsafe {&string(m.key_values.key(i))} pkey := unsafe {m.key_values.key(i)}
mut index, mut meta := m.key_to_index(*pkey) mut index, mut meta := m.key_to_index(pkey)
index, meta = m.meta_less(index, meta) index, meta = m.meta_less(index, meta)
m.meta_greater(index, meta, u32(i)) 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. // If the key exists, its respective value is returned.
fn (mut m map) get_and_set(key string, zero voidptr) voidptr { fn (mut m map) get_and_set(key string, zero voidptr) voidptr {
for { for {
mut index, mut meta := m.key_to_index(key) mut index, mut meta := m.key_to_index(&key)
for { for {
if meta == unsafe {m.metas[index]} { if meta == unsafe {m.metas[index]} {
kv_index := int(unsafe {m.metas[index + 1]}) kv_index := int(unsafe {m.metas[index + 1]})
pkey := unsafe {&string(m.key_values.key(kv_index))} pkey := unsafe {m.key_values.key(kv_index)}
if fast_string_eq(key, *pkey) { if m.keys_eq(&key, pkey) {
return unsafe {byteptr(pkey) + m.key_values.key_bytes} 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. // the method returns a reference to its mapped value.
// If not, a zero/default value is returned. // If not, a zero/default value is returned.
fn (m map) get(key string, zero voidptr) voidptr { 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 { for {
if meta == unsafe {m.metas[index]} { if meta == unsafe {m.metas[index]} {
kv_index := int(unsafe {m.metas[index + 1]}) kv_index := int(unsafe {m.metas[index + 1]})
pkey := unsafe {&string(m.key_values.key(kv_index))} pkey := unsafe {m.key_values.key(kv_index)}
if fast_string_eq(key, *pkey) { if m.keys_eq(&key, pkey) {
return unsafe {byteptr(pkey) + m.key_values.key_bytes} 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. // Checks whether a particular key exists in the map.
fn (m map) exists(key string) bool { 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 { for {
if meta == unsafe {m.metas[index]} { if meta == unsafe {m.metas[index]} {
kv_index := int(unsafe {m.metas[index + 1]}) kv_index := int(unsafe {m.metas[index + 1]})
pkey := unsafe {&string(m.key_values.key(kv_index))} pkey := unsafe {m.key_values.key(kv_index)}
if fast_string_eq(key, *pkey) { if m.keys_eq(&key, pkey) {
return true return true
} }
} }
@ -464,13 +475,13 @@ fn (m map) exists(key string) bool {
// Removes the mapping of a particular key from the map. // Removes the mapping of a particular key from the map.
pub fn (mut m map) delete(key string) { 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) index, meta = m.meta_less(index, meta)
// Perform backwards shifting // Perform backwards shifting
for meta == unsafe {m.metas[index]} { for meta == unsafe {m.metas[index]} {
kv_index := int(unsafe {m.metas[index + 1]}) kv_index := int(unsafe {m.metas[index + 1]})
pkey := unsafe {&string(m.key_values.key(kv_index))} 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 { for (unsafe {m.metas[index + 2]} >> hashbits) > 1 {
unsafe { unsafe {
m.metas[index] = m.metas[index + 2] - probe_inc 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 { pub fn (m map) clone() map {
metasize := int(sizeof(u32) * (m.cap + 2 + m.extra_metas)) metasize := int(sizeof(u32) * (m.cap + 2 + m.extra_metas))
res := map{ res := map{
key_bytes: m.key_bytes
value_bytes: m.value_bytes value_bytes: m.value_bytes
cap: m.cap cap: m.cap
cached_hashbits: m.cached_hashbits cached_hashbits: m.cached_hashbits