]> gitweb.factorcode.org Git - factor.git/blob - core/combinators/combinators.factor
Move call( and execute( to core
[factor.git] / core / combinators / combinators.factor
1 ! Copyright (C) 2006, 2009 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 <PRIVATE
9
10 : call-effect-unsafe ( quot effect -- ) drop call ;
11
12 : execute-effect-unsafe ( word effect -- ) drop execute ;
13
14 M: object throw 5 getenv [ die ] or (( error -- * )) call-effect-unsafe ;
15
16 PRIVATE>
17
18 ERROR: wrong-values effect ;
19
20 ! We can't USE: effects here so we forward reference slots instead
21 SLOT: in
22 SLOT: out
23
24 : call-effect ( quot effect -- )
25     [ [ datastack ] dip dip ] dip
26     [ in>> length ] [ out>> length ] [ ] tri [ check-datastack ] dip
27     [ wrong-values ] curry unless ;
28
29 : execute-effect ( word effect -- )
30     [ [ execute ] curry ] dip call-effect ;
31
32 ! cleave
33 : cleave ( x seq -- )
34     [ call ] with each ;
35
36 : cleave>quot ( seq -- quot )
37     [ [ keep ] curry ] map concat [ drop ] append [ ] like ;
38
39 ! 2cleave
40 : 2cleave ( x y seq -- )
41     [ 2keep ] each 2drop ;
42
43 : 2cleave>quot ( seq -- quot )
44     [ [ 2keep ] curry ] map concat [ 2drop ] append [ ] like ;
45
46 ! 3cleave
47 : 3cleave ( x y z seq -- )
48     [ 3keep ] each 3drop ;
49
50 : 3cleave>quot ( seq -- quot )
51     [ [ 3keep ] curry ] map concat [ 3drop ] append [ ] like ;
52
53 ! spread
54 : spread>quot ( seq -- quot )
55     [ ] [ [ dup empty? [ [ dip ] curry ] unless ] dip append ] reduce ;
56
57 : spread ( objs... seq -- )
58     spread>quot call ;
59
60 ! cond
61 ERROR: no-cond ;
62
63 : cond ( assoc -- )
64     [ dup callable? [ drop t ] [ first call ] if ] find nip
65     [ dup callable? [ call ] [ second call ] if ]
66     [ no-cond ] if* ;
67
68 : alist>quot ( default assoc -- quot )
69     [ rot \ if 3array append [ ] like ] assoc-each ;
70
71 : cond>quot ( assoc -- quot )
72     [ dup pair? [ [ t ] swap 2array ] unless ] map
73     reverse [ no-cond ] swap alist>quot ;
74
75 ! case
76 ERROR: no-case object ;
77
78 : case-find ( obj assoc -- obj' )
79     [
80         dup array? [
81             dupd first dup word? [
82                 execute
83             ] [
84                 dup wrapper? [ wrapped>> ] when
85             ] if =
86         ] [ callable? ] if
87     ] find nip ;
88
89 : case ( obj assoc -- )
90     case-find {
91         { [ dup array? ] [ nip second call ] }
92         { [ dup callable? ] [ call ] }
93         { [ dup not ] [ drop no-case ] }
94     } cond ;
95
96 : linear-case-quot ( default assoc -- quot )
97     [
98         [ 1quotation \ dup prefix \ = suffix ]
99         [ \ drop prefix ] bi*
100     ] assoc-map alist>quot ;
101
102 : (distribute-buckets) ( buckets pair keys -- )
103     dup t eq? [
104         drop [ swap adjoin ] curry each
105     ] [
106         [
107             [ 2dup ] dip hashcode pick length rem rot nth adjoin
108         ] each 2drop
109     ] if ;
110
111 : <buckets> ( initial length -- array )
112     next-power-of-2 swap [ nip clone ] curry map ;
113
114 : distribute-buckets ( alist initial quot -- buckets )
115     swapd [ [ dup first ] dip call 2array ] curry map
116     [ length <buckets> dup ] keep
117     [ first2 (distribute-buckets) ] with each ; inline
118
119 : hash-case-table ( default assoc -- array )
120     V{ } [ 1array ] distribute-buckets
121     [ [ [ literalize ] dip ] assoc-map linear-case-quot ] with map ;
122
123 : hash-dispatch-quot ( table -- quot )
124     [ length 1- [ fixnum-bitand ] curry ] keep
125     [ dispatch ] curry append ;
126
127 : hash-case-quot ( default assoc -- quot )
128     hash-case-table hash-dispatch-quot
129     [ dup hashcode >fixnum ] prepend ;
130
131 : contiguous-range? ( keys -- ? )
132     dup [ fixnum? ] all? [
133         dup all-unique? [
134             [ prune length ]
135             [ [ supremum ] [ infimum ] bi - ]
136             bi - 1 =
137         ] [ drop f ] if
138     ] [ drop f ] if ;
139
140 : dispatch-case-quot ( default assoc -- quot )
141     [
142         \ dup ,
143         dup keys [ infimum , ] [ supremum , ] bi \ between? ,
144         [
145             dup keys infimum , [ - >fixnum ] %
146             sort-keys values [ >quotation ] map ,
147             \ dispatch ,
148         ] [ ] make , , \ if ,
149     ] [ ] make ;
150
151 : case>quot ( default assoc -- quot )
152     dup keys {
153         { [ dup empty? ] [ 2drop ] }
154         { [ dup [ length 4 <= ] [ [ word? ] any? ] bi or ] [ drop linear-case-quot ] }
155         { [ dup contiguous-range? ] [ drop dispatch-case-quot ] }
156         { [ dup [ wrapper? ] any? not ] [ drop hash-case-quot ] }
157         { [ dup [ wrapper? ] all? ] [ drop [ [ wrapped>> ] dip ] assoc-map hash-case-quot ] }
158         [ drop linear-case-quot ]
159     } cond ;
160
161 ! recursive-hashcode
162 : recursive-hashcode ( n obj quot -- code )
163     pick 0 <= [ 3drop 0 ] [ [ 1- ] 2dip call ] if ; inline
164
165 ! These go here, not in sequences and hashtables, since those
166 ! two cannot depend on us
167 M: sequence hashcode* [ sequence-hashcode ] recursive-hashcode ;
168
169 M: reversed hashcode* [ sequence-hashcode ] recursive-hashcode ;
170
171 M: slice hashcode* [ sequence-hashcode ] recursive-hashcode ;
172
173 M: hashtable hashcode*
174     [
175         dup assoc-size 1 eq?
176         [ assoc-hashcode ] [ nip assoc-size ] if
177     ] recursive-hashcode ;