1 ! Copyright (C) 2005, 2009 Slava Pestov.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs growable.private hashtables
4 kernel kernel.private math math.order math.private sequences
5 sequences.private vectors ;
8 ! Optimized merge-sort:
10 ! 1) only allocates 2 temporary arrays
12 ! 2) first phase (interchanging pairs x[i], x[i+1] where
13 ! x[i] > x[i+1]) is handled specially
22 { from1 array-capacity }
23 { to1 array-capacity }
24 { from2 array-capacity }
25 { to2 array-capacity } ;
27 : l-elt ( merge -- elt ) [ from1>> ] [ seq>> ] bi nth-unsafe ; inline
29 : r-elt ( merge -- elt ) [ from2>> ] [ seq>> ] bi nth-unsafe ; inline
31 : l-done? ( merge -- ? ) [ from1>> ] [ to1>> ] bi eq? ; inline
33 : r-done? ( merge -- ? ) [ from2>> ] [ to2>> ] bi eq? ; inline
38 [ to1>> ] [ from1>> fixnum-fast ] [ accum>> length integer>fixnum-strict ] tri
39 [ fixnum+fast >>length ] 2keep
40 ] [ seq>> ] [ from1>> roll dupd fixnum+fast ] tri
41 copy-loop drop ; inline
46 [ to2>> ] [ from2>> fixnum-fast ] [ accum>> length integer>fixnum-strict ] tri
47 [ fixnum+fast >>length ] 2keep
48 ] [ seq>> ] [ from2>> roll dupd fixnum+fast ] tri
49 copy-loop drop ; inline
52 [ l-elt ] [ [ 1 + ] change-from1 accum>> ] bi push-unsafe ; inline
55 [ r-elt ] [ [ 1 + ] change-from2 accum>> ] bi push-unsafe ; inline
57 : decide? ( merge quot: ( elt1 elt2 -- <=> ) -- ? )
58 [ [ l-elt ] [ r-elt ] bi ] dip call +gt+ eq? ; inline
60 : (merge) ( merge quot: ( elt1 elt2 -- <=> ) -- )
61 over r-done? [ drop dump-l ] [
62 over l-done? [ drop dump-r ] [
64 [ over r-next ] [ over l-next ] if
67 ] if ; inline recursive
69 : flip-accum ( merge -- )
70 dup [ accum>> ] [ accum1>> ] bi eq? [
71 dup accum1>> underlying>> >>seq
75 dup accum2>> underlying>> >>seq
77 dup accum>> 0 >>length 2drop ; inline
79 : <merge> ( seq -- merge )
82 swap length <vector> >>accum2
83 dup accum1>> underlying>> >>seq
84 dup accum2>> >>accum ; inline
86 : compute-midpoint ( merge -- merge )
87 dup [ from1>> ] [ to2>> ] bi + 2/ >>to1 ; inline
89 : merging ( from to merge -- )
93 dup [ to1>> ] [ seq>> length ] bi min >>to1
94 dup [ to2>> ] [ seq>> length ] bi min >>to2
98 : nth-chunk ( n size -- from to ) [ * dup ] keep + ; inline
100 : chunks ( length size -- n ) [ align ] keep /i ; inline
102 : each-chunk ( length size quot -- )
103 [ [ chunks ] keep ] dip
104 [ nth-chunk ] prepose curry
105 each-integer ; inline
107 : merge ( from to merge quot -- )
108 [ [ merging ] keep ] dip (merge) ; inline
110 : sort-pass ( merge size quot -- )
113 over [ seq>> length ] 2dip
115 [ merge ] 2curry each-chunk ; inline
117 : sort-loop ( merge quot -- )
118 [ 2 over seq>> length [ over > ] curry ] dip
119 [ [ 1 shift 2dup ] dip sort-pass ] curry
122 : each-pair ( seq quot -- )
123 [ [ length 1 + 2/ ] keep ] dip
124 [ [ 1 shift dup 1 + ] dip ] prepose curry each-integer ; inline
126 : (sort-pairs) ( i1 i2 seq quot accum -- )
127 [ 2dup length = ] 2dip rot [
128 [ drop nip nth-unsafe ] dip push-unsafe
131 [ [ nth-unsafe ] curry bi@ 2dup ] dip call +gt+ eq?
133 ] dip [ push-unsafe ] curry bi@
136 : sort-pairs ( merge quot -- )
137 [ [ seq>> ] [ accum>> ] bi ] dip swap
138 [ (sort-pairs) ] 2curry each-pair ; inline
142 : sort-with ( seq quot: ( obj1 obj2 -- <=> ) -- sortedseq )
144 [ sort-pairs ] [ sort-loop ] [ drop accum>> underlying>> ] 2tri ; inline
146 : inv-sort-with ( seq quot: ( obj1 obj2 -- <=> ) -- sortedseq )
147 '[ @ invert-comparison ] sort-with ; inline
149 : sort ( seq -- sortedseq ) [ <=> ] sort-with ;
151 : inv-sort ( seq -- sortedseq ) [ >=< ] sort-with ;
153 : sort-by ( seq quot: ( elt -- key ) -- sortedseq )
154 [ compare ] curry sort-with ; inline
156 : inv-sort-by ( seq quot: ( elt -- key ) -- sortedseq )
157 [ compare invert-comparison ] curry sort-with ; inline
159 ALIAS: natural-sort sort ! temporary, deprecated
163 : check-bounds ( alist n -- alist )
164 [ swap bounds-check 2drop ] curry dupd each ; inline
168 GENERIC: sort-keys ( obj -- sortedseq )
170 M: object sort-keys >alist sort-keys ;
172 M: sequence sort-keys
173 0 check-bounds [ first-unsafe ] sort-by ;
175 M: hashtable sort-keys
176 >alist [ { array } declare first-unsafe ] sort-by ;
178 GENERIC: inv-sort-keys ( obj -- sortedseq )
180 M: object inv-sort-keys >alist inv-sort-keys ;
182 M: sequence inv-sort-keys
183 0 check-bounds [ first-unsafe ] inv-sort-by ;
185 M: hashtable inv-sort-keys
186 >alist [ { array } declare first-unsafe ] inv-sort-by ;
188 GENERIC: sort-values ( obj -- sortedseq )
190 M: object sort-values >alist sort-values ;
192 M: sequence sort-values
193 1 check-bounds [ second-unsafe ] sort-by ;
195 M: hashtable sort-values
196 >alist [ { array } declare second-unsafe ] sort-by ;
198 : sort-pair ( a b -- c d ) 2dup after? [ swap ] when ;
200 GENERIC: inv-sort-values ( obj -- sortedseq )
202 M: object inv-sort-values >alist inv-sort-values ;
204 M: sequence inv-sort-values
205 1 check-bounds [ second-unsafe ] inv-sort-by ;
207 M: hashtable inv-sort-values
208 >alist [ { array } declare second-unsafe ] inv-sort-by ;