factor/core/hashtables/hashtables.factor

175 lines
4.0 KiB
Factor
Raw Normal View History

2008-06-09 06:22:21 -04:00
! Copyright (C) 2005, 2008 Slava Pestov.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays kernel kernel.private slots.private math
assocs math.private sequences sequences.private vectors ;
2007-09-20 18:09:08 -04:00
IN: hashtables
TUPLE: hashtable
2008-06-29 22:37:57 -04:00
{ count array-capacity }
{ deleted array-capacity }
{ array array } ;
2007-09-20 18:09:08 -04:00
<PRIVATE
: wrap ( i array -- n )
2008-07-16 17:48:09 -04:00
length>> 1 fixnum-fast fixnum-bitand ; inline
2007-09-20 18:09:08 -04:00
: hash@ ( key array -- i )
>r hashcode >fixnum dup fixnum+fast r> wrap ; inline
: probe ( array i -- array i )
2 fixnum+fast over wrap ; inline
2008-07-14 00:26:20 -04:00
: no-key ( key array -- array n ? ) nip f f ; inline
: (key@) ( key array i -- array n ? )
2008-03-06 12:28:49 -05:00
3dup swap array-nth
dup ((empty)) eq?
2008-07-14 00:26:20 -04:00
[ 3drop no-key ] [
2008-03-29 21:28:07 -04:00
= [ rot drop t ] [ probe (key@) ] if
2008-07-18 20:22:59 -04:00
] if ; inline recursive
2007-09-20 18:09:08 -04:00
: key@ ( key hash -- array n ? )
2008-07-16 17:48:09 -04:00
array>> dup length>> 0 eq?
2008-07-14 00:26:20 -04:00
[ no-key ] [ 2dup hash@ (key@) ] if ; inline
2007-09-20 18:09:08 -04:00
: <hash-array> ( n -- array )
1+ next-power-of-2 4 * ((empty)) <array> ; inline
: init-hash ( hash -- )
0 >>count 0 >>deleted drop ; inline
2007-09-20 18:09:08 -04:00
: reset-hash ( n hash -- )
swap <hash-array> >>array init-hash ;
2007-09-20 18:09:08 -04:00
: (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
2008-07-18 20:22:59 -04:00
] if ; inline recursive
2007-09-20 18:09:08 -04:00
: new-key@ ( key hash -- array n empty? )
array>> 2dup hash@ (new-key@) ; inline
2007-09-20 18:09:08 -04:00
: set-nth-pair ( value key seq n -- )
2007-09-20 18:09:08 -04:00
2 fixnum+fast [ set-slot ] 2keep
1 fixnum+fast set-slot ; inline
: hash-count+ ( hash -- )
[ 1+ ] change-count drop ; inline
2007-09-20 18:09:08 -04:00
: hash-deleted+ ( hash -- )
[ 1+ ] change-deleted drop ; inline
2007-09-20 18:09:08 -04:00
2008-06-09 06:22:21 -04:00
: (rehash) ( hash alist -- )
2008-07-14 00:26:20 -04:00
swap [ swapd set-at ] curry assoc-each ; inline
2007-09-20 18:09:08 -04:00
: hash-large? ( hash -- ? )
2008-07-14 00:26:20 -04:00
[ count>> 3 fixnum*fast 1 fixnum+fast ]
2008-07-16 17:48:09 -04:00
[ array>> length>> ] bi fixnum> ; inline
2007-09-20 18:09:08 -04:00
: hash-stale? ( hash -- ? )
2008-07-14 00:26:20 -04:00
[ deleted>> 10 fixnum*fast ] [ count>> ] bi fixnum> ; inline
2007-09-20 18:09:08 -04:00
: grow-hash ( hash -- )
2008-06-09 06:22:21 -04:00
[ dup >alist swap assoc-size 1+ ] keep
2007-09-20 18:09:08 -04:00
[ reset-hash ] keep
2008-07-14 00:26:20 -04:00
swap (rehash) ; inline
2007-09-20 18:09:08 -04:00
: ?grow-hash ( hash -- )
dup hash-large? [
grow-hash
] [
dup hash-stale? [
grow-hash
] [
drop
] if
] if ; inline
PRIVATE>
: <hashtable> ( n -- hash )
hashtable new [ reset-hash ] keep ;
2007-09-20 18:09:08 -04:00
M: hashtable at* ( key hash -- value ? )
key@ [ 3 fixnum+fast slot t ] [ 2drop f f ] if ;
M: hashtable clear-assoc ( hash -- )
[ init-hash ] [ array>> [ drop ((empty)) ] change-each ] bi ;
2007-09-20 18:09:08 -04:00
M: hashtable delete-at ( key hash -- )
tuck key@ [
>r >r ((tombstone)) dup r> r> set-nth-pair
2007-09-20 18:09:08 -04:00
hash-deleted+
] [
3drop
] if ;
M: hashtable assoc-size ( hash -- n )
[ count>> ] [ deleted>> ] bi - ;
2007-09-20 18:09:08 -04:00
: rehash ( hash -- )
dup >alist >r
dup clear-assoc
r> (rehash) ;
2007-09-20 18:09:08 -04:00
M: hashtable set-at ( value key hash -- )
2008-07-14 00:26:20 -04:00
dup ?grow-hash
2dup new-key@
[ rot hash-count+ set-nth-pair ]
[ rot drop set-nth-pair ] if ;
2007-09-20 18:09:08 -04:00
: associate ( value key -- hash )
2 <hashtable> [ set-at ] keep ;
<PRIVATE
: push-unsafe ( elt seq -- )
[ length ] keep
[ underlying>> set-array-nth ]
[ >r 1+ r> (>>length) ]
2bi ; inline
PRIVATE>
2008-06-09 06:22:21 -04:00
M: hashtable >alist
[ array>> [ length 2/ ] keep ] [ assoc-size <vector> ] bi [
[
>r
>r 1 fixnum-shift-fast r>
[ array-nth ] [ >r 1 fixnum+fast r> array-nth ] 2bi r>
pick tombstone? [ 3drop ] [ [ 2array ] dip push-unsafe ] if
] 2curry each
] keep { } like ;
2007-09-20 18:09:08 -04:00
M: hashtable clone
(clone) [ clone ] change-array ;
2007-09-20 18:09:08 -04:00
M: hashtable equal?
over hashtable? [
2dup [ assoc-size ] bi@ eq?
[ assoc= ] [ 2drop f ] if
] [ 2drop f ] if ;
2007-09-20 18:09:08 -04:00
! 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* ;
INSTANCE: hashtable assoc