-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhash-table.fs
152 lines (115 loc) · 4.68 KB
/
hash-table.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
\ hash table
\ Copyright © 2010-2021 Bernd Paysan
\ This program is free software: you can redistribute it and/or modify
\ it under the terms of the GNU Affero General Public License as published by
\ the Free Software Foundation, either version 3 of the License, or
\ (at your option) any later version.
\ This program is distributed in the hope that it will be useful,
\ but WITHOUT ANY WARRANTY; without even the implied warranty of
\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\ GNU Affero General Public License for more details.
\ You should have received a copy of the GNU Affero General Public License
\ along with this program. If not, see <http://www.gnu.org/licenses/>.
\ generic hash table functions
2 64s buffer: hashinit
:is 'image defers 'image hashinit 2 64s erase ;
\ this computes a cryptographic somewhat secure hash over the input string
User hash-state 2 64s cell- uallot drop
: string-hash ( addr u -- ) hashinit hash-state [ 2 64s ]L move
false hash-state hashkey2 ;
: hash$ ( -- addr u ) hash-state [ 2 64s ]L ;
\ hierarchical hash table
\ hash tables store key,value-pairs.
\ Each hierarchy uses one byte of state as index (only lower 7 bits)
\ if there is a collission, add another indirection
uvalue last#
: #!? ( addrval u addrkey u bucket -- true / addrval u addrkey u false )
dup >r @ 0= IF r@ $! r@ cell+ $! r> to last#
true EXIT THEN
2dup r@ $@ str= IF 2drop r@ cell+ $! r> to last# true EXIT THEN
rdrop false ;
: #@? ( addrkey u bucket -- addrval u true / addrkey u false )
dup >r @ 0= IF rdrop false EXIT THEN
2dup r@ $@ str= IF 2drop r> dup to last# cell+ $@ true EXIT THEN
rdrop false ;
: bucket-off ( bucket -- )
?dup-IF dup $free cell+ $free THEN ;
: #free? ( addrkey u bucket -- true / addrkey u false )
dup >r @ 0= IF rdrop false EXIT THEN
2dup r@ $@ str= IF 2drop r> bucket-off true EXIT THEN
rdrop false ;
$180 cells Constant table-size#
: hash@ ( bucket -- addr ) dup
>r @ 0= IF table-size# allocate throw dup table-size# erase dup r> !
ELSE r> @ THEN ;
warnings @ warnings off \ hash-bang will be redefined
: #! ( addrval u addrkey u hash -- ) { hash }
2dup string-hash hash$ bounds ?DO
I c@ $7F and 2* cells hash hash@ + #!? IF
UNLOOP EXIT THEN
I c@ $80 or $80 + cells hash hash@ + to hash
LOOP 2drop 2drop true abort" hash exhausted, please reboot universe" ;
warnings !
: #@ ( addrkey u hash -- addrval u / 0 0 ) { hash }
2dup string-hash hash$ bounds ?DO
I c@ $7F and 2* cells hash @ dup 0= IF 2drop LEAVE THEN
+ #@? IF UNLOOP EXIT THEN
I c@ $80 or $80 + cells hash @ + to hash
LOOP 2drop #0. ;
: #+! ( addr1 u1 addr2 u2 hash -- ) >r
2dup r@ #@ d0= IF r> #! ELSE 2drop rdrop last# cell+ $+! THEN ;
: #free ( addrkey u hash -- ) { hash }
2dup string-hash hash$ bounds ?DO
I c@ $7F and 2* cells hash @ dup 0= IF 2drop LEAVE THEN
+ #free? IF UNLOOP EXIT THEN
I c@ $80 or $80 + cells hash @ + to hash
LOOP 2drop ;
: #frees ( hash -- ) dup @ 0= IF drop EXIT THEN dup
>r @ $100 cells bounds DO I $free cell +LOOP
r@ @ $100 cells + $80 cells bounds DO I recurse cell +LOOP
r@ @ free throw r> off ;
-1 8 rshift invert Constant msbyte#
: leftalign ( key -- key' )
BEGIN dup msbyte# and 0= WHILE 8 lshift dup 0= UNTIL THEN ;
: #key ( addrkey u hash -- path / -1 ) 0 { hash key }
2dup string-hash hash$ drop cell bounds ?DO
key 8 lshift I c@ $80 or or to key
I c@ $7F and 2* cells hash @ dup 0= IF 2drop LEAVE THEN
+ #@? IF 2drop key -$81 and leftalign UNLOOP EXIT THEN
I c@ $80 or $80 + cells hash @ + to hash
LOOP 2drop -1 ;
: #.key ( path hash -- item ) @ { hash }
BEGIN
hash 0= IF drop 0 EXIT THEN
$100 um* dup $80 and WHILE
$80 + cells hash + @ to hash
REPEAT \ stack: pathlow pathhigh (<=$7F)
nip 2* cells hash + ;
: #map { hash xt -- } \ xt: ( ... node -- ... )
hash @ 0= ?EXIT
hash @ $100 cells bounds DO
I @ IF I xt execute THEN
2 cells +LOOP
hash @ $100 cells + $80 cells bounds DO
I @ IF I xt recurse THEN
cell +LOOP ;
: #.entry ( hash-entry -- ) dup $@ type ." -> " cell+ $@ type cr ;
0 warnings !@
: #. ( hash -- ) ['] #.entry #map ;
warnings !
' Variable alias hash:
\ test: move dictionary to hash
\\\
variable ht
: test ( -- )
context @ cell+ BEGIN @ dup WHILE
dup name>string 2dup ht #!
REPEAT drop ;
: test1 ( -- )
context @ cell+ BEGIN @ dup WHILE
dup name>string 2dup ht #@ str= 0= IF ." unequal" cr THEN
REPEAT drop ;
: test2 ( -- )
context @ cell+ BEGIN @ dup WHILE
dup name>string 2dup ht #key dup h. cr ht #.key $@ str= 0= IF ." unequal" cr THEN
REPEAT drop ;