]> gitweb.factorcode.org Git - factor.git/blob - core/combinators/combinators.factor
core: Rename iota to <iota> so we can have TUPLE: iota ... ; instead of TUPLE: iota...
[factor.git] / core / combinators / combinators.factor
1 ! Copyright (C) 2006, 2010 Slava Pestov, Daniel Ehrenberg.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs hashtables kernel kernel.private
4 make math math.order math.private quotations sequences
5 sequences.private sets sorting words ;
6 IN: combinators
7
8 ! Most of these combinators have compile-time expansions in
9 ! the optimizing compiler. See stack-checker.transforms and
10 ! compiler.tree.propagation.call-effect
11
12 <PRIVATE
13
14 : call-effect-unsafe ( quot effect -- ) drop call ;
15
16 : execute-effect-unsafe ( word effect -- ) drop execute ;
17
18 M: object throw
19     ERROR-HANDLER-QUOT special-object [ die ] or
20     ( error -- * ) call-effect-unsafe ;
21
22 PRIVATE>
23
24 ERROR: wrong-values quot call-site ;
25
26 ! We can't USE: effects here so we forward reference slots instead
27 SLOT: in
28 SLOT: out
29 SLOT: terminated?
30
31 : call-effect ( quot effect -- )
32     ! Don't use fancy combinators here, since this word always
33     ! runs unoptimized
34     2dup [
35         [ [ get-datastack ] dip dip ] dip
36         dup terminated?>> [ 2drop f ] [
37             dup in>> length swap out>> length
38             check-datastack
39         ] if
40     ] 2dip rot
41     [ 2drop ] [ wrong-values ] if ;
42
43 : execute-effect ( word effect -- )
44     [ [ execute ] curry ] dip call-effect ;
45
46 ! cleave
47 : cleave ( x seq -- )
48     [ call ] with each ;
49
50 : cleave>quot ( seq -- quot )
51     [ [ keep ] curry ] map concat [ drop ] append [ ] like ;
52
53 ! 2cleave
54 : 2cleave ( x y seq -- )
55     [ 2keep ] each 2drop ;
56
57 : 2cleave>quot ( seq -- quot )
58     [ [ 2keep ] curry ] map concat [ 2drop ] append [ ] like ;
59
60 ! 3cleave
61 : 3cleave ( x y z seq -- )
62     [ 3keep ] each 3drop ;
63
64 : 3cleave>quot ( seq -- quot )
65     [ [ 3keep ] curry ] map concat [ 3drop ] append [ ] like ;
66
67 ! 4cleave
68 : 4cleave ( w x y z seq -- )
69     [ 4keep ] each 4drop ;
70
71 : 4cleave>quot ( seq -- quot )
72     [ [ 4keep ] curry ] map concat [ 4drop ] append [ ] like ;
73
74 ! spread
75 : shallow-spread>quot ( seq -- quot )
76     [ ] [ [ dup empty? [ [ dip ] curry ] unless ] dip append ] reduce ;
77
78 : deep-spread>quot ( seq -- quot )
79     [ ] [ [ [ dip ] curry ] dip append ] reduce ;
80
81 : spread ( objs... seq -- )
82     deep-spread>quot call ;
83
84 ! cond
85 ERROR: no-cond ;
86
87 : cond ( assoc -- )
88     [ dup callable? [ drop t ] [ first call ] if ] find nip
89     [ dup callable? [ call ] [ second call ] if ]
90     [ no-cond ] if* ;
91
92 : alist>quot ( default assoc -- quot )
93     [ rot \ if 3array append [ ] like ] assoc-each ;
94
95 : cond>quot ( assoc -- quot )
96     [ dup pair? [ [ t ] swap 2array ] unless ] map
97     reverse! [ no-cond ] swap alist>quot ;
98
99 ! case
100 ERROR: no-case object ;
101
102 : case-find ( obj assoc -- obj' )
103     [
104         dup array? [
105             dupd first dup word? [
106                 execute
107             ] [
108                 dup wrapper? [ wrapped>> ] when
109             ] if =
110         ] [ callable? ] if
111     ] find nip ;
112
113 \ case-find t "no-compile" set-word-prop
114
115 : case ( obj assoc -- )
116     case-find {
117         { [ dup array? ] [ nip second call ] }
118         { [ dup callable? ] [ call ] }
119         { [ dup not ] [ drop no-case ] }
120     } cond ;
121
122 : linear-case-quot ( default assoc -- quot )
123     [
124         [ 1quotation \ dup prefix \ = suffix ]
125         [ \ drop prefix ] bi*
126     ] assoc-map reverse! alist>quot ;
127
128 <PRIVATE
129
130 : (distribute-buckets) ( buckets pair keys -- )
131     dup t eq? [
132         drop [ swap adjoin ] curry each
133     ] [
134         [
135             [ 2dup ] dip hashcode pick length rem rot nth adjoin
136         ] each 2drop
137     ] if ;
138
139 : <buckets> ( initial length -- array )
140     next-power-of-2 <iota> swap [ nip clone ] curry map ;
141
142 : distribute-buckets ( alist initial quot -- buckets )
143     swapd [ [ dup first ] dip call 2array ] curry map
144     [ length <buckets> dup ] keep
145     [ first2 (distribute-buckets) ] with each ; inline
146
147 : hash-case-table ( default assoc -- array )
148     V{ } [ 1array ] distribute-buckets [
149         [ [ literalize ] dip ] assoc-map linear-case-quot
150     ] with map ;
151
152 : hash-dispatch-quot ( table -- quot )
153     [ length 1 - [ fixnum-bitand ] curry ] keep
154     [ dispatch ] curry append ;
155
156 : hash-case-quot ( default assoc -- quot )
157     hash-case-table hash-dispatch-quot
158     [ dup hashcode >fixnum ] prepend ;
159
160 : contiguous-range? ( keys -- ? )
161     dup [ fixnum? ] all? [
162         dup all-unique? [
163             [ length ] [ supremum ] [ infimum ] tri - - 1 =
164         ] [ drop f ] if
165     ] [ drop f ] if ;
166
167 : dispatch-case-quot ( default assoc -- quot )
168     [
169         \ dup , \ integer? , [
170             \ integer>fixnum-strict , \ dup ,
171             dup keys [ infimum , ] [ supremum , ] bi \ between? ,
172             [
173                 dup keys infimum , \ - ,
174                 sort-keys values [ >quotation ] map ,
175                 \ dispatch ,
176             ] [ ] make , dup , \ if ,
177         ] [ ] make , , \ if ,
178     ] [ ] make ;
179
180 PRIVATE>
181
182 : case>quot ( default assoc -- quot )
183     dup keys {
184         { [ dup empty? ] [ 2drop ] }
185         { [ dup [ length 4 <= ] [ [ word? ] any? ] bi or ] [ drop linear-case-quot ] }
186         { [ dup contiguous-range? ] [ drop dispatch-case-quot ] }
187         { [ dup [ wrapper? ] any? not ] [ drop hash-case-quot ] }
188         { [ dup [ wrapper? ] all? ] [ drop [ [ wrapped>> ] dip ] assoc-map hash-case-quot ] }
189         [ drop linear-case-quot ]
190     } cond ;
191
192 : recursive-hashcode ( n obj quot -- code )
193     pick 0 <= [ 3drop 0 ] [ [ 1 - ] 2dip call ] if ; inline
194
195 ! These go here, not in sequences and hashtables, since those
196 ! two cannot depend on us
197 M: sequence hashcode* [ sequence-hashcode ] recursive-hashcode ;
198
199 M: array hashcode* [ sequence-hashcode ] recursive-hashcode ;
200
201 M: reversed hashcode* [ sequence-hashcode ] recursive-hashcode ;
202
203 M: slice hashcode* [ sequence-hashcode ] recursive-hashcode ;
204
205 M: iota hashcode*
206     over 0 <= [ 2drop 0 ] [
207         nip length 0 swap [ sequence-hashcode-step ] each-integer
208     ] if ;
209
210 M: hashtable hashcode*
211     [
212         dup assoc-size 1 eq?
213         [ assoc-hashcode ] [ nip assoc-size ] if
214     ] recursive-hashcode ;
215
216 : to-fixed-point ( ... object quot: ( ... object(n) -- ... object(n+1) ) -- ... object(n) )
217     [ keep over = ] keep [ to-fixed-point ] curry unless ; inline recursive