Skip to content

Commit f27fd63

Browse files
authored
builtin: map: one voidptr for all values
1 parent 4794c6a commit f27fd63

File tree

1 file changed

+53
-56
lines changed

1 file changed

+53
-56
lines changed

vlib/builtin/map.v

Lines changed: 53 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -92,43 +92,42 @@ fn fast_string_eq(a, b string) bool {
9292
return C.memcmp(a.str, b.str, b.len) == 0
9393
}
9494

95-
struct KeyValue {
96-
key string
97-
mut:
98-
value voidptr
99-
}
100-
10195
// Dynamic array with very low growth factor
10296
struct DenseArray {
97+
value_bytes int
10398
mut:
104-
cap u32
105-
size u32
106-
deletes u32
107-
data &KeyValue
99+
cap u32
100+
size u32
101+
deletes u32
102+
keys &string
103+
values byteptr
108104
}
109105

110106
[inline]
111-
fn new_dense_array() DenseArray {
112-
unsafe{
113-
return DenseArray{
114-
cap: 8
115-
size: 0
116-
deletes: 0
117-
data: &KeyValue(malloc(8 * sizeof(KeyValue)))
118-
}
107+
[unsafe_fn]
108+
fn new_dense_array(value_bytes int) DenseArray {
109+
return DenseArray{
110+
value_bytes: value_bytes
111+
cap: 8
112+
size: 0
113+
deletes: 0
114+
keys: &string(malloc(8 * sizeof(string)))
115+
values: malloc(8 * value_bytes)
119116
}
120117
}
121118

122119
// Push element to array and return index
123120
// The growth-factor is roughly 1.125 `(x + (x >> 3))`
124121
[inline]
125-
fn (d mut DenseArray) push(kv KeyValue) u32 {
122+
fn (d mut DenseArray) push(key string, value voidptr) u32 {
126123
if d.cap == d.size {
127-
d.cap += d.cap>>3
128-
d.data = &KeyValue(C.realloc(d.data, sizeof(KeyValue) * d.cap))
124+
d.cap += d.cap >> 3
125+
d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
126+
d.values = C.realloc(d.values, d.value_bytes * d.cap)
129127
}
130128
push_index := d.size
131-
d.data[push_index] = kv
129+
d.keys[push_index] = key
130+
C.memcpy(d.values + push_index * d.value_bytes, value, d.value_bytes)
132131
d.size++
133132
return push_index
134133
}
@@ -140,25 +139,33 @@ fn (d DenseArray) get(i int) voidptr {
140139
panic('DenseArray.get: index out of range (i == $i, d.len == $d.size)')
141140
}
142141
}
143-
return byteptr(d.data) + i * sizeof(KeyValue)
142+
return byteptr(d.keys) + i * sizeof(string)
144143
}
145144

146145
// Move all zeros to the end of the array
147146
// and resize array
148147
fn (d mut DenseArray) zeros_to_end() {
148+
mut tmp_value := malloc(d.value_bytes)
149149
mut count := u32(0)
150150
for i in 0 .. d.size {
151-
if d.data[i].key.str != 0 {
152-
tmp := d.data[count]
153-
d.data[count] = d.data[i]
154-
d.data[i] = tmp
151+
if d.keys[i].str != 0 {
152+
// swap keys
153+
tmp_key := d.keys[count]
154+
d.keys[count] = d.keys[i]
155+
d.keys[i] = tmp_key
156+
// swap values (TODO: optimize)
157+
C.memcpy(tmp_value, d.values + count * d.value_bytes, d.value_bytes)
158+
C.memcpy(d.values + count * d.value_bytes, d.values + i * d.value_bytes, d.value_bytes)
159+
C.memcpy(d.values + i * d.value_bytes, tmp_value, d.value_bytes)
155160
count++
156161
}
157162
}
163+
free(tmp_value)
158164
d.deletes = 0
159165
d.size = count
160166
d.cap = if count < 8 { u32(8) } else { count }
161-
d.data = &KeyValue(C.realloc(d.data, sizeof(KeyValue) * d.cap))
167+
d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
168+
d.values = C.realloc(d.values, d.value_bytes * d.cap)
162169
}
163170

164171
pub struct map {
@@ -185,17 +192,13 @@ pub mut:
185192
size int
186193
}
187194

188-
// TODO: remove this after vc is regenerated.
189-
fn new_map(n, value_bytes int) map {
190-
return new_map_1(value_bytes)
191-
}
192195
fn new_map_1(value_bytes int) map {
193196
return map{
194197
value_bytes: value_bytes
195198
cap: init_cap
196199
cached_hashbits: max_cached_hashbits
197200
shift: init_log_capicity
198-
key_values: new_dense_array()
201+
key_values: new_dense_array(value_bytes)
199202
metas: &u32(vcalloc(sizeof(u32) * (init_capicity + extra_metas_inc)))
200203
extra_metas: extra_metas_inc
201204
size: 0
@@ -271,20 +274,14 @@ fn (m mut map) set(key string, value voidptr) {
271274
// While we might have a match
272275
for meta == m.metas[index] {
273276
kv_index := m.metas[index + 1]
274-
if fast_string_eq(key, m.key_values.data[kv_index].key) {
275-
C.memcpy(m.key_values.data[kv_index].value, value, m.value_bytes)
277+
if fast_string_eq(key, m.key_values.keys[kv_index]) {
278+
C.memcpy(m.key_values.values + kv_index * m.value_bytes , value, m.value_bytes)
276279
return
277280
}
278281
index += 2
279282
meta += probe_inc
280283
}
281-
// Match not possible anymore
282-
kv := KeyValue{
283-
key: key
284-
value: malloc(m.value_bytes)
285-
}
286-
C.memcpy(kv.value, value, m.value_bytes)
287-
kv_index := m.key_values.push(kv)
284+
kv_index := m.key_values.push(key, value)
288285
m.meta_greater(index, meta, kv_index)
289286
m.size++
290287
}
@@ -301,20 +298,19 @@ fn (m mut map) expand() {
301298
}
302299
else {
303300
m.cached_rehash(old_cap)
301+
m.cached_hashbits--
304302
}
305-
m.cached_hashbits--
306303
}
307304

308305
fn (m mut map) rehash() {
309306
meta_bytes := sizeof(u32) * (m.cap + 2 + m.extra_metas)
310307
m.metas = &u32(C.realloc(m.metas, meta_bytes))
311308
C.memset(m.metas, 0, meta_bytes)
312309
for i := u32(0); i < m.key_values.size; i++ {
313-
if m.key_values.data[i].key.str == 0 {
310+
if m.key_values.keys[i].str == 0 {
314311
continue
315312
}
316-
kv := m.key_values.data[i]
317-
mut index,mut meta := m.key_to_index(kv.key)
313+
mut index,mut meta := m.key_to_index(m.key_values.keys[i])
318314
index,meta = m.meta_less(index, meta)
319315
m.meta_greater(index, meta, i)
320316
}
@@ -347,8 +343,8 @@ fn (m map) get3(key string, zero voidptr) voidptr {
347343
index,meta = m.meta_less(index, meta)
348344
for meta == m.metas[index] {
349345
kv_index := m.metas[index + 1]
350-
if fast_string_eq(key, m.key_values.data[kv_index].key) {
351-
return m.key_values.data[kv_index].value
346+
if fast_string_eq(key, m.key_values.keys[kv_index]) {
347+
return voidptr(m.key_values.values + kv_index * m.value_bytes)
352348
}
353349
index += 2
354350
meta += probe_inc
@@ -361,7 +357,7 @@ fn (m map) exists(key string) bool {
361357
index,meta = m.meta_less(index, meta)
362358
for meta == m.metas[index] {
363359
kv_index := m.metas[index + 1]
364-
if fast_string_eq(key, m.key_values.data[kv_index].key) {
360+
if fast_string_eq(key, m.key_values.keys[kv_index]) {
365361
return true
366362
}
367363
index += 2
@@ -376,7 +372,7 @@ pub fn (m mut map) delete(key string) {
376372
// Perform backwards shifting
377373
for meta == m.metas[index] {
378374
kv_index := m.metas[index + 1]
379-
if fast_string_eq(key, m.key_values.data[kv_index].key) {
375+
if fast_string_eq(key, m.key_values.keys[kv_index]) {
380376
for (m.metas[index + 2]>>hashbits) > 1 {
381377
m.metas[index] = m.metas[index + 2] - probe_inc
382378
m.metas[index + 1] = m.metas[index + 3]
@@ -385,7 +381,7 @@ pub fn (m mut map) delete(key string) {
385381
m.size--
386382
m.metas[index] = 0
387383
m.key_values.deletes++
388-
C.memset(&m.key_values.data[kv_index], 0, sizeof(KeyValue))
384+
C.memset(&m.key_values.keys[kv_index], 0, sizeof(string))
389385
if m.key_values.size <= 32 {
390386
return
391387
}
@@ -407,10 +403,10 @@ pub fn (m &map) keys() []string {
407403
mut keys := [''].repeat(m.size)
408404
mut j := 0
409405
for i := u32(0); i < m.key_values.size; i++ {
410-
if m.key_values.data[i].key.str == 0 {
406+
if m.key_values.keys[i].str == 0 {
411407
continue
412408
}
413-
keys[j] = m.key_values.data[i].key
409+
keys[j] = m.key_values.keys[i]
414410
j++
415411
}
416412
return keys
@@ -420,12 +416,13 @@ pub fn (m &map) keys() []string {
420416
pub fn (m map) free() {
421417
free(m.metas)
422418
for i := u32(0); i < m.key_values.size; i++ {
423-
if m.key_values.data[i].key.str == 0 {
419+
if m.key_values.keys[i].str == 0 {
424420
continue
425421
}
426-
m.key_values.data[i].key.free()
422+
m.key_values.keys[i].free()
427423
}
428-
free(m.key_values.data)
424+
free(m.key_values.keys)
425+
free(m.key_values.values)
429426
}
430427

431428
pub fn (m map_string) str() string {

0 commit comments

Comments
 (0)