builtin: map: one voidptr for all values

pull/4708/head
ka-weihe 2020-05-04 14:56:19 +02:00 committed by GitHub
parent 4794c6a0e7
commit f27fd63f8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 53 additions and 56 deletions

View File

@ -92,43 +92,42 @@ fn fast_string_eq(a, b string) bool {
return C.memcmp(a.str, b.str, b.len) == 0 return C.memcmp(a.str, b.str, b.len) == 0
} }
struct KeyValue {
key string
mut:
value voidptr
}
// Dynamic array with very low growth factor // Dynamic array with very low growth factor
struct DenseArray { struct DenseArray {
value_bytes int
mut: mut:
cap u32 cap u32
size u32 size u32
deletes u32 deletes u32
data &KeyValue keys &string
values byteptr
} }
[inline] [inline]
fn new_dense_array() DenseArray { [unsafe_fn]
unsafe{ fn new_dense_array(value_bytes int) DenseArray {
return DenseArray{ return DenseArray{
cap: 8 value_bytes: value_bytes
size: 0 cap: 8
deletes: 0 size: 0
data: &KeyValue(malloc(8 * sizeof(KeyValue))) deletes: 0
} keys: &string(malloc(8 * sizeof(string)))
values: malloc(8 * value_bytes)
} }
} }
// Push element to array and return index // Push element to array and return index
// The growth-factor is roughly 1.125 `(x + (x >> 3))` // The growth-factor is roughly 1.125 `(x + (x >> 3))`
[inline] [inline]
fn (d mut DenseArray) push(kv KeyValue) u32 { fn (d mut DenseArray) push(key string, value voidptr) u32 {
if d.cap == d.size { if d.cap == d.size {
d.cap += d.cap>>3 d.cap += d.cap >> 3
d.data = &KeyValue(C.realloc(d.data, sizeof(KeyValue) * d.cap)) d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
d.values = C.realloc(d.values, d.value_bytes * d.cap)
} }
push_index := d.size push_index := d.size
d.data[push_index] = kv d.keys[push_index] = key
C.memcpy(d.values + push_index * d.value_bytes, value, d.value_bytes)
d.size++ d.size++
return push_index return push_index
} }
@ -140,25 +139,33 @@ fn (d DenseArray) get(i int) voidptr {
panic('DenseArray.get: index out of range (i == $i, d.len == $d.size)') panic('DenseArray.get: index out of range (i == $i, d.len == $d.size)')
} }
} }
return byteptr(d.data) + i * sizeof(KeyValue) return byteptr(d.keys) + i * sizeof(string)
} }
// Move all zeros to the end of the array // Move all zeros to the end of the array
// and resize array // and resize array
fn (d mut DenseArray) zeros_to_end() { fn (d mut DenseArray) zeros_to_end() {
mut tmp_value := malloc(d.value_bytes)
mut count := u32(0) mut count := u32(0)
for i in 0 .. d.size { for i in 0 .. d.size {
if d.data[i].key.str != 0 { if d.keys[i].str != 0 {
tmp := d.data[count] // swap keys
d.data[count] = d.data[i] tmp_key := d.keys[count]
d.data[i] = tmp d.keys[count] = d.keys[i]
d.keys[i] = tmp_key
// swap values (TODO: optimize)
C.memcpy(tmp_value, d.values + count * d.value_bytes, d.value_bytes)
C.memcpy(d.values + count * d.value_bytes, d.values + i * d.value_bytes, d.value_bytes)
C.memcpy(d.values + i * d.value_bytes, tmp_value, d.value_bytes)
count++ count++
} }
} }
free(tmp_value)
d.deletes = 0 d.deletes = 0
d.size = count d.size = count
d.cap = if count < 8 { u32(8) } else { count } d.cap = if count < 8 { u32(8) } else { count }
d.data = &KeyValue(C.realloc(d.data, sizeof(KeyValue) * d.cap)) d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
d.values = C.realloc(d.values, d.value_bytes * d.cap)
} }
pub struct map { pub struct map {
@ -185,17 +192,13 @@ pub mut:
size int size int
} }
// TODO: remove this after vc is regenerated.
fn new_map(n, value_bytes int) map {
return new_map_1(value_bytes)
}
fn new_map_1(value_bytes int) map { fn new_map_1(value_bytes int) map {
return map{ return map{
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() key_values: new_dense_array(value_bytes)
metas: &u32(vcalloc(sizeof(u32) * (init_capicity + extra_metas_inc))) metas: &u32(vcalloc(sizeof(u32) * (init_capicity + extra_metas_inc)))
extra_metas: extra_metas_inc extra_metas: extra_metas_inc
size: 0 size: 0
@ -271,20 +274,14 @@ fn (m mut map) set(key string, value voidptr) {
// While we might have a match // While we might have a match
for meta == m.metas[index] { for meta == m.metas[index] {
kv_index := m.metas[index + 1] kv_index := m.metas[index + 1]
if fast_string_eq(key, m.key_values.data[kv_index].key) { if fast_string_eq(key, m.key_values.keys[kv_index]) {
C.memcpy(m.key_values.data[kv_index].value, value, m.value_bytes) C.memcpy(m.key_values.values + kv_index * m.value_bytes , value, m.value_bytes)
return return
} }
index += 2 index += 2
meta += probe_inc meta += probe_inc
} }
// Match not possible anymore kv_index := m.key_values.push(key, value)
kv := KeyValue{
key: key
value: malloc(m.value_bytes)
}
C.memcpy(kv.value, value, m.value_bytes)
kv_index := m.key_values.push(kv)
m.meta_greater(index, meta, kv_index) m.meta_greater(index, meta, kv_index)
m.size++ m.size++
} }
@ -301,8 +298,8 @@ fn (m mut map) expand() {
} }
else { else {
m.cached_rehash(old_cap) m.cached_rehash(old_cap)
m.cached_hashbits--
} }
m.cached_hashbits--
} }
fn (m mut map) rehash() { fn (m mut map) rehash() {
@ -310,11 +307,10 @@ fn (m mut map) rehash() {
m.metas = &u32(C.realloc(m.metas, meta_bytes)) m.metas = &u32(C.realloc(m.metas, meta_bytes))
C.memset(m.metas, 0, meta_bytes) C.memset(m.metas, 0, meta_bytes)
for i := u32(0); i < m.key_values.size; i++ { for i := u32(0); i < m.key_values.size; i++ {
if m.key_values.data[i].key.str == 0 { if m.key_values.keys[i].str == 0 {
continue continue
} }
kv := m.key_values.data[i] mut index,mut meta := m.key_to_index(m.key_values.keys[i])
mut index,mut meta := m.key_to_index(kv.key)
index,meta = m.meta_less(index, meta) index,meta = m.meta_less(index, meta)
m.meta_greater(index, meta, i) m.meta_greater(index, meta, i)
} }
@ -347,8 +343,8 @@ fn (m map) get3(key string, zero voidptr) voidptr {
index,meta = m.meta_less(index, meta) index,meta = m.meta_less(index, meta)
for meta == m.metas[index] { for meta == m.metas[index] {
kv_index := m.metas[index + 1] kv_index := m.metas[index + 1]
if fast_string_eq(key, m.key_values.data[kv_index].key) { if fast_string_eq(key, m.key_values.keys[kv_index]) {
return m.key_values.data[kv_index].value return voidptr(m.key_values.values + kv_index * m.value_bytes)
} }
index += 2 index += 2
meta += probe_inc meta += probe_inc
@ -361,7 +357,7 @@ fn (m map) exists(key string) bool {
index,meta = m.meta_less(index, meta) index,meta = m.meta_less(index, meta)
for meta == m.metas[index] { for meta == m.metas[index] {
kv_index := m.metas[index + 1] kv_index := m.metas[index + 1]
if fast_string_eq(key, m.key_values.data[kv_index].key) { if fast_string_eq(key, m.key_values.keys[kv_index]) {
return true return true
} }
index += 2 index += 2
@ -376,7 +372,7 @@ pub fn (m mut map) delete(key string) {
// Perform backwards shifting // Perform backwards shifting
for meta == m.metas[index] { for meta == m.metas[index] {
kv_index := m.metas[index + 1] kv_index := m.metas[index + 1]
if fast_string_eq(key, m.key_values.data[kv_index].key) { if fast_string_eq(key, m.key_values.keys[kv_index]) {
for (m.metas[index + 2]>>hashbits) > 1 { for (m.metas[index + 2]>>hashbits) > 1 {
m.metas[index] = m.metas[index + 2] - probe_inc m.metas[index] = m.metas[index + 2] - probe_inc
m.metas[index + 1] = m.metas[index + 3] m.metas[index + 1] = m.metas[index + 3]
@ -385,7 +381,7 @@ pub fn (m mut map) delete(key string) {
m.size-- m.size--
m.metas[index] = 0 m.metas[index] = 0
m.key_values.deletes++ m.key_values.deletes++
C.memset(&m.key_values.data[kv_index], 0, sizeof(KeyValue)) C.memset(&m.key_values.keys[kv_index], 0, sizeof(string))
if m.key_values.size <= 32 { if m.key_values.size <= 32 {
return return
} }
@ -407,10 +403,10 @@ pub fn (m &map) keys() []string {
mut keys := [''].repeat(m.size) mut keys := [''].repeat(m.size)
mut j := 0 mut j := 0
for i := u32(0); i < m.key_values.size; i++ { for i := u32(0); i < m.key_values.size; i++ {
if m.key_values.data[i].key.str == 0 { if m.key_values.keys[i].str == 0 {
continue continue
} }
keys[j] = m.key_values.data[i].key keys[j] = m.key_values.keys[i]
j++ j++
} }
return keys return keys
@ -420,12 +416,13 @@ pub fn (m &map) keys() []string {
pub fn (m map) free() { pub fn (m map) free() {
free(m.metas) free(m.metas)
for i := u32(0); i < m.key_values.size; i++ { for i := u32(0); i < m.key_values.size; i++ {
if m.key_values.data[i].key.str == 0 { if m.key_values.keys[i].str == 0 {
continue continue
} }
m.key_values.data[i].key.free() m.key_values.keys[i].free()
} }
free(m.key_values.data) free(m.key_values.keys)
free(m.key_values.values)
} }
pub fn (m map_string) str() string { pub fn (m map_string) str() string {