map: add voidptr key methods (#7377)

pull/7385/head
Nick Treleaven 2020-12-18 06:37:59 +00:00 committed by GitHub
parent d96dcefb06
commit 3976228ae0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 67 additions and 25 deletions

View File

@ -266,6 +266,10 @@ fn (m &map) key_to_index(pkey voidptr) (u32, u32) {
return u32(index), u32(meta) return u32(index), u32(meta)
} }
fn (m &map) free_key(pkey voidptr) {
(*&string(pkey)).free()
}
[inline] [inline]
fn (m &map) meta_less(_index u32, _metas u32) (u32, u32) { fn (m &map) meta_less(_index u32, _metas u32) (u32, u32) {
mut index := _index mut index := _index
@ -321,21 +325,26 @@ fn (mut m map) ensure_extra_metas(probe_count u32) {
} }
} }
// bootstrap
fn (mut m map) set(key string, value voidptr) {
m.set_1(&key, value)
}
// Insert new element to the map. The element is inserted if its key is // Insert new element to the map. The element is inserted if its key is
// not equivalent to the key of any other element already in the container. // not equivalent to the key of any other element already in the container.
// If the key already exists, its value is changed to the value of the new element. // If the key already exists, its value is changed to the value of the new element.
fn (mut m map) set(key string, value voidptr) { fn (mut m map) set_1(key voidptr, value voidptr) {
load_factor := f32(m.len << 1) / f32(m.cap) load_factor := f32(m.len << 1) / f32(m.cap)
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 {m.key_values.key(kv_index)} pkey := unsafe {m.key_values.key(kv_index)}
if m.keys_eq(&key, pkey) { if m.keys_eq(key, pkey) {
unsafe { unsafe {
pval := byteptr(pkey) + m.key_bytes pval := byteptr(pkey) + m.key_bytes
C.memcpy(pval, value, m.value_bytes) C.memcpy(pval, value, m.value_bytes)
@ -345,7 +354,7 @@ fn (mut m map) set(key 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++
} }
@ -411,17 +420,21 @@ fn (mut m map) cached_rehash(old_cap u32) {
unsafe {free(old_metas)} unsafe {free(old_metas)}
} }
fn (mut m map) get_and_set(key string, zero voidptr) voidptr {
return m.get_and_set_1(&key, zero)
}
// This method is used for assignment operators. If the argument-key // This method is used for assignment operators. If the argument-key
// does not exist in the map, it's added to the map along with the zero/default value. // does not exist in the map, it's added to the map along with the zero/default value.
// 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_1(key voidptr, 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 {m.key_values.key(kv_index)} pkey := unsafe {m.key_values.key(kv_index)}
if m.keys_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}
} }
} }
@ -432,22 +445,26 @@ fn (mut m map) get_and_set(key string, zero voidptr) voidptr {
} }
} }
// Key not found, insert key with zero-value // Key not found, insert key with zero-value
m.set(key, zero) m.set_1(key, zero)
} }
assert false assert false
return voidptr(0) return voidptr(0)
} }
fn (m map) get(key string, zero voidptr) voidptr {
return m.get_1(&key, zero)
}
// If `key` matches the key of an element in the container, // If `key` matches the key of an element in the container,
// 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_1(key voidptr, 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 {m.key_values.key(kv_index)} pkey := unsafe {m.key_values.key(kv_index)}
if m.keys_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}
} }
} }
@ -460,14 +477,18 @@ fn (m map) get(key string, zero voidptr) voidptr {
return zero return zero
} }
// 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) return m.exists_1(&key)
}
// Checks whether a particular key exists in the map.
fn (m map) exists_1(key voidptr) bool {
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 {m.key_values.key(kv_index)} pkey := unsafe {m.key_values.key(kv_index)}
if m.keys_eq(&key, pkey) { if m.keys_eq(key, pkey) {
return true return true
} }
} }
@ -480,15 +501,19 @@ fn (m map) exists(key string) bool {
return false return false
} }
// 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) m.delete_1(&key)
}
// Removes the mapping of a particular key from the map.
pub fn (mut m map) delete_1(key voidptr) {
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 {m.key_values.key(kv_index)}
if m.keys_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
@ -504,9 +529,9 @@ pub fn (mut m map) delete(key string) {
unsafe { unsafe {
m.key_values.all_deleted[kv_index] = 1 m.key_values.all_deleted[kv_index] = 1
m.metas[index] = 0 m.metas[index] = 0
m.free_key(pkey)
// Mark key as deleted // Mark key as deleted
(*pkey).free() C.memset(pkey, 0, m.key_bytes)
C.memset(pkey, 0, sizeof(string))
} }
if m.key_values.len <= 32 { if m.key_values.len <= 32 {
return return
@ -523,10 +548,27 @@ pub fn (mut m map) delete(key string) {
} }
} }
// Returns all keys in the map. // bootstrap
pub fn (m &map) keys() []string { pub fn (m &map) keys() []string {
mut keys := []string{len: m.len} mut keys := []string{len: m.len}
mut item := unsafe {byteptr(keys.data)} mut item := unsafe {byteptr(keys.data)}
for i := 0; i < m.key_values.len; i++ {
if !m.key_values.has_index(i) {
continue
}
unsafe {
pkey := m.key_values.key(i)
m.key_values.clone_key(item, pkey)
item += m.key_bytes
}
}
return keys
}
// Returns all keys in the map.
pub fn (m &map) keys_1() array {
mut keys := __new_array(m.len, 0, m.key_bytes)
mut item := unsafe {byteptr(keys.data)}
if m.key_values.deletes == 0 { if m.key_values.deletes == 0 {
for i := 0; i < m.key_values.len; i++ { for i := 0; i < m.key_values.len; i++ {
unsafe { unsafe {
@ -596,8 +638,8 @@ pub fn (m &map) free() {
if m.key_values.deletes == 0 { if m.key_values.deletes == 0 {
for i := 0; i < m.key_values.len; i++ { for i := 0; i < m.key_values.len; i++ {
unsafe { unsafe {
pkey := &string(m.key_values.key(i)) pkey := m.key_values.key(i)
(*pkey).free() m.free_key(pkey)
} }
} }
} else { } else {
@ -606,8 +648,8 @@ pub fn (m &map) free() {
continue continue
} }
unsafe { unsafe {
pkey := &string(m.key_values.key(i)) pkey := m.key_values.key(i)
(*pkey).free() m.free_key(pkey)
} }
} }
unsafe {free(m.key_values.all_deleted)} unsafe {free(m.key_values.all_deleted)}