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.
|
2008-06-28 03:36:20 -04:00
|
|
|
USING: accessors arrays kernel kernel.private slots.private math
|
2008-11-12 00:03:50 -05:00
|
|
|
assocs math.private sequences sequences.private vectors ;
|
2007-09-20 18:09:08 -04:00
|
|
|
IN: hashtables
|
|
|
|
|
2008-06-28 03:36:20 -04:00
|
|
|
TUPLE: hashtable
|
2008-06-29 22:37:57 -04:00
|
|
|
{ count array-capacity }
|
|
|
|
{ deleted array-capacity }
|
|
|
|
{ array array } ;
|
2008-06-28 03:36:20 -04:00
|
|
|
|
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 )
|
2008-11-23 03:44:56 -05:00
|
|
|
[ hashcode >fixnum dup fixnum+fast ] dip wrap ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: 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 -- )
|
2008-06-28 03:36:20 -04:00
|
|
|
0 >>count 0 >>deleted drop ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: reset-hash ( n hash -- )
|
2008-06-28 03:36:20 -04:00
|
|
|
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? )
|
2008-06-28 03:36:20 -04:00
|
|
|
array>> 2dup hash@ (new-key@) ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2007-10-04 18:45:06 -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 -- )
|
2008-06-28 03:36:20 -04:00
|
|
|
[ 1+ ] change-count drop ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: hash-deleted+ ( hash -- )
|
2008-06-28 03:36:20 -04:00
|
|
|
[ 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 )
|
2008-04-13 16:06:09 -04:00
|
|
|
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 -- )
|
2008-06-28 03:36:20 -04:00
|
|
|
[ init-hash ] [ array>> [ drop ((empty)) ] change-each ] bi ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: hashtable delete-at ( key hash -- )
|
|
|
|
tuck key@ [
|
2008-11-23 03:44:56 -05:00
|
|
|
[ ((tombstone)) dup ] 2dip set-nth-pair
|
2007-09-20 18:09:08 -04:00
|
|
|
hash-deleted+
|
|
|
|
] [
|
|
|
|
3drop
|
|
|
|
] if ;
|
|
|
|
|
|
|
|
M: hashtable assoc-size ( hash -- n )
|
2008-06-28 03:36:20 -04:00
|
|
|
[ count>> ] [ deleted>> ] bi - ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: rehash ( hash -- )
|
2008-11-23 03:44:56 -05:00
|
|
|
dup >alist [
|
2008-06-28 03:36:20 -04:00
|
|
|
dup clear-assoc
|
2008-11-23 03:44:56 -05:00
|
|
|
] dip (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 ;
|
|
|
|
|
2008-11-12 01:10:50 -05:00
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
: push-unsafe ( elt seq -- )
|
|
|
|
[ length ] keep
|
|
|
|
[ underlying>> set-array-nth ]
|
2008-12-06 10:16:29 -05:00
|
|
|
[ [ 1 fixnum+fast { array-capacity } declare ] dip (>>length) ]
|
2008-11-12 01:10:50 -05:00
|
|
|
2bi ; inline
|
|
|
|
|
|
|
|
PRIVATE>
|
|
|
|
|
2008-06-09 06:22:21 -04:00
|
|
|
M: hashtable >alist
|
2008-11-12 01:10:50 -05:00
|
|
|
[ array>> [ length 2/ ] keep ] [ assoc-size <vector> ] bi [
|
2008-11-12 00:03:50 -05:00
|
|
|
[
|
2008-11-23 03:44:56 -05:00
|
|
|
[
|
|
|
|
[ 1 fixnum-shift-fast ] dip
|
|
|
|
[ array-nth ] [ [ 1 fixnum+fast ] dip array-nth ] 2bi
|
|
|
|
] dip
|
2008-11-12 01:10:50 -05:00
|
|
|
pick tombstone? [ 3drop ] [ [ 2array ] dip push-unsafe ] if
|
2008-11-12 00:03:50 -05:00
|
|
|
] 2curry each
|
2008-11-12 01:10:50 -05:00
|
|
|
] keep { } like ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: hashtable clone
|
2008-06-28 03:36:20 -04:00
|
|
|
(clone) [ clone ] change-array ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: hashtable equal?
|
2008-02-14 02:03:57 -05:00
|
|
|
over hashtable? [
|
2008-11-12 00:03:50 -05:00
|
|
|
2dup [ assoc-size ] bi@ eq?
|
2008-02-14 02:03:57 -05:00
|
|
|
[ 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
|