mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
builtin: a very early version of the hashmap
This commit is contained in:
parent
d535e78c98
commit
841d824216
@ -875,6 +875,7 @@ fn new_v(args[]string) &V {
|
||||
'int.v',
|
||||
'utf8.v',
|
||||
'map.v',
|
||||
'hashmap.v',
|
||||
'option.v',
|
||||
]
|
||||
//println(builtins)
|
||||
|
80
vlib/builtin/hashmap.v
Normal file
80
vlib/builtin/hashmap.v
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
/*
|
||||
This is work in progress.
|
||||
A very early test version of the hashmap with a fixed size.
|
||||
Only works with string keys and int values for now.
|
||||
*/
|
||||
|
||||
import math
|
||||
|
||||
struct hashmap {
|
||||
cap int
|
||||
keys []string
|
||||
table []hashmapentry
|
||||
elm_size int
|
||||
pub:
|
||||
nr_collisions int
|
||||
}
|
||||
|
||||
struct hashmapentry {
|
||||
key string
|
||||
val int
|
||||
next &hashmapentry // linked list for collisions
|
||||
}
|
||||
|
||||
const (
|
||||
min_cap = 2 << 10
|
||||
max_cap = 2 << 20
|
||||
)
|
||||
|
||||
fn new_hashmap(planned_nr_items int) hashmap {
|
||||
mut cap := planned_nr_items * 3
|
||||
if cap < min_cap {
|
||||
cap = min_cap
|
||||
}
|
||||
if cap > max_cap {
|
||||
cap = max_cap
|
||||
}
|
||||
return hashmap{
|
||||
cap: cap
|
||||
elm_size: 4
|
||||
table: _make(cap, cap, sizeof(hashmapentry))
|
||||
}
|
||||
}
|
||||
|
||||
fn (m mut hashmap) set(key string, val int) {
|
||||
hash := int(math.abs(key.hash()))
|
||||
idx := hash % m.cap
|
||||
if m.table[idx].key.len != 0 {
|
||||
//println('\nset() idx=$idx key="$key" hash="$hash" val=$val')
|
||||
m.nr_collisions++
|
||||
//println('collision:' + m.table[idx].key)
|
||||
mut e := &m.table[idx]
|
||||
for e.next != 0 {
|
||||
e = e.next
|
||||
}
|
||||
e.next = &hashmapentry{key, val, 0}
|
||||
} else {
|
||||
m.table[idx] = hashmapentry{key, val, 0}
|
||||
}
|
||||
}
|
||||
|
||||
fn (m mut hashmap) get(key string) int {
|
||||
hash := int(math.abs(key.hash()))
|
||||
idx := hash % m.cap
|
||||
mut e := &m.table[idx]
|
||||
for e.next != 0 { // todo unsafe {
|
||||
if e.key == key {
|
||||
return e.val
|
||||
}
|
||||
e = e.next
|
||||
}
|
||||
return e.val
|
||||
}
|
||||
|
||||
|
33
vlib/builtin/hashmap_test.v
Normal file
33
vlib/builtin/hashmap_test.v
Normal file
@ -0,0 +1,33 @@
|
||||
import rand
|
||||
import strings
|
||||
|
||||
fn test_random_strings() {
|
||||
mut m := new_hashmap(1000)
|
||||
for i in 0..1000 {
|
||||
mut buf := []byte
|
||||
for j in 0..10 {
|
||||
buf << byte(rand.next(int(`z`) - int(`a`)) + `a`)
|
||||
}
|
||||
s := string(buf)
|
||||
//println(s)
|
||||
m.set(s, i)
|
||||
assert m.get(s) == i
|
||||
}
|
||||
m.set('foo', 12)
|
||||
val := m.get('foo')
|
||||
assert val == 12
|
||||
}
|
||||
|
||||
fn test_large_hashmap() {
|
||||
N := 300 * 1000
|
||||
mut nums := new_hashmap(N)
|
||||
for i := 0; i < N; i++ {
|
||||
key := i.str()
|
||||
nums.set(key, i)
|
||||
}
|
||||
println('nr collisions: $nums.nr_collisions')
|
||||
for i := 0; i < N; i++ {
|
||||
key := i.str()
|
||||
assert nums.get(key) == i
|
||||
}
|
||||
}
|
@ -8,3 +8,4 @@ pub fn repeat(c byte, n int) string {
|
||||
arr[n] = `\0`
|
||||
return string(arr, n)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user