]> gitweb.factorcode.org Git - factor.git/blob - core/combinators/combinators.factor
Merge branch 'bags' of git://github.com/littledan/Factor
[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 sequences sequences.private math.private
4 kernel kernel.private math assocs quotations vectors
5 hashtables sorting words sets math.order make ;
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     5 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
30 : call-effect ( quot effect -- )
31     ! Don't use fancy combinators here, since this word always
32     ! runs unoptimized
33     [ datastack ] 2dip
34     2dup [
35         [ dip ] dip
36         dup in>> length swap out>> length
37         check-datastack
38     ] 2dip rot
39     [ 2drop ] [ wrong-values ] if ;
40
41 : execute-effect ( word effect -- )
42     [ [ execute ] curry ] dip call-effect ;
43
44 ! cleave
45 : cleave ( x seq -- )
46     [ call ] with each ;
47
48 : cleave>quot ( seq -- quot )
49     [ [ keep ] curry ] map concat [ drop ] append [ ] like ;
50
51 ! 2cleave
52 : 2cleave ( x y seq -- )
53     [ 2keep ] each 2drop ;
54
55 : 2cleave>quot ( seq -- quot )
56     [ [ 2keep ] curry ] map concat [ 2drop ] append [ ] like ;
57
58 ! 3cleave
59 : 3cleave ( x y z seq -- )
60     [ 3keep ] each 3drop ;
61
62 : 3cleave>quot ( seq -- quot )
63     [ [ 3keep ] curry ] map concat [ 3drop ] append [ ] like ;
64
65 ! spread
66 : spread>quot ( seq -- quot )
67     [ ] [ [ dup empty? [ [ dip ] curry ] unless ] dip append ] reduce ;
68
69 : spread ( objs... seq -- )
70     spread>quot call ;
71
72 ! cond
73 ERROR: no-cond ;
74
75 : cond ( assoc -- )
76     [ dup callable? [ drop t ] [ first call ] if ] find nip
77     [ dup callable? [ call ] [ second call ] if ]
78     [ no-cond ] if* ;
79
80 : alist>quot ( default assoc -- quot )
81     [ rot \ if 3array append [ ] like ] assoc-each ;
82
83 : cond>quot ( assoc -- quot )
84     [ dup pair? [ [ t ] swap 2array ] unless ] map
85     reverse [ no-cond ] swap alist>quot ;
86
87 ! case
88 ERROR: no-case object ;
89
90 : case-find ( obj assoc -- obj' )
91     [
92         dup array? [
93             dupd first dup word? [
94                 execute
95             ] [
96                 dup wrapper? [ wrapped>> ] when
97             ] if =
98         ] [ callable? ] if
99     ] find nip ;
100
101 \ case-find t "no-compile" set-word-prop
102
103 : case ( obj assoc -- )
104     case-find {
105         { [ dup array? ] [ nip second call ] }
106         { [ dup callable? ] [ call ] }
107         { [ dup not ] [ drop no-case ] }
108     } cond ;
109
110 : linear-case-quot ( default assoc -- quot )
111     [
112         [ 1quotation \ dup prefix \ = suffix ]
113         [ \ drop prefix ] bi*
114     ] assoc-map alist>quot ;
115
116 <PRIVATE
117
118 : (distribute-buckets) ( buckets pair keys -- )
119     dup t eq? [
120         drop [ swap adjoin ] curry each
121     ] [
122         [
123             [ 2dup ] dip hashcode pick length rem rot nth adjoin
124         ] each 2drop
125     ] if ;
126
127 : <buckets> ( initial length -- array )
128     next-power-of-2 iota swap [ nip clone ] curry map ;
129
130 : distribute-buckets ( alist initial quot -- buckets )
131     swapd [ [ dup first ] dip call 2array ] curry map
132     [ length <buckets> dup ] keep
133     [ first2 (distribute-buckets) ] with each ; inline
134
135 : hash-case-table ( default assoc -- array )
136     V{ } [ 1array ] distribute-buckets
137     [ [ [ literalize ] dip ] assoc-map linear-case-quot ] with map ;
138
139 : hash-dispatch-quot ( table -- quot )
140     [ length 1 - [ fixnum-bitand ] curry ] keep
141     [ dispatch ] curry append ;
142
143 : hash-case-quot ( default assoc -- quot )
144     hash-case-table hash-dispatch-quot
145     [ dup hashcode >fixnum ] prepend ;
146
147 : contiguous-range? ( keys -- ? )
148     dup [ fixnum? ] all? [
149         dup all-unique? [
150             [ length ]
151             [ [ supremum ] [ infimum ] bi - ]
152             bi - 1 =
153         ] [ drop f ] if
154     ] [ drop f ] if ;
155
156 : dispatch-case-quot ( default assoc -- quot )
157     [
158         \ dup ,
159         dup keys [ infimum , ] [ supremum , ] bi \ between? ,
160         [
161             dup keys infimum , [ - >fixnum ] %
162             sort-keys values [ >quotation ] map ,
163             \ dispatch ,
164         ] [ ] make , , \ if ,
165     ] [ ] make ;
166
167 PRIVATE>
168
169 : case>quot ( default assoc -- quot )
170     dup keys {
171         { [ dup empty? ] [ 2drop ] }
172         { [ dup [ length 4 <= ] [ [ word? ] any? ] bi or ] [ drop linear-case-quot ] }
173         { [ dup contiguous-range? ] [ drop dispatch-case-quot ] }
174         { [ dup [ wrapper? ] any? not ] [ drop hash-case-quot ] }
175         { [ dup [ wrapper? ] all? ] [ drop [ [ wrapped>> ] dip ] assoc-map hash-case-quot ] }
176         [ drop linear-case-quot ]
177     } cond ;
178
179 : recursive-hashcode ( n obj quot -- code )
180     pick 0 <= [ 3drop 0 ] [ [ 1 - ] 2dip call ] if ; inline
181
182 ! These go here, not in sequences and hashtables, since those
183 ! two cannot depend on us
184 M: sequence hashcode* [ sequence-hashcode ] recursive-hashcode ;
185
186 M: reversed hashcode* [ sequence-hashcode ] recursive-hashcode ;
187
188 M: slice hashcode* [ sequence-hashcode ] recursive-hashcode ;
189
190 M: hashtable hashcode*
191     [
192         dup assoc-size 1 eq?
193         [ assoc-hashcode ] [ nip assoc-size ] if
194     ] recursive-hashcode ;
195
196 : to-fixed-point ( ... object quot: ( ... object(n) -- ... object(n+1) ) -- ... object(n) )
197     [ keep over = ] keep [ to-fixed-point ] curry unless ; inline recursive