builtin: map: one voidptr for all values
parent
4794c6a0e7
commit
f27fd63f8c
|
@ -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{
|
||||||
|
value_bytes: value_bytes
|
||||||
cap: 8
|
cap: 8
|
||||||
size: 0
|
size: 0
|
||||||
deletes: 0
|
deletes: 0
|
||||||
data: &KeyValue(malloc(8 * sizeof(KeyValue)))
|
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 {
|
||||||
|
|
Loading…
Reference in New Issue