GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
oct-sort.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2003-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24// Code stolen in large part from Python's, listobject.c, which itself had
25// no license header. However, thanks to Tim Peters for the parts of the
26// code I ripped-off.
27//
28// As required in the Python license the short description of the changes
29// made are
30//
31// * convert the sorting code in listobject.cc into a generic class,
32// replacing PyObject* with the type of the class T.
33//
34// * replaced usages of malloc, free, memcpy and memmove by standard C++
35// new [], delete [] and std::copy and std::copy_backward. Note that replacing
36// memmove by std::copy is possible if the destination starts before the source.
37// If not, std::copy_backward needs to be used.
38//
39// * templatize comparison operator in most methods, provide possible dispatch
40//
41// * duplicate methods to avoid by-the-way indexed sorting
42//
43// * add methods for verifying sortedness of array
44//
45// * row sorting via breadth-first tree subsorting
46//
47// * binary lookup and sequential binary lookup optimized for dense downsampling.
48//
49// * NOTE: the memory management routines rely on the fact that delete [] silently
50// ignores null pointers. Don't gripe about the missing checks - they're there.
51//
52//
53// The Python license is
54//
55// PSF LICENSE AGREEMENT FOR PYTHON 2.3
56// --------------------------------------
57//
58// 1. This LICENSE AGREEMENT is between the Python Software Foundation
59// ("PSF"), and the Individual or Organization ("Licensee") accessing and
60// otherwise using Python 2.3 software in source or binary form and its
61// associated documentation.
62//
63// 2. Subject to the terms and conditions of this License Agreement, PSF
64// hereby grants Licensee a nonexclusive, royalty-free, world-wide
65// license to reproduce, analyze, test, perform and/or display publicly,
66// prepare derivative works, distribute, and otherwise use Python 2.3
67// alone or in any derivative version, provided, however, that PSF's
68// License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
69// 2001, 2002, 2003 Python Software Foundation; All Rights Reserved" are
70// retained in Python 2.3 alone or in any derivative version prepared by
71// Licensee.
72//
73// 3. In the event Licensee prepares a derivative work that is based on
74// or incorporates Python 2.3 or any part thereof, and wants to make
75// the derivative work available to others as provided herein, then
76// Licensee hereby agrees to include in any such work a brief summary of
77// the changes made to Python 2.3.
78//
79// 4. PSF is making Python 2.3 available to Licensee on an "AS IS"
80// basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
81// IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
82// DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
83// FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT
84// INFRINGE ANY THIRD PARTY RIGHTS.
85//
86// 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
87// 2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
88// A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3,
89// OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
90//
91// 6. This License Agreement will automatically terminate upon a material
92// breach of its terms and conditions.
93//
94// 7. Nothing in this License Agreement shall be deemed to create any
95// relationship of agency, partnership, or joint venture between PSF and
96// Licensee. This License Agreement does not grant permission to use PSF
97// trademarks or trade name in a trademark sense to endorse or promote
98// products or services of Licensee, or any third party.
99//
100// 8. By copying, installing or otherwise using Python 2.3, Licensee
101// agrees to be bound by the terms and conditions of this License
102// Agreement.
103//
104////////////////////////////////////////////////////////////////////////
105
106// This file should not include config.h. It is only included in other
107// C++ source files that should have included config.h before including
108// this file.
109
110#include <algorithm>
111#include <cstring>
112#include <stack>
113
114#include "lo-error.h"
115#include "lo-mappers.h"
116#include "quit.h"
117#include "oct-sort.h"
118#include "oct-locbuf.h"
119
120template <typename T>
122 m_compare (ascending_compare), m_ms (nullptr)
123{ }
124
125template <typename T>
127 : m_compare (comp), m_ms (nullptr)
128{ }
129
130template <typename T>
132{
133 delete m_ms;
134}
135
136template <typename T>
137void
139{
140 if (mode == ASCENDING)
141 m_compare = ascending_compare;
142 else if (mode == DESCENDING)
143 m_compare = descending_compare;
144 else
145 m_compare = compare_fcn_type ();
146}
147
148template <typename T>
149template <typename Comp>
150void
152 octave_idx_type start, Comp comp)
153{
154 if (start == 0)
155 ++start;
156
157 for (; start < nel; ++start)
158 {
159 /* set l to where *start belongs */
160 octave_idx_type l = 0;
161 octave_idx_type r = start;
162 T pivot = data[start];
163 /* Invariants:
164 * pivot >= all in [lo, l).
165 * pivot < all in [r, start).
166 * The second is vacuously true at the start.
167 */
168 do
169 {
170 octave_idx_type p = l + ((r - l) >> 1);
171 if (comp (pivot, data[p]))
172 r = p;
173 else
174 l = p+1;
175 }
176 while (l < r);
177 /* The invariants still hold, so pivot >= all in [lo, l) and
178 pivot < all in [l, start), so pivot belongs at l. Note
179 that if there are elements equal to pivot, l points to the
180 first slot after them -- that's why this sort is stable.
181 Slide over to make room.
182 Caution: using memmove is much slower under MSVC 5;
183 we're not usually moving many slots. */
184 // NOTE: using swap and going upwards appears to be faster.
185 for (octave_idx_type p = l; p < start; p++)
186 std::swap (pivot, data[p]);
187 data[start] = pivot;
188 }
189
190 return;
191}
192
193template <typename T>
194template <typename Comp>
195void
197 octave_idx_type start, Comp comp)
198{
199 if (start == 0)
200 ++start;
201
202 for (; start < nel; ++start)
203 {
204 /* set l to where *start belongs */
205 octave_idx_type l = 0;
206 octave_idx_type r = start;
207 T pivot = data[start];
208 /* Invariants:
209 * pivot >= all in [lo, l).
210 * pivot < all in [r, start).
211 * The second is vacuously true at the start.
212 */
213 do
214 {
215 octave_idx_type p = l + ((r - l) >> 1);
216 if (comp (pivot, data[p]))
217 r = p;
218 else
219 l = p+1;
220 }
221 while (l < r);
222 /* The invariants still hold, so pivot >= all in [lo, l) and
223 pivot < all in [l, start), so pivot belongs at l. Note
224 that if there are elements equal to pivot, l points to the
225 first slot after them -- that's why this sort is stable.
226 Slide over to make room.
227 Caution: using memmove is much slower under MSVC 5;
228 we're not usually moving many slots. */
229 // NOTE: using swap and going upwards appears to be faster.
230 for (octave_idx_type p = l; p < start; p++)
231 std::swap (pivot, data[p]);
232 data[start] = pivot;
233 octave_idx_type ipivot = idx[start];
234 for (octave_idx_type p = l; p < start; p++)
235 std::swap (ipivot, idx[p]);
236 idx[start] = ipivot;
237 }
238
239 return;
240}
241
242/*
243Return the length of the run beginning at lo, in the slice [lo, hi). lo < hi
244is required on entry. "A run" is the longest ascending sequence, with
245
246 lo[0] <= lo[1] <= lo[2] <= ...
247
248or the longest descending sequence, with
249
250 lo[0] > lo[1] > lo[2] > ...
251
252DESCENDING is set to false in the former case, or to true in the latter.
253For its intended use in a stable mergesort, the strictness of the defn of
254"descending" is needed so that the caller can safely reverse a descending
255sequence without violating stability (strict > ensures there are no equal
256elements to get out of order).
257
258Returns -1 in case of error.
259*/
260template <typename T>
261template <typename Comp>
263octave_sort<T>::count_run (T *lo, octave_idx_type nel, bool& descending,
264 Comp comp)
265{
267 T *hi = lo + nel;
268
269 descending = false;
270 ++lo;
271 if (lo == hi)
272 return 1;
273
274 n = 2;
275
276 if (comp (*lo, *(lo-1)))
277 {
278 descending = true;
279 for (lo = lo+1; lo < hi; ++lo, ++n)
280 {
281 if (comp (*lo, *(lo-1)))
282 ;
283 else
284 break;
285 }
286 }
287 else
288 {
289 for (lo = lo+1; lo < hi; ++lo, ++n)
290 {
291 if (comp (*lo, *(lo-1)))
292 break;
293 }
294 }
295
296 return n;
297}
298
299/*
300Locate the proper position of key in a sorted vector; if the vector contains
301an element equal to key, return the position immediately to the left of
302the leftmost equal element. [gallop_right() does the same except returns
303the position to the right of the rightmost equal element (if any).]
304
305"a" is a sorted vector with n elements, starting at a[0]. n must be > 0.
306
307"hint" is an index at which to begin the search, 0 <= hint < n. The closer
308hint is to the final result, the faster this runs.
309
310The return value is the int k in 0..n such that
311
312 a[k-1] < key <= a[k]
313
314pretending that *(a-1) is minus infinity and a[n] is plus infinity. IOW,
315key belongs at index k; or, IOW, the first k elements of a should precede
316key, and the last n-k should follow key.
317
318Returns -1 on error. See listsort.txt for info on the method.
319*/
320template <typename T>
321template <typename Comp>
324 octave_idx_type hint,
325 Comp comp)
326{
327 octave_idx_type ofs;
328 octave_idx_type lastofs;
330
331 a += hint;
332 lastofs = 0;
333 ofs = 1;
334 if (comp (*a, key))
335 {
336 /* a[hint] < key -- gallop right, until
337 * a[hint + lastofs] < key <= a[hint + ofs]
338 */
339 const octave_idx_type maxofs = n - hint; /* &a[n-1] is highest */
340 while (ofs < maxofs)
341 {
342 if (comp (a[ofs], key))
343 {
344 lastofs = ofs;
345 ofs = (ofs << 1) + 1;
346 if (ofs <= 0) /* int overflow */
347 ofs = maxofs;
348 }
349 else /* key <= a[hint + ofs] */
350 break;
351 }
352 if (ofs > maxofs)
353 ofs = maxofs;
354 /* Translate back to offsets relative to &a[0]. */
355 lastofs += hint;
356 ofs += hint;
357 }
358 else
359 {
360 /* key <= a[hint] -- gallop left, until
361 * a[hint - ofs] < key <= a[hint - lastofs]
362 */
363 const octave_idx_type maxofs = hint + 1; /* &a[0] is lowest */
364 while (ofs < maxofs)
365 {
366 if (comp (*(a-ofs), key))
367 break;
368 /* key <= a[hint - ofs] */
369 lastofs = ofs;
370 ofs = (ofs << 1) + 1;
371 if (ofs <= 0) /* int overflow */
372 ofs = maxofs;
373 }
374 if (ofs > maxofs)
375 ofs = maxofs;
376 /* Translate back to positive offsets relative to &a[0]. */
377 k = lastofs;
378 lastofs = hint - ofs;
379 ofs = hint - k;
380 }
381 a -= hint;
382
383 /* Now a[lastofs] < key <= a[ofs], so key belongs somewhere to the
384 * right of lastofs but no farther right than ofs. Do a binary
385 * search, with invariant a[lastofs-1] < key <= a[ofs].
386 */
387 ++lastofs;
388 while (lastofs < ofs)
389 {
390 octave_idx_type m = lastofs + ((ofs - lastofs) >> 1);
391
392 if (comp (a[m], key))
393 lastofs = m+1; /* a[m] < key */
394 else
395 ofs = m; /* key <= a[m] */
396 }
397
398 return ofs;
399}
400
401/*
402Exactly like gallop_left(), except that if key already exists in a[0:n],
403finds the position immediately to the right of the rightmost equal value.
404
405The return value is the int k in 0..n such that
406
407 a[k-1] <= key < a[k]
408
409or -1 if error.
410
411The code duplication is massive, but this is enough different given that
412we're sticking to "<" comparisons that it's much harder to follow if
413written as one routine with yet another "left or right?" flag.
414*/
415template <typename T>
416template <typename Comp>
419 octave_idx_type hint,
420 Comp comp)
421{
422 octave_idx_type ofs;
423 octave_idx_type lastofs;
425
426 a += hint;
427 lastofs = 0;
428 ofs = 1;
429 if (comp (key, *a))
430 {
431 /* key < a[hint] -- gallop left, until
432 * a[hint - ofs] <= key < a[hint - lastofs]
433 */
434 const octave_idx_type maxofs = hint + 1; /* &a[0] is lowest */
435 while (ofs < maxofs)
436 {
437 if (comp (key, *(a-ofs)))
438 {
439 lastofs = ofs;
440 ofs = (ofs << 1) + 1;
441 if (ofs <= 0) /* int overflow */
442 ofs = maxofs;
443 }
444 else /* a[hint - ofs] <= key */
445 break;
446 }
447 if (ofs > maxofs)
448 ofs = maxofs;
449 /* Translate back to positive offsets relative to &a[0]. */
450 k = lastofs;
451 lastofs = hint - ofs;
452 ofs = hint - k;
453 }
454 else
455 {
456 /* a[hint] <= key -- gallop right, until
457 * a[hint + lastofs] <= key < a[hint + ofs]
458 */
459 const octave_idx_type maxofs = n - hint; /* &a[n-1] is highest */
460 while (ofs < maxofs)
461 {
462 if (comp (key, a[ofs]))
463 break;
464 /* a[hint + ofs] <= key */
465 lastofs = ofs;
466 ofs = (ofs << 1) + 1;
467 if (ofs <= 0) /* int overflow */
468 ofs = maxofs;
469 }
470 if (ofs > maxofs)
471 ofs = maxofs;
472 /* Translate back to offsets relative to &a[0]. */
473 lastofs += hint;
474 ofs += hint;
475 }
476 a -= hint;
477
478 /* Now a[lastofs] <= key < a[ofs], so key belongs somewhere to the
479 * right of lastofs but no farther right than ofs. Do a binary
480 * search, with invariant a[lastofs-1] <= key < a[ofs].
481 */
482 ++lastofs;
483 while (lastofs < ofs)
484 {
485 octave_idx_type m = lastofs + ((ofs - lastofs) >> 1);
486
487 if (comp (key, a[m]))
488 ofs = m; /* key < a[m] */
489 else
490 lastofs = m+1; /* a[m] <= key */
491 }
492
493 return ofs;
494}
495
496static inline octave_idx_type
497roundupsize (std::size_t n)
498{
499 unsigned int nbits = 3;
500 std::size_t n2 = n >> 8;
501
502 /* Round up:
503 * If n < 256, to a multiple of 8.
504 * If n < 2048, to a multiple of 64.
505 * If n < 16384, to a multiple of 512.
506 * If n < 131072, to a multiple of 4096.
507 * If n < 1048576, to a multiple of 32768.
508 * If n < 8388608, to a multiple of 262144.
509 * If n < 67108864, to a multiple of 2097152.
510 * If n < 536870912, to a multiple of 16777216.
511 * ...
512 * If n < 2**(5+3*i), to a multiple of 2**(3*i).
513 *
514 * This over-allocates proportional to the list size, making room
515 * for additional growth. The over-allocation is mild, but is
516 * enough to give linear-time amortized behavior over a long
517 * sequence of appends() in the presence of a poorly-performing
518 * system realloc() (which is a reality, e.g., across all flavors
519 * of Windows, with Win9x behavior being particularly bad -- and
520 * we've still got address space fragmentation problems on Win9x
521 * even with this scheme, although it requires much longer lists to
522 * provoke them than it used to).
523 */
524 while (n2)
525 {
526 n2 >>= 3;
527 nbits += 3;
528 }
529
530 std::size_t new_size = ((n >> nbits) + 1) << nbits;
531
532 if (new_size == 0
533 || new_size
534 > static_cast<std::size_t> (std::numeric_limits<octave_idx_type>::max ()))
535 (*current_liboctave_error_handler)
536 ("unable to allocate sufficient memory for sort");
537
538 return static_cast<octave_idx_type> (new_size);
539}
540
541/* Ensure enough temp memory for 'need' array slots is available.
542 * Returns 0 on success and -1 if the memory can't be gotten.
543 */
544template <typename T>
545void
547{
548 if (need <= m_alloced)
549 return;
550
551 need = roundupsize (need);
552 /* Don't realloc! That can cost cycles to copy the old data, but
553 * we don't care what's in the block.
554 */
555 delete [] m_a;
556 delete [] m_ia; // Must do this or fool possible next getmemi.
557 m_a = new T [need];
558 m_alloced = need;
559
560}
561
562template <typename T>
563void
565{
566 if (m_ia && need <= m_alloced)
567 return;
568
569 need = roundupsize (need);
570 /* Don't realloc! That can cost cycles to copy the old data, but
571 * we don't care what's in the block.
572 */
573 delete [] m_a;
574 delete [] m_ia;
575
576 m_a = new T [need];
577 m_ia = new octave_idx_type [need];
578 m_alloced = need;
579}
580
581/* Merge the na elements starting at pa with the nb elements starting at pb
582 * in a stable way, in-place. na and nb must be > 0, and pa + na == pb.
583 * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the
584 * merge, and should have na <= nb. See listsort.txt for more info.
585 * Return 0 if successful, -1 if error.
586 */
587template <typename T>
588template <typename Comp>
589int
591 T *pb, octave_idx_type nb,
592 Comp comp)
593{
595 T *dest;
596 int result = -1; /* guilty until proved innocent */
597 octave_idx_type min_gallop = m_ms->m_min_gallop;
598
599 m_ms->getmem (na);
600
601 std::copy (pa, pa + na, m_ms->m_a);
602 dest = pa;
603 pa = m_ms->m_a;
604
605 *dest++ = *pb++;
606 --nb;
607 if (nb == 0)
608 goto Succeed;
609 if (na == 1)
610 goto CopyB;
611
612 for (;;)
613 {
614 octave_idx_type acount = 0; /* # of times A won in a row */
615 octave_idx_type bcount = 0; /* # of times B won in a row */
616
617 /* Do the straightforward thing until (if ever) one run
618 * appears to win consistently.
619 */
620 for (;;)
621 {
622
623 // FIXME: these loops are candidates for further optimizations.
624 // Rather than testing everything in each cycle, it may be more
625 // efficient to do it in hunks.
626 if (comp (*pb, *pa))
627 {
628 *dest++ = *pb++;
629 ++bcount;
630 acount = 0;
631 --nb;
632 if (nb == 0)
633 goto Succeed;
634 if (bcount >= min_gallop)
635 break;
636 }
637 else
638 {
639 *dest++ = *pa++;
640 ++acount;
641 bcount = 0;
642 --na;
643 if (na == 1)
644 goto CopyB;
645 if (acount >= min_gallop)
646 break;
647 }
648 }
649
650 /* One run is winning so consistently that galloping may
651 * be a huge win. So try that, and continue galloping until
652 * (if ever) neither run appears to be winning consistently
653 * anymore.
654 */
655 ++min_gallop;
656 do
657 {
658 min_gallop -= (min_gallop > 1);
659 m_ms->m_min_gallop = min_gallop;
660 k = gallop_right (*pb, pa, na, 0, comp);
661 acount = k;
662 if (k)
663 {
664 if (k < 0)
665 goto Fail;
666 dest = std::copy (pa, pa + k, dest);
667 pa += k;
668 na -= k;
669 if (na == 1)
670 goto CopyB;
671 /* na==0 is impossible now if the comparison
672 * function is consistent, but we can't assume
673 * that it is.
674 */
675 if (na == 0)
676 goto Succeed;
677 }
678 *dest++ = *pb++;
679 --nb;
680 if (nb == 0)
681 goto Succeed;
682
683 k = gallop_left (*pa, pb, nb, 0, comp);
684 bcount = k;
685 if (k)
686 {
687 if (k < 0)
688 goto Fail;
689 dest = std::copy (pb, pb + k, dest);
690 pb += k;
691 nb -= k;
692 if (nb == 0)
693 goto Succeed;
694 }
695 *dest++ = *pa++;
696 --na;
697 if (na == 1)
698 goto CopyB;
699 }
700 while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP);
701
702 ++min_gallop; /* penalize it for leaving galloping mode */
703 m_ms->m_min_gallop = min_gallop;
704 }
705
706Succeed:
707 result = 0;
708
709Fail:
710 if (na)
711 std::copy (pa, pa + na, dest);
712 return result;
713
714CopyB:
715 /* The last element of pa belongs at the end of the merge. */
716 std::copy (pb, pb + nb, dest);
717 dest[nb] = *pa;
718
719 return 0;
720}
721
722template <typename T>
723template <typename Comp>
724int
726 T *pb, octave_idx_type *ipb, octave_idx_type nb,
727 Comp comp)
728{
730 T *dest;
731 octave_idx_type *idest;
732 int result = -1; /* guilty until proved innocent */
733 octave_idx_type min_gallop = m_ms->m_min_gallop;
734
735 m_ms->getmemi (na);
736
737 std::copy (pa, pa + na, m_ms->m_a);
738 std::copy (ipa, ipa + na, m_ms->m_ia);
739 dest = pa; idest = ipa;
740 pa = m_ms->m_a; ipa = m_ms->m_ia;
741
742 *dest++ = *pb++; *idest++ = *ipb++;
743 --nb;
744 if (nb == 0)
745 goto Succeed;
746 if (na == 1)
747 goto CopyB;
748
749 for (;;)
750 {
751 octave_idx_type acount = 0; /* # of times A won in a row */
752 octave_idx_type bcount = 0; /* # of times B won in a row */
753
754 /* Do the straightforward thing until (if ever) one run
755 * appears to win consistently.
756 */
757 for (;;)
758 {
759
760 if (comp (*pb, *pa))
761 {
762 *dest++ = *pb++; *idest++ = *ipb++;
763 ++bcount;
764 acount = 0;
765 --nb;
766 if (nb == 0)
767 goto Succeed;
768 if (bcount >= min_gallop)
769 break;
770 }
771 else
772 {
773 *dest++ = *pa++; *idest++ = *ipa++;
774 ++acount;
775 bcount = 0;
776 --na;
777 if (na == 1)
778 goto CopyB;
779 if (acount >= min_gallop)
780 break;
781 }
782 }
783
784 /* One run is winning so consistently that galloping may
785 * be a huge win. So try that, and continue galloping until
786 * (if ever) neither run appears to be winning consistently
787 * anymore.
788 */
789 ++min_gallop;
790 do
791 {
792 min_gallop -= (min_gallop > 1);
793 m_ms->m_min_gallop = min_gallop;
794 k = gallop_right (*pb, pa, na, 0, comp);
795 acount = k;
796 if (k)
797 {
798 if (k < 0)
799 goto Fail;
800 dest = std::copy (pa, pa + k, dest);
801 idest = std::copy (ipa, ipa + k, idest);
802 pa += k; ipa += k;
803 na -= k;
804 if (na == 1)
805 goto CopyB;
806 /* na==0 is impossible now if the comparison
807 * function is consistent, but we can't assume
808 * that it is.
809 */
810 if (na == 0)
811 goto Succeed;
812 }
813 *dest++ = *pb++; *idest++ = *ipb++;
814 --nb;
815 if (nb == 0)
816 goto Succeed;
817
818 k = gallop_left (*pa, pb, nb, 0, comp);
819 bcount = k;
820 if (k)
821 {
822 if (k < 0)
823 goto Fail;
824 dest = std::copy (pb, pb + k, dest);
825 idest = std::copy (ipb, ipb + k, idest);
826 pb += k; ipb += k;
827 nb -= k;
828 if (nb == 0)
829 goto Succeed;
830 }
831 *dest++ = *pa++; *idest++ = *ipa++;
832 --na;
833 if (na == 1)
834 goto CopyB;
835 }
836 while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP);
837
838 ++min_gallop; /* penalize it for leaving galloping mode */
839 m_ms->m_min_gallop = min_gallop;
840 }
841
842Succeed:
843 result = 0;
844
845Fail:
846 if (na)
847 {
848 std::copy (pa, pa + na, dest);
849 std::copy (ipa, ipa + na, idest);
850 }
851 return result;
852
853CopyB:
854 /* The last element of pa belongs at the end of the merge. */
855 std::copy (pb, pb + nb, dest);
856 std::copy (ipb, ipb + nb, idest);
857 dest[nb] = *pa;
858 idest[nb] = *ipa;
859
860 return 0;
861}
862
863/* Merge the na elements starting at pa with the nb elements starting at pb
864 * in a stable way, in-place. na and nb must be > 0, and pa + na == pb.
865 * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the
866 * merge, and should have na >= nb. See listsort.txt for more info.
867 * Return 0 if successful, -1 if error.
868 */
869template <typename T>
870template <typename Comp>
871int
873 T *pb, octave_idx_type nb,
874 Comp comp)
875{
877 T *dest;
878 int result = -1; /* guilty until proved innocent */
879 T *basea, *baseb;
880 octave_idx_type min_gallop = m_ms->m_min_gallop;
881
882 m_ms->getmem (nb);
883
884 dest = pb + nb - 1;
885 std::copy (pb, pb + nb, m_ms->m_a);
886 basea = pa;
887 baseb = m_ms->m_a;
888 pb = m_ms->m_a + nb - 1;
889 pa += na - 1;
890
891 *dest-- = *pa--;
892 --na;
893 if (na == 0)
894 goto Succeed;
895 if (nb == 1)
896 goto CopyA;
897
898 for (;;)
899 {
900 octave_idx_type acount = 0; /* # of times A won in a row */
901 octave_idx_type bcount = 0; /* # of times B won in a row */
902
903 /* Do the straightforward thing until (if ever) one run
904 * appears to win consistently.
905 */
906 for (;;)
907 {
908 if (comp (*pb, *pa))
909 {
910 *dest-- = *pa--;
911 ++acount;
912 bcount = 0;
913 --na;
914 if (na == 0)
915 goto Succeed;
916 if (acount >= min_gallop)
917 break;
918 }
919 else
920 {
921 *dest-- = *pb--;
922 ++bcount;
923 acount = 0;
924 --nb;
925 if (nb == 1)
926 goto CopyA;
927 if (bcount >= min_gallop)
928 break;
929 }
930 }
931
932 /* One run is winning so consistently that galloping may
933 * be a huge win. So try that, and continue galloping until
934 * (if ever) neither run appears to be winning consistently
935 * anymore.
936 */
937 ++min_gallop;
938 do
939 {
940 min_gallop -= (min_gallop > 1);
941 m_ms->m_min_gallop = min_gallop;
942 k = gallop_right (*pb, basea, na, na-1, comp);
943 if (k < 0)
944 goto Fail;
945 k = na - k;
946 acount = k;
947 if (k)
948 {
949 dest = std::copy_backward (pa+1 - k, pa+1, dest+1) - 1;
950 pa -= k;
951 na -= k;
952 if (na == 0)
953 goto Succeed;
954 }
955 *dest-- = *pb--;
956 --nb;
957 if (nb == 1)
958 goto CopyA;
959
960 k = gallop_left (*pa, baseb, nb, nb-1, comp);
961 if (k < 0)
962 goto Fail;
963 k = nb - k;
964 bcount = k;
965 if (k)
966 {
967 dest -= k;
968 pb -= k;
969 std::copy (pb+1, pb+1 + k, dest+1);
970 nb -= k;
971 if (nb == 1)
972 goto CopyA;
973 /* nb==0 is impossible now if the comparison
974 * function is consistent, but we can't assume
975 * that it is.
976 */
977 if (nb == 0)
978 goto Succeed;
979 }
980 *dest-- = *pa--;
981 --na;
982 if (na == 0)
983 goto Succeed;
984 }
985 while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP);
986 ++min_gallop; /* penalize it for leaving galloping mode */
987 m_ms->m_min_gallop = min_gallop;
988 }
989
990Succeed:
991 result = 0;
992
993Fail:
994 if (nb)
995 std::copy (baseb, baseb + nb, dest-(nb-1));
996 return result;
997
998CopyA:
999 /* The first element of pb belongs at the front of the merge. */
1000 dest = std::copy_backward (pa+1 - na, pa+1, dest+1) - 1;
1001 pa -= na;
1002 *dest = *pb;
1003
1004 return 0;
1005}
1006
1007template <typename T>
1008template <typename Comp>
1009int
1011 T *pb, octave_idx_type *ipb, octave_idx_type nb,
1012 Comp comp)
1013{
1015 T *dest;
1016 octave_idx_type *idest;
1017 int result = -1; /* guilty until proved innocent */
1018 T *basea, *baseb;
1019 octave_idx_type *ibaseb;
1020 octave_idx_type min_gallop = m_ms->m_min_gallop;
1021
1022 m_ms->getmemi (nb);
1023
1024 dest = pb + nb - 1;
1025 idest = ipb + nb - 1;
1026 std::copy (pb, pb + nb, m_ms->m_a);
1027 std::copy (ipb, ipb + nb, m_ms->m_ia);
1028 basea = pa;
1029 baseb = m_ms->m_a; ibaseb = m_ms->m_ia;
1030 pb = m_ms->m_a + nb - 1; ipb = m_ms->m_ia + nb - 1;
1031 pa += na - 1; ipa += na - 1;
1032
1033 *dest-- = *pa--; *idest-- = *ipa--;
1034 --na;
1035 if (na == 0)
1036 goto Succeed;
1037 if (nb == 1)
1038 goto CopyA;
1039
1040 for (;;)
1041 {
1042 octave_idx_type acount = 0; /* # of times A won in a row */
1043 octave_idx_type bcount = 0; /* # of times B won in a row */
1044
1045 /* Do the straightforward thing until (if ever) one run
1046 * appears to win consistently.
1047 */
1048 for (;;)
1049 {
1050 if (comp (*pb, *pa))
1051 {
1052 *dest-- = *pa--; *idest-- = *ipa--;
1053 ++acount;
1054 bcount = 0;
1055 --na;
1056 if (na == 0)
1057 goto Succeed;
1058 if (acount >= min_gallop)
1059 break;
1060 }
1061 else
1062 {
1063 *dest-- = *pb--; *idest-- = *ipb--;
1064 ++bcount;
1065 acount = 0;
1066 --nb;
1067 if (nb == 1)
1068 goto CopyA;
1069 if (bcount >= min_gallop)
1070 break;
1071 }
1072 }
1073
1074 /* One run is winning so consistently that galloping may
1075 * be a huge win. So try that, and continue galloping until
1076 * (if ever) neither run appears to be winning consistently
1077 * anymore.
1078 */
1079 ++min_gallop;
1080 do
1081 {
1082 min_gallop -= (min_gallop > 1);
1083 m_ms->m_min_gallop = min_gallop;
1084 k = gallop_right (*pb, basea, na, na-1, comp);
1085 if (k < 0)
1086 goto Fail;
1087 k = na - k;
1088 acount = k;
1089 if (k)
1090 {
1091 dest = std::copy_backward (pa+1 - k, pa+1, dest+1) - 1;
1092 idest = std::copy_backward (ipa+1 - k, ipa+1, idest+1) - 1;
1093 pa -= k; ipa -= k;
1094 na -= k;
1095 if (na == 0)
1096 goto Succeed;
1097 }
1098 *dest-- = *pb--; *idest-- = *ipb--;
1099 --nb;
1100 if (nb == 1)
1101 goto CopyA;
1102
1103 k = gallop_left (*pa, baseb, nb, nb-1, comp);
1104 if (k < 0)
1105 goto Fail;
1106 k = nb - k;
1107 bcount = k;
1108 if (k)
1109 {
1110 dest -= k; idest -= k;
1111 pb -= k; ipb -= k;
1112 std::copy (pb+1, pb+1 + k, dest+1);
1113 std::copy (ipb+1, ipb+1 + k, idest+1);
1114 nb -= k;
1115 if (nb == 1)
1116 goto CopyA;
1117 /* nb==0 is impossible now if the comparison
1118 * function is consistent, but we can't assume
1119 * that it is.
1120 */
1121 if (nb == 0)
1122 goto Succeed;
1123 }
1124 *dest-- = *pa--; *idest-- = *ipa--;
1125 --na;
1126 if (na == 0)
1127 goto Succeed;
1128 }
1129 while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP);
1130 ++min_gallop; /* penalize it for leaving galloping mode */
1131 m_ms->m_min_gallop = min_gallop;
1132 }
1133
1134Succeed:
1135 result = 0;
1136
1137Fail:
1138 if (nb)
1139 {
1140 std::copy (baseb, baseb + nb, dest-(nb-1));
1141 std::copy (ibaseb, ibaseb + nb, idest-(nb-1));
1142 }
1143 return result;
1144
1145CopyA:
1146 /* The first element of pb belongs at the front of the merge. */
1147 dest = std::copy_backward (pa+1 - na, pa+1, dest+1) - 1;
1148 idest = std::copy_backward (ipa+1 - na, ipa+1, idest+1) - 1;
1149 pa -= na; ipa -= na;
1150 *dest = *pb; *idest = *ipb;
1151
1152 return 0;
1153}
1154
1155/* Merge the two runs at stack indices i and i+1.
1156 * Returns 0 on success, -1 on error.
1157 */
1158template <typename T>
1159template <typename Comp>
1160int
1162 Comp comp)
1163{
1164 T *pa, *pb;
1165 octave_idx_type na, nb;
1167
1168 pa = data + m_ms->m_pending[i].m_base;
1169 na = m_ms->m_pending[i].m_len;
1170 pb = data + m_ms->m_pending[i+1].m_base;
1171 nb = m_ms->m_pending[i+1].m_len;
1172
1173 /* Record the length of the combined runs; if i is the 3rd-last
1174 * run now, also slide over the last run (which isn't involved
1175 * in this merge). The current run i+1 goes away in any case.
1176 */
1177 m_ms->m_pending[i].m_len = na + nb;
1178 if (i == m_ms->m_n - 3)
1179 m_ms->m_pending[i+1] = m_ms->m_pending[i+2];
1180 m_ms->m_n--;
1181
1182 /* Where does b start in a? Elements in a before that can be
1183 * ignored (already in place).
1184 */
1185 k = gallop_right (*pb, pa, na, 0, comp);
1186 if (k < 0)
1187 return -1;
1188 pa += k;
1189 na -= k;
1190 if (na == 0)
1191 return 0;
1192
1193 /* Where does a end in b? Elements in b after that can be
1194 * ignored (already in place).
1195 */
1196 nb = gallop_left (pa[na-1], pb, nb, nb-1, comp);
1197 if (nb <= 0)
1198 return nb;
1199
1200 /* Merge what remains of the runs, using a temp array with
1201 * min (na, nb) elements.
1202 */
1203 if (na <= nb)
1204 return merge_lo (pa, na, pb, nb, comp);
1205 else
1206 return merge_hi (pa, na, pb, nb, comp);
1207}
1208
1209template <typename T>
1210template <typename Comp>
1211int
1213 Comp comp)
1214{
1215 T *pa, *pb;
1216 octave_idx_type *ipa, *ipb;
1217 octave_idx_type na, nb;
1219
1220 pa = data + m_ms->m_pending[i].m_base;
1221 ipa = idx + m_ms->m_pending[i].m_base;
1222 na = m_ms->m_pending[i].m_len;
1223 pb = data + m_ms->m_pending[i+1].m_base;
1224 ipb = idx + m_ms->m_pending[i+1].m_base;
1225 nb = m_ms->m_pending[i+1].m_len;
1226
1227 /* Record the length of the combined runs; if i is the 3rd-last
1228 * run now, also slide over the last run (which isn't involved
1229 * in this merge). The current run i+1 goes away in any case.
1230 */
1231 m_ms->m_pending[i].m_len = na + nb;
1232 if (i == m_ms->m_n - 3)
1233 m_ms->m_pending[i+1] = m_ms->m_pending[i+2];
1234 m_ms->m_n--;
1235
1236 /* Where does b start in a? Elements in a before that can be
1237 * ignored (already in place).
1238 */
1239 k = gallop_right (*pb, pa, na, 0, comp);
1240 if (k < 0)
1241 return -1;
1242 pa += k; ipa += k;
1243 na -= k;
1244 if (na == 0)
1245 return 0;
1246
1247 /* Where does a end in b? Elements in b after that can be
1248 * ignored (already in place).
1249 */
1250 nb = gallop_left (pa[na-1], pb, nb, nb-1, comp);
1251 if (nb <= 0)
1252 return nb;
1253
1254 /* Merge what remains of the runs, using a temp array with
1255 * min (na, nb) elements.
1256 */
1257 if (na <= nb)
1258 return merge_lo (pa, ipa, na, pb, ipb, nb, comp);
1259 else
1260 return merge_hi (pa, ipa, na, pb, ipb, nb, comp);
1261}
1262
1263/* Examine the stack of runs waiting to be merged, merging adjacent runs
1264 * until the stack invariants are re-established:
1265 *
1266 * 1. len[-3] > len[-2] + len[-1]
1267 * 2. len[-2] > len[-1]
1268 *
1269 * See listsort.txt for more info.
1270 *
1271 * Returns 0 on success, -1 on error.
1272 */
1273template <typename T>
1274template <typename Comp>
1275int
1276octave_sort<T>::merge_collapse (T *data, Comp comp)
1277{
1278 struct s_slice *p = m_ms->m_pending;
1279
1280 while (m_ms->m_n > 1)
1281 {
1282 octave_idx_type n = m_ms->m_n - 2;
1283 if (n > 0 && p[n-1].m_len <= p[n].m_len + p[n+1].m_len)
1284 {
1285 if (p[n-1].m_len < p[n+1].m_len)
1286 --n;
1287 if (merge_at (n, data, comp) < 0)
1288 return -1;
1289 }
1290 else if (p[n].m_len <= p[n+1].m_len)
1291 {
1292 if (merge_at (n, data, comp) < 0)
1293 return -1;
1294 }
1295 else
1296 break;
1297 }
1298
1299 return 0;
1300}
1301
1302template <typename T>
1303template <typename Comp>
1304int
1305octave_sort<T>::merge_collapse (T *data, octave_idx_type *idx, Comp comp)
1306{
1307 struct s_slice *p = m_ms->m_pending;
1308
1309 while (m_ms->m_n > 1)
1310 {
1311 octave_idx_type n = m_ms->m_n - 2;
1312 if (n > 0 && p[n-1].m_len <= p[n].m_len + p[n+1].m_len)
1313 {
1314 if (p[n-1].m_len < p[n+1].m_len)
1315 --n;
1316 if (merge_at (n, data, idx, comp) < 0)
1317 return -1;
1318 }
1319 else if (p[n].m_len <= p[n+1].m_len)
1320 {
1321 if (merge_at (n, data, idx, comp) < 0)
1322 return -1;
1323 }
1324 else
1325 break;
1326 }
1327
1328 return 0;
1329}
1330
1331/* Regardless of invariants, merge all runs on the stack until only one
1332 * remains. This is used at the end of the mergesort.
1333 *
1334 * Returns 0 on success, -1 on error.
1335 */
1336template <typename T>
1337template <typename Comp>
1338int
1339octave_sort<T>::merge_force_collapse (T *data, Comp comp)
1340{
1341 struct s_slice *p = m_ms->m_pending;
1342
1343 while (m_ms->m_n > 1)
1344 {
1345 octave_idx_type n = m_ms->m_n - 2;
1346 if (n > 0 && p[n-1].m_len < p[n+1].m_len)
1347 --n;
1348 if (merge_at (n, data, comp) < 0)
1349 return -1;
1350 }
1351
1352 return 0;
1353}
1354
1355template <typename T>
1356template <typename Comp>
1357int
1359{
1360 struct s_slice *p = m_ms->m_pending;
1361
1362 while (m_ms->m_n > 1)
1363 {
1364 octave_idx_type n = m_ms->m_n - 2;
1365 if (n > 0 && p[n-1].m_len < p[n+1].m_len)
1366 --n;
1367 if (merge_at (n, data, idx, comp) < 0)
1368 return -1;
1369 }
1370
1371 return 0;
1372}
1373
1374/* Compute a good value for the minimum run length; natural runs shorter
1375 * than this are boosted artificially via binary insertion.
1376 *
1377 * If n < 64, return n (it's too small to bother with fancy stuff).
1378 * Else if n is an exact power of 2, return 32.
1379 * Else return an int k, 32 <= k <= 64, such that n/k is close to, but
1380 * strictly less than, an exact power of 2.
1381 *
1382 * See listsort.txt for more info.
1383 */
1384template <typename T>
1387{
1388 octave_idx_type r = 0; /* becomes 1 if any 1 bits are shifted off */
1389
1390 while (n >= 64)
1391 {
1392 r |= n & 1;
1393 n >>= 1;
1394 }
1395
1396 return n + r;
1397}
1398
1399template <typename T>
1400template <typename Comp>
1401void
1402octave_sort<T>::sort (T *data, octave_idx_type nel, Comp comp)
1403{
1404 /* Re-initialize the Mergestate as this might be the second time called */
1405 if (! m_ms) m_ms = new MergeState;
1406
1407 m_ms->reset ();
1408 m_ms->getmem (MERGESTATE_TEMP_SIZE);
1409
1410 if (nel > 1)
1411 {
1412 octave_idx_type nremaining = nel;
1413 octave_idx_type lo = 0;
1414
1415 /* March over the array once, left to right, finding natural runs,
1416 * and extending short natural runs to minrun elements.
1417 */
1418 octave_idx_type minrun = merge_compute_minrun (nremaining);
1419 do
1420 {
1421 bool descending;
1423
1424 /* Identify next run. */
1425 n = count_run (data + lo, nremaining, descending, comp);
1426 if (n < 0)
1427 return;
1428 if (descending)
1429 std::reverse (data + lo, data + lo + n);
1430 /* If short, extend to min (minrun, nremaining). */
1431 if (n < minrun)
1432 {
1433 const octave_idx_type force = (nremaining <= minrun ? nremaining
1434 : minrun);
1435 binarysort (data + lo, force, n, comp);
1436 n = force;
1437 }
1438 /* Push run onto m_pending-runs stack, and maybe merge. */
1439 liboctave_panic_unless (m_ms->m_n < MAX_MERGE_PENDING);
1440 m_ms->m_pending[m_ms->m_n].m_base = lo;
1441 m_ms->m_pending[m_ms->m_n].m_len = n;
1442 m_ms->m_n++;
1443 if (merge_collapse (data, comp) < 0)
1444 return;
1445 /* Advance to find next run. */
1446 lo += n;
1447 nremaining -= n;
1448 }
1449 while (nremaining);
1450
1451 merge_force_collapse (data, comp);
1452 }
1453}
1454
1455template <typename T>
1456template <typename Comp>
1457void
1459 Comp comp)
1460{
1461 /* Re-initialize the Mergestate as this might be the second time called */
1462 if (! m_ms) m_ms = new MergeState;
1463
1464 m_ms->reset ();
1465 m_ms->getmemi (MERGESTATE_TEMP_SIZE);
1466
1467 if (nel > 1)
1468 {
1469 octave_idx_type nremaining = nel;
1470 octave_idx_type lo = 0;
1471
1472 /* March over the array once, left to right, finding natural runs,
1473 * and extending short natural runs to minrun elements.
1474 */
1475 octave_idx_type minrun = merge_compute_minrun (nremaining);
1476 do
1477 {
1478 bool descending;
1480
1481 /* Identify next run. */
1482 n = count_run (data + lo, nremaining, descending, comp);
1483 if (n < 0)
1484 return;
1485 if (descending)
1486 {
1487 std::reverse (data + lo, data + lo + n);
1488 std::reverse (idx + lo, idx + lo + n);
1489 }
1490 /* If short, extend to min (minrun, nremaining). */
1491 if (n < minrun)
1492 {
1493 const octave_idx_type force = (nremaining <= minrun ? nremaining
1494 : minrun);
1495 binarysort (data + lo, idx + lo, force, n, comp);
1496 n = force;
1497 }
1498 /* Push run onto m_pending-runs stack, and maybe merge. */
1499 liboctave_panic_unless (m_ms->m_n < MAX_MERGE_PENDING);
1500 m_ms->m_pending[m_ms->m_n].m_base = lo;
1501 m_ms->m_pending[m_ms->m_n].m_len = n;
1502 m_ms->m_n++;
1503 if (merge_collapse (data, idx, comp) < 0)
1504 return;
1505 /* Advance to find next run. */
1506 lo += n;
1507 nremaining -= n;
1508 }
1509 while (nremaining);
1510
1511 merge_force_collapse (data, idx, comp);
1512 }
1513}
1514
1515template <typename T>
1517 typename ref_param<T>::type);
1518
1519template <typename T>
1520void
1522{
1523#if defined (INLINE_ASCENDING_SORT)
1524 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1525 sort (data, nel, std::less<T> ());
1526 else
1527#endif
1528#if defined (INLINE_DESCENDING_SORT)
1529 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1530 sort (data, nel, std::greater<T> ());
1531 else
1532#endif
1533 if (m_compare)
1534 sort (data, nel, m_compare);
1535}
1536
1537template <typename T>
1538void
1540{
1541#if defined (INLINE_ASCENDING_SORT)
1542 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1543 sort (data, idx, nel, std::less<T> ());
1544 else
1545#endif
1546#if defined (INLINE_DESCENDING_SORT)
1547 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1548 sort (data, idx, nel, std::greater<T> ());
1549 else
1550#endif
1551 if (m_compare)
1552 sort (data, idx, nel, m_compare);
1553}
1554
1555template <typename T>
1556template <typename Comp>
1557bool
1558octave_sort<T>::issorted (const T *data, octave_idx_type nel, Comp comp)
1559{
1560 const T *end = data + nel;
1561 if (data != end)
1562 {
1563 const T *next = data;
1564 while (++next != end)
1565 {
1566 if (comp (*next, *data))
1567 break;
1568 data = next;
1569 }
1570 data = next;
1571 }
1572
1573 return data == end;
1574}
1575
1576template <typename T>
1577bool
1579{
1580 bool retval = false;
1581#if defined (INLINE_ASCENDING_SORT)
1582 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1583 retval = issorted (data, nel, std::less<T> ());
1584 else
1585#endif
1586#if defined (INLINE_DESCENDING_SORT)
1587 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1588 retval = issorted (data, nel, std::greater<T> ());
1589 else
1590#endif
1591 if (m_compare)
1592 retval = issorted (data, nel, m_compare);
1593
1594 return retval;
1595}
1596
1597struct sortrows_run_t
1598{
1599public:
1600 sortrows_run_t (octave_idx_type c, octave_idx_type o, octave_idx_type n)
1601 : col (c), ofs (o), nel (n) { }
1602 //--------
1603 octave_idx_type col, ofs, nel;
1604};
1605
1606template <typename T>
1607template <typename Comp>
1608void
1609octave_sort<T>::sort_rows (const T *data, octave_idx_type *idx,
1611 Comp comp)
1612{
1613 OCTAVE_LOCAL_BUFFER (T, buf, rows);
1614 for (octave_idx_type i = 0; i < rows; i++)
1615 idx[i] = i;
1616
1617 if (cols == 0 || rows <= 1)
1618 return;
1619
1620 // This is a breadth-first traversal.
1621 typedef sortrows_run_t run_t;
1622 std::stack<run_t> runs;
1623
1624 runs.push (run_t (0, 0, rows));
1625
1626 while (! runs.empty ())
1627 {
1628 octave_idx_type col = runs.top ().col;
1629 octave_idx_type ofs = runs.top ().ofs;
1630 octave_idx_type nel = runs.top ().nel;
1631 runs.pop ();
1632 liboctave_panic_unless (nel > 1);
1633
1634 T *lbuf = buf + ofs;
1635 const T *ldata = data + rows*col;
1636 octave_idx_type *lidx = idx + ofs;
1637
1638 // Gather.
1639 for (octave_idx_type i = 0; i < nel; i++)
1640 lbuf[i] = ldata[lidx[i]];
1641
1642 // Sort.
1643 sort (lbuf, lidx, nel, comp);
1644
1645 // Identify constant runs and schedule subsorts.
1646 if (col < cols-1)
1647 {
1648 octave_idx_type lst = 0;
1649 for (octave_idx_type i = 0; i < nel; i++)
1650 {
1651 if (comp (lbuf[lst], lbuf[i]))
1652 {
1653 if (i > lst + 1)
1654 runs.push (run_t (col+1, ofs + lst, i - lst));
1655 lst = i;
1656 }
1657 }
1658 if (nel > lst + 1)
1659 runs.push (run_t (col+1, ofs + lst, nel - lst));
1660 }
1661 }
1662}
1663
1664template <typename T>
1665void
1668{
1669#if defined (INLINE_ASCENDING_SORT)
1670 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1671 sort_rows (data, idx, rows, cols, std::less<T> ());
1672 else
1673#endif
1674#if defined (INLINE_DESCENDING_SORT)
1675 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1676 sort_rows (data, idx, rows, cols, std::greater<T> ());
1677 else
1678#endif
1679 if (m_compare)
1680 sort_rows (data, idx, rows, cols, m_compare);
1681}
1682
1683template <typename T>
1684template <typename Comp>
1685bool
1687 octave_idx_type cols, Comp comp)
1688{
1689 if (rows <= 1 || cols == 0)
1690 return true;
1691
1692 // This is a breadth-first traversal.
1693 const T *lastrow = data + rows*(cols - 1);
1694 typedef std::pair<const T *, octave_idx_type> run_t;
1695 std::stack<run_t> runs;
1696
1697 bool sorted = true;
1698 runs.push (run_t (data, rows));
1699 while (sorted && ! runs.empty ())
1700 {
1701 const T *lo = runs.top ().first;
1702 octave_idx_type n = runs.top ().second;
1703 runs.pop ();
1704 if (lo < lastrow)
1705 {
1706 // Not the final column.
1707 liboctave_panic_unless (n > 1);
1708 const T *hi = lo + n;
1709 const T *lst = lo;
1710 for (lo++; lo < hi; lo++)
1711 {
1712 if (comp (*lst, *lo))
1713 {
1714 if (lo > lst + 1)
1715 runs.push (run_t (lst + rows, lo - lst));
1716 lst = lo;
1717 }
1718 else if (comp (*lo, *lst))
1719 break;
1720
1721 }
1722 if (lo == hi)
1723 {
1724 if (lo > lst + 1)
1725 runs.push (run_t (lst + rows, lo - lst));
1726 }
1727 else
1728 {
1729 sorted = false;
1730 break;
1731 }
1732 }
1733 else
1734 // The final column - use fast code.
1735 sorted = issorted (lo, n, comp);
1736 }
1737
1738 return sorted;
1739}
1740
1741template <typename T>
1742bool
1744 octave_idx_type cols)
1745{
1746 bool retval = false;
1747#if defined (INLINE_ASCENDING_SORT)
1748 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1749 retval = is_sorted_rows (data, rows, cols, std::less<T> ());
1750 else
1751#endif
1752#if defined (INLINE_DESCENDING_SORT)
1753 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1754 retval = is_sorted_rows (data, rows, cols, std::greater<T> ());
1755 else
1756#endif
1757 if (m_compare)
1758 retval = is_sorted_rows (data, rows, cols, m_compare);
1759
1760 return retval;
1761}
1762
1763// The simple binary lookup.
1764
1765template <typename T>
1766template <typename Comp>
1768octave_sort<T>::lookup (const T *data, octave_idx_type nel,
1769 const T& value, Comp comp)
1770{
1771 octave_idx_type lo = 0;
1772 octave_idx_type hi = nel;
1773
1774 while (lo < hi)
1775 {
1776 octave_idx_type mid = lo + ((hi-lo) >> 1);
1777 if (comp (value, data[mid]))
1778 hi = mid;
1779 else
1780 lo = mid + 1;
1781 }
1782
1783 return lo;
1784}
1785
1786template <typename T>
1789 const T& value)
1790{
1791 octave_idx_type retval = 0;
1792#if defined (INLINE_ASCENDING_SORT)
1793 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1794 retval = lookup (data, nel, value, std::less<T> ());
1795 else
1796#endif
1797#if defined (INLINE_DESCENDING_SORT)
1798 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1799 retval = lookup (data, nel, value, std::greater<T> ());
1800 else
1801#endif
1802 if (m_compare)
1803 retval = lookup (data, nel, value, m_compare);
1804
1805 return retval;
1806}
1807
1808template <typename T>
1809template <typename Comp>
1810void
1811octave_sort<T>::lookup (const T *data, octave_idx_type nel,
1812 const T *values, octave_idx_type nvalues,
1813 octave_idx_type *idx, Comp comp)
1814{
1815 // Use a sequence of binary lookups.
1816 // FIXME: Can this be sped up generally? The sorted merge case is dealt with
1817 // elsewhere.
1818 for (octave_idx_type j = 0; j < nvalues; j++)
1819 idx[j] = lookup (data, nel, values[j], comp);
1820}
1821
1822template <typename T>
1823void
1825 const T *values, octave_idx_type nvalues,
1826 octave_idx_type *idx)
1827{
1828#if defined (INLINE_ASCENDING_SORT)
1829 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1830 lookup (data, nel, values, nvalues, idx, std::less<T> ());
1831 else
1832#endif
1833#if defined (INLINE_DESCENDING_SORT)
1834 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1835 lookup (data, nel, values, nvalues, idx, std::greater<T> ());
1836 else
1837#endif
1838 if (m_compare)
1839 lookup (data, nel, values, nvalues, idx, m_compare);
1840}
1841
1842template <typename T>
1843template <typename Comp>
1844void
1846 const T *values, octave_idx_type nvalues,
1847 octave_idx_type *idx, bool rev, Comp comp)
1848{
1849 if (rev)
1850 {
1851 octave_idx_type i = 0;
1852 octave_idx_type j = nvalues - 1;
1853
1854 if (nvalues > 0 && nel > 0)
1855 {
1856 while (true)
1857 {
1858 if (comp (values[j], data[i]))
1859 {
1860 idx[j] = i;
1861 if (--j < 0)
1862 break;
1863 }
1864 else if (++i == nel)
1865 break;
1866 }
1867 }
1868
1869 for (; j >= 0; j--)
1870 idx[j] = i;
1871 }
1872 else
1873 {
1874 octave_idx_type i = 0;
1875 octave_idx_type j = 0;
1876
1877 if (nvalues > 0 && nel > 0)
1878 {
1879 while (true)
1880 {
1881 if (comp (values[j], data[i]))
1882 {
1883 idx[j] = i;
1884 if (++j == nvalues)
1885 break;
1886 }
1887 else if (++i == nel)
1888 break;
1889 }
1890 }
1891
1892 for (; j != nvalues; j++)
1893 idx[j] = i;
1894 }
1895}
1896
1897template <typename T>
1898void
1900 const T *values, octave_idx_type nvalues,
1901 octave_idx_type *idx, bool rev)
1902{
1903#if defined (INLINE_ASCENDING_SORT)
1904 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1905 lookup_sorted (data, nel, values, nvalues, idx, rev, std::less<T> ());
1906 else
1907#endif
1908#if defined (INLINE_DESCENDING_SORT)
1909 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1910 lookup_sorted (data, nel, values, nvalues, idx, rev, std::greater<T> ());
1911 else
1912#endif
1913 if (m_compare)
1914 lookup_sorted (data, nel, values, nvalues, idx, rev, m_compare);
1915}
1916
1917template <typename T>
1918template <typename Comp>
1919void
1922 Comp comp)
1923{
1924 // Simply wrap the STL algorithms.
1925 // FIXME: this will fail if we attempt to inline <,> for Complex.
1926 if (up == lo+1)
1927 std::nth_element (data, data + lo, data + nel, comp);
1928 else if (lo == 0)
1929 std::partial_sort (data, data + up, data + nel, comp);
1930 else
1931 {
1932 std::nth_element (data, data + lo, data + nel, comp);
1933 if (up == lo + 2)
1934 {
1935 // Finding two subsequent elements.
1936 std::swap (data[lo+1],
1937 *std::min_element (data + lo + 1, data + nel, comp));
1938 }
1939 else
1940 std::partial_sort (data + lo + 1, data + up, data + nel, comp);
1941 }
1942}
1943
1944template <typename T>
1945void
1948{
1949 if (up < 0)
1950 up = lo + 1;
1951
1952#if defined (INLINE_ASCENDING_SORT)
1953 if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
1954 nth_element (data, nel, lo, up, std::less<T> ());
1955 else
1956#endif
1957#if defined (INLINE_DESCENDING_SORT)
1958 if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
1959 nth_element (data, nel, lo, up, std::greater<T> ());
1960 else
1961#endif
1962 if (m_compare)
1963 nth_element (data, nel, lo, up, m_compare);
1964}
1965
1966template <typename T>
1967bool
1969 typename ref_param<T>::type y)
1970{
1971 return x < y;
1972}
1973
1974template <typename T>
1975bool
1977 typename ref_param<T>::type y)
1978{
1979 return x > y;
1980}
octave_idx_type lookup(const T *x, octave_idx_type n, T y)
void set_compare(const compare_fcn_type &comp)
Definition oct-sort.h:115
void sort_rows(const T *data, octave_idx_type *idx, octave_idx_type rows, octave_idx_type cols)
Definition oct-sort.cc:1666
static bool descending_compare(typename ref_param< T >::type, typename ref_param< T >::type)
Definition oct-sort.cc:1976
bool issorted(const T *data, octave_idx_type nel)
Definition oct-sort.cc:1578
std::function< bool(typename ref_param< T >::type, typename ref_param< T >::type)> compare_fcn_type
Definition oct-sort.h:105
static bool ascending_compare(typename ref_param< T >::type, typename ref_param< T >::type)
Definition oct-sort.cc:1968
octave_idx_type lookup(const T *data, octave_idx_type nel, const T &value)
Definition oct-sort.cc:1788
void sort(T *data, octave_idx_type nel)
Definition oct-sort.cc:1521
void nth_element(T *data, octave_idx_type nel, octave_idx_type lo, octave_idx_type up=-1)
Definition oct-sort.cc:1946
bool is_sorted_rows(const T *data, octave_idx_type rows, octave_idx_type cols)
Definition oct-sort.cc:1743
void lookup_sorted(const T *data, octave_idx_type nel, const T *values, octave_idx_type nvalues, octave_idx_type *idx, bool rev=false)
Definition oct-sort.cc:1899
if_then_else< is_class_type< T >::no, T, Tconst & >::result type
Definition lo-traits.h:121
#define liboctave_panic_unless(cond)
Definition lo-error.h:102
F77_RET_T const F77_DBLE * x
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition oct-locbuf.h:44
bool(*)(typename ref_param< T >::type, typename ref_param< T >::type) compare_fcn_ptr
Definition oct-sort.cc:1517
sortmode
Definition oct-sort.h:97
@ ASCENDING
Definition oct-sort.h:97
@ DESCENDING
Definition oct-sort.h:97