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-29 01:52:32 +03:00
|
|
|
import strings
|
2019-08-05 05:34:12 +03:00
|
|
|
|
2019-06-22 21:20:28 +03:00
|
|
|
struct map {
|
|
|
|
element_size int
|
2019-09-01 22:51:16 +03:00
|
|
|
root &mapnode
|
2019-08-29 01:52:32 +03:00
|
|
|
pub:
|
|
|
|
size int
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|
|
|
|
|
2019-08-29 01:52:32 +03:00
|
|
|
struct mapnode {
|
2019-09-01 22:51:16 +03:00
|
|
|
left &mapnode
|
|
|
|
right &mapnode
|
2019-08-29 01:52:32 +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-08-29 01:52:32 +03:00
|
|
|
root: 0
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2019-08-29 01:52:32 +03:00
|
|
|
// `m := { 'one': 1, 'two': 2 }`
|
2019-09-01 22:51:16 +03:00
|
|
|
fn new_map_init(cap, elm_size int, keys &string, vals voidptr) map {
|
2019-08-03 10:44:08 +03:00
|
|
|
mut res := map {
|
|
|
|
element_size: elm_size
|
2019-08-29 01:52:32 +03:00
|
|
|
root: 0
|
2019-08-03 10:44:08 +03:00
|
|
|
}
|
|
|
|
for i in 0 .. cap {
|
2019-08-29 01:52:32 +03:00
|
|
|
res._set(keys[i], vals + i * elm_size)
|
|
|
|
}
|
2019-08-03 10:44:08 +03:00
|
|
|
return res
|
2019-08-29 01:52:32 +03:00
|
|
|
}
|
2019-08-03 10:44:08 +03:00
|
|
|
|
2019-09-01 22:51:16 +03:00
|
|
|
fn new_node(key string, val voidptr, element_size int) &mapnode {
|
2019-08-29 01:52:32 +03:00
|
|
|
new_e := &mapnode {
|
2019-06-22 21:20:28 +03:00
|
|
|
key: key
|
2019-07-14 12:01:32 +03:00
|
|
|
val: malloc(element_size)
|
|
|
|
left: 0
|
2019-08-29 01:52:32 +03:00
|
|
|
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-08-29 01:52:32 +03:00
|
|
|
fn (m mut map) insert(n mut mapnode, key string, val voidptr) {
|
2019-07-14 12:01:32 +03:00
|
|
|
if n.key == key {
|
|
|
|
C.memcpy(n.val, val, m.element_size)
|
2019-08-29 01:52:32 +03:00
|
|
|
return
|
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
if n.key > key {
|
2019-08-26 00:08:06 +03:00
|
|
|
if n.left == 0 {
|
2019-08-29 01:52:32 +03:00
|
|
|
n.left = new_node(key, val, m.element_size)
|
|
|
|
m.size++
|
|
|
|
} else {
|
|
|
|
m.insert(mut n.left, key, val)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2019-08-26 00:08:06 +03:00
|
|
|
if n.right == 0 {
|
2019-08-29 01:52:32 +03:00
|
|
|
n.right = new_node(key, val, m.element_size)
|
|
|
|
m.size++
|
|
|
|
} else {
|
|
|
|
m.insert(mut n.right, key, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn (n & mapnode) find(key string, out voidptr, element_size int) bool{
|
2019-07-14 12:01:32 +03:00
|
|
|
if n.key == key {
|
|
|
|
C.memcpy(out, n.val, element_size)
|
2019-08-29 01:52:32 +03:00
|
|
|
return true
|
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
else if n.key > key {
|
2019-08-26 00:08:06 +03:00
|
|
|
if n.left == 0 {
|
2019-08-29 01:52:32 +03:00
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return n.left.find(key, out, element_size)
|
|
|
|
}
|
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
else {
|
2019-08-26 00:08:06 +03:00
|
|
|
if n.right == 0 {
|
2019-08-29 01:52:32 +03:00
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return n.right.find(key, out, element_size)
|
|
|
|
}
|
2019-08-10 11:26:42 +03:00
|
|
|
}
|
2019-08-29 01:52:32 +03:00
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
|
2019-08-29 01:52:32 +03:00
|
|
|
// same as `find`, but doesn't return a value. Used by `exists`
|
|
|
|
fn (n & mapnode) find2(key string, element_size int) bool{
|
2019-07-14 12:01:32 +03:00
|
|
|
if n.key == key {
|
2019-08-29 01:52:32 +03:00
|
|
|
return true
|
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
else if n.key > key {
|
|
|
|
if isnil(n.left) {
|
2019-08-29 01:52:32 +03:00
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return n.left.find2(key, element_size)
|
|
|
|
}
|
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
else {
|
|
|
|
if isnil(n.right) {
|
2019-08-29 01:52:32 +03:00
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return n.right.find2(key, element_size)
|
|
|
|
}
|
2019-08-10 11:26:42 +03:00
|
|
|
}
|
2019-08-29 01:52:32 +03:00
|
|
|
}
|
2019-07-14 12:01:32 +03:00
|
|
|
|
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) {
|
2019-08-29 01:52:32 +03:00
|
|
|
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-08-29 01:52: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-08-29 01:52:32 +03:00
|
|
|
*/
|
2019-06-22 21:20:28 +03:00
|
|
|
|
2019-08-29 01:52:32 +03:00
|
|
|
fn preorder_keys(node &mapnode, keys mut []string, key_i int) int {
|
2019-08-11 20:43:21 +03:00
|
|
|
mut i := key_i
|
2019-07-31 11:46:00 +03:00
|
|
|
if !node.is_empty {
|
2019-09-17 22:41:58 +03:00
|
|
|
keys[i] = node.key
|
2019-08-11 20:43:21 +03:00
|
|
|
i++
|
|
|
|
}
|
2019-08-29 01:52:32 +03:00
|
|
|
if !isnil(node.left) {
|
2019-08-11 20:43:21 +03:00
|
|
|
i = preorder_keys(node.left, mut keys, i)
|
2019-08-29 01:52:32 +03:00
|
|
|
}
|
|
|
|
if !isnil(node.right) {
|
2019-08-11 20:43:21 +03:00
|
|
|
i = preorder_keys(node.right, mut keys, i)
|
|
|
|
}
|
|
|
|
return i
|
2019-08-29 01:52:32 +03:00
|
|
|
}
|
2019-06-22 21:20:28 +03:00
|
|
|
|
2019-09-25 05:56:10 +03:00
|
|
|
pub fn (m &map) keys() []string {
|
2019-09-19 05:22:24 +03:00
|
|
|
mut keys := [''].repeat(m.size)
|
2019-07-14 12:01:32 +03:00
|
|
|
if isnil(m.root) {
|
2019-08-11 20:43:21 +03:00
|
|
|
return keys
|
|
|
|
}
|
|
|
|
preorder_keys(m.root, mut keys, 0)
|
|
|
|
return 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-08-26 00:08:06 +03:00
|
|
|
if m.root == 0 {
|
2019-08-29 01:52:32 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
return m.root.find(key, out, m.element_size)
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|
|
|
|
|
2019-08-29 01:52:32 +03:00
|
|
|
pub fn (n mut mapnode) delete(key string, element_size int) {
|
2019-07-30 22:27:31 +03:00
|
|
|
if n.key == key {
|
|
|
|
C.memset(n.val, 0, element_size)
|
2019-08-29 01:52:32 +03:00
|
|
|
n.is_empty = true
|
|
|
|
return
|
|
|
|
}
|
2019-07-30 22:27:31 +03:00
|
|
|
else if n.key > key {
|
|
|
|
if isnil(n.left) {
|
2019-08-29 01:52:32 +03:00
|
|
|
return
|
|
|
|
} else {
|
|
|
|
n.left.delete(key, element_size)
|
|
|
|
}
|
|
|
|
}
|
2019-07-30 22:27:31 +03:00
|
|
|
else {
|
|
|
|
if isnil(n.right) {
|
2019-08-29 01:52:32 +03:00
|
|
|
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-07-30 22:27:31 +03:00
|
|
|
|
2019-09-15 15:36:05 +03:00
|
|
|
pub fn (m map) exists(key string) {
|
2019-08-29 01:52:32 +03:00
|
|
|
panic('map.exists(key) was removed from the language. Use `key in map` instead.')
|
2019-07-23 23:57:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn (m map) _exists(key string) bool {
|
2019-08-29 01:52: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-09-09 16:22:39 +03:00
|
|
|
fn (n mut mapnode) free() {
|
|
|
|
if n.val != 0 {
|
|
|
|
free(n.val)
|
|
|
|
}
|
|
|
|
if n.left != 0 {
|
|
|
|
n.left.free()
|
|
|
|
}
|
|
|
|
if n.right != 0 {
|
|
|
|
n.right.free()
|
|
|
|
}
|
|
|
|
free(n)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (m mut map) free() {
|
|
|
|
if m.root == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
m.root.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)
|
2019-08-29 01:52:32 +03:00
|
|
|
sb.writeln('{')
|
|
|
|
for key, val in m {
|
|
|
|
sb.writeln(' "$key" => "$val"')
|
2019-08-05 05:34:12 +03:00
|
|
|
}
|
2019-08-29 01:52:32 +03:00
|
|
|
sb.writeln('}')
|
|
|
|
return sb.str()
|
2019-06-22 21:20:28 +03:00
|
|
|
}
|