File indexing completed on 2024-04-28 04:36:21

0001 /*
0002  * C++ implementation of timsort
0003  *
0004  * ported from Python's and OpenJDK's:
0005  * - http://svn.python.org/projects/python/trunk/Objects/listobject.c
0006  * - http://cr.openjdk.java.net/~martin/webrevs/openjdk7/timsort/raw_files/new/src/share/classes/java/util/TimSort.java
0007  *
0008  * Copyright (c) 2011 Fuji, Goro (gfx) <gfuji@cpan.org>.
0009  * Copyright (c) 2019-2021 Morwenn.
0010  * Copyright (c) 2021 Igor Kushnir <igorkuo@gmail.com>.
0011  *
0012  * Permission is hereby granted, free of charge, to any person obtaining a copy
0013  * of this software and associated documentation files (the "Software"), to
0014  * deal in the Software without restriction, including without limitation the
0015  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
0016  * sell copies of the Software, and to permit persons to whom the Software is
0017  * furnished to do so, subject to the following conditions:
0018  *
0019  * The above copyright notice and this permission notice shall be included in
0020  * all copies or substantial portions of the Software.
0021  *
0022  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0023  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0024  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0025  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0026  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0027  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
0028  * IN THE SOFTWARE.
0029  */
0030 
0031 #ifndef GFX_TIMSORT_HPP
0032 #define GFX_TIMSORT_HPP
0033 
0034 #include <algorithm>
0035 #include <functional>
0036 #include <iterator>
0037 #include <utility>
0038 #include <vector>
0039 
0040 // Semantic versioning macros
0041 
0042 #define GFX_TIMSORT_VERSION_MAJOR 2
0043 #define GFX_TIMSORT_VERSION_MINOR 1
0044 #define GFX_TIMSORT_VERSION_PATCH 0
0045 
0046 // Diagnostic selection macros
0047 
0048 #if defined(GFX_TIMSORT_ENABLE_ASSERT) || defined(GFX_TIMSORT_ENABLE_AUDIT)
0049 #   include <cassert>
0050 #endif
0051 
0052 #ifdef GFX_TIMSORT_ENABLE_ASSERT
0053 #   define GFX_TIMSORT_ASSERT(expr) assert(expr)
0054 #else
0055 #   define GFX_TIMSORT_ASSERT(expr) ((void)0)
0056 #endif
0057 
0058 #ifdef GFX_TIMSORT_ENABLE_AUDIT
0059 #   define GFX_TIMSORT_AUDIT(expr) assert(expr)
0060 #else
0061 #   define GFX_TIMSORT_AUDIT(expr) ((void)0)
0062 #endif
0063 
0064 #ifdef GFX_TIMSORT_ENABLE_LOG
0065 #   include <iostream>
0066 #   define GFX_TIMSORT_LOG(expr) (std::clog << "# " << __func__ << ": " << expr << std::endl)
0067 #else
0068 #   define GFX_TIMSORT_LOG(expr) ((void)0)
0069 #endif
0070 
0071 
0072 namespace gfx {
0073 
0074 // ---------------------------------------
0075 // Implementation details
0076 // ---------------------------------------
0077 
0078 namespace detail {
0079 
0080 // Equivalent to C++20 std::identity
0081 struct identity {
0082     template <typename T>
0083     constexpr T&& operator()(T&& value) const noexcept
0084     {
0085         return std::forward<T>(value);
0086     }
0087 };
0088 
0089 // Merge a predicate and a projection function
0090 template <typename Compare, typename Projection>
0091 struct projection_compare {
0092     projection_compare(Compare comp, Projection proj) : compare(comp), projection(proj) {
0093     }
0094 
0095     template <typename T, typename U>
0096     bool operator()(T &&lhs, U &&rhs) {
0097 #ifdef __cpp_lib_invoke
0098         return static_cast<bool>(std::invoke(compare,
0099             std::invoke(projection, std::forward<T>(lhs)),
0100             std::invoke(projection, std::forward<U>(rhs))
0101         ));
0102 #else
0103         return static_cast<bool>(compare(
0104             projection(std::forward<T>(lhs)),
0105             projection(std::forward<U>(rhs))
0106         ));
0107 #endif
0108     }
0109 
0110     Compare compare;
0111     Projection projection;
0112 };
0113 
0114 template <typename Iterator> struct run {
0115     typedef typename std::iterator_traits<Iterator>::difference_type diff_t;
0116 
0117     Iterator base;
0118     diff_t len;
0119 
0120     run(Iterator b, diff_t l) : base(b), len(l) {
0121     }
0122 };
0123 
0124 template <typename RandomAccessIterator, typename Compare> class TimSort {
0125     typedef RandomAccessIterator iter_t;
0126     typedef typename std::iterator_traits<iter_t>::value_type value_t;
0127     typedef typename std::iterator_traits<iter_t>::reference ref_t;
0128     typedef typename std::iterator_traits<iter_t>::difference_type diff_t;
0129 
0130     static const int MIN_MERGE = 32;
0131     static const int MIN_GALLOP = 7;
0132 
0133     int minGallop_; // default to MIN_GALLOP
0134 
0135     std::vector<value_t> tmp_; // temp storage for merges
0136     typedef typename std::vector<value_t>::iterator tmp_iter_t;
0137 
0138     std::vector<run<RandomAccessIterator> > pending_;
0139 
0140     static void binarySort(iter_t const lo, iter_t const hi, iter_t start, Compare compare) {
0141         GFX_TIMSORT_ASSERT(lo <= start);
0142         GFX_TIMSORT_ASSERT(start <= hi);
0143         if (start == lo) {
0144             ++start;
0145         }
0146         for (; start < hi; ++start) {
0147             GFX_TIMSORT_ASSERT(lo <= start);
0148             value_t pivot = std::move(*start);
0149 
0150             iter_t const pos = std::upper_bound(lo, start, pivot, compare);
0151             for (iter_t p = start; p > pos; --p) {
0152                 *p = std::move(*(p - 1));
0153             }
0154             *pos = std::move(pivot);
0155         }
0156     }
0157 
0158     static diff_t countRunAndMakeAscending(iter_t const lo, iter_t const hi, Compare compare) {
0159         GFX_TIMSORT_ASSERT(lo < hi);
0160 
0161         iter_t runHi = lo + 1;
0162         if (runHi == hi) {
0163             return 1;
0164         }
0165 
0166         if (compare(*runHi, *lo)) { // decreasing
0167             do {
0168                 ++runHi;
0169             } while (runHi < hi && compare(*runHi, *(runHi - 1)));
0170             std::reverse(lo, runHi);
0171         } else { // non-decreasing
0172             do {
0173                 ++runHi;
0174             } while (runHi < hi && !compare(*runHi, *(runHi - 1)));
0175         }
0176 
0177         return runHi - lo;
0178     }
0179 
0180     static diff_t minRunLength(diff_t n) {
0181         GFX_TIMSORT_ASSERT(n >= 0);
0182 
0183         diff_t r = 0;
0184         while (n >= 2 * MIN_MERGE) {
0185             r |= (n & 1);
0186             n >>= 1;
0187         }
0188         return n + r;
0189     }
0190 
0191     TimSort() : minGallop_(MIN_GALLOP) {
0192     }
0193 
0194     // Silence GCC -Winline warning
0195     ~TimSort() {}
0196 
0197     void pushRun(iter_t const runBase, diff_t const runLen) {
0198         pending_.push_back(run<iter_t>(runBase, runLen));
0199     }
0200 
0201     void mergeCollapse(Compare compare) {
0202         while (pending_.size() > 1) {
0203             diff_t n = pending_.size() - 2;
0204 
0205             if ((n > 0 && pending_[n - 1].len <= pending_[n].len + pending_[n + 1].len) ||
0206                 (n > 1 && pending_[n - 2].len <= pending_[n - 1].len + pending_[n].len)) {
0207                 if (pending_[n - 1].len < pending_[n + 1].len) {
0208                     --n;
0209                 }
0210                 mergeAt(n, compare);
0211             } else if (pending_[n].len <= pending_[n + 1].len) {
0212                 mergeAt(n, compare);
0213             } else {
0214                 break;
0215             }
0216         }
0217     }
0218 
0219     void mergeForceCollapse(Compare compare) {
0220         while (pending_.size() > 1) {
0221             diff_t n = pending_.size() - 2;
0222 
0223             if (n > 0 && pending_[n - 1].len < pending_[n + 1].len) {
0224                 --n;
0225             }
0226             mergeAt(n, compare);
0227         }
0228     }
0229 
0230     void mergeAt(diff_t const i, Compare compare) {
0231         diff_t const stackSize = pending_.size();
0232         GFX_TIMSORT_ASSERT(stackSize >= 2);
0233         GFX_TIMSORT_ASSERT(i >= 0);
0234         GFX_TIMSORT_ASSERT(i == stackSize - 2 || i == stackSize - 3);
0235 
0236         iter_t base1 = pending_[i].base;
0237         diff_t len1 = pending_[i].len;
0238         iter_t base2 = pending_[i + 1].base;
0239         diff_t len2 = pending_[i + 1].len;
0240 
0241         pending_[i].len = len1 + len2;
0242 
0243         if (i == stackSize - 3) {
0244             pending_[i + 1] = pending_[i + 2];
0245         }
0246 
0247         pending_.pop_back();
0248 
0249         mergeConsecutiveRuns(base1, len1, base2, len2, std::move(compare));
0250     }
0251 
0252     void mergeConsecutiveRuns(iter_t base1, diff_t len1, iter_t base2, diff_t len2, Compare compare) {
0253         GFX_TIMSORT_ASSERT(len1 > 0);
0254         GFX_TIMSORT_ASSERT(len2 > 0);
0255         GFX_TIMSORT_ASSERT(base1 + len1 == base2);
0256 
0257         diff_t const k = gallopRight(*base2, base1, len1, 0, compare);
0258         GFX_TIMSORT_ASSERT(k >= 0);
0259 
0260         base1 += k;
0261         len1 -= k;
0262 
0263         if (len1 == 0) {
0264             return;
0265         }
0266 
0267         len2 = gallopLeft(*(base1 + (len1 - 1)), base2, len2, len2 - 1, compare);
0268         GFX_TIMSORT_ASSERT(len2 >= 0);
0269         if (len2 == 0) {
0270             return;
0271         }
0272 
0273         if (len1 <= len2) {
0274             mergeLo(base1, len1, base2, len2, compare);
0275         } else {
0276             mergeHi(base1, len1, base2, len2, compare);
0277         }
0278     }
0279 
0280     template <typename Iter>
0281     static diff_t gallopLeft(ref_t key, Iter const base, diff_t const len,
0282                              diff_t const hint, Compare compare) {
0283         GFX_TIMSORT_ASSERT(len > 0);
0284         GFX_TIMSORT_ASSERT(hint >= 0);
0285         GFX_TIMSORT_ASSERT(hint < len);
0286 
0287         diff_t lastOfs = 0;
0288         diff_t ofs = 1;
0289 
0290         if (compare(*(base + hint), key)) {
0291             diff_t const maxOfs = len - hint;
0292             while (ofs < maxOfs && compare(*(base + (hint + ofs)), key)) {
0293                 lastOfs = ofs;
0294                 ofs = (ofs << 1) + 1;
0295 
0296                 if (ofs <= 0) { // int overflow
0297                     ofs = maxOfs;
0298                 }
0299             }
0300             if (ofs > maxOfs) {
0301                 ofs = maxOfs;
0302             }
0303 
0304             lastOfs += hint;
0305             ofs += hint;
0306         } else {
0307             diff_t const maxOfs = hint + 1;
0308             while (ofs < maxOfs && !compare(*(base + (hint - ofs)), key)) {
0309                 lastOfs = ofs;
0310                 ofs = (ofs << 1) + 1;
0311 
0312                 if (ofs <= 0) {
0313                     ofs = maxOfs;
0314                 }
0315             }
0316             if (ofs > maxOfs) {
0317                 ofs = maxOfs;
0318             }
0319 
0320             diff_t const tmp = lastOfs;
0321             lastOfs = hint - ofs;
0322             ofs = hint - tmp;
0323         }
0324         GFX_TIMSORT_ASSERT(-1 <= lastOfs);
0325         GFX_TIMSORT_ASSERT(lastOfs < ofs);
0326         GFX_TIMSORT_ASSERT(ofs <= len);
0327 
0328         return std::lower_bound(base + (lastOfs + 1), base + ofs, key, compare) - base;
0329     }
0330 
0331     template <typename Iter>
0332     static diff_t gallopRight(ref_t key, Iter const base, diff_t const len,
0333                               diff_t const hint, Compare compare) {
0334         GFX_TIMSORT_ASSERT(len > 0);
0335         GFX_TIMSORT_ASSERT(hint >= 0);
0336         GFX_TIMSORT_ASSERT(hint < len);
0337 
0338         diff_t ofs = 1;
0339         diff_t lastOfs = 0;
0340 
0341         if (compare(key, *(base + hint))) {
0342             diff_t const maxOfs = hint + 1;
0343             while (ofs < maxOfs && compare(key, *(base + (hint - ofs)))) {
0344                 lastOfs = ofs;
0345                 ofs = (ofs << 1) + 1;
0346 
0347                 if (ofs <= 0) {
0348                     ofs = maxOfs;
0349                 }
0350             }
0351             if (ofs > maxOfs) {
0352                 ofs = maxOfs;
0353             }
0354 
0355             diff_t const tmp = lastOfs;
0356             lastOfs = hint - ofs;
0357             ofs = hint - tmp;
0358         } else {
0359             diff_t const maxOfs = len - hint;
0360             while (ofs < maxOfs && !compare(key, *(base + (hint + ofs)))) {
0361                 lastOfs = ofs;
0362                 ofs = (ofs << 1) + 1;
0363 
0364                 if (ofs <= 0) { // int overflow
0365                     ofs = maxOfs;
0366                 }
0367             }
0368             if (ofs > maxOfs) {
0369                 ofs = maxOfs;
0370             }
0371 
0372             lastOfs += hint;
0373             ofs += hint;
0374         }
0375         GFX_TIMSORT_ASSERT(-1 <= lastOfs);
0376         GFX_TIMSORT_ASSERT(lastOfs < ofs);
0377         GFX_TIMSORT_ASSERT(ofs <= len);
0378 
0379         return std::upper_bound(base + (lastOfs + 1), base + ofs, key, compare) - base;
0380     }
0381 
0382     static void rotateLeft(iter_t first, iter_t last)
0383     {
0384         value_t tmp = std::move(*first);
0385         iter_t last_1 = std::move(first + 1, last, first);
0386         *last_1 = std::move(tmp);
0387     }
0388 
0389     static void rotateRight(iter_t first, iter_t last)
0390     {
0391         iter_t last_1 = last - 1;
0392         value_t tmp = std::move(*last_1);
0393         std::move_backward(first, last_1, last);
0394         *first = std::move(tmp);
0395     }
0396 
0397 
0398     void mergeLo(iter_t const base1, diff_t len1, iter_t const base2, diff_t len2, Compare compare) {
0399         GFX_TIMSORT_ASSERT(len1 > 0);
0400         GFX_TIMSORT_ASSERT(len2 > 0);
0401         GFX_TIMSORT_ASSERT(base1 + len1 == base2);
0402 
0403         if (len1 == 1) {
0404             return rotateLeft(base1, base2 + len2);
0405         }
0406         if (len2 == 1) {
0407             return rotateRight(base1, base2 + len2);
0408         }
0409 
0410         copy_to_tmp(base1, len1);
0411 
0412         tmp_iter_t cursor1 = tmp_.begin();
0413         iter_t cursor2 = base2;
0414         iter_t dest = base1;
0415 
0416         *dest = std::move(*cursor2);
0417         ++cursor2;
0418         ++dest;
0419         --len2;
0420 
0421         int minGallop(minGallop_);
0422 
0423         // outer:
0424         while (true) {
0425             diff_t count1 = 0;
0426             diff_t count2 = 0;
0427 
0428             do {
0429                 GFX_TIMSORT_ASSERT(len1 > 1);
0430                 GFX_TIMSORT_ASSERT(len2 > 0);
0431 
0432                 if (compare(*cursor2, *cursor1)) {
0433                     *dest = std::move(*cursor2);
0434                     ++cursor2;
0435                     ++dest;
0436                     ++count2;
0437                     count1 = 0;
0438                     if (--len2 == 0) {
0439                         goto epilogue;
0440                     }
0441                 } else {
0442                     *dest = std::move(*cursor1);
0443                     ++cursor1;
0444                     ++dest;
0445                     ++count1;
0446                     count2 = 0;
0447                     if (--len1 == 1) {
0448                         goto epilogue;
0449                     }
0450                 }
0451             } while ((count1 | count2) < minGallop);
0452 
0453             do {
0454                 GFX_TIMSORT_ASSERT(len1 > 1);
0455                 GFX_TIMSORT_ASSERT(len2 > 0);
0456 
0457                 count1 = gallopRight(*cursor2, cursor1, len1, 0, compare);
0458                 if (count1 != 0) {
0459                     std::move_backward(cursor1, cursor1 + count1, dest + count1);
0460                     dest += count1;
0461                     cursor1 += count1;
0462                     len1 -= count1;
0463 
0464                     if (len1 <= 1) {
0465                         goto epilogue;
0466                     }
0467                 }
0468                 *dest = std::move(*cursor2);
0469                 ++cursor2;
0470                 ++dest;
0471                 if (--len2 == 0) {
0472                     goto epilogue;
0473                 }
0474 
0475                 count2 = gallopLeft(*cursor1, cursor2, len2, 0, compare);
0476                 if (count2 != 0) {
0477                     std::move(cursor2, cursor2 + count2, dest);
0478                     dest += count2;
0479                     cursor2 += count2;
0480                     len2 -= count2;
0481                     if (len2 == 0) {
0482                         goto epilogue;
0483                     }
0484                 }
0485                 *dest = std::move(*cursor1);
0486                 ++cursor1;
0487                 ++dest;
0488                 if (--len1 == 1) {
0489                     goto epilogue;
0490                 }
0491 
0492                 --minGallop;
0493             } while ((count1 >= MIN_GALLOP) | (count2 >= MIN_GALLOP));
0494 
0495             if (minGallop < 0) {
0496                 minGallop = 0;
0497             }
0498             minGallop += 2;
0499         } // end of "outer" loop
0500 
0501         epilogue: // merge what is left from either cursor1 or cursor2
0502 
0503         minGallop_ = (std::min)(minGallop, 1);
0504 
0505         if (len1 == 1) {
0506             GFX_TIMSORT_ASSERT(len2 > 0);
0507             std::move(cursor2, cursor2 + len2, dest);
0508             *(dest + len2) = std::move(*cursor1);
0509         } else {
0510             GFX_TIMSORT_ASSERT(len1 != 0 && "Comparison function violates its general contract");
0511             GFX_TIMSORT_ASSERT(len2 == 0);
0512             GFX_TIMSORT_ASSERT(len1 > 1);
0513             std::move(cursor1, cursor1 + len1, dest);
0514         }
0515     }
0516 
0517     void mergeHi(iter_t const base1, diff_t len1, iter_t const base2, diff_t len2, Compare compare) {
0518         GFX_TIMSORT_ASSERT(len1 > 0);
0519         GFX_TIMSORT_ASSERT(len2 > 0);
0520         GFX_TIMSORT_ASSERT(base1 + len1 == base2);
0521 
0522         if (len1 == 1) {
0523             return rotateLeft(base1, base2 + len2);
0524         }
0525         if (len2 == 1) {
0526             return rotateRight(base1, base2 + len2);
0527         }
0528 
0529         copy_to_tmp(base2, len2);
0530 
0531         iter_t cursor1 = base1 + len1;
0532         tmp_iter_t cursor2 = tmp_.begin() + (len2 - 1);
0533         iter_t dest = base2 + (len2 - 1);
0534 
0535         *dest = std::move(*(--cursor1));
0536         --dest;
0537         --len1;
0538 
0539         int minGallop(minGallop_);
0540 
0541         // outer:
0542         while (true) {
0543             diff_t count1 = 0;
0544             diff_t count2 = 0;
0545 
0546             // The next loop is a hot path of the algorithm, so we decrement
0547             // eagerly the cursor so that it always points directly to the value
0548             // to compare, but we have to implement some trickier logic to make
0549             // sure that it points to the next value again by the end of said loop
0550             --cursor1;
0551 
0552             do {
0553                 GFX_TIMSORT_ASSERT(len1 > 0);
0554                 GFX_TIMSORT_ASSERT(len2 > 1);
0555 
0556                 if (compare(*cursor2, *cursor1)) {
0557                     *dest = std::move(*cursor1);
0558                     --dest;
0559                     ++count1;
0560                     count2 = 0;
0561                     if (--len1 == 0) {
0562                         goto epilogue;
0563                     }
0564                     --cursor1;
0565                 } else {
0566                     *dest = std::move(*cursor2);
0567                     --cursor2;
0568                     --dest;
0569                     ++count2;
0570                     count1 = 0;
0571                     if (--len2 == 1) {
0572                         ++cursor1; // See comment before the loop
0573                         goto epilogue;
0574                     }
0575                 }
0576             } while ((count1 | count2) < minGallop);
0577             ++cursor1; // See comment before the loop
0578 
0579             do {
0580                 GFX_TIMSORT_ASSERT(len1 > 0);
0581                 GFX_TIMSORT_ASSERT(len2 > 1);
0582 
0583                 count1 = len1 - gallopRight(*cursor2, base1, len1, len1 - 1, compare);
0584                 if (count1 != 0) {
0585                     dest -= count1;
0586                     cursor1 -= count1;
0587                     len1 -= count1;
0588                     std::move_backward(cursor1, cursor1 + count1, dest + (1 + count1));
0589 
0590                     if (len1 == 0) {
0591                         goto epilogue;
0592                     }
0593                 }
0594                 *dest = std::move(*cursor2);
0595                 --cursor2;
0596                 --dest;
0597                 if (--len2 == 1) {
0598                     goto epilogue;
0599                 }
0600 
0601                 count2 = len2 - gallopLeft(*(cursor1 - 1), tmp_.begin(), len2, len2 - 1, compare);
0602                 if (count2 != 0) {
0603                     dest -= count2;
0604                     cursor2 -= count2;
0605                     len2 -= count2;
0606                     std::move(cursor2 + 1, cursor2 + (1 + count2), dest + 1);
0607                     if (len2 <= 1) {
0608                         goto epilogue;
0609                     }
0610                 }
0611                 *dest = std::move(*(--cursor1));
0612                 --dest;
0613                 if (--len1 == 0) {
0614                     goto epilogue;
0615                 }
0616 
0617                 --minGallop;
0618             } while ((count1 >= MIN_GALLOP) | (count2 >= MIN_GALLOP));
0619 
0620             if (minGallop < 0) {
0621                 minGallop = 0;
0622             }
0623             minGallop += 2;
0624         } // end of "outer" loop
0625 
0626         epilogue: // merge what is left from either cursor1 or cursor2
0627 
0628         minGallop_ = (std::min)(minGallop, 1);
0629 
0630         if (len2 == 1) {
0631             GFX_TIMSORT_ASSERT(len1 > 0);
0632             dest -= len1;
0633             std::move_backward(cursor1 - len1, cursor1, dest + (1 + len1));
0634             *dest = std::move(*cursor2);
0635         } else {
0636             GFX_TIMSORT_ASSERT(len2 != 0 && "Comparison function violates its general contract");
0637             GFX_TIMSORT_ASSERT(len1 == 0);
0638             GFX_TIMSORT_ASSERT(len2 > 1);
0639             std::move(tmp_.begin(), tmp_.begin() + len2, dest - (len2 - 1));
0640         }
0641     }
0642 
0643     void copy_to_tmp(iter_t const begin, diff_t len) {
0644         tmp_.assign(std::make_move_iterator(begin),
0645                     std::make_move_iterator(begin + len));
0646     }
0647 
0648 public:
0649 
0650     static void merge(iter_t const lo, iter_t const mid, iter_t const hi, Compare compare) {
0651         GFX_TIMSORT_ASSERT(lo <= mid);
0652         GFX_TIMSORT_ASSERT(mid <= hi);
0653 
0654         if (lo == mid || mid == hi) {
0655             return; // nothing to do
0656         }
0657 
0658         TimSort ts;
0659         ts.mergeConsecutiveRuns(lo, mid - lo, mid, hi - mid, std::move(compare));
0660 
0661         GFX_TIMSORT_LOG("1st size: " << (mid - lo) << "; 2nd size: " << (hi - mid)
0662                                      << "; tmp_.size(): " << ts.tmp_.size());
0663     }
0664 
0665     static void sort(iter_t const lo, iter_t const hi, Compare compare) {
0666         GFX_TIMSORT_ASSERT(lo <= hi);
0667 
0668         diff_t nRemaining = (hi - lo);
0669         if (nRemaining < 2) {
0670             return; // nothing to do
0671         }
0672 
0673         if (nRemaining < MIN_MERGE) {
0674             diff_t const initRunLen = countRunAndMakeAscending(lo, hi, compare);
0675             GFX_TIMSORT_LOG("initRunLen: " << initRunLen);
0676             binarySort(lo, hi, lo + initRunLen, compare);
0677             return;
0678         }
0679 
0680         TimSort ts;
0681         diff_t const minRun = minRunLength(nRemaining);
0682         iter_t cur = lo;
0683         do {
0684             diff_t runLen = countRunAndMakeAscending(cur, hi, compare);
0685 
0686             if (runLen < minRun) {
0687                 diff_t const force = (std::min)(nRemaining, minRun);
0688                 binarySort(cur, cur + force, cur + runLen, compare);
0689                 runLen = force;
0690             }
0691 
0692             ts.pushRun(cur, runLen);
0693             ts.mergeCollapse(compare);
0694 
0695             cur += runLen;
0696             nRemaining -= runLen;
0697         } while (nRemaining != 0);
0698 
0699         GFX_TIMSORT_ASSERT(cur == hi);
0700         ts.mergeForceCollapse(compare);
0701         GFX_TIMSORT_ASSERT(ts.pending_.size() == 1);
0702 
0703         GFX_TIMSORT_LOG("size: " << (hi - lo) << " tmp_.size(): " << ts.tmp_.size()
0704                                  << " pending_.size(): " << ts.pending_.size());
0705     }
0706 };
0707 
0708 } // namespace detail
0709 
0710 
0711 // ---------------------------------------
0712 // Public interface implementation
0713 // ---------------------------------------
0714 
0715 /**
0716  * Stably merges two consecutive sorted ranges [first, middle) and [middle, last) into one
0717  * sorted range [first, last) with a comparison function and a projection function.
0718  */
0719 template <typename RandomAccessIterator, typename Compare, typename Projection>
0720 void timmerge(RandomAccessIterator first, RandomAccessIterator middle,
0721               RandomAccessIterator last, Compare compare, Projection projection) {
0722     typedef detail::projection_compare<Compare, Projection> compare_t;
0723     compare_t comp(std::move(compare), std::move(projection));
0724     GFX_TIMSORT_AUDIT(std::is_sorted(first, middle, comp) && "Precondition");
0725     GFX_TIMSORT_AUDIT(std::is_sorted(middle, last, comp) && "Precondition");
0726     detail::TimSort<RandomAccessIterator, compare_t>::merge(first, middle, last, comp);
0727     GFX_TIMSORT_AUDIT(std::is_sorted(first, last, comp) && "Postcondition");
0728 }
0729 
0730 /**
0731  * Same as std::inplace_merge(first, middle, last, compare).
0732  */
0733 template <typename RandomAccessIterator, typename Compare>
0734 void timmerge(RandomAccessIterator first, RandomAccessIterator middle,
0735               RandomAccessIterator last, Compare compare) {
0736     gfx::timmerge(first, middle, last, compare, detail::identity());
0737 }
0738 
0739 /**
0740  * Same as std::inplace_merge(first, middle, last).
0741  */
0742 template <typename RandomAccessIterator>
0743 void timmerge(RandomAccessIterator first, RandomAccessIterator middle,
0744               RandomAccessIterator last) {
0745     typedef typename std::iterator_traits<RandomAccessIterator>::value_type value_type;
0746     gfx::timmerge(first, middle, last, std::less<value_type>(), detail::identity());
0747 }
0748 
0749 /**
0750  * Stably sorts a range with a comparison function and a projection function.
0751  */
0752 template <typename RandomAccessIterator, typename Compare, typename Projection>
0753 void timsort(RandomAccessIterator const first, RandomAccessIterator const last,
0754              Compare compare, Projection projection) {
0755     typedef detail::projection_compare<Compare, Projection> compare_t;
0756     compare_t comp(std::move(compare), std::move(projection));
0757     detail::TimSort<RandomAccessIterator, compare_t>::sort(first, last, comp);
0758     GFX_TIMSORT_AUDIT(std::is_sorted(first, last, comp) && "Postcondition");
0759 }
0760 
0761 /**
0762  * Same as std::stable_sort(first, last, compare).
0763  */
0764 template <typename RandomAccessIterator, typename Compare>
0765 void timsort(RandomAccessIterator const first, RandomAccessIterator const last, Compare compare) {
0766     gfx::timsort(first, last, compare, detail::identity());
0767 }
0768 
0769 /**
0770  * Same as std::stable_sort(first, last).
0771  */
0772 template <typename RandomAccessIterator>
0773 void timsort(RandomAccessIterator const first, RandomAccessIterator const last) {
0774     typedef typename std::iterator_traits<RandomAccessIterator>::value_type value_type;
0775     gfx::timsort(first, last, std::less<value_type>(), detail::identity());
0776 }
0777 
0778 /**
0779  * Stably sorts a range with a comparison function and a projection function.
0780  */
0781 template <typename RandomAccessRange, typename Compare, typename Projection>
0782 void timsort(RandomAccessRange &range, Compare compare, Projection projection) {
0783     gfx::timsort(std::begin(range), std::end(range), compare, projection);
0784 }
0785 
0786 /**
0787  * Same as std::stable_sort(std::begin(range), std::end(range), compare).
0788  */
0789 template <typename RandomAccessRange, typename Compare>
0790 void timsort(RandomAccessRange &range, Compare compare) {
0791     gfx::timsort(std::begin(range), std::end(range), compare);
0792 }
0793 
0794 /**
0795  * Same as std::stable_sort(std::begin(range), std::end(range)).
0796  */
0797 template <typename RandomAccessRange>
0798 void timsort(RandomAccessRange &range) {
0799     gfx::timsort(std::begin(range), std::end(range));
0800 }
0801 
0802 } // namespace gfx
0803 
0804 #undef GFX_TIMSORT_ENABLE_ASSERT
0805 #undef GFX_TIMSORT_ASSERT
0806 #undef GFX_TIMSORT_ENABLE_AUDIT
0807 #undef GFX_TIMSORT_AUDIT
0808 #undef GFX_TIMSORT_ENABLE_LOG
0809 #undef GFX_TIMSORT_LOG
0810 
0811 #endif // GFX_TIMSORT_HPP