factor/core/hash-sets/hash-sets.factor

220 lines
5.6 KiB
Factor
Raw Normal View History

2010-02-26 11:01:57 -05:00
! Copyright (C) 2010 Daniel Ehrenberg
! Copyright (C) 2005, 2011 John Benediktsson, Slava Pestov.
2010-02-26 11:01:57 -05:00
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays combinators growable.private hash-sets
2014-02-07 01:38:48 -05:00
hashtables.private kernel kernel.private math math.private
sequences sequences.private sets sets.private slots.private
vectors ;
2010-02-26 11:01:57 -05:00
IN: hash-sets
TUPLE: hash-set
2016-05-30 12:40:09 -04:00
{ count array-capacity }
{ deleted array-capacity }
{ array array } ;
2010-02-26 11:01:57 -05:00
<PRIVATE
: hash@ ( key array -- i )
[ hashcode >fixnum ] dip wrap ; inline
: probe ( array i probe# -- array i probe# )
1 fixnum+fast [ fixnum+fast over wrap ] keep ; inline
: no-key ( key array -- array n ? ) nip f f ; inline
: (key@) ( key array i probe# -- array n ? )
[ 3dup swap array-nth ] dip over +empty+ eq?
[ 4drop no-key ] [
[ = ] dip swap
[ drop rot drop t ]
[ probe (key@) ]
if
] if ; inline recursive
: key@ ( key hash -- array n ? )
array>> dup length>> 0 eq?
[ no-key ] [ 2dup hash@ 0 (key@) ] if ; inline
: <hash-array> ( n -- array )
3 * 1 + 2/ next-power-of-2 +empty+ <array> ; inline
: reset-hash ( n hash -- )
swap <hash-array> >>array init-hash ; inline
: (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@) ]
if
] if ; inline recursive
2013-03-23 19:58:03 -04:00
: new-key@ ( key hash -- array n ? )
[ array>> 2dup hash@ 0 f (new-key@) ] keep swap
2013-03-23 19:58:03 -04:00
[ over [ hash-deleted- ] [ hash-count+ ] if swap or t ] [ 2drop f ] if ; inline
: set-nth-item ( key array n -- )
2 fixnum+fast set-slot ; inline
2013-03-23 19:58:03 -04:00
: (adjoin) ( key hash -- ? )
dupd new-key@ [ set-nth-item ] dip ; inline
2013-03-08 01:02:02 -05:00
: (delete) ( key hash -- ? )
[ nip ] [ key@ ] 2bi [
[ +tombstone+ ] 2dip set-nth-item
hash-deleted+ t
] [
3drop f
] if ; inline
2013-03-08 01:02:02 -05:00
: (rehash) ( seq hash -- )
2013-03-23 19:58:03 -04:00
[ (adjoin) drop ] curry each ; inline
: hash-large? ( hash -- ? )
[ count>> 1 fixnum+fast 3 fixnum*fast ]
2014-01-06 02:09:07 -05:00
[ array>> length>> 1 fixnum-shift-fast ] bi fixnum>= ; inline
2014-02-07 01:38:48 -05:00
: each-member ( ... array quot: ( ... elt -- ... ) -- ... )
2013-03-26 18:19:43 -04:00
[ if ] curry [ dup tombstone? [ drop ] ] prepose each ; inline
: grow-hash ( hash -- )
{ hash-set } declare [
[ array>> ]
[ cardinality 1 + ]
[ reset-hash ] tri
2013-03-23 19:58:03 -04:00
] keep [ (adjoin) drop ] curry each-member ;
: ?grow-hash ( hash -- )
dup hash-large? [ grow-hash ] [ drop ] if ; inline
PRIVATE>
2013-03-08 09:15:27 -05:00
: <hash-set> ( capacity -- hash-set )
integer>fixnum-strict
2014-01-08 12:55:45 -05:00
[ 0 0 ] dip <hash-array> hash-set boa ; inline
2013-03-08 09:15:27 -05:00
M: hash-set in?
key@ 2nip ;
2013-03-08 09:15:27 -05:00
M: hash-set clear-set
[ init-hash ] [ array>> [ drop +empty+ ] map! drop ] bi ;
2013-03-08 09:15:27 -05:00
M: hash-set delete
(delete) drop ;
M: hash-set ?delete
(delete) ;
2013-03-08 09:15:27 -05:00
M: hash-set cardinality
[ count>> ] [ deleted>> ] bi - ; inline
2013-03-08 09:15:27 -05:00
: rehash ( hash-set -- )
[ members ] [ clear-set ] [ (rehash) ] tri ;
2013-03-23 19:58:03 -04:00
M: hash-set adjoin
dup ?grow-hash (adjoin) drop ;
M: hash-set ?adjoin
2013-03-08 01:02:02 -05:00
dup ?grow-hash (adjoin) ;
M: hash-set members
2014-02-07 01:38:48 -05:00
[ array>> 0 swap ] [ cardinality f <array> ] bi [
[ [ over ] dip set-nth-unsafe 1 + ] curry each-member
] keep nip ;
M: hash-set clone
(clone) [ clone ] change-array ; inline
M: hash-set equal?
over hash-set? [ set= ] [ 2drop f ] if ;
: >hash-set ( members -- hash-set )
dup length <hash-set> [ (rehash) ] keep ; inline
M: hash-set set-like
drop dup hash-set? [ ?members >hash-set ] unless ; inline
2010-02-26 11:01:57 -05:00
INSTANCE: hash-set set
2013-03-26 18:19:43 -04:00
! Overrides for performance
<PRIVATE
: and-tombstones ( quot: ( elt -- ? ) -- quot: ( elt -- ? ) )
[ if ] curry [ dup tombstone? [ drop t ] ] prepose ; inline
: not-tombstones ( quot: ( elt -- ? ) -- quot: ( elt -- ? ) )
[ if ] curry [ dup tombstone? [ drop f ] ] prepose ; inline
: array/tester ( hash-set1 hash-set2 -- array quot )
[ array>> ] dip [ in? ] curry ; inline
: filter-members ( hash-set array quot: ( elt -- ? ) -- accum )
[ dup ] prepose rot cardinality <vector> [
[ push-unsafe ] curry [ [ drop ] if ] curry
compose each
] keep ; inline
PRIVATE>
M: hash-set intersect
over hash-set? [
small/large dupd array/tester not-tombstones
filter-members >hash-set
] [ (intersect) >hash-set ] if ;
2013-03-26 19:00:31 -04:00
M: hash-set intersects?
over hash-set? [
small/large array/tester not-tombstones any?
2013-03-26 19:00:31 -04:00
] [ small/large sequence/tester any? ] if ;
M: hash-set union
over hash-set? [
small/large [ array>> ] [ clone ] bi*
[ [ adjoin ] curry each-member ] keep
] [ (union) >hash-set ] if ;
M: hash-set diff
over hash-set? [
dupd array/tester [ not ] compose not-tombstones
filter-members >hash-set
] [ (diff) >hash-set ] if ;
2013-03-26 18:19:43 -04:00
M: hash-set subset?
over hash-set? [
2dup [ cardinality ] bi@ > [ 2drop f ] [
array/tester and-tombstones all?
] if
] [ call-next-method ] if ;
M: hash-set set=
over hash-set? [
2dup [ cardinality ] bi@ eq? [
array/tester and-tombstones all?
] [ 2drop f ] if
] [ call-next-method ] if ;
M: hash-set hashcode*
[
dup cardinality 1 eq?
[ members hashcode* ] [ nip cardinality ] if
] recursive-hashcode ;
2013-03-26 18:19:43 -04:00
! Default methods
M: f fast-set drop 0 <hash-set> ;
2010-02-26 11:01:57 -05:00
M: sequence fast-set >hash-set ;
M: sequence duplicates
dup length <hash-set> [ ?adjoin ] curry reject ;
M: sequence all-unique?
dup length <hash-set> [ ?adjoin ] curry all? ;