1 ! Copyright (C) 2008, 2010 Slava Pestov.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays classes.algebra classes.tuple kernel
4 math math.order parser sequences sequences.private sets sorting ;
8 { from number read-only }
9 { length integer read-only }
10 { step number read-only } ;
14 : sign/mod ( x y -- z w )
15 [ [ /i ] 2keep pick * - ] keep 0 < [ neg ] when ; inline
19 : <range> ( a b step -- range )
21 [ sign/mod 0 < [ 1 + ] unless 0 max ] keep
24 M: range length length>> ; inline
27 [ step>> * ] keep from>> + ; inline
29 ! We want M\ tuple hashcode, not M\ sequence hashcode here!
30 ! sequences hashcode is O(n) in number of elements
31 M: range hashcode* tuple-hashcode ;
33 INSTANCE: range immutable-sequence
38 [ swap [ first-unsafe ] [ last-unsafe ] bi + * 2 / ] if-zero ;
41 dup step>> 0 > [ first ] [ last ] if ;
44 dup step>> 0 > [ last ] [ first ] if ;
48 : twiddle ( a b -- a b step ) 2dup > -1 1 ? ; inline
50 : (a.. ( a b step -- a' b' step ) dup [ + ] curry 2dip ; inline
52 : ..b) ( a b step -- a' b' step )
53 2over - over mod zero? [ dup [ - ] curry dip ] when ; inline
57 : [a..b] ( a b -- range ) twiddle <range> ; inline
59 : (a..b] ( a b -- range ) twiddle (a.. <range> ; inline
61 : [a..b) ( a b -- range ) twiddle ..b) <range> ; inline
63 : (a..b) ( a b -- range ) twiddle (a.. ..b) <range> ; inline
65 : [0..b] ( b -- range ) 0 swap [a..b] ; inline
67 : [1..b] ( b -- range ) 1 swap [a..b] ; inline
69 : [0..b) ( b -- range ) 0 swap [a..b) ; inline
71 : [1..b) ( b -- range ) 1 swap [a..b) ; inline
73 ! Some methods can be much faster for ranges
77 : >range< ( range -- start stop step )
78 [ from>> ] [ length>> ] [ step>> ] tri [ swap 1 - * over + ] keep ;
80 : >forward-range< ( range -- start stop step )
81 >range< dup neg? [ abs swapd ] when ;
83 : forward-range ( range -- range' )
84 >forward-range< <range> ; inline
86 CONSTANT: empty-range T{ range f 1 0 1 }
88 :: intersect-range ( range1 range2 -- range3 )
89 range1 empty? range2 empty? or [ empty-range ] [
90 range1 >forward-range< :> ( start1 stop1 step1 )
91 range2 >forward-range< :> ( start2 stop2 step2 )
92 step1 step2 gcd :> ( x g )
93 start1 start2 - g /mod :> ( z y )
94 y zero? not [ empty-range ] [
95 start1 x z step1 * * - :> b
97 start1 start2 [ b over - a rem + ] bi@ max :> m
98 stop1 stop2 [ dup b - a rem - ] bi@ min :> n
107 >forward-range< [ 3dup between? ] dip swap
108 [ nip 3dup [ - ] dip /i * + = ] [ 4drop f ] if
111 M: range cardinality length>> ;
113 M: range all-unique? drop t ;
115 M: range duplicates drop f ;
117 M: range members >array ; ! XXX: just return a T{ range } ? ;
120 over range? [ intersect-range ] [ call-next-method ] if ;
124 [ intersect-range length>> zero? not ]
125 [ call-next-method ] if ;
129 [ [ [ empty-range ] [ forward-range ] if-empty ] bi@ = ]
130 [ call-next-method ] if ;
134 [ over empty? [ 2drop t ] [ dupd intersect-range = ] if ]
135 [ call-next-method ] if ;
137 SYNTAX: ..= dup pop scan-object [a..b] suffix! ;
139 SYNTAX: ..< dup pop scan-object [a..b) suffix! ;