2019-06-23 05:21:30 +03:00
|
|
|
// 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.
|
|
|
|
|
2019-06-22 21:20:28 +03:00
|
|
|
module builtin
|
|
|
|
|
2019-08-05 05:34:12 +03:00
|
|
|
import strings
|
|
|
|
|
2019-06-22 21:20:28 +03:00
|
|
|
struct map {
|
|
|
|
element_size int
|
2019-07-14 12:01:32 +03:00
|
|
|
root *Node
|
|
|
|
_keys []string // used by `keys()` TODO remove this from map struct,
|
|
|
|
key_i int // store in a separate var
|
|
|
|
pub:
|
|
|
|
size int
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|
|
|
|
|
2019-07-14 12:01:32 +03:00
|
|
|
struct Node {
|
|
|
|
left *Node
|
|
|
|
right *Node
|
2019-07-31 10:56:08 +03:00
|
|
|
is_empty bool
|
2019-06-22 21:20:28 +03:00
|
|
|
key string
|
|
|
|
val voidptr
|
|
|
|
}
|
|
|
|
|
2019-06-30 23:44:15 +03:00
|
|
|
fn new_map(cap, elm_size int) map {
|
2019-06-22 21:20:28 +03:00
|
|
|
res := map {
|
|
|
|
element_size: elm_size
|
2019-07-14 12:01:32 +03:00
|
|
|
root: 0
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2019-08-03 10:44:08 +03:00
|
|
|
// `m := { 'one': 1, 'two': 2 }`
|
|
|
|
fn new_map_init(cap, elm_size int, keys *string, vals voidptr) map {
|
|
|
|
mut res := map {
|
|
|
|
element_size: elm_size
|
|
|
|
root: 0
|
|
|
|
}
|
|
|
|
for i in 0 .. cap {
|
|
|
|
res._set(keys[i], vals + i * elm_size)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2019-07-14 12:01:32 +03:00
|
|
|
fn new_node(key string, val voidptr, element_size int) *Node {
|
|
|
|
new_e := &Node {
|
2019-06-22 21:20:28 +03:00
|
|
|
key: key
|
2019-07-14 12:01:32 +03:00
|
|
|
val: malloc(element_size)
|
|
|
|
left: 0
|
|
|
|
right: 0
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
C.memcpy(new_e.val, val, element_size)
|
2019-06-22 21:20:28 +03:00
|
|
|
return new_e
|
|
|
|
}
|
|
|
|
|
2019-07-14 12:01:32 +03:00
|
|
|
fn (m mut map) insert(n mut Node, key string, val voidptr) {
|
|
|
|
if n.key == key {
|
|
|
|
C.memcpy(n.val, val, m.element_size)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if n.key > key {
|
|
|
|
if isnil(n.left) {
|
|
|
|
n.left = new_node(key, val, m.element_size)
|
|
|
|
m.size++
|
|
|
|
} else {
|
|
|
|
m.insert(mut n.left, key, val)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if isnil(n.right) {
|
|
|
|
n.right = new_node(key, val, m.element_size)
|
|
|
|
m.size++
|
|
|
|
} else {
|
|
|
|
m.insert(mut n.right, key, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (n & Node) find(key string, out voidptr, element_size int) bool{
|
|
|
|
if n.key == key {
|
|
|
|
C.memcpy(out, n.val, element_size)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
else if n.key > key {
|
|
|
|
if isnil(n.left) {
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return n.left.find(key, out, element_size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if isnil(n.right) {
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return n.right.find(key, out, element_size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// same as `find`, but doesn't return a value. Used by `exists`
|
|
|
|
fn (n & Node) find2(key string, element_size int) bool{
|
|
|
|
if n.key == key {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
else if n.key > key {
|
|
|
|
if isnil(n.left) {
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return n.left.find2(key, element_size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if isnil(n.right) {
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return n.right.find2(key, element_size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-06-22 21:20:28 +03:00
|
|
|
fn (m mut map) _set(key string, val voidptr) {
|
2019-07-14 12:01:32 +03:00
|
|
|
if isnil(m.root) {
|
|
|
|
m.root = new_node(key, val, m.element_size)
|
|
|
|
m.size++
|
|
|
|
return
|
|
|
|
}
|
|
|
|
m.insert(mut m.root, key, val)
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|
|
|
|
|
2019-07-14 12:01:32 +03:00
|
|
|
/*
|
2019-06-22 21:20:28 +03:00
|
|
|
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)
|
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
*/
|
2019-06-22 21:20:28 +03:00
|
|
|
|
2019-07-14 12:01:32 +03:00
|
|
|
fn (m mut map) preorder_keys(node &Node) {
|
2019-07-31 11:46:00 +03:00
|
|
|
if !node.is_empty {
|
2019-07-14 12:01:32 +03:00
|
|
|
m._keys[m.key_i] = node.key
|
|
|
|
m.key_i++
|
2019-07-31 11:46:00 +03:00
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
if !isnil(node.left) {
|
|
|
|
m.preorder_keys(node.left)
|
|
|
|
}
|
|
|
|
if !isnil(node.right) {
|
|
|
|
m.preorder_keys(node.right)
|
|
|
|
}
|
|
|
|
}
|
2019-06-22 21:20:28 +03:00
|
|
|
|
2019-07-14 12:01:32 +03:00
|
|
|
pub fn (m mut map) keys() []string {
|
|
|
|
m._keys = [''; m.size]
|
|
|
|
m.key_i = 0
|
|
|
|
if isnil(m.root) {
|
|
|
|
return m._keys
|
|
|
|
}
|
|
|
|
m.preorder_keys(m.root)
|
|
|
|
return m._keys
|
2019-06-24 12:29:54 +03:00
|
|
|
}
|
|
|
|
|
2019-06-22 21:20:28 +03:00
|
|
|
fn (m map) get(key string, out voidptr) bool {
|
2019-07-14 12:01:32 +03:00
|
|
|
if isnil(m.root) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return m.root.find(key, out, m.element_size)
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|
|
|
|
|
2019-07-30 22:27:31 +03:00
|
|
|
pub fn (n mut Node) delete(key string, element_size int) {
|
|
|
|
if n.key == key {
|
|
|
|
C.memset(n.val, 0, element_size)
|
2019-07-31 10:56:08 +03:00
|
|
|
n.is_empty = true
|
2019-07-30 22:27:31 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
else if n.key > key {
|
|
|
|
if isnil(n.left) {
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
n.left.delete(key, element_size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if isnil(n.right) {
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
n.right.delete(key, element_size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (m mut map) delete(key string) {
|
|
|
|
m.root.delete(key, m.element_size)
|
|
|
|
m.size--
|
|
|
|
}
|
|
|
|
|
2019-06-27 14:14:59 +03:00
|
|
|
pub fn (m map) exists(key string) bool {
|
2019-07-23 23:57:06 +03:00
|
|
|
panic('map.exists(key) was removed from the language. Use `key in map` instead.')
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (m map) _exists(key string) bool {
|
2019-07-14 12:01:32 +03:00
|
|
|
return !isnil(m.root) && m.root.find2(key, m.element_size)
|
2019-06-24 23:37:53 +03:00
|
|
|
}
|
|
|
|
|
2019-06-27 14:14:59 +03:00
|
|
|
pub fn (m map) print() {
|
2019-06-22 21:20:28 +03:00
|
|
|
println('<<<<<<<<')
|
2019-07-14 12:01:32 +03:00
|
|
|
//for i := 0; i < m.entries.len; i++ {
|
2019-06-22 21:20:28 +03:00
|
|
|
// entry := m.entries[i]
|
|
|
|
// println('$entry.key => $entry.val')
|
2019-07-14 12:01:32 +03:00
|
|
|
//}
|
2019-06-24 23:37:53 +03:00
|
|
|
/*
|
2019-06-22 21:20:28 +03:00
|
|
|
for i := 0; i < m.cap * m.element_size; i++ {
|
|
|
|
b := m.table[i]
|
|
|
|
print('$i: ')
|
|
|
|
C.printf('%02x', b)
|
|
|
|
println('')
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
println('>>>>>>>>>>')
|
|
|
|
}
|
|
|
|
|
2019-06-27 14:14:59 +03:00
|
|
|
pub fn (m map) free() {
|
2019-06-22 21:20:28 +03:00
|
|
|
// C.free(m.table)
|
|
|
|
// C.free(m.keys_table)
|
|
|
|
}
|
|
|
|
|
2019-06-27 14:14:59 +03:00
|
|
|
pub fn (m map_string) str() string {
|
2019-07-14 12:01:32 +03:00
|
|
|
if m.size == 0 {
|
2019-06-22 21:20:28 +03:00
|
|
|
return '{}'
|
|
|
|
}
|
2019-08-05 06:54:16 +03:00
|
|
|
mut sb := strings.new_builder(50)
|
|
|
|
sb.writeln('{')
|
2019-08-05 05:34:12 +03:00
|
|
|
for key, val in m {
|
2019-08-05 06:54:16 +03:00
|
|
|
sb.writeln(' "$key" => "$val"')
|
2019-08-05 05:34:12 +03:00
|
|
|
}
|
2019-08-05 06:54:16 +03:00
|
|
|
sb.writeln('}')
|
|
|
|
return sb.str()
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|