193 lines
4.6 KiB
Factor
Executable File
193 lines
4.6 KiB
Factor
Executable File
! Copyright (C) 2005, 2007 Slava Pestov.
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
USING: arrays kernel kernel.private slots.private math assocs
|
|
math.private sequences sequences.private vectors ;
|
|
IN: hashtables
|
|
|
|
<PRIVATE
|
|
|
|
: wrap ( i array -- n )
|
|
array-capacity 1 fixnum-fast fixnum-bitand ; inline
|
|
|
|
: hash@ ( key array -- i )
|
|
>r hashcode >fixnum dup fixnum+fast r> wrap ; inline
|
|
|
|
: probe ( array i -- array i )
|
|
2 fixnum+fast over wrap ; inline
|
|
|
|
: (key@) ( key keys i -- array n ? )
|
|
3dup swap array-nth
|
|
dup ((empty)) eq?
|
|
[ 3drop nip f f ]
|
|
[
|
|
=
|
|
[ rot drop t ]
|
|
[ probe (key@) ]
|
|
if
|
|
]
|
|
if ; inline
|
|
|
|
: key@ ( key hash -- array n ? )
|
|
hash-array 2dup hash@ (key@) ; inline
|
|
|
|
: <hash-array> ( n -- array )
|
|
1+ next-power-of-2 4 * ((empty)) <array> ; inline
|
|
|
|
: init-hash ( hash -- )
|
|
0 over set-hash-count 0 swap set-hash-deleted ;
|
|
|
|
: reset-hash ( n hash -- )
|
|
swap <hash-array> over set-hash-array init-hash ;
|
|
|
|
: (new-key@) ( key keys i -- keys n empty? )
|
|
3dup swap array-nth dup ((empty)) eq? [
|
|
2drop rot drop t
|
|
] [
|
|
= [
|
|
rot drop f
|
|
] [
|
|
probe (new-key@)
|
|
] if
|
|
] if ; inline
|
|
|
|
: new-key@ ( key hash -- array n empty? )
|
|
hash-array 2dup hash@ (new-key@) ; inline
|
|
|
|
: nth-pair ( n seq -- key value )
|
|
swap 2 fixnum+fast 2dup slot -rot 1 fixnum+fast slot ;
|
|
inline
|
|
|
|
: set-nth-pair ( value key seq n -- )
|
|
2 fixnum+fast [ set-slot ] 2keep
|
|
1 fixnum+fast set-slot ; inline
|
|
|
|
: hash-count+ ( hash -- )
|
|
dup hash-count 1+ swap set-hash-count ; inline
|
|
|
|
: hash-deleted+ ( hash -- )
|
|
dup hash-deleted 1+ swap set-hash-deleted ; inline
|
|
|
|
: (set-hash) ( value key hash -- new? )
|
|
2dup new-key@
|
|
[ rot hash-count+ set-nth-pair t ]
|
|
[ rot drop set-nth-pair f ] if ; inline
|
|
|
|
: find-pair-next >r 2 fixnum+fast r> ; inline
|
|
|
|
: (find-pair) ( quot i array -- key value ? )
|
|
2dup array-capacity eq? [
|
|
3drop f f f
|
|
] [
|
|
2dup array-nth tombstone? [
|
|
find-pair-next (find-pair)
|
|
] [
|
|
[ nth-pair rot call ] 3keep roll [
|
|
nth-pair >r nip r> t
|
|
] [
|
|
find-pair-next (find-pair)
|
|
] if
|
|
] if
|
|
] if ; inline
|
|
|
|
: find-pair ( array quot -- key value ? ) 0 rot (find-pair) ; inline
|
|
|
|
: (rehash) ( hash array -- )
|
|
[ swap pick (set-hash) drop f ] find-pair 2drop 2drop ;
|
|
|
|
: hash-large? ( hash -- ? )
|
|
dup hash-count 3 fixnum*fast
|
|
swap hash-array array-capacity > ;
|
|
|
|
: hash-stale? ( hash -- ? )
|
|
dup hash-deleted 10 fixnum*fast swap hash-count fixnum> ;
|
|
|
|
: grow-hash ( hash -- )
|
|
[ dup hash-array swap assoc-size 1+ ] keep
|
|
[ reset-hash ] keep
|
|
swap (rehash) ;
|
|
|
|
: ?grow-hash ( hash -- )
|
|
dup hash-large? [
|
|
grow-hash
|
|
] [
|
|
dup hash-stale? [
|
|
grow-hash
|
|
] [
|
|
drop
|
|
] if
|
|
] if ; inline
|
|
|
|
PRIVATE>
|
|
|
|
: <hashtable> ( n -- hash )
|
|
hashtable construct-empty [ reset-hash ] keep ;
|
|
|
|
M: hashtable at* ( key hash -- value ? )
|
|
key@ [ 3 fixnum+fast slot t ] [ 2drop f f ] if ;
|
|
|
|
M: hashtable clear-assoc ( hash -- )
|
|
dup init-hash hash-array [ drop ((empty)) ] change-each ;
|
|
|
|
M: hashtable delete-at ( key hash -- )
|
|
tuck key@ [
|
|
>r >r ((tombstone)) dup r> r> set-nth-pair
|
|
hash-deleted+
|
|
] [
|
|
3drop
|
|
] if ;
|
|
|
|
M: hashtable assoc-size ( hash -- n )
|
|
dup hash-count swap hash-deleted - ;
|
|
|
|
: rehash ( hash -- )
|
|
dup hash-array
|
|
dup length ((empty)) <array> pick set-hash-array
|
|
0 pick set-hash-count
|
|
0 pick set-hash-deleted
|
|
(rehash) ;
|
|
|
|
M: hashtable set-at ( value key hash -- )
|
|
dup >r (set-hash) [ r> ?grow-hash ] [ r> drop ] if ;
|
|
|
|
: associate ( value key -- hash )
|
|
2 <hashtable> [ set-at ] keep ;
|
|
|
|
M: hashtable assoc-find ( hash quot -- key value ? )
|
|
>r hash-array r> find-pair ;
|
|
|
|
M: hashtable clone
|
|
(clone) dup hash-array clone over set-hash-array ;
|
|
|
|
M: hashtable equal?
|
|
over hashtable? [
|
|
2dup [ assoc-size ] 2apply number=
|
|
[ assoc= ] [ 2drop f ] if
|
|
] [ 2drop f ] if ;
|
|
|
|
! Default method
|
|
M: assoc new-assoc drop <hashtable> ;
|
|
|
|
M: f new-assoc drop <hashtable> ;
|
|
|
|
: >hashtable ( assoc -- hashtable )
|
|
H{ } assoc-clone-like ;
|
|
|
|
M: hashtable assoc-like
|
|
drop dup hashtable? [ >hashtable ] unless ;
|
|
|
|
: ?set-at ( value key assoc/f -- assoc )
|
|
[ [ set-at ] keep ] [ associate ] if* ;
|
|
|
|
: (prune) ( hash vec elt -- )
|
|
rot 2dup key?
|
|
[ 3drop ] [ dupd dupd set-at swap push ] if ; inline
|
|
|
|
: prune ( seq -- newseq )
|
|
dup length <hashtable> over length <vector>
|
|
rot [ >r 2dup r> (prune) ] each nip ;
|
|
|
|
: all-unique? ( seq -- ? )
|
|
dup prune [ length ] 2apply = ;
|
|
|
|
INSTANCE: hashtable assoc
|