2011-11-12 18:35:19 -05:00
|
|
|
! Copyright (C) 2005, 2011 John Benediktsson, Slava Pestov.
|
2007-09-20 18:09:08 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2013-03-05 13:34:47 -05:00
|
|
|
USING: accessors arrays assocs kernel kernel.private math
|
|
|
|
math.private sequences sequences.private slots.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
|
|
|
|
2011-10-02 20:49:11 -04:00
|
|
|
: probe ( array i probe# -- array i probe# )
|
2011-10-02 16:47:51 -04:00
|
|
|
2 fixnum+fast [ fixnum+fast over wrap ] keep ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-07-14 00:26:20 -04:00
|
|
|
: no-key ( key array -- array n ? ) nip f f ; inline
|
|
|
|
|
2011-10-02 16:47:51 -04:00
|
|
|
: (key@) ( key array i probe# -- array n ? )
|
|
|
|
[ 3dup swap array-nth ] dip over ((empty)) eq?
|
2012-10-23 15:26:14 -04:00
|
|
|
[ 4drop no-key ] [
|
2011-10-02 16:47:51 -04:00
|
|
|
[ = ] dip swap
|
|
|
|
[ drop 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?
|
2011-10-02 16:47:51 -04:00
|
|
|
[ no-key ] [ 2dup hash@ 0 (key@) ] if ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: <hash-array> ( n -- array )
|
2009-05-01 20:58:24 -04:00
|
|
|
1 + next-power-of-2 4 * ((empty)) <array> ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: 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-12-06 16:31:35 -05:00
|
|
|
swap <hash-array> >>array init-hash ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2011-11-10 15:37:14 -05:00
|
|
|
: hash-count+ ( hash -- )
|
2011-11-12 18:35:19 -05:00
|
|
|
[ 1 fixnum+fast ] change-count drop ; inline
|
2011-11-10 15:37:14 -05:00
|
|
|
|
|
|
|
: hash-deleted+ ( hash -- )
|
2011-11-12 18:35:19 -05:00
|
|
|
[ 1 fixnum+fast ] change-deleted drop ; inline
|
2011-11-10 15:37:14 -05:00
|
|
|
|
|
|
|
: hash-deleted- ( hash -- )
|
2011-11-12 18:35:19 -05:00
|
|
|
[ 1 fixnum-fast ] change-deleted drop ; inline
|
2011-11-10 15:37:14 -05:00
|
|
|
|
|
|
|
! i = first-empty-or-found
|
|
|
|
! j = first-deleted
|
2011-11-12 18:35:19 -05:00
|
|
|
! empty? = if true, key was not found
|
|
|
|
!
|
|
|
|
! if empty? is f:
|
|
|
|
! - we want to store into i
|
|
|
|
!
|
|
|
|
! if empty? is t:
|
|
|
|
! - we want to store into j if j is not f
|
|
|
|
! - otherwise we want to store into i
|
|
|
|
! - ... and increment count
|
|
|
|
|
2011-11-10 15:37:14 -05:00
|
|
|
: (new-key@) ( key array i probe# j -- array i j empty? )
|
|
|
|
[ 2dup swap array-nth ] 2dip pick tombstone?
|
|
|
|
[
|
|
|
|
rot ((empty)) eq?
|
|
|
|
[ nip [ drop ] 3dip t ]
|
|
|
|
[ pick or [ probe ] dip (new-key@) ]
|
|
|
|
if
|
|
|
|
] [
|
|
|
|
[ [ pick ] dip = ] 2dip rot
|
|
|
|
[ nip [ drop ] 3dip f ]
|
|
|
|
[ [ probe ] dip (new-key@) ]
|
2011-10-02 16:47:51 -04:00
|
|
|
if
|
2008-07-18 20:22:59 -04:00
|
|
|
] if ; inline recursive
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2011-11-10 15:37:14 -05:00
|
|
|
: new-key@ ( key hash -- array n )
|
2011-11-12 18:35:19 -05:00
|
|
|
[ array>> 2dup hash@ 0 f (new-key@) ] keep swap
|
|
|
|
[ over [ hash-deleted- ] [ hash-count+ ] if swap or ] [ 2drop ] if ; 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
|
|
|
|
|
2013-03-08 01:01:50 -05:00
|
|
|
: (set-at) ( value key hash -- )
|
|
|
|
dupd new-key@ set-nth-pair ; inline
|
|
|
|
|
|
|
|
: (rehash) ( alist hash -- )
|
|
|
|
[ 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
|
|
|
|
2013-03-21 02:02:40 -04:00
|
|
|
: each-pair ( array quot: ( key value -- ) -- )
|
|
|
|
[
|
|
|
|
[ length 2/ ] keep [
|
|
|
|
[ 1 fixnum-shift-fast ] dip [ array-nth ] 2keep
|
|
|
|
pick tombstone? [ 3drop ]
|
|
|
|
] curry
|
|
|
|
] dip [ [ 1 fixnum+fast ] dip array-nth ] prepose
|
|
|
|
[ if ] curry compose each-integer ; inline
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
: grow-hash ( hash -- )
|
2013-03-07 23:51:46 -05:00
|
|
|
{ hashtable } declare [
|
2013-03-21 02:02:40 -04:00
|
|
|
[ array>> ]
|
2013-03-07 23:51:46 -05:00
|
|
|
[ assoc-size 1 + ]
|
|
|
|
[ reset-hash ] tri
|
2013-03-21 02:02:40 -04:00
|
|
|
] keep [ swapd (set-at) ] curry each-pair ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: ?grow-hash ( hash -- )
|
2011-11-10 15:37:14 -05:00
|
|
|
dup hash-large? [ grow-hash ] [ drop ] if ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
PRIVATE>
|
|
|
|
|
|
|
|
: <hashtable> ( n -- hash )
|
2009-03-31 09:16:04 -04:00
|
|
|
hashtable new [ reset-hash ] keep ; inline
|
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 -- )
|
2009-10-27 23:32:56 -04:00
|
|
|
[ init-hash ] [ array>> [ drop ((empty)) ] map! drop ] bi ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: hashtable delete-at ( key hash -- )
|
2009-01-23 19:20:47 -05:00
|
|
|
[ nip ] [ key@ ] 2bi [
|
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 )
|
2009-08-17 23:32:21 -04:00
|
|
|
[ count>> ] [ deleted>> ] bi - ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: rehash ( hash -- )
|
2013-03-08 01:01:50 -05:00
|
|
|
[ >alist ] [ clear-assoc ] [ (rehash) ] tri ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: hashtable set-at ( value key hash -- )
|
2013-03-08 01:01:50 -05:00
|
|
|
dup ?grow-hash (set-at) ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: associate ( value key -- hash )
|
2012-08-03 00:43:37 -04:00
|
|
|
1 <hashtable> [ set-at ] keep ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-11-12 01:10:50 -05:00
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
: push-unsafe ( elt seq -- )
|
|
|
|
[ length ] keep
|
|
|
|
[ underlying>> set-array-nth ]
|
2010-05-05 16:52:54 -04: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
|
2013-03-21 02:02:40 -04:00
|
|
|
[ array>> ] [ assoc-size <vector> ] bi [
|
|
|
|
[ [ 2array ] dip push-unsafe ] curry each-pair
|
2008-11-12 01:10:50 -05:00
|
|
|
] keep { } like ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: hashtable clone
|
2009-08-17 23:32:21 -04:00
|
|
|
(clone) [ clone ] change-array ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: hashtable equal?
|
2011-01-03 23:37:17 -05:00
|
|
|
over hashtable? [ assoc= ] [ 2drop f ] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! Default method
|
2009-08-17 23:32:21 -04:00
|
|
|
M: assoc new-assoc drop <hashtable> ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2009-08-17 23:32:21 -04:00
|
|
|
M: f new-assoc drop <hashtable> ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: >hashtable ( assoc -- hashtable )
|
2013-03-08 01:01:50 -05:00
|
|
|
[ >alist ] [ assoc-size <hashtable> ] bi [ (rehash) ] keep ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: hashtable assoc-like
|
2009-08-17 23:32:21 -04:00
|
|
|
drop dup hashtable? [ >hashtable ] unless ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: ?set-at ( value key assoc/f -- assoc )
|
|
|
|
[ [ set-at ] keep ] [ associate ] if* ;
|
|
|
|
|
2011-10-02 23:28:51 -04:00
|
|
|
! borrowed from boost::hash_combine, but the
|
|
|
|
! magic number is 2^29/phi instead of 2^32/phi
|
|
|
|
! due to max fixnum value on 32-bit machines
|
|
|
|
: hash-combine ( obj oldhash -- newhash )
|
2011-11-23 21:49:33 -05:00
|
|
|
[ hashcode 0x13c6ef37 + ] dip
|
2011-10-02 23:28:51 -04:00
|
|
|
[ 6 shift ] [ -2 shift ] bi + + ;
|
|
|
|
|
2012-08-24 18:00:33 -04:00
|
|
|
ERROR: malformed-hashtable-pair seq pair ;
|
|
|
|
|
|
|
|
: check-hashtable ( seq -- seq )
|
|
|
|
dup [ dup length 2 = [ drop ] [ malformed-hashtable-pair ] if ] each ;
|
|
|
|
|
|
|
|
: parse-hashtable ( seq -- hashtable )
|
|
|
|
check-hashtable H{ } assoc-clone-like ;
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
INSTANCE: hashtable assoc
|