182 lines
3.2 KiB
Go
182 lines
3.2 KiB
Go
|
// 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
|
||
|
|
||
|
struct map {
|
||
|
// cap int
|
||
|
// keys []string
|
||
|
// table byteptr
|
||
|
// keys_table *string
|
||
|
// table *Entry
|
||
|
element_size int
|
||
|
// collisions []Entry
|
||
|
pub:
|
||
|
entries []Entry
|
||
|
is_sorted bool
|
||
|
}
|
||
|
|
||
|
struct Entry {
|
||
|
pub:
|
||
|
key string
|
||
|
val voidptr
|
||
|
// linked list for collisions
|
||
|
// next *Entry
|
||
|
}
|
||
|
|
||
|
pub fn new_map(cap, elm_size int) map {
|
||
|
res := map {
|
||
|
// len: len,
|
||
|
element_size: elm_size
|
||
|
// entries:
|
||
|
// keys: []string
|
||
|
}
|
||
|
return res
|
||
|
}
|
||
|
|
||
|
fn (m &map) new_entry(key string, val voidptr) Entry {
|
||
|
new_e := Entry {
|
||
|
key: key
|
||
|
val: malloc(m.element_size)
|
||
|
// next: 0
|
||
|
}
|
||
|
C.memcpy(new_e.val, val, m.element_size)
|
||
|
return new_e
|
||
|
}
|
||
|
|
||
|
fn (m mut map) _set(key string, val voidptr) {
|
||
|
e := m.new_entry(key, val)
|
||
|
for i := 0; i < m.entries.len; i++ {
|
||
|
entry := m.entries[i]
|
||
|
if entry.key == key {
|
||
|
// e := Entry2{key: key, val: val}
|
||
|
m.entries[i] = e
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
m.entries << e// m.new_entry(key, val)
|
||
|
m.is_sorted = false
|
||
|
}
|
||
|
|
||
|
fn volt_abs(n int) int {
|
||
|
// println('volt_abs($n)')
|
||
|
if n < 0 {
|
||
|
// println('< 0: -($n)')
|
||
|
return -n
|
||
|
}
|
||
|
return n
|
||
|
}
|
||
|
|
||
|
fn (m map) bs(query string, start, end int, out voidptr) {
|
||
|
// println('bs "$query" $start -> $end')
|
||
|
mid := start + ((end - start) / 2)
|
||
|
if end - start == 0 {
|
||
|
last := m.entries[end]
|
||
|
C.memcpy(out, last.val, m.element_size)
|
||
|
return
|
||
|
}
|
||
|
if end - start == 1 {
|
||
|
first := m.entries[start]
|
||
|
C.memcpy(out, first.val, m.element_size)
|
||
|
return
|
||
|
}
|
||
|
if mid >= m.entries.len {
|
||
|
return
|
||
|
}
|
||
|
mid_msg := m.entries[mid]
|
||
|
// println('mid.key=$mid_msg.key')
|
||
|
if query < mid_msg.key {
|
||
|
m.bs(query, start, mid, out)
|
||
|
return
|
||
|
}
|
||
|
m.bs(query, mid, end, out)
|
||
|
}
|
||
|
|
||
|
fn compare_map(a, b *Entry) int {
|
||
|
if a.key < b.key {
|
||
|
return -1
|
||
|
}
|
||
|
if a.key > b.key {
|
||
|
return 1
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
pub fn (m mut map) sort() {
|
||
|
m.entries.sort_with_compare(compare_map)
|
||
|
m.is_sorted = true
|
||
|
}
|
||
|
|
||
|
pub fn (m map) keys() []string {
|
||
|
mut keys := []string{}
|
||
|
for i := 0; i < m.entries.len; i++ {
|
||
|
entry := m.entries[i]
|
||
|
keys << entry.key
|
||
|
}
|
||
|
return keys
|
||
|
}
|
||
|
|
||
|
fn (m map) get(key string, out voidptr) bool {
|
||
|
if m.is_sorted {
|
||
|
// println('\n\nget "$key" sorted')
|
||
|
m.bs(key, 0, m.entries.len, out)
|
||
|
return true
|
||
|
}
|
||
|
for i := 0; i < m.entries.len; i++ {
|
||
|
entry := m.entries[i]
|
||
|
if entry.key == key {
|
||
|
C.memcpy(out, entry.val, m.element_size)
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
pub fn (m map) exists(key string) bool {
|
||
|
for i := 0; i < m.entries.len; i++ {
|
||
|
entry := m.entries[i]
|
||
|
if entry.key == key {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
pub fn (m map) print() {
|
||
|
println('<<<<<<<<')
|
||
|
for i := 0; i < m.entries.len; i++ {
|
||
|
// entry := m.entries[i]
|
||
|
// println('$entry.key => $entry.val')
|
||
|
}
|
||
|
/*
|
||
|
for i := 0; i < m.cap * m.element_size; i++ {
|
||
|
b := m.table[i]
|
||
|
print('$i: ')
|
||
|
C.printf('%02x', b)
|
||
|
println('')
|
||
|
}
|
||
|
*/
|
||
|
println('>>>>>>>>>>')
|
||
|
}
|
||
|
|
||
|
pub fn (m map) free() {
|
||
|
// C.free(m.table)
|
||
|
// C.free(m.keys_table)
|
||
|
}
|
||
|
|
||
|
pub fn (m map_string) str() string {
|
||
|
// return 'not impl'
|
||
|
if m.entries.len == 0 {
|
||
|
return '{}'
|
||
|
}
|
||
|
// TODO use bytes buffer
|
||
|
mut s := '{\n'
|
||
|
for entry in m.entries {
|
||
|
val := m[entry.key]
|
||
|
s += ' "$entry.key" => "$val"\n'
|
||
|
}
|
||
|
s += '}'
|
||
|
return s
|
||
|
}
|