1/*************** CSort C Program Source Code File (.CPP) ***************/
2/* PROGRAM NAME: CSORT */
3/* ------------- */
4/* Version 2.2 */
5/* */
6/* COPYRIGHT: */
7/* ---------- */
8/* (C) Copyright to the author Olivier Bertrand 1995-2016 */
9/* */
10/* WHAT THIS PROGRAM DOES: */
11/* ----------------------- */
12/* This program is the C++ sorting routines that use qsort/insert */
13/* algorithm and produces an offset/break table while sorting. */
14/* */
15/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
16/* -------------------------------------- */
17/* */
18/* REQUIRED FILES: */
19/* --------------- */
20/* csort.cpp - Source code */
21/* */
22/* REQUIRED LIBRARIES: */
23/* ------------------- */
24/* OS2DEF.LIB - OS2 libray definition subset. */
25/* */
26/* REQUIRED PROGRAMS: */
27/* ------------------ */
28/* Microsoft C++ Compiler */
29/* or GNU Compiler/Linker */
30/* or BORLAND 4.5 C++ compiler */
31/* */
32/* NOTE */
33/* ---- */
34/* These functions are not 64-bits ready. */
35/* */
36/***********************************************************************/
37
38/***********************************************************************/
39/* Include relevant MariaDB header file. */
40/***********************************************************************/
41#include "my_global.h"
42
43/***********************************************************************/
44/* Include application header files */
45/***********************************************************************/
46#include <stdlib.h> /* C standard library */
47#include <string.h> /* String manipulation declares */
48#include <stdio.h> /* Required for sprintf declare */
49#if defined(_DEBUG)
50#include <assert.h> /* Assertion routine declares */
51#endif
52
53/***********************************************************************/
54/* Include CSort class header file */
55/***********************************************************************/
56#include "global.h"
57#include "plgdbsem.h" /* For MBLOCK type definition */
58#include "csort.h" /* CSort class definition */
59#include "osutil.h"
60
61#if !defined(BIGSORT)
62#define BIGSORT 200000
63#endif // !BIGSORT
64
65/***********************************************************************/
66/* DB static external variables. */
67/***********************************************************************/
68extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
69
70/***********************************************************************/
71/* Initialize the CSORT static members. */
72/***********************************************************************/
73int CSORT::Limit = 0;
74double CSORT::Lg2 = log(2.0);
75size_t CSORT::Cpn[1000] = {0}; /* Precalculated cmpnum values */
76
77/***********************************************************************/
78/* CSORT constructor. */
79/***********************************************************************/
80CSORT::CSORT(bool cns, int th, int mth)
81 : Pex((int*&)Index.Memp), Pof((int*&)Offset.Memp)
82 {
83 G = NULL;
84 Dup =NULL;
85 Cons = cns;
86 Thresh = th;
87 Mthresh = mth;
88 Nitem = 0;
89 Index = Nmblk;
90 Offset = Nmblk;
91 Swix = NULL;
92 Savmax = 0;
93 Savcur = 0;
94 Savstep = NULL;
95 } // end of CSORT constructor
96
97/***********************************************************************/
98/* CSORT intialization. */
99/***********************************************************************/
100int CSORT::Qsort(PGLOBAL g, int nb)
101 {
102 int rc;
103
104#if defined(_DEBUG)
105 assert(Index.Size >= nb * sizeof(int));
106#endif
107
108 if (nb > BIGSORT) {
109 G = g;
110 Dup = (PDBUSER)g->Activityp->Aptr;
111
112 if (Dup->Proginfo) {
113 Savstep = Dup->Step;
114 Savmax = Dup->ProgMax;
115 Savcur = Dup->ProgCur;
116
117 // Evaluate the number of comparisons that we will do
118 Dup->ProgMax = Cmpnum(nb);
119 Dup->ProgCur = 0;
120 Dup->Step = (char*)PlugSubAlloc(g, NULL, 32);
121 sprintf((char*)Dup->Step, MSG(SORTING_VAL), nb);
122 } else
123 Dup = NULL;
124
125 } else
126 Dup = NULL;
127
128 Nitem = nb;
129
130 for (int n = 0; n < Nitem; n++)
131 Pex[n] = n;
132
133 rc = (Cons) ? Qsortc() : Qsortx();
134
135 if (Dup) {
136 // Restore any change in progress info settings
137// printf("Progcur=%u\n", Dup->ProgCur);
138
139 Dup->Step = Savstep;
140 Dup->ProgMax = Savmax;
141 Dup->ProgCur = Savcur;
142 } // endif Subcor
143
144 return rc;
145 } // end of QSort
146
147#if defined(DEBTRACE)
148/***********************************************************************/
149/* Debug routine to be used by sort for specific data (dummy as now) */
150/***********************************************************************/
151void CSORT::DebugSort(int ph, int n, int *base, int *mid, int *tmp)
152 {
153 htrc("phase=%d n=%d base=%p mid=%p tmp=%p\n",
154 ph, n, base, mid, tmp);
155 } // end of DebugSort
156#endif
157
158/***********************************************************************/
159/* Qsortx: Version adapted from qsortx.c by O.Bertrand */
160/* This version is specialy adapted for Index sorting, meaning that */
161/* the data is not moved, but the Index only is sorted. */
162/* Index array elements are any 4-byte word (a pointer or a int int */
163/* array index), they are not interpreted except by the user provided */
164/* comparison routine which must works accordingly. */
165/* In addition, this program takes care of data in which there is a */
166/* high rate of repetitions. */
167/* CAUTION: the sort algorithm used here is not conservative. Equal */
168/* values will be internally stored in unpredictable order. */
169/* The THRESHold below is the insertion sort threshold, and also the */
170/* threshold for continuing que quicksort partitioning. */
171/* The MTHREShold is where we stop finding a better median. */
172/* These two quantities should be adjusted dynamically depending upon */
173/* the repetition rate of the data. */
174/* Algorithm used: */
175/* First, set up some global parameters for Qstx to share. Then, */
176/* quicksort with Qstx(), and then a cleanup insertion sort ourselves. */
177/* Sound simple? It's not... */
178/***********************************************************************/
179int CSORT::Qsortx(void)
180 {
181 register int c;
182 register int lo, hi, min;
183 register int i, j, rc = 0;
184 // To do: rc should be checked for being used uninitialized
185 int *top;
186#ifdef DEBTRACE
187 int ncp;
188
189 num_comp = 0;
190#endif
191
192 /*********************************************************************/
193 /* Prepare the Offset array that will be updated during sorts. */
194 /*********************************************************************/
195 if (Pof)
196 for (Pof[Nitem] = Nitem, j = 0; j < Nitem; j++)
197 Pof[j] = 0;
198 else
199 j = Nitem + 1;
200
201 /*********************************************************************/
202 /* Sort on one or zero element is obvious. */
203 /*********************************************************************/
204 if (Nitem <= 1)
205 return Nitem;
206
207 /*********************************************************************/
208 /* Thresh seems to be good as (10 * n / rep). But for testing we */
209 /* set it directly as one parameter of the Xset function call. */
210 /* Note: this should be final as the rep parameter is no more used. */
211 /*********************************************************************/
212 top = Pex + Nitem;
213
214#ifdef DEBTRACE
215 htrc("Qsortx: nitem=%d thresh=%d mthresh=%d\n",
216 Nitem, Thresh, Mthresh);
217#endif
218
219 /*********************************************************************/
220 /* If applicable, do a rough preliminary quick sort. */
221 /*********************************************************************/
222 if (Nitem >= Thresh)
223 Qstx(Pex, top);
224
225#ifdef DEBTRACE
226 htrc(" after quick sort num_comp=%d\n", num_comp);
227 ncp = num_comp;
228 num_comp = 0;
229#ifdef DEBUG2
230 DebugSort((Pof) ? 1 : 4, Nitem, Pex, NULL, NULL);
231#endif
232#endif
233
234 if (Thresh > 2) {
235 if (Pof)
236 /*****************************************************************/
237 /* The preliminary search for the smallest element has been */
238 /* removed so with no sentinel in place, we must check for x */
239 /* going below the Pof pointer. For each remaining element */
240 /* group from [1] to [n-1], set hi to the index of the element */
241 /* AFTER which this one goes. Then, do the standard insertion */
242 /* sort shift on an integer at a time basis for each equal */
243 /* element group in the frob. */
244 /*****************************************************************/
245 for (min = hi = 0; min < Nitem; min = hi) {
246 if (Pof[hi]) {
247 hi += Pof[hi];
248 continue;
249 } // endif Pof
250
251 Pof[min] = 1;
252
253#ifdef DEBUG2
254 htrc("insert from min=%d\n", min);
255#endif
256
257 for (lo = hi; !Pof[++hi]; lo = hi) {
258 while (lo >= min && (rc = Qcompare(Pex + lo, Pex + hi)) > 0)
259 if (Pof[lo] > 0)
260 lo -= Pof[lo];
261 else
262 return -2;
263
264 if (++lo != hi) {
265 c = Pex[hi];
266
267 for (i = j = hi; i > 0; i = j)
268 if (Pof[i - 1] <= 0)
269 return -3;
270 else if ((j -= Pof[i - 1]) >= lo) {
271 Pex[i] = Pex[j];
272 Pof[j + 1] = Pof[i] = Pof[j];
273 } else
274 break;
275
276 Pex[i] = c;
277 } // endif lo
278
279 if (rc)
280 Pof[lo] = 1;
281 else {
282 i = lo - Pof[lo - 1];
283 Pof[lo] = ++Pof[i];
284 } // endelse
285
286#ifdef DEBUG2
287 htrc("rc=%d lo=%d hi=%d trx=%d\n", rc, lo, hi, Pof[lo]);
288#endif
289
290 } // endfor hi
291
292 } // endfor min
293
294 else
295 /*****************************************************************/
296 /* Call conservative insertion sort not using/setting offset. */
297 /*****************************************************************/
298 Istc(Pex, Pex + MY_MIN(Nitem, Thresh), top);
299
300 } // endif Thresh
301
302#ifdef DEBTRACE
303 htrc(" after insert sort num_comp=%d\n", num_comp);
304 num_comp += ncp;
305#endif
306
307 if (Pof)
308 /*******************************************************************/
309 /* Reduce the Offset array. */
310 /*******************************************************************/
311 for (i = j = 0; i <= Nitem; j++, i += c) {
312#ifdef DEBUG2
313 htrc(" trxp(%d)=%d trxp(%d)=%d c=%d\n",
314 i, Pof[i], j, Pof[j], c);
315#endif
316 if ((c = Pof[i]))
317 Pof[j] = i;
318 else
319 return -4;
320
321 } // endfor i
322
323 return (j - 1);
324 } // end of Qsortx
325
326/***********************************************************************/
327/* Qstx: Do a quicksort on index elements (just one int int). */
328/* First, find the median element, and put that one in the first place */
329/* as the discriminator. (This "median" is just the median of the */
330/* first, last and middle elements). (Using this median instead of */
331/* the first element is a big win). Then, the usual partitioning/ */
332/* swapping, followed by moving the discriminator into the right place.*/
333/* Element equal to the discriminator are placed against it, so the */
334/* mid (discriminator) block grows when equal elements exist. This is */
335/* a huge win in case of repartitions with few different elements. */
336/* The mid block being at its final position, its first and last */
337/* elements are marked in the offset list (used to make break list). */
338/* Then, figure out the sizes of the two partitions, do the smaller */
339/* one recursively and the larger one via a repeat of this code. */
340/* Stopping when there are less than THRESH elements in a partition */
341/* and cleaning up with an insertion sort (in our caller) is a huge */
342/* win(?). All data swaps are done in-line, which is space-losing but */
343/* time-saving. (And there are only three places where this is done). */
344/***********************************************************************/
345void CSORT::Qstx(int *base, int *max)
346 {
347 register int *i, *j, *jj, *mid, *him, c;
348 int *tmp;
349 int lo, hi, rc;
350 size_t zlo, zhi, cnm;
351
352 zlo = zhi = cnm = 0; // Avoid warning message
353
354 lo = (int)(max - base); // Number of elements as longs
355
356 if (Dup)
357 cnm = Cmpnum(lo);
358
359 do {
360 /*******************************************************************/
361 /* At the top here, lo is the number of integers of elements in */
362 /* the current partition. (Which should be max - base). */
363 /* Find the median of the first, last, and middle element and make */
364 /* that the middle element. Set j to largest of first and middle. */
365 /* If max is larger than that guy, then it's that guy, else */
366 /* compare max with loser of first and take larger. Things are */
367 /* set up to prefer the middle, then the first in case of ties. */
368 /* In addition, hi and rc are set to comparison results. So if hi */
369 /* is null, the two high values are equal and if rc is null, the */
370 /* two low values are equal. This was used to set which test will */
371 /* be made by LE and which one by LT (does not apply anymore). */
372 /*******************************************************************/
373 him = mid = i = base + (lo >> 1);
374 hi = rc = 0;
375
376#ifdef DEBTRACE
377 tmp = max - 1;
378 htrc("--> block base=%d size=%d\n", base - Pex, lo);
379 DebugSort(2, 0, base, mid, tmp);
380#endif
381
382 if (lo >= Mthresh) {
383 rc = Qcompare((jj = base), i);
384 j = (rc > 0) ? jj : i;
385 hi = Qcompare(j, (tmp = max - 1));
386
387 if (hi > 0 && rc) {
388 j = (j == jj) ? i : jj; // switch to first loser
389
390 if ((rc = Qcompare(j, tmp)) < 0)
391 j = tmp;
392
393 } // endif
394
395 if (j != i) {
396 c = *i;
397 *i = *j;
398 *j = c;
399 } // endif j
400
401 } else if (lo == 2) {
402 /*****************************************************************/
403 /* Small group. Do special quicker processing. */
404 /*****************************************************************/
405 if ((rc = Qcompare(base, (him = base + 1))) > 0)
406 c = *base, *base = *him, *him = c;
407
408 if (Pof)
409 Pof[base - Pex] = Pof[him - Pex] = (rc) ? 1 : 2;
410
411 break;
412 } // endif lo
413
414#ifdef DEBTRACE
415 DebugSort(3, hi, NULL, mid, &rc);
416#endif
417
418 /*******************************************************************/
419 /* Semi-standard quicksort partitioning/swapping. Added here is */
420 /* a test on equality. All values equal to the mid element are */
421 /* placed under or over it. Mid block can be also moved when it */
422 /* is necessary because the other partition is full. At the end */
423 /* of the for loop the mid block is definitely positionned. */
424 /*******************************************************************/
425 for (i = base, j = max - 1; ;) {
426 CONT:
427 while (i < mid)
428 if ((rc = Qcompare(i, mid)) < 0)
429 i++;
430 else if (!rc) {
431 c = *i;
432 *i = *(--mid);
433 *mid = c;
434 } else
435 break;
436
437 while (j > him)
438 if ((rc = Qcompare(him, j)) < 0)
439 j--;
440 else if (!rc) {
441 c = *j;
442 *j = *(++him);
443 *him = c;
444 } else if (i == mid) { // Triple move:
445 c = *j; // j goes under mid block
446 *j = *(++him); // val over mid block -> j
447 *him = *mid++; // and mid block goes one
448 *i++ = c; // position higher.
449 } else { // i <-> j
450 c = *i;
451 *i++ = *j;
452 *j-- = c;
453 goto CONT;
454 } // endif's
455
456 if (i == mid)
457 break;
458 else { // Triple move:
459 c = *i; // i goes over mid block
460 *i = *(--mid); // val under mid block -> i
461 *mid = *him--; // and mid block goes one
462 *j-- = c; // position lower.
463 } // endelse
464
465 } // endfor i
466
467 /*******************************************************************/
468 /* The mid block being placed at its final position we can now set */
469 /* the offset array values indicating break point and block size. */
470 /*******************************************************************/
471 j = mid;
472 i = him + 1;
473
474 if (Pof)
475 Pof[him - Pex] = Pof[mid - Pex] = (int)(i - j);
476
477 /*******************************************************************/
478 /* Look at sizes of the two partitions, do the smaller one first */
479 /* by recursion, then do the larger one by making sure lo is its */
480 /* size, base and max are update correctly, and branching back. */
481 /* But only repeat (recursively or by branching) if the partition */
482 /* is of at least size THRESH. */
483 /*******************************************************************/
484 lo = (int)(j - base);
485 hi = (int)(max - i);
486
487 if (Dup) { // Update progress information
488 zlo = Cmpnum(lo);
489 zhi = Cmpnum(hi);
490 Dup->ProgCur += cnm - (zlo + zhi);
491 } // endif Dup
492
493#ifdef DEBTRACE
494 htrc(" done lo=%d sep=%d hi=%d\n", lo, i - j, hi);
495#endif
496
497 if (lo <= hi) {
498 if (lo >= Thresh)
499 Qstx(base, j);
500 else if (lo == 1 && Pof)
501 Pof[base - Pex] = 1;
502
503 base = i;
504 lo = hi;
505 cnm = zhi;
506 } else {
507 if (hi >= Thresh)
508 Qstx(i, max);
509 else if (hi == 1 && Pof)
510 Pof[i - Pex] = 1;
511
512 max = j;
513 cnm = zlo;
514 } // endif
515
516 if (lo == 1 && Pof)
517 Pof[base - Pex] = 1;
518
519 } while (lo >= Thresh); // enddo
520
521 } // end of Qstx
522
523/***********************************************************************/
524/* Qsortc.c: Version adapted from qsort.c by O.Bertrand */
525/* This version is specialy adapted for Index sorting, meaning that */
526/* the data is not moved, but the Index only is sorted. */
527/* Index array elements are any 4-byte word (a pointer or a int int */
528/* array index), they are not interpreted except by the user provided */
529/* comparison routine which must works accordingly. */
530/* In addition, this program takes care of data in which there is a */
531/* high rate of repetitions. */
532/* NOTE: the sort algorithm used here is conservative. Equal and */
533/* greater than values are internally stored in additional work area. */
534/* The THRESHold below is the insertion sort threshold, and also the */
535/* threshold for continuing que quicksort partitioning. */
536/* The MTHREShold is where we stop finding a better median. */
537/* These two quantities should be adjusted dynamically depending upon */
538/* the repetition rate of the data. */
539/* Algorithm used: */
540/* First, set up some global parameters for Qstc to share. Then, */
541/* quicksort with Qstc(), and then a cleanup insertion sort ourselves.*/
542/* Sound simple? It's not... */
543/***********************************************************************/
544int CSORT::Qsortc(void)
545 {
546 register int c;
547 register int lo, hi, min;
548 register int i, j, k, m, rc = 0;
549 // To do: rc should be checked for being used uninitialized
550 int *max;
551#ifdef DEBTRACE
552 int ncp;
553
554 num_comp = 0;
555#endif
556
557 /*********************************************************************/
558 /* Prepare the Offset array that will be updated during sorts. */
559 /*********************************************************************/
560 if (Pof)
561 for (Pof[Nitem] = Nitem, j = 0; j < Nitem; j++)
562 Pof[j] = 0;
563 else
564 j = Nitem + 1;
565
566 /*********************************************************************/
567 /* Sort on one or zero element is obvious. */
568 /*********************************************************************/
569 if (Nitem <= 1)
570 return Nitem;
571
572 /*********************************************************************/
573 /* Thresh seems to be good as (10 * n / rep). But for testing we */
574 /* set it directly as one parameter of the Xset function call. */
575 /* Note: this should be final as the rep parameter is no more used. */
576 /*********************************************************************/
577 max = Pex + Nitem;
578
579#ifdef DEBTRACE
580 htrc("Qsortc: nitem=%d thresh=%d mthresh=%d\n",
581 Nitem, Thresh, Mthresh);
582#endif
583
584 /*********************************************************************/
585 /* If applicable, do a rough preliminary conservative quick sort. */
586 /*********************************************************************/
587 if (Nitem >= Thresh) {
588 if (!(Swix = (int *)malloc(Nitem * sizeof(int))))
589 return -1;
590
591 Qstc(Pex, max);
592
593 free(Swix);
594 Swix = NULL;
595 } // endif n
596
597#ifdef DEBTRACE
598 htrc(" after quick sort num_comp=%d\n", num_comp);
599 ncp = num_comp;
600 num_comp = 0;
601#ifdef DEBUG2
602 DebugSort((Pof) ? 1 : 4, Nitem, Pex, NULL, NULL);
603#endif
604#endif
605
606 if (Thresh > 2) {
607 if (Pof)
608 /*****************************************************************/
609 /* The preliminary search for the smallest element has been */
610 /* removed so with no sentinel in place, we must check for x */
611 /* going below the Pof pointer. For each remaining element */
612 /* group from [1] to [n-1], set hi to the index of the element */
613 /* AFTER which this one goes. Then, do the standard insertion */
614 /* sort shift on an integer at a time basis for each equal */
615 /* element group in the frob. */
616 /*****************************************************************/
617 for (min = hi = 0; min < Nitem; min = hi) {
618 if (Pof[hi]) {
619 hi += Pof[hi];
620 continue;
621 } // endif
622
623 Pof[min] = 1;
624
625#ifdef DEBUG2
626 htrc("insert from min=%d\n", min);
627#endif
628
629 for (lo = hi; !Pof[++hi]; lo = hi) {
630 while (lo >= min && (rc = Qcompare(Pex + lo, Pex + hi)) > 0)
631 if (Pof[lo] > 0)
632 lo -= Pof[lo];
633 else
634 return -2;
635
636 if (++lo != hi) {
637 c = Pex[hi];
638
639 for (i = j = hi; i > 0; i = j)
640 if (Pof[i - 1] <= 0)
641 return -3;
642 else if ((j -= Pof[i - 1]) >= lo) {
643 for (k = m = i; --m >= j; k--) // Move intermediate
644 Pex[k] = Pex[m]; // for conservation.
645
646 Pof[j + 1] = Pof[i] = Pof[j];
647 } else
648 break;
649
650 Pex[i] = c;
651 } // endif
652
653 if (rc)
654 Pof[lo] = 1;
655 else {
656 i = lo - Pof[lo - 1];
657 Pof[lo] = ++Pof[i];
658 } // endelse
659
660#ifdef DEBUG2
661 htrc("rc=%d lo=%d hi=%d ofx=%d\n", rc, lo, hi, Pof[lo]);
662#endif
663
664 } // endfor hi
665
666 } // endfor min
667
668 else
669 /*****************************************************************/
670 /* Call conservative insertion sort not using/setting offset. */
671 /*****************************************************************/
672 Istc(Pex, Pex + MY_MIN(Nitem, Thresh), max);
673
674 } // endif Thresh
675
676#ifdef DEBTRACE
677 htrc(" after insert sort num_comp=%d\n", num_comp);
678 num_comp += ncp;
679#endif
680
681 if (Pof)
682 /*******************************************************************/
683 /* Reduce the Offset array. */
684 /*******************************************************************/
685 for (i = j = 0; i <= Nitem; j++, i += c) {
686#ifdef DEBUG2
687 htrc(" Pof(%d)=%d Pof(%d)=%d c=%d\n",
688 i, Pof[i], j, Pof[j], c);
689#endif
690 if ((c = Pof[i]))
691 Pof[j] = i;
692 else
693 return -4;
694
695 } // endfor i
696
697 return (j - 1);
698 } // end of Qsortc
699
700/***********************************************************************/
701/* Qstc: Do a quicksort on index elements (just one int int). */
702/* First, find the median element, and set it as the discriminator. */
703/* (This "median" is just the median of the first, last and middle */
704/* elements). (Using this median instead of the first element is a */
705/* big win). Then, the special partitioning/swapping, where elements */
706/* smaller than the discriminator are placed in the sorted block, */
707/* elements equal to the discriminator are placed backward from the */
708/* top of the work area and elements greater than *j (discriminator) */
709/* are placed in the work area from its bottom. Then the elements in */
710/* the work area are placed back in the sort area in natural order, */
711/* making the sort conservative. Non equal blocks shrink faster when */
712/* equal elements exist. This is a huge win in case of repartitions */
713/* with few different elements. The mid block being at its final */
714/* position, its first and last elements are marked in the offset */
715/* list (used to make break list). Then, figure out the sizes of the */
716/* two partitions, do the smaller one recursively and the larger one */
717/* via a repeat of this code. Stopping when there are less than */
718/* THRESH elements in a partition and cleaning up with an insertion */
719/* sort (in our caller) is a huge win (yet to be proved?). */
720/***********************************************************************/
721void CSORT::Qstc(int *base, int *max)
722 {
723 register int *i, *j, *jj, *lt, *eq, *gt, *mid;
724 int c = 0, lo, hi, rc;
725 size_t zlo, zhi, cnm;
726
727 zlo = zhi = cnm = 0; // Avoid warning message
728
729 lo = (int)(max - base); // Number of elements as longs
730
731 if (Dup)
732 cnm = Cmpnum(lo);
733
734 do {
735 /*******************************************************************/
736 /* At the top here, lo is the number of integers of elements in */
737 /* the current partition. (Which should be max - base). Find the */
738 /* median of the first, last, and middle element and make that */
739 /* the compare element. Set jj to smallest of middle and last. */
740 /* If base is smaller or equal than that guy, then it's that guy, */
741 /* else compare base with loser of first and take smaller. Things */
742 /* are set up to prefer the top, then the middle in case of ties. */
743 /*******************************************************************/
744 i = base + (lo >> 1);
745 jj = mid = max - 1;
746
747#ifdef DEBTRACE
748 htrc("--> block base=%d size=%d\n", base - Pex, lo);
749 DebugSort(2, 0, base, i, mid);
750#endif
751
752 if (lo >= Mthresh) {
753 jj = ((rc = Qcompare(i, mid)) < 0) ? i : mid;
754
755 if (rc && Qcompare(base, jj) > 0) {
756 jj = (jj == mid) ? i : mid; // switch to first loser
757
758 if (Qcompare(base, jj) < 0)
759 jj = base;
760
761 } // endif
762
763 if (jj != mid) {
764 /***************************************************************/
765 /* The compare element must be at the top of the block so it */
766 /* cannot be overwritten while making the partitioning. So */
767 /* save the last block value which will be compared later. */
768 /***************************************************************/
769 c = *mid;
770 *mid = *jj;
771 } // endif
772
773 } else if (lo == 2) {
774 /*****************************************************************/
775 /* Small group. Do special quicker processing. */
776 /*****************************************************************/
777 if ((rc = Qcompare(base, (i = base + 1))) > 0) {
778 c = *base;
779 *base = *i;
780 *i = c;
781 } // endif rc
782
783 if (Pof)
784 Pof[base - Pex] = Pof[i - Pex] = (rc) ? 1 : 2;
785
786 break;
787 } // endif lo
788
789#ifdef DEBTRACE
790 DebugSort(3, lo, NULL, jj, &rc);
791#endif
792
793 /*******************************************************************/
794 /* Non-standard quicksort partitioning using additional storage */
795 /* to store values less than, equal or greater than the middle */
796 /* element. This uses more memory but provides conservation of */
797 /* the equal elements order. */
798 /*******************************************************************/
799 lt = base;
800 eq = Swix + lo;
801 gt = Swix;
802
803 if (jj == mid) {
804 /*****************************************************************/
805 /* Compare element was last. No problem. */
806 /*****************************************************************/
807 for (i = base; i < max; i++)
808 if ((rc = Qcompare(i, mid)) < 0)
809 *lt++ = *i;
810 else if (rc > 0)
811 *gt++ = *i;
812 else
813 *--eq = *i;
814
815 } else {
816 /*****************************************************************/
817 /* Compare element was not last and was copied to top of block. */
818 /*****************************************************************/
819 for (i = base; i < mid; i++)
820 if ((rc = Qcompare(i, mid)) < 0)
821 *lt++ = *i;
822 else if (rc > 0)
823 *gt++ = *i;
824 else
825 *--eq = *i;
826
827 /*****************************************************************/
828 /* Restore saved last value and do the comparison from there. */
829 /*****************************************************************/
830 *--i = c;
831
832 if ((rc = Qcompare(i, mid)) < 0)
833 *lt++ = *i;
834 else if (rc > 0)
835 *gt++ = *i;
836 else
837 *--eq = *i;
838
839 } // endif
840
841 /*******************************************************************/
842 /* Now copy the equal and greater values back in the main array in */
843 /* the same order they have been placed in the work area. */
844 /*******************************************************************/
845 for (j = Swix + lo, i = lt; j > eq; )
846 *i++ = *--j;
847
848 for (j = Swix, jj = i; j < gt; )
849 *i++ = *j++;
850
851 /*******************************************************************/
852 /* The mid block being placed at its final position we can now set */
853 /* the offset array values indicating break point and block size. */
854 /*******************************************************************/
855 if (Pof)
856 Pof[lt - Pex] = Pof[(jj - 1) - Pex] = (int)(jj - lt);
857
858 /*******************************************************************/
859 /* Look at sizes of the two partitions, do the smaller one first */
860 /* by recursion, then do the larger one by making sure lo is its */
861 /* size, base and max are update correctly, and branching back. */
862 /* But only repeat (recursively or by branching) if the partition */
863 /* is of at least size THRESH. */
864 /*******************************************************************/
865 lo = (int)(lt - base);
866 hi = (int)(gt - Swix);
867
868 if (Dup) { // Update progress information
869 zlo = Cmpnum(lo);
870 zhi = Cmpnum(hi);
871 Dup->ProgCur += cnm - (zlo + zhi);
872 } // endif Dup
873
874#ifdef DEBTRACE
875 htrc(" done lo=%d hi=%d\n",
876 lo, /*Swix + lt - base - eq,*/ hi);
877#endif
878
879 if (lo <= hi) {
880 if (lo >= Thresh)
881 Qstc(base, lt);
882 else if (lo == 1 && Pof)
883 Pof[base - Pex] = 1;
884
885 base = jj;
886 lo = hi;
887 cnm = zhi;
888 } else {
889 if (hi >= Thresh)
890 Qstc(jj, max);
891 else if (hi == 1 && Pof)
892 Pof[jj - Pex] = 1;
893
894 max = lt;
895 cnm = zlo;
896 } // endif
897
898 if (lo == 1 && Pof)
899 Pof[base - Pex] = 1;
900
901 } while (lo >= Thresh); // enddo
902
903 } // end of Qstc
904
905/***********************************************************************/
906/* Conservative insertion sort not using/setting offset array. */
907/***********************************************************************/
908void CSORT::Istc(int *base, int *hi, int *max)
909 {
910 register int c = 0;
911 register int *lo;
912 register int *i, *j;
913
914 /*********************************************************************/
915 /* First put smallest element, which must be in the first THRESH, */
916 /* in the first position as a sentinel. This is done just by */
917 /* searching the 1st THRESH elements (or the 1st n if n < THRESH) */
918 /* finding the min, and shifting it into the first position. */
919 /*********************************************************************/
920 for (j = lo = base; ++lo < hi; )
921 if (Qcompare(j, lo) > 0)
922 j = lo;
923
924 if (j != base) { // shift j into place
925 c = *j;
926
927 for (i = j; --j >= base; i = j)
928 *i = *j;
929
930 *base = c;
931 } // endif j
932
933#ifdef DEBTRACE
934 htrc("sentinel %d in place, base=%p hi=%p max=%p\n",
935 c, base, hi, max);
936#endif
937
938 /*********************************************************************/
939 /* With our sentinel in place, we now run the following hyper- */
940 /* fast insertion sort. For each remaining element, lo, from [1] */
941 /* to [n-1], set hi to the index of the element AFTER which this */
942 /* one goes. Then, do the standard insertion sort shift for each */
943 /* element in the frob. */
944 /*********************************************************************/
945 for (lo = base; (hi = ++lo) < max;) {
946 while (Qcompare(--hi, lo) > 0) ;
947
948#ifdef DEBUG2
949 htrc("after while: hi(%p)=%d lo(%p)=%d\n",
950 hi, *hi, lo, *lo);
951#endif
952
953 if (++hi != lo) {
954 c = *lo;
955
956 for (i = j = lo; --j >= hi; i = j)
957 *i = *j;
958
959 *i = c;
960 } // endif hi
961
962 } // endfor lo
963
964 } // end of Istc
965
966/* -------------------------- End of CSort --------------------------- */
967