/* * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright 2009 Google Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util; /** * This is a near duplicate of {@link TimSort}, modified for use with * arrays of objects that implement {@link Comparable}, instead of using * explicit comparators. * *
If you are using an optimizing VM, you may find that ComparableTimSort * offers no performance benefit over TimSort in conjunction with a * comparator that simply returns {@code ((Comparable)first).compareTo(Second)}. * If this is the case, you are better off deleting ComparableTimSort to * eliminate the code duplication. (See Arrays.java for details.) * * @author Josh Bloch */ class ComparableTimSort { /** * This is the minimum sized sequence that will be merged. Shorter * sequences will be lengthened by calling binarySort. If the entire * array is less than this length, no merges will be performed. * * This constant should be a power of two. It was 64 in Tim Peter's C * implementation, but 32 was empirically determined to work better in * this implementation. In the unlikely event that you set this constant * to be a number that's not a power of two, you'll need to change the * {@link #minRunLength} computation. * * If you decrease this constant, you must change the stackLen * computation in the TimSort constructor, or you risk an * ArrayOutOfBounds exception. See listsort.txt for a discussion * of the minimum stack length required as a function of the length * of the array being sorted and the minimum merge sequence length. */ private static final int MIN_MERGE = 32; /** * The array being sorted. */ private final Object[] a; /** * When we get into galloping mode, we stay there until both runs win less * often than MIN_GALLOP consecutive times. */ private static final int MIN_GALLOP = 7; /** * This controls when we get *into* galloping mode. It is initialized * to MIN_GALLOP. The mergeLo and mergeHi methods nudge it higher for * random data, and lower for highly structured data. */ private int minGallop = MIN_GALLOP; /** * Maximum initial size of tmp array, which is used for merging. The array * can grow to accommodate demand. * * Unlike Tim's original C version, we do not allocate this much storage * when sorting smaller arrays. This change was required for performance. */ private static final int INITIAL_TMP_STORAGE_LENGTH = 256; /** * Temp storage for merges. A workspace array may optionally be * provided in constructor, and if so will be used as long as it * is big enough. */ private Object[] tmp; private int tmpBase; // base of tmp array slice private int tmpLen; // length of tmp array slice /** * A stack of pending runs yet to be merged. Run i starts at * address base[i] and extends for len[i] elements. It's always * true (so long as the indices are in bounds) that: * * runBase[i] + runLen[i] == runBase[i + 1] * * so we could cut the storage for this, but it's a minor amount, * and keeping all the info explicit simplifies the code. */ private int stackSize = 0; // Number of pending runs on stack private final int[] runBase; private final int[] runLen; /** * Creates a TimSort instance to maintain the state of an ongoing sort. * * @param a the array to be sorted * @param work a workspace array (slice) * @param workBase origin of usable space in work array * @param workLen usable size of work array */ private ComparableTimSort(Object[] a, Object[] work, int workBase, int workLen) { this.a = a; // Allocate temp storage (which may be increased later if necessary) int len = a.length; int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ? len >>> 1 : INITIAL_TMP_STORAGE_LENGTH; if (work == null || workLen < tlen || workBase + tlen > work.length) { tmp = new Object[tlen]; tmpBase = 0; tmpLen = tlen; } else { tmp = work; tmpBase = workBase; tmpLen = workLen; } /* * Allocate runs-to-be-merged stack (which cannot be expanded). The * stack length requirements are described in listsort.txt. The C * version always uses the same stack length (85), but this was * measured to be too expensive when sorting "mid-sized" arrays (e.g., * 100 elements) in Java. Therefore, we use smaller (but sufficiently * large) stack lengths for smaller arrays. The "magic numbers" in the * computation below must be changed if MIN_MERGE is decreased. See * the MIN_MERGE declaration above for more information. * The maximum value of 49 allows for an array up to length * Integer.MAX_VALUE-4, if array is filled by the worst case stack size * increasing scenario. More explanations are given in section 4 of: * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf */ int stackLen = (len < 120 ? 5 : len < 1542 ? 10 : len < 119151 ? 24 : 49); runBase = new int[stackLen]; runLen = new int[stackLen]; } /* * The next method (package private and static) constitutes the * entire API of this class. */ /** * Sorts the given range, using the given workspace array slice * for temp storage when possible. This method is designed to be * invoked from public methods (in class Arrays) after performing * any necessary array bounds checks and expanding parameters into * the required forms. * * @param a the array to be sorted * @param lo the index of the first element, inclusive, to be sorted * @param hi the index of the last element, exclusive, to be sorted * @param work a workspace array (slice) * @param workBase origin of usable space in work array * @param workLen usable size of work array * @since 1.8 */ static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) { assert a != null && lo >= 0 && lo <= hi && hi <= a.length; int nRemaining = hi - lo; if (nRemaining < 2) return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges if (nRemaining < MIN_MERGE) { int initRunLen = countRunAndMakeAscending(a, lo, hi); binarySort(a, lo, hi, lo + initRunLen); return; } /** * March over the array once, left to right, finding natural runs, * extending short natural runs to minRun elements, and merging runs * to maintain stack invariant. */ ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen); int minRun = minRunLength(nRemaining); do { // Identify next run int runLen = countRunAndMakeAscending(a, lo, hi); // If run is short, extend to min(minRun, nRemaining) if (runLen < minRun) { int force = nRemaining <= minRun ? nRemaining : minRun; binarySort(a, lo, lo + force, lo + runLen); runLen = force; } // Push run onto pending-run stack, and maybe merge ts.pushRun(lo, runLen); ts.mergeCollapse(); // Advance to find next run lo += runLen; nRemaining -= runLen; } while (nRemaining != 0); // Merge all remaining runs to complete sort assert lo == hi; ts.mergeForceCollapse(); assert ts.stackSize == 1; } /** * Sorts the specified portion of the specified array using a binary * insertion sort. This is the best method for sorting small numbers * of elements. It requires O(n log n) compares, but O(n^2) data * movement (worst case). * * If the initial part of the specified range is already sorted, * this method can take advantage of it: the method assumes that the * elements from index {@code lo}, inclusive, to {@code start}, * exclusive are already sorted. * * @param a the array in which a range is to be sorted * @param lo the index of the first element in the range to be sorted * @param hi the index after the last element in the range to be sorted * @param start the index of the first element in the range that is * not already known to be sorted ({@code lo <= start <= hi}) */ @SuppressWarnings({"fallthrough", "rawtypes", "unchecked"}) private static void binarySort(Object[] a, int lo, int hi, int start) { assert lo <= start && start <= hi; if (start == lo) start++; for ( ; start < hi; start++) { Comparable pivot = (Comparable) a[start]; // Set left (and right) to the index where a[start] (pivot) belongs int left = lo; int right = start; assert left <= right; /* * Invariants: * pivot >= all in [lo, left). * pivot < all in [right, start). */ while (left < right) { int mid = (left + right) >>> 1; if (pivot.compareTo(a[mid]) < 0) right = mid; else left = mid + 1; } assert left == right; /* * The invariants still hold: pivot >= all in [lo, left) and * pivot < all in [left, start), so pivot belongs at left. Note * that if there are elements equal to pivot, left points to the * first slot after them -- that's why this sort is stable. * Slide elements over to make room for pivot. */ int n = start - left; // The number of elements to move // Switch is just an optimization for arraycopy in default case switch (n) { case 2: a[left + 2] = a[left + 1]; case 1: a[left + 1] = a[left]; break; default: System.arraycopy(a, left, a, left + 1, n); } a[left] = pivot; } } /** * Returns the length of the run beginning at the specified position in * the specified array and reverses the run if it is descending (ensuring * that the run will always be ascending when the method returns). * * A run is the longest ascending sequence with: * * a[lo] <= a[lo + 1] <= a[lo + 2] <= ... * * or the longest descending sequence with: * * a[lo] > a[lo + 1] > a[lo + 2] > ... * * For its intended use in a stable mergesort, the strictness of the * definition of "descending" is needed so that the call can safely * reverse a descending sequence without violating stability. * * @param a the array in which a run is to be counted and possibly reversed * @param lo index of the first element in the run * @param hi index after the last element that may be contained in the run. It is required that {@code lo < hi}. * @return the length of the run beginning at the specified position in * the specified array */ @SuppressWarnings({"unchecked", "rawtypes"}) private static int countRunAndMakeAscending(Object[] a, int lo, int hi) { assert lo < hi; int runHi = lo + 1; if (runHi == hi) return 1; // Find end of run, and reverse range if descending if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0) runHi++; reverseRange(a, lo, runHi); } else { // Ascending while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0) runHi++; } return runHi - lo; } /** * Reverse the specified range of the specified array. * * @param a the array in which a range is to be reversed * @param lo the index of the first element in the range to be reversed * @param hi the index after the last element in the range to be reversed */ private static void reverseRange(Object[] a, int lo, int hi) { hi--; while (lo < hi) { Object t = a[lo]; a[lo++] = a[hi]; a[hi--] = t; } } /** * Returns the minimum acceptable run length for an array of the specified * length. Natural runs shorter than this will be extended with * {@link #binarySort}. * * Roughly speaking, the computation is: * * If n < MIN_MERGE, return n (it's too small to bother with fancy stuff). * Else if n is an exact power of 2, return MIN_MERGE/2. * Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k * is close to, but strictly less than, an exact power of 2. * * For the rationale, see listsort.txt. * * @param n the length of the array to be sorted * @return the length of the minimum run to be merged */ private static int minRunLength(int n) { assert n >= 0; int r = 0; // Becomes 1 if any 1 bits are shifted off while (n >= MIN_MERGE) { r |= (n & 1); n >>= 1; } return n + r; } /** * Pushes the specified run onto the pending-run stack. * * @param runBase index of the first element in the run * @param runLen the number of elements in the run */ private void pushRun(int runBase, int runLen) { this.runBase[stackSize] = runBase; this.runLen[stackSize] = runLen; stackSize++; } /** * Examines the stack of runs waiting to be merged and merges adjacent runs * until the stack invariants are reestablished: * * 1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1] * 2. runLen[i - 2] > runLen[i - 1] * * This method is called each time a new run is pushed onto the stack, * so the invariants are guaranteed to hold for i < stackSize upon * entry to the method. */ private void mergeCollapse() { while (stackSize > 1) { int n = stackSize - 2; if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) { if (runLen[n - 1] < runLen[n + 1]) n--; mergeAt(n); } else if (runLen[n] <= runLen[n + 1]) { mergeAt(n); } else { break; // Invariant is established } } } /** * Merges all runs on the stack until only one remains. This method is * called once, to complete the sort. */ private void mergeForceCollapse() { while (stackSize > 1) { int n = stackSize - 2; if (n > 0 && runLen[n - 1] < runLen[n + 1]) n--; mergeAt(n); } } /** * Merges the two runs at stack indices i and i+1. Run i must be * the penultimate or antepenultimate run on the stack. In other words, * i must be equal to stackSize-2 or stackSize-3. * * @param i stack index of the first of the two runs to merge */ @SuppressWarnings("unchecked") private void mergeAt(int i) { assert stackSize >= 2; assert i >= 0; assert i == stackSize - 2 || i == stackSize - 3; int base1 = runBase[i]; int len1 = runLen[i]; int base2 = runBase[i + 1]; int len2 = runLen[i + 1]; assert len1 > 0 && len2 > 0; assert base1 + len1 == base2; /* * Record the length of the combined runs; if i is the 3rd-last * run now, also slide over the last run (which isn't involved * in this merge). The current run (i+1) goes away in any case. */ runLen[i] = len1 + len2; if (i == stackSize - 3) { runBase[i + 1] = runBase[i + 2]; runLen[i + 1] = runLen[i + 2]; } stackSize--; /* * Find where the first element of run2 goes in run1. Prior elements * in run1 can be ignored (because they're already in place). */ int k = gallopRight((Comparable