This source file includes following definitions.
- inorder
- binarysort
- count_run
- gallop_left
- gallop_right
- merge_init
- merge_markmem
- cleanup_mem
- merge_getmem
- needmem
- merge_lo
- merge_hi
- merge_at
- powerloop
- found_new_run
- merge_force_collapse
- merge_compute_minrun
- reverse_vector
- tim_sort
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 #include <config.h>
34 #include "lisp.h"
35
36
37
38
39
40
41
42
43 #define MAX_MERGE_PENDING PTRDIFF_WIDTH
44
45
46
47
48 #define GALLOP_WIN_MIN 7
49
50
51
52
53 #define MERGESTATE_TEMP_SIZE 256
54
55 struct stretch
56 {
57 Lisp_Object *base;
58 ptrdiff_t len;
59 int power;
60 };
61
62 struct reloc
63 {
64 Lisp_Object **src;
65 Lisp_Object **dst;
66 ptrdiff_t *size;
67 int order;
68 };
69
70
71 typedef struct
72 {
73 Lisp_Object *listbase;
74 ptrdiff_t listlen;
75
76
77
78
79
80 int n;
81 struct stretch pending[MAX_MERGE_PENDING];
82
83
84
85
86
87
88 ptrdiff_t min_gallop;
89
90
91
92
93
94 Lisp_Object *a;
95 ptrdiff_t alloced;
96 specpdl_ref count;
97 Lisp_Object temparray[MERGESTATE_TEMP_SIZE];
98
99
100
101
102
103 struct reloc reloc;
104
105
106
107 Lisp_Object predicate;
108 } merge_state;
109
110
111
112
113 static inline bool
114 inorder (const Lisp_Object predicate, const Lisp_Object a, const Lisp_Object b)
115 {
116 return !NILP (call2 (predicate, a, b));
117 }
118
119
120
121
122
123
124
125
126 static void
127 binarysort (merge_state *ms, Lisp_Object *lo, const Lisp_Object *hi,
128 Lisp_Object *start)
129 {
130 Lisp_Object pred = ms->predicate;
131
132 eassume (lo <= start && start <= hi);
133 if (lo == start)
134 ++start;
135 for (; start < hi; ++start)
136 {
137 Lisp_Object *l = lo;
138 Lisp_Object *r = start;
139 Lisp_Object pivot = *r;
140
141 eassume (l < r);
142 do {
143 Lisp_Object *p = l + ((r - l) >> 1);
144 if (inorder (pred, pivot, *p))
145 r = p;
146 else
147 l = p + 1;
148 } while (l < r);
149 eassume (l == r);
150 for (Lisp_Object *p = start; p > l; --p)
151 p[0] = p[-1];
152 *l = pivot;
153 }
154 }
155
156
157
158
159
160
161
162
163
164
165
166 static ptrdiff_t
167 count_run (merge_state *ms, Lisp_Object *lo, const Lisp_Object *hi,
168 bool *descending)
169 {
170 Lisp_Object pred = ms->predicate;
171
172 eassume (lo < hi);
173 *descending = 0;
174 ++lo;
175 ptrdiff_t n = 1;
176 if (lo == hi)
177 return n;
178
179 n = 2;
180 if (inorder (pred, lo[0], lo[-1]))
181 {
182 *descending = 1;
183 for (lo = lo + 1; lo < hi; ++lo, ++n)
184 {
185 if (!inorder (pred, lo[0], lo[-1]))
186 break;
187 }
188 }
189 else
190 {
191 for (lo = lo + 1; lo < hi; ++lo, ++n)
192 {
193 if (inorder (pred, lo[0], lo[-1]))
194 break;
195 }
196 }
197
198 return n;
199 }
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222 static ptrdiff_t
223 gallop_left (merge_state *ms, const Lisp_Object key, Lisp_Object *a,
224 const ptrdiff_t n, const ptrdiff_t hint)
225 {
226 Lisp_Object pred = ms->predicate;
227
228 eassume (a && n > 0 && hint >= 0 && hint < n);
229
230 a += hint;
231 ptrdiff_t lastofs = 0;
232 ptrdiff_t ofs = 1;
233 if (inorder (pred, *a, key))
234 {
235
236
237 const ptrdiff_t maxofs = n - hint;
238 while (ofs < maxofs)
239 {
240 if (inorder (pred, a[ofs], key))
241 {
242 lastofs = ofs;
243 eassume (ofs <= (PTRDIFF_MAX - 1) / 2);
244 ofs = (ofs << 1) + 1;
245 }
246 else
247 break;
248 }
249 if (ofs > maxofs)
250 ofs = maxofs;
251
252 lastofs += hint;
253 ofs += hint;
254 }
255 else
256 {
257
258
259 const ptrdiff_t maxofs = hint + 1;
260 while (ofs < maxofs)
261 {
262 if (inorder (pred, a[-ofs], key))
263 break;
264
265 lastofs = ofs;
266 eassume (ofs <= (PTRDIFF_MAX - 1) / 2);
267 ofs = (ofs << 1) + 1;
268 }
269 if (ofs > maxofs)
270 ofs = maxofs;
271
272 ptrdiff_t k = lastofs;
273 lastofs = hint - ofs;
274 ofs = hint - k;
275 }
276 a -= hint;
277
278 eassume (-1 <= lastofs && lastofs < ofs && ofs <= n);
279
280
281
282 ++lastofs;
283 while (lastofs < ofs)
284 {
285 ptrdiff_t m = lastofs + ((ofs - lastofs) >> 1);
286
287 if (inorder (pred, a[m], key))
288 lastofs = m + 1;
289 else
290 ofs = m;
291 }
292 eassume (lastofs == ofs);
293 return ofs;
294 }
295
296
297
298
299
300
301
302
303
304
305
306 static ptrdiff_t
307 gallop_right (merge_state *ms, const Lisp_Object key, Lisp_Object *a,
308 const ptrdiff_t n, const ptrdiff_t hint)
309 {
310 Lisp_Object pred = ms->predicate;
311
312 eassume (a && n > 0 && hint >= 0 && hint < n);
313
314 a += hint;
315 ptrdiff_t lastofs = 0;
316 ptrdiff_t ofs = 1;
317 if (inorder (pred, key, *a))
318 {
319
320
321 const ptrdiff_t maxofs = hint + 1;
322 while (ofs < maxofs)
323 {
324 if (inorder (pred, key, a[-ofs]))
325 {
326 lastofs = ofs;
327 eassume (ofs <= (PTRDIFF_MAX - 1) / 2);
328 ofs = (ofs << 1) + 1;
329 }
330 else
331 break;
332 }
333 if (ofs > maxofs)
334 ofs = maxofs;
335
336 ptrdiff_t k = lastofs;
337 lastofs = hint - ofs;
338 ofs = hint - k;
339 }
340 else
341 {
342
343
344 const ptrdiff_t maxofs = n - hint;
345 while (ofs < maxofs)
346 {
347 if (inorder (pred, key, a[ofs]))
348 break;
349
350 lastofs = ofs;
351 eassume (ofs <= (PTRDIFF_MAX - 1) / 2);
352 ofs = (ofs << 1) + 1;
353 }
354 if (ofs > maxofs)
355 ofs = maxofs;
356
357 lastofs += hint;
358 ofs += hint;
359 }
360 a -= hint;
361
362 eassume (-1 <= lastofs && lastofs < ofs && ofs <= n);
363
364
365
366 ++lastofs;
367 while (lastofs < ofs)
368 {
369 ptrdiff_t m = lastofs + ((ofs - lastofs) >> 1);
370
371 if (inorder (pred, key, a[m]))
372 ofs = m;
373 else
374 lastofs = m + 1;
375 }
376 eassume (lastofs == ofs);
377 return ofs;
378 }
379
380
381 static void
382 merge_init (merge_state *ms, const ptrdiff_t list_size, Lisp_Object *lo,
383 const Lisp_Object predicate)
384 {
385 eassume (ms != NULL);
386
387 ms->a = ms->temparray;
388 ms->alloced = MERGESTATE_TEMP_SIZE;
389
390 ms->n = 0;
391 ms->min_gallop = GALLOP_WIN_MIN;
392 ms->listlen = list_size;
393 ms->listbase = lo;
394 ms->predicate = predicate;
395 ms->reloc = (struct reloc){NULL, NULL, NULL, 0};
396 }
397
398
399
400
401
402
403 static void
404 merge_markmem (void *arg)
405 {
406 merge_state *ms = arg;
407 eassume (ms != NULL);
408
409 if (ms->reloc.size != NULL && *ms->reloc.size > 0)
410 {
411 eassume (ms->reloc.src != NULL);
412 mark_objects (*ms->reloc.src, *ms->reloc.size);
413 }
414 }
415
416
417
418
419
420
421 static void
422 cleanup_mem (void *arg)
423 {
424 merge_state *ms = arg;
425 eassume (ms != NULL);
426
427
428
429
430
431
432
433 if (ms->reloc.order != 0 && *ms->reloc.size > 0)
434 {
435 eassume (*ms->reloc.src != NULL && *ms->reloc.dst != NULL);
436 ptrdiff_t n = *ms->reloc.size;
437 ptrdiff_t shift = ms->reloc.order == -1 ? 0 : n - 1;
438 memcpy (*ms->reloc.dst - shift, *ms->reloc.src, n * word_size);
439 }
440
441
442 xfree (ms->a);
443 }
444
445
446
447
448
449
450
451 static void
452 merge_getmem (merge_state *ms, const ptrdiff_t need)
453 {
454 eassume (ms != NULL);
455
456 if (ms->a == ms->temparray)
457 {
458
459
460 specpdl_ref count = SPECPDL_INDEX ();
461 record_unwind_protect_ptr_mark (cleanup_mem, ms, merge_markmem);
462 ms->count = count;
463 }
464 else
465 {
466
467
468
469
470 xfree (ms->a);
471 }
472 ms->a = xmalloc (need * word_size);
473 ms->alloced = need;
474 }
475
476
477 static inline void
478 needmem (merge_state *ms, ptrdiff_t na)
479 {
480 if (na > ms->alloced)
481 merge_getmem (ms, na);
482 }
483
484
485
486
487
488
489
490 static void
491 merge_lo (merge_state *ms, Lisp_Object *ssa, ptrdiff_t na, Lisp_Object *ssb,
492 ptrdiff_t nb)
493 {
494 Lisp_Object pred = ms->predicate;
495
496 eassume (ms && ssa && ssb && na > 0 && nb > 0);
497 eassume (ssa + na == ssb);
498 needmem (ms, na);
499 memcpy (ms->a, ssa, na * word_size);
500 Lisp_Object *dest = ssa;
501 ssa = ms->a;
502
503 ms->reloc = (struct reloc){&ssa, &dest, &na, -1};
504
505 *dest++ = *ssb++;
506 --nb;
507 if (nb == 0)
508 goto Succeed;
509 if (na == 1)
510 goto CopyB;
511
512 ptrdiff_t min_gallop = ms->min_gallop;
513 for (;;)
514 {
515 ptrdiff_t acount = 0;
516
517 ptrdiff_t bcount = 0;
518
519 for (;;)
520 {
521 eassume (na > 1 && nb > 0);
522 if (inorder (pred, *ssb, *ssa))
523 {
524 *dest++ = *ssb++ ;
525 ++bcount;
526 acount = 0;
527 --nb;
528 if (nb == 0)
529 goto Succeed;
530 if (bcount >= min_gallop)
531 break;
532 }
533 else
534 {
535 *dest++ = *ssa++;
536 ++acount;
537 bcount = 0;
538 --na;
539 if (na == 1)
540 goto CopyB;
541 if (acount >= min_gallop)
542 break;
543 }
544 }
545
546
547
548
549
550 ++min_gallop;
551 do {
552 eassume (na > 1 && nb > 0);
553 min_gallop -= min_gallop > 1;
554 ms->min_gallop = min_gallop;
555 ptrdiff_t k = gallop_right (ms, ssb[0], ssa, na, 0);
556 acount = k;
557 if (k)
558 {
559 memcpy (dest, ssa, k * word_size);
560 dest += k;
561 ssa += k;
562 na -= k;
563 if (na == 1)
564 goto CopyB;
565
566
567 if (na == 0)
568 goto Succeed;
569 }
570 *dest++ = *ssb++ ;
571 --nb;
572 if (nb == 0)
573 goto Succeed;
574
575 k = gallop_left (ms, ssa[0], ssb, nb, 0);
576 bcount = k;
577 if (k)
578 {
579 memmove (dest, ssb, k * word_size);
580 dest += k;
581 ssb += k;
582 nb -= k;
583 if (nb == 0)
584 goto Succeed;
585 }
586 *dest++ = *ssa++;
587 --na;
588 if (na == 1)
589 goto CopyB;
590 } while (acount >= GALLOP_WIN_MIN || bcount >= GALLOP_WIN_MIN);
591 ++min_gallop;
592 ms->min_gallop = min_gallop;
593 }
594 Succeed:
595 ms->reloc = (struct reloc){NULL, NULL, NULL, 0};
596
597 if (na)
598 memcpy (dest, ssa, na * word_size);
599 return;
600 CopyB:
601 eassume (na == 1 && nb > 0);
602 ms->reloc = (struct reloc){NULL, NULL, NULL, 0};
603
604
605 memmove (dest, ssb, nb * word_size);
606 dest[nb] = ssa[0];
607 }
608
609
610
611
612
613
614
615 static void
616 merge_hi (merge_state *ms, Lisp_Object *ssa, ptrdiff_t na,
617 Lisp_Object *ssb, ptrdiff_t nb)
618 {
619 Lisp_Object pred = ms->predicate;
620
621 eassume (ms && ssa && ssb && na > 0 && nb > 0);
622 eassume (ssa + na == ssb);
623 needmem (ms, nb);
624 Lisp_Object *dest = ssb;
625 dest += nb - 1;
626 memcpy(ms->a, ssb, nb * word_size);
627 Lisp_Object *basea = ssa;
628 Lisp_Object *baseb = ms->a;
629 ssb = ms->a + nb - 1;
630 ssa += na - 1;
631
632 ms->reloc = (struct reloc){&baseb, &dest, &nb, 1};
633
634 *dest-- = *ssa--;
635 --na;
636 if (na == 0)
637 goto Succeed;
638 if (nb == 1)
639 goto CopyA;
640
641 ptrdiff_t min_gallop = ms->min_gallop;
642 for (;;) {
643 ptrdiff_t acount = 0;
644 ptrdiff_t bcount = 0;
645
646 for (;;) {
647 eassume (na > 0 && nb > 1);
648 if (inorder (pred, *ssb, *ssa))
649 {
650 *dest-- = *ssa--;
651 ++acount;
652 bcount = 0;
653 --na;
654 if (na == 0)
655 goto Succeed;
656 if (acount >= min_gallop)
657 break;
658 }
659 else
660 {
661 *dest-- = *ssb--;
662 ++bcount;
663 acount = 0;
664 --nb;
665 if (nb == 1)
666 goto CopyA;
667 if (bcount >= min_gallop)
668 break;
669 }
670 }
671
672
673
674
675 ++min_gallop;
676 do {
677 eassume (na > 0 && nb > 1);
678 min_gallop -= min_gallop > 1;
679 ms->min_gallop = min_gallop;
680 ptrdiff_t k = gallop_right (ms, ssb[0], basea, na, na - 1);
681 k = na - k;
682 acount = k;
683 if (k)
684 {
685 dest += -k;
686 ssa += -k;
687 memmove(dest + 1, ssa + 1, k * word_size);
688 na -= k;
689 if (na == 0)
690 goto Succeed;
691 }
692 *dest-- = *ssb--;
693 --nb;
694 if (nb == 1)
695 goto CopyA;
696
697 k = gallop_left (ms, ssa[0], baseb, nb, nb - 1);
698 k = nb - k;
699 bcount = k;
700 if (k)
701 {
702 dest += -k;
703 ssb += -k;
704 memcpy(dest + 1, ssb + 1, k * word_size);
705 nb -= k;
706 if (nb == 1)
707 goto CopyA;
708
709
710 if (nb == 0)
711 goto Succeed;
712 }
713 *dest-- = *ssa--;
714 --na;
715 if (na == 0)
716 goto Succeed;
717 } while (acount >= GALLOP_WIN_MIN || bcount >= GALLOP_WIN_MIN);
718 ++min_gallop;
719 ms->min_gallop = min_gallop;
720 }
721 Succeed:
722 ms->reloc = (struct reloc){NULL, NULL, NULL, 0};
723 if (nb)
724 memcpy (dest - nb + 1, baseb, nb * word_size);
725 return;
726 CopyA:
727 eassume (nb == 1 && na > 0);
728 ms->reloc = (struct reloc){NULL, NULL, NULL, 0};
729
730 memmove (dest + 1 - na, ssa + 1 - na, na * word_size);
731 dest += -na;
732 ssa += -na;
733 dest[0] = ssb[0];
734 }
735
736
737
738
739 static void
740 merge_at (merge_state *ms, const ptrdiff_t i)
741 {
742 eassume (ms != NULL);
743 eassume (ms->n >= 2);
744 eassume (i >= 0);
745 eassume (i == ms->n - 2 || i == ms->n - 3);
746
747 Lisp_Object *ssa = ms->pending[i].base;
748 ptrdiff_t na = ms->pending[i].len;
749 Lisp_Object *ssb = ms->pending[i + 1].base;
750 ptrdiff_t nb = ms->pending[i + 1].len;
751 eassume (na > 0 && nb > 0);
752 eassume (ssa + na == ssb);
753
754
755
756
757 ms->pending[i].len = na + nb;
758 if (i == ms->n - 3)
759 ms->pending[i + 1] = ms->pending[i + 2];
760 --ms->n;
761
762
763
764 ptrdiff_t k = gallop_right (ms, *ssb, ssa, na, 0);
765 eassume (k >= 0);
766 ssa += k;
767 na -= k;
768 if (na == 0)
769 return;
770
771
772
773 nb = gallop_left (ms, ssa[na - 1], ssb, nb, nb - 1);
774 if (nb == 0)
775 return;
776 eassume (nb > 0);
777
778
779 if (na <= nb)
780 merge_lo (ms, ssa, na, ssb, nb);
781 else
782 merge_hi (ms, ssa, na, ssb, nb);
783 }
784
785
786
787
788
789
790 static int
791 powerloop (const ptrdiff_t s1, const ptrdiff_t n1, const ptrdiff_t n2,
792 const ptrdiff_t n)
793 {
794 eassume (s1 >= 0);
795 eassume (n1 > 0 && n2 > 0);
796 eassume (s1 + n1 + n2 <= n);
797
798
799
800
801
802
803
804
805 ptrdiff_t a = 2 * s1 + n1;
806 ptrdiff_t b = a + n1 + n2;
807 int result = 0;
808
809 for (;;)
810 {
811 ++result;
812 if (a >= n)
813 {
814 eassume (b >= a);
815 a -= n;
816 b -= n;
817 }
818 else if (b >= n)
819 {
820 break;
821 }
822 eassume (a < b && b < n);
823 a <<= 1;
824 b <<= 1;
825 }
826 return result;
827 }
828
829
830
831
832
833
834
835
836 static void
837 found_new_run (merge_state *ms, const ptrdiff_t n2)
838 {
839 eassume (ms != NULL);
840 if (ms->n)
841 {
842 eassume (ms->n > 0);
843 struct stretch *p = ms->pending;
844 ptrdiff_t s1 = p[ms->n - 1].base - ms->listbase;
845 ptrdiff_t n1 = p[ms->n - 1].len;
846 int power = powerloop (s1, n1, n2, ms->listlen);
847 while (ms->n > 1 && p[ms->n - 2].power > power)
848 {
849 merge_at (ms, ms->n - 2);
850 }
851 eassume (ms->n < 2 || p[ms->n - 2].power < power);
852 p[ms->n - 1].power = power;
853 }
854 }
855
856
857
858
859
860 static void
861 merge_force_collapse (merge_state *ms)
862 {
863 struct stretch *p = ms->pending;
864
865 eassume (ms != NULL);
866 while (ms->n > 1)
867 {
868 ptrdiff_t n = ms->n - 2;
869 if (n > 0 && p[n - 1].len < p[n + 1].len)
870 --n;
871 merge_at (ms, n);
872 }
873 }
874
875
876
877
878
879
880
881
882
883
884 static ptrdiff_t
885 merge_compute_minrun (ptrdiff_t n)
886 {
887 ptrdiff_t r = 0;
888
889
890 eassume (n >= 0);
891 while (n >= 64)
892 {
893 r |= n & 1;
894 n >>= 1;
895 }
896 return n + r;
897 }
898
899
900 static void
901 reverse_vector (Lisp_Object *s, const ptrdiff_t n)
902 {
903 for (ptrdiff_t i = 0; i < n >> 1; i++)
904 {
905 Lisp_Object tem = s[i];
906 s[i] = s[n - i - 1];
907 s[n - i - 1] = tem;
908 }
909 }
910
911
912
913
914 void
915 tim_sort (Lisp_Object predicate, Lisp_Object *seq, const ptrdiff_t length)
916 {
917 if (SYMBOLP (predicate))
918 {
919
920
921 Lisp_Object fun = XSYMBOL (predicate)->u.s.function;
922 if (SYMBOLP (fun))
923
924 fun = indirect_function (fun);
925
926 if (!NILP (fun) && !(CONSP (fun) && EQ (XCAR (fun), Qautoload)))
927 predicate = fun;
928 }
929
930 merge_state ms;
931 Lisp_Object *lo = seq;
932
933 merge_init (&ms, length, lo, predicate);
934
935
936
937 const ptrdiff_t minrun = merge_compute_minrun (length);
938 ptrdiff_t nremaining = length;
939 do {
940 bool descending;
941
942
943 ptrdiff_t n = count_run (&ms, lo, lo + nremaining, &descending);
944 if (descending)
945 reverse_vector (lo, n);
946
947 if (n < minrun)
948 {
949 const ptrdiff_t force = nremaining <= minrun ?
950 nremaining : minrun;
951 binarysort (&ms, lo, lo + force, lo + n);
952 n = force;
953 }
954 eassume (ms.n == 0 || ms.pending[ms.n - 1].base +
955 ms.pending[ms.n - 1].len == lo);
956 found_new_run (&ms, n);
957
958 eassume (ms.n < MAX_MERGE_PENDING);
959 ms.pending[ms.n].base = lo;
960 ms.pending[ms.n].len = n;
961 ++ms.n;
962
963 lo += n;
964 nremaining -= n;
965 } while (nremaining);
966
967 merge_force_collapse (&ms);
968 eassume (ms.n == 1);
969 eassume (ms.pending[0].len == length);
970 lo = ms.pending[0].base;
971
972 if (ms.a != ms.temparray)
973 unbind_to (ms.count, Qnil);
974 }