planckforth/lib/table.fs
2021-12-04 06:37:59 +09:00

113 lines
2.6 KiB
Forth

\ planckforth -
\ Copyright (C) 2021 nineties
( === Hash Table === )
include lib/bitscan.fs
include lib/array.fs
private{
s" Key not found" exception constant KEY-NOT-FOUND export
create prime_numbers
5 , 11 , 17 , 37 , 67 , 131 , 257 , 521 , 1031 ,
2053 , 4099 , 8209 , 16411 , 32771 , 65537 , 131101 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 ,
struct
cell% field table>bucket
cell% field table>hash ( hash function )
cell% field table>equal ( equal function for keys )
cell% field table>entries ( list of entries )
int% field table>size ( number of entries )
end-struct table%
struct
cell% field entry>key
cell% field entry>value
cell% field entry>sibling ( pointer to the next entry in bucket )
cell% field entry>next ( pointer to the next entry in entries )
int% field entry>hash ( the hash value )
end-struct entry%
: table-size ( tbl -- n ) table>size @ ; export
: make-table-with-hint ( hash equal n -- tbl )
bitscan-reverse cells prime_numbers + @ ( n to bucket size )
make-array ( allocate bucket )
( hash equal bucket )
table% %allocate throw
tuck table>bucket !
tuck table>equal !
tuck table>hash !
0 over table>entries !
0 over table>size !
;
10 constant DEFAULT_TABLE_SIZE_HINT
: make-table ( hash equal -- tbl )
DEFAULT_TABLE_SIZE_HINT make-table-with-hint
; export
: release-table ( tbl -- )
dup table>entries @
begin ?dup while
dup entry>next @
swap
free
repeat
dup table>bucket @ release-array
free
; export
: table@-helper ( key tbl -- entry )
2dup table>hash @ execute ( key tbl hashed-key )
over table>bucket @ array-size mod ( key tbl idx )
over table>bucket @ array@ ( key tbl entry )
swap table>equal @ -rot ( equal key entry )
begin ?dup while
dup entry>key @
2 pick 4 pick execute if
( equal key entry )
nip nip exit
then
repeat
2drop 0
;
: table@ ( key tbl -- v )
2dup table@-helper ?dup if
entry>value @ nip nip
else
KEY-NOT-FOUND throw
then
; export
: ?table-in ( key tbl -- n )
table@-helper 0 <>
; export
( tables for major builtin types )
: hash-next ( n1 n2 -- n3 )
+ 6122117 * 1627577 +
;
: hash-int ( n -- n )
0 hash-next
; export
: make-int-table ( -- tbl )
['] hash-int ['] = make-table
; export
}private
T{ make-int-table constant A -> }T
T{ A table-size -> 0 }T
T{ 0 A ' table@ catch -> 0 A KEY-NOT-FOUND }T
T{ 0 A ?table-in -> false }T