Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 3 commits into from
Dec 14, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 32 additions & 20 deletions vlib/builtin/map.v
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -311,23 +322,23 @@ 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
}
index += 2
meta += probe_inc
}
kv_index := m.key_values.push(key, value)
kv_index := m.key_values.push(&key, value)
Copy link
Contributor Author

@ntrel ntrel Dec 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes a mistake from one of the DenseArray voidptr pulls. In practice this line change has no effect, because V automatically takes the address. I filed #7291 because I don't think it should.

m.meta_greater(index, meta, u32(kv_index))
m.len++
}
Expand Down Expand Up @@ -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))
}
Expand Down Expand Up @@ -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}
}
}
Expand All @@ -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}
}
}
Expand All @@ -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
}
}
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down