Merge pull request #400 from asarhaddon/improve-mal-impl-macro-no-meta
[jackhill/mal.git] / yorick / hash.i
1 // Implement our old naive O(n) map because Yeti's hash table (h_new()) cannot
2 // be used inside arrays and structs (we can't get a pointer to hash table).
3 // This prevents saving pointer to environment in MalFunction for example.
4
5 struct Hash {
6 pointer keys
7 pointer vals
8 }
9
10 func hash_new(void)
11 {
12 return Hash(keys=&[], vals=&[])
13 }
14
15 func hash_get(h, key)
16 {
17 for (i = 1; i <= numberof(*h.keys); ++i) {
18 if ((*h.keys)(i) == key) return *((*h.vals)(i))
19 }
20 return nil
21 }
22
23 func hash_has_key(h, key)
24 {
25 for (i = 1; i <= numberof(*h.keys); ++i) {
26 if ((*h.keys)(i) == key) return 1
27 }
28 return 0
29 }
30
31 func hash_set(&h, key, val)
32 {
33 if (is_void(*h.keys)) {
34 h.keys = &[key]
35 h.vals = &[&val]
36 return
37 }
38 for (i = 1; i <= numberof(*h.keys); ++i) {
39 if ((*h.keys)(i) == key) {
40 (*h.vals)(i) = &val
41 return
42 }
43 }
44 tmp = *h.keys
45 grow, tmp, [key]
46 h.keys = &tmp
47 tmp = *h.vals
48 grow, tmp, [&val]
49 h.vals = &tmp
50 }
51
52 func hash_delete(&h, key)
53 {
54 if (is_void(*h.keys) || numberof(*h.keys) == 0) return
55 k = *h.keys
56 v = *h.vals
57 if (numberof(k) == 1) {
58 if (k(1) == key) {
59 h.keys = &[]
60 h.vals = &[]
61 return
62 }
63 }
64 for (i = 1; i <= numberof(k); ++i) {
65 if (k(i) == key) {
66 if (i == 1) {
67 h.keys = &(k(i+1:))
68 h.vals = &(v(i+1:))
69 } else if (i == numberof(k)) {
70 h.keys = &(k(1:i-1))
71 h.vals = &(v(1:i-1))
72 } else {
73 h.keys = &grow(k(1:i-1), k(i+1:))
74 h.vals = &grow(v(1:i-1), v(i+1:))
75 }
76 return
77 }
78 }
79 }