From 19ca842c3471890584eb276b6627fa4393b07453 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Sat, 7 Mar 2015 20:25:27 +0100 Subject: [PATCH] - starting work on sorting functions using tim's sort obtained from [https://github.com/psilva261/timsort] --- README.md | 4 +- utils/sort.go | 37 ++ utils/sort_test.go | 102 ++++ utils/timsort/LICENSE | 19 + utils/timsort/timsort.go | 1148 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 1309 insertions(+), 1 deletion(-) create mode 100644 utils/sort.go create mode 100644 utils/sort_test.go create mode 100644 utils/timsort/LICENSE create mode 100644 utils/timsort/timsort.go diff --git a/README.md b/README.md index 4994606..7b2e47f 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Implementation of various data structures in Go. ###Containers -All data structures implement the continer interface with the following methods: +All data structures implement the container interface with the following methods: ```go type Interface interface { @@ -548,3 +548,5 @@ For direct contributions, branch of from master and do _pull request_. ## License This library is distributed under the BSD-style license found in the [LICENSE](https://github.com/emirpasic/gods/blob/master/LICENSE) file. + +TimSort copied from (psilva261/timsort)[https://github.com/psilva261/timsort] with [LICENSE](https://github.com/emirpasic/gods/blob/master/utils/timsort/LICENSE) file. \ No newline at end of file diff --git a/utils/sort.go b/utils/sort.go new file mode 100644 index 0000000..51397b3 --- /dev/null +++ b/utils/sort.go @@ -0,0 +1,37 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// Util methods for sorting a slice of values with respect to the comparator + +package utils + +import "github.com/emirpasic/gods/utils/timsort" + +// Sorts values (in-place) +func Sort(values []interface{}, comparator Comparator) { + less := func(a, b interface{}) bool { return comparator(a, b) < 0 } + timsort.Sort(values, less) +} diff --git a/utils/sort_test.go b/utils/sort_test.go new file mode 100644 index 0000000..d1e523b --- /dev/null +++ b/utils/sort_test.go @@ -0,0 +1,102 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package utils + +import ( + "testing" +) + +func TestSortInts(t *testing.T) { + ints := []interface{}{} + ints = append(ints, 4) + ints = append(ints, 1) + ints = append(ints, 2) + ints = append(ints, 3) + + Sort(ints, IntComparator) + + for i := 1; i < len(ints); i++ { + if ints[i-1].(int) > ints[i].(int) { + t.Errorf("Not sorted!") + } + } + +} + +func TestSortStrings(t *testing.T) { + + strings := []interface{}{} + strings = append(strings, "d") + strings = append(strings, "a") + strings = append(strings, "b") + strings = append(strings, "c") + + Sort(strings, StringComparator) + + for i := 1; i < len(strings); i++ { + if strings[i-1].(string) > strings[i].(string) { + t.Errorf("Not sorted!") + } + } +} + +func TestSortStructs(t *testing.T) { + type User struct { + id int + name string + } + + byID := func(a, b interface{}) int { + c1 := a.(User) + c2 := b.(User) + switch { + case c1.id > c2.id: + return 1 + case c1.id < c2.id: + return -1 + default: + return 0 + } + } + + // o1,o2,expected + users := []interface{}{ + User{4, "d"}, + User{1, "a"}, + User{3, "c"}, + User{2, "b"}, + } + + Sort(users, byID) + + for i := 1; i < len(users); i++ { + if users[i-1].(User).id > users[i].(User).id { + t.Errorf("Not sorted!") + } + } + +} diff --git a/utils/timsort/LICENSE b/utils/timsort/LICENSE new file mode 100644 index 0000000..208ba42 --- /dev/null +++ b/utils/timsort/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010-2011 Mike Kroutikov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/utils/timsort/timsort.go b/utils/timsort/timsort.go new file mode 100644 index 0000000..861c379 --- /dev/null +++ b/utils/timsort/timsort.go @@ -0,0 +1,1148 @@ +// Obtained from: https://github.com/psilva261/timsort + +/* +Copyright (c) 2010-2011 Mike Kroutikov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE +*/ + +// Fast stable sort, uses external comparator. +// +// A stable, adaptive, iterative mergesort that requires far fewer than +// n lg(n) comparisons when running on partially sorted arrays, while +// offering performance comparable to a traditional mergesort when run +// on random arrays. Like all proper mergesorts, this sort is stable and +// runs O(n log n) time (worst case). In the worst case, this sort requires +// temporary storage space for n/2 object references; in the best case, +// it requires only a small constant amount of space. +// +// This implementation was derived from Java's TimSort object by Josh Bloch, +// which, in turn, was based on the original code by Tim Peters: +// +// http://svn.python.org/projects/python/trunk/Objects/listsort.txt +// +// Mike K. + +package timsort + +import ( + "errors" + "fmt" +) + +const ( + /** + * 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. + */ + _MIN_MERGE = 32 + // mk: tried higher MIN_MERGE and got slower sorting (348->375) + // c_MIN_MERGE = 64 + + /** + * When we get into galloping mode, we stay there until both runs win less + * often than c_MIN_GALLOP consecutive times. + */ + _MIN_GALLOP = 7 + + /** + * 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. + */ + _INITIAL_TMP_STORAGE_LENGTH = 256 +) + +// Delegate type that sorting uses as a comparator +type LessThan func(a, b interface{}) bool + +type timSortHandler struct { + + /** + * The array being sorted. + */ + a []interface{} + + /** + * The comparator for this sort. + */ + lt LessThan + + /** + * This controls when we get *into* galloping mode. It is initialized + * to c_MIN_GALLOP. The mergeLo and mergeHi methods nudge it higher for + * random data, and lower for highly structured data. + */ + minGallop int + + /** + * Temp storage for merges. + */ + tmp []interface{} // Actual runtime type will be Object[], regardless of T + + /** + * 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. + */ + stackSize int // Number of pending runs on stack + runBase []int + runLen []int +} + +/** + * Creates a TimSort instance to maintain the state of an ongoing sort. + * + * @param a the array to be sorted + * @param c the comparator to determine the order of the sort + */ +func newTimSort(a []interface{}, lt LessThan) (self *timSortHandler) { + self = new(timSortHandler) + + self.a = a + self.lt = lt + self.minGallop = _MIN_GALLOP + self.stackSize = 0 + + // Allocate temp storage (which may be increased later if necessary) + len := len(a) + + tmpSize := _INITIAL_TMP_STORAGE_LENGTH + if len < 2*tmpSize { + tmpSize = len / 2 + } + + self.tmp = make([]interface{}, tmpSize) + + /* + * 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 c_MIN_MERGE is decreased. See + * the c_MIN_MERGE declaration above for more information. + */ + // mk: confirmed that for small sorts this optimization gives measurable (albeit small) + // performance enhancement + stackLen := 40 + if len < 120 { + stackLen = 5 + } else if len < 1542 { + stackLen = 10 + } else if len < 119151 { + stackLen = 19 + } + + self.runBase = make([]int, stackLen) + self.runLen = make([]int, stackLen) + + return self +} + +// Sorts an array using the provided comparator +func Sort(a []interface{}, lt LessThan) (err error) { + lo := 0 + hi := len(a) + nRemaining := hi + + 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 { + initRunLen, err := countRunAndMakeAscending(a, lo, hi, lt) + if err != nil { + return err + } + + return binarySort(a, lo, hi, lo+initRunLen, lt) + } + + /** + * 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. + */ + + ts := newTimSort(a, lt) + minRun, err := minRunLength(nRemaining) + if err != nil { + return + } + for { + // Identify next run + runLen, err := countRunAndMakeAscending(a, lo, hi, lt) + if err != nil { + return err + } + + // If run is short, extend to min(minRun, nRemaining) + if runLen < minRun { + force := minRun + if nRemaining <= minRun { + force = nRemaining + } + if err = binarySort(a, lo, lo+force, lo+runLen, lt); err != nil { + return err + } + runLen = force + } + + // Push run onto pending-run stack, and maybe merge + ts.pushRun(lo, runLen) + if err = ts.mergeCollapse(); err != nil { + return err + } + + // Advance to find next run + lo += runLen + nRemaining -= runLen + if nRemaining == 0 { + break + } + } + + // Merge all remaining runs to complete sort + if lo != hi { + return errors.New("lo==hi!") + } + + if err = ts.mergeForceCollapse(); err != nil { + return + } + if ts.stackSize != 1 { + return errors.New("ts.stackSize != 1") + } + return +} + +/** + * 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} + * @param c comparator to used for the sort + */ +func binarySort(a []interface{}, lo, hi, start int, lt LessThan) (err error) { + if lo > start || start > hi { + return errors.New("lo <= start && start <= hi") + } + + if start == lo { + start++ + } + + for ; start < hi; start++ { + pivot := a[start] + + // Set left (and right) to the index where a[start] (pivot) belongs + left := lo + right := start + + if left > right { + return errors.New("left <= right") + } + + /* + * Invariants: + * pivot >= all in [lo, left). + * pivot < all in [right, start). + */ + for left < right { + mid := (left + right) / 2 + if lt(pivot, a[mid]) { + right = mid + } else { + left = mid + 1 + } + } + + if left != right { + return errors.New("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 to make room for pivot. + */ + n := start - left // The number of elements to move + // just an optimization for copy in default case + if n <= 2 { + if n == 2 { + a[left+2] = a[left+1] + } + if n > 0 { + a[left+1] = a[left] + } + } else { + copy(a[left+1:], a[left:left+n]) + } + a[left] = pivot + } + return +} + +/** + * 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}. + * @param c the comparator to used for the sort + * @return the length of the run beginning at the specified position in + * the specified array +*/ +func countRunAndMakeAscending(a []interface{}, lo, hi int, lt LessThan) (int, error) { + + if lo >= hi { + return 0, errors.New("lo < hi") + } + + runHi := lo + 1 + if runHi == hi { + return 1, nil + } + + // Find end of run, and reverse range if descending + if lt(a[runHi], a[lo]) { // Descending + runHi++ + + for runHi < hi && lt(a[runHi], a[runHi-1]) { + runHi++ + } + reverseRange(a, lo, runHi) + } else { // Ascending + for runHi < hi && !lt(a[runHi], a[runHi-1]) { + runHi++ + } + } + + return runHi - lo, nil +} + +/** + * 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 + */ +func reverseRange(a []interface{}, lo, hi int) { + hi-- + for lo < hi { + a[lo], a[hi] = a[hi], a[lo] + lo++ + hi-- + } +} + +/** + * 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 < c_MIN_MERGE, return n (it's too small to bother with fancy stuff). + * Else if n is an exact power of 2, return c_MIN_MERGE/2. + * Else return an int k, c_MIN_MERGE/2 <= k <= c_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 + */ +func minRunLength(n int) (int, error) { + if n < 0 { + return 0, errors.New("n >= 0") + } + r := 0 // Becomes 1 if any 1 bits are shifted off + for n >= _MIN_MERGE { + r |= (n & 1) + n >>= 1 + } + return n + r, nil +} + +/** + * 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 + */ +func (self *timSortHandler) pushRun(runBase, runLen int) { + self.runBase[self.stackSize] = runBase + self.runLen[self.stackSize] = runLen + self.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. + */ +func (self *timSortHandler) mergeCollapse() (err error) { + for self.stackSize > 1 { + n := self.stackSize - 2 + if n > 0 && self.runLen[n-1] <= self.runLen[n]+self.runLen[n+1] { + if self.runLen[n-1] < self.runLen[n+1] { + n-- + } + if err = self.mergeAt(n); err != nil { + return + } + } else if self.runLen[n] <= self.runLen[n+1] { + if err = self.mergeAt(n); err != nil { + return + } + } else { + break // Invariant is established + } + } + return +} + +/** + * Merges all runs on the stack until only one remains. This method is + * called once, to complete the sort. + */ +func (self *timSortHandler) mergeForceCollapse() (err error) { + for self.stackSize > 1 { + n := self.stackSize - 2 + if n > 0 && self.runLen[n-1] < self.runLen[n+1] { + n-- + } + if err = self.mergeAt(n); err != nil { + return + } + } + return +} + +/** + * 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 + */ +func (self *timSortHandler) mergeAt(i int) (err error) { + if self.stackSize < 2 { + return errors.New("stackSize >= 2") + } + + if i < 0 { + return errors.New(" i >= 0") + } + + if i != self.stackSize-2 && i != self.stackSize-3 { + return errors.New("if i == stackSize - 2 || i == stackSize - 3") + } + + base1 := self.runBase[i] + len1 := self.runLen[i] + base2 := self.runBase[i+1] + len2 := self.runLen[i+1] + + if len1 <= 0 || len2 <= 0 { + return errors.New("len1 > 0 && len2 > 0") + } + + if base1+len1 != base2 { + return errors.New("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. + */ + self.runLen[i] = len1 + len2 + if i == self.stackSize-3 { + self.runBase[i+1] = self.runBase[i+2] + self.runLen[i+1] = self.runLen[i+2] + } + self.stackSize-- + + /* + * Find where the first element of run2 goes in run1. Prior elements + * in run1 can be ignored (because they're already in place). + */ + k, err := gallopRight(self.a[base2], self.a, base1, len1, 0, self.lt) + if err != nil { + return err + } + if k < 0 { + return errors.New(" k >= 0;") + } + base1 += k + len1 -= k + if len1 == 0 { + return + } + + /* + * Find where the last element of run1 goes in run2. Subsequent elements + * in run2 can be ignored (because they're already in place). + */ + len2, err = gallopLeft(self.a[base1+len1-1], self.a, base2, len2, len2-1, self.lt) + if err != nil { + return + } + if len2 < 0 { + return errors.New(" len2 >= 0;") + } + if len2 == 0 { + return + } + + // Merge remaining runs, using tmp array with min(len1, len2) elements + if len1 <= len2 { + err = self.mergeLo(base1, len1, base2, len2) + if err != nil { + return errors.New(fmt.Sprintf("mergeLo: %v", err)) + } + } else { + err = self.mergeHi(base1, len1, base2, len2) + if err != nil { + return errors.New(fmt.Sprintf("mergeHi: %v", err)) + } + } + return +} + +/** + * Locates the position at which to insert the specified key into the + * specified sorted range; if the range contains an element equal to key, + * returns the index of the leftmost equal element. + * + * @param key the key whose insertion point to search for + * @param a the array in which to search + * @param base the index of the first element in the range + * @param len the length of the range; must be > 0 + * @param hint the index at which to begin the search, 0 <= hint < n. + * The closer hint is to the result, the faster this method will run. + * @param c the comparator used to order the range, and to search + * @return the int k, 0 <= k <= n such that a[b + k - 1] < key <= a[b + k], + * pretending that a[b - 1] is minus infinity and a[b + n] is infinity. + * In other words, key belongs at index b + k; or in other words, + * the first k elements of a should precede key, and the last n - k + * should follow it. + */ +func gallopLeft(key interface{}, a []interface{}, base, len, hint int, c LessThan) (int, error) { + if len <= 0 || hint < 0 || hint >= len { + return 0, errors.New(" len > 0 && hint >= 0 && hint < len;") + } + lastOfs := 0 + ofs := 1 + + if c(a[base+hint], key) { + // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs] + maxOfs := len - hint + for ofs < maxOfs && c(a[base+hint+ofs], key) { + lastOfs = ofs + ofs = (ofs << 1) + 1 + if ofs <= 0 { // int overflow + ofs = maxOfs + } + } + if ofs > maxOfs { + ofs = maxOfs + } + + // Make offsets relative to base + lastOfs += hint + ofs += hint + } else { // key <= a[base + hint] + // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs] + maxOfs := hint + 1 + for ofs < maxOfs && !c(a[base+hint-ofs], key) { + lastOfs = ofs + ofs = (ofs << 1) + 1 + if ofs <= 0 { // int overflow + ofs = maxOfs + } + } + if ofs > maxOfs { + ofs = maxOfs + } + + // Make offsets relative to base + tmp := lastOfs + lastOfs = hint - ofs + ofs = hint - tmp + } + + if -1 > lastOfs || lastOfs >= ofs || ofs > len { + return 0, errors.New(" -1 <= lastOfs && lastOfs < ofs && ofs <= len;") + } + + /* + * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere + * to the right of lastOfs but no farther right than ofs. Do a binary + * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs]. + */ + lastOfs++ + for lastOfs < ofs { + m := lastOfs + (ofs-lastOfs)/2 + + if c(a[base+m], key) { + lastOfs = m + 1 // a[base + m] < key + } else { + ofs = m // key <= a[base + m] + } + } + + if lastOfs != ofs { + return 0, errors.New(" lastOfs == ofs") // so a[base + ofs - 1] < key <= a[base + ofs] + } + return ofs, nil +} + +/** + * Like gallopLeft, except that if the range contains an element equal to + * key, gallopRight returns the index after the rightmost equal element. + * + * @param key the key whose insertion point to search for + * @param a the array in which to search + * @param base the index of the first element in the range + * @param len the length of the range; must be > 0 + * @param hint the index at which to begin the search, 0 <= hint < n. + * The closer hint is to the result, the faster this method will run. + * @param c the comparator used to order the range, and to search + * @return the int k, 0 <= k <= n such that a[b + k - 1] <= key < a[b + k] + */ +func gallopRight(key interface{}, a []interface{}, base, len, hint int, c LessThan) (int, error) { + if len <= 0 || hint < 0 || hint >= len { + return 0, errors.New(" len > 0 && hint >= 0 && hint < len;") + } + + ofs := 1 + lastOfs := 0 + if c(key, a[base+hint]) { + // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs] + maxOfs := hint + 1 + for ofs < maxOfs && c(key, a[base+hint-ofs]) { + lastOfs = ofs + ofs = (ofs << 1) + 1 + if ofs <= 0 { // int overflow + ofs = maxOfs + } + } + if ofs > maxOfs { + ofs = maxOfs + } + + // Make offsets relative to b + tmp := lastOfs + lastOfs = hint - ofs + ofs = hint - tmp + } else { // a[b + hint] <= key + // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs] + maxOfs := len - hint + for ofs < maxOfs && !c(key, a[base+hint+ofs]) { + lastOfs = ofs + ofs = (ofs << 1) + 1 + if ofs <= 0 { // int overflow + ofs = maxOfs + } + } + if ofs > maxOfs { + ofs = maxOfs + } + + // Make offsets relative to b + lastOfs += hint + ofs += hint + } + if -1 > lastOfs || lastOfs >= ofs || ofs > len { + return 0, errors.New("-1 <= lastOfs && lastOfs < ofs && ofs <= len") + } + + /* + * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to + * the right of lastOfs but no farther right than ofs. Do a binary + * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs]. + */ + lastOfs++ + for lastOfs < ofs { + m := lastOfs + (ofs-lastOfs)/2 + + if c(key, a[base+m]) { + ofs = m // key < a[b + m] + } else { + lastOfs = m + 1 // a[b + m] <= key + } + } + if lastOfs != ofs { + return 0, errors.New(" lastOfs == ofs") // so a[b + ofs - 1] <= key < a[b + ofs] + } + return ofs, nil +} + +/** + * Merges two adjacent runs in place, in a stable fashion. The first + * element of the first run must be greater than the first element of the + * second run (a[base1] > a[base2]), and the last element of the first run + * (a[base1 + len1-1]) must be greater than all elements of the second run. + * + * For performance, this method should be called only when len1 <= len2; + * its twin, mergeHi should be called if len1 >= len2. (Either method + * may be called if len1 == len2.) + * + * @param base1 index of first element in first run to be merged + * @param len1 length of first run to be merged (must be > 0) + * @param base2 index of first element in second run to be merged + * (must be aBase + aLen) + * @param len2 length of second run to be merged (must be > 0) + */ +func (self *timSortHandler) mergeLo(base1, len1, base2, len2 int) (err error) { + if len1 <= 0 || len2 <= 0 || base1+len1 != base2 { + return errors.New(" len1 > 0 && len2 > 0 && base1 + len1 == base2") + } + + // Copy first run into temp array + a := self.a // For performance + tmp := self.ensureCapacity(len1) + + copy(tmp, a[base1:base1+len1]) + + cursor1 := 0 // Indexes into tmp array + cursor2 := base2 // Indexes int a + dest := base1 // Indexes int a + + // Move first element of second run and deal with degenerate cases + a[dest] = a[cursor2] + dest++ + cursor2++ + len2-- + if len2 == 0 { + copy(a[dest:dest+len1], tmp) + return + } + if len1 == 1 { + copy(a[dest:dest+len2], a[cursor2:cursor2+len2]) + a[dest+len2] = tmp[cursor1] // Last elt of run 1 to end of merge + return + } + + lt := self.lt // Use local variable for performance + minGallop := self.minGallop // " " " " " + +outer: + for { + count1 := 0 // Number of times in a row that first run won + count2 := 0 // Number of times in a row that second run won + + /* + * Do the straightforward thing until (if ever) one run starts + * winning consistently. + */ + for { + if len1 <= 1 || len2 <= 0 { + return errors.New(" len1 > 1 && len2 > 0") + } + + if lt(a[cursor2], tmp[cursor1]) { + a[dest] = a[cursor2] + dest++ + cursor2++ + count2++ + count1 = 0 + len2-- + if len2 == 0 { + break outer + } + } else { + a[dest] = tmp[cursor1] + dest++ + cursor1++ + count1++ + count2 = 0 + len1-- + if len1 == 1 { + break outer + } + } + if (count1 | count2) >= minGallop { + break + } + } + + /* + * One run is winning so consistently that galloping may be a + * huge win. So try that, and continue galloping until (if ever) + * neither run appears to be winning consistently anymore. + */ + for { + if len1 <= 1 || len2 <= 0 { + return errors.New("len1 > 1 && len2 > 0") + } + count1, err = gallopRight(a[cursor2], tmp, cursor1, len1, 0, lt) + if err != nil { + return + } + if count1 != 0 { + copy(a[dest:dest+count1], tmp[cursor1:cursor1+count1]) + dest += count1 + cursor1 += count1 + len1 -= count1 + if len1 <= 1 { // len1 == 1 || len1 == 0 + break outer + } + } + a[dest] = a[cursor2] + dest++ + cursor2++ + len2-- + if len2 == 0 { + break outer + } + + count2, err = gallopLeft(tmp[cursor1], a, cursor2, len2, 0, lt) + if err != nil { + return + } + if count2 != 0 { + copy(a[dest:dest+count2], a[cursor2:cursor2+count2]) + dest += count2 + cursor2 += count2 + len2 -= count2 + if len2 == 0 { + break outer + } + } + a[dest] = tmp[cursor1] + dest++ + cursor1++ + len1-- + if len1 == 1 { + break outer + } + minGallop-- + if count1 < _MIN_GALLOP && count2 < _MIN_GALLOP { + break + } + } + if minGallop < 0 { + minGallop = 0 + } + minGallop += 2 // Penalize for leaving gallop mode + } // End of "outer" loop + + if minGallop < 1 { + minGallop = 1 + } + self.minGallop = minGallop // Write back to field + + if len1 == 1 { + + if len2 <= 0 { + return errors.New(" len2 > 0;") + } + copy(a[dest:dest+len2], a[cursor2:cursor2+len2]) + a[dest+len2] = tmp[cursor1] // Last elt of run 1 to end of merge + } else if len1 == 0 { + return errors.New("Comparison method violates its general contract!") + } else { + if len2 != 0 { + return errors.New("len2 == 0;") + } + if len1 <= 1 { + return errors.New(" len1 > 1;") + } + + copy(a[dest:dest+len1], tmp[cursor1:cursor1+len1]) + } + return +} + +/** + * Like mergeLo, except that this method should be called only if + * len1 >= len2; mergeLo should be called if len1 <= len2. (Either method + * may be called if len1 == len2.) + * + * @param base1 index of first element in first run to be merged + * @param len1 length of first run to be merged (must be > 0) + * @param base2 index of first element in second run to be merged + * (must be aBase + aLen) + * @param len2 length of second run to be merged (must be > 0) + */ +func (self *timSortHandler) mergeHi(base1, len1, base2, len2 int) (err error) { + if len1 <= 0 || len2 <= 0 || base1+len1 != base2 { + return errors.New("len1 > 0 && len2 > 0 && base1 + len1 == base2;") + } + + // Copy second run into temp array + a := self.a // For performance + tmp := self.ensureCapacity(len2) + + copy(tmp, a[base2:base2+len2]) + + cursor1 := base1 + len1 - 1 // Indexes into a + cursor2 := len2 - 1 // Indexes into tmp array + dest := base2 + len2 - 1 // Indexes into a + + // Move last element of first run and deal with degenerate cases + a[dest] = a[cursor1] + dest-- + cursor1-- + len1-- + if len1 == 0 { + dest -= len2 - 1 + copy(a[dest:dest+len2], tmp) + return + } + if len2 == 1 { + dest -= len1 - 1 + cursor1 -= len1 - 1 + copy(a[dest:dest+len1], a[cursor1:cursor1+len1]) + a[dest-1] = tmp[cursor2] + return + } + + lt := self.lt // Use local variable for performance + minGallop := self.minGallop // " " " " " + +outer: + for { + count1 := 0 // Number of times in a row that first run won + count2 := 0 // Number of times in a row that second run won + + /* + * Do the straightforward thing until (if ever) one run + * appears to win consistently. + */ + for { + if len1 <= 0 || len2 <= 1 { + return errors.New(" len1 > 0 && len2 > 1;") + } + if lt(tmp[cursor2], a[cursor1]) { + a[dest] = a[cursor1] + dest-- + cursor1-- + count1++ + count2 = 0 + len1-- + if len1 == 0 { + break outer + } + } else { + a[dest] = tmp[cursor2] + dest-- + cursor2-- + count2++ + count1 = 0 + len2-- + if len2 == 1 { + break outer + } + } + if (count1 | count2) >= minGallop { + break + } + } + + /* + * One run is winning so consistently that galloping may be a + * huge win. So try that, and continue galloping until (if ever) + * neither run appears to be winning consistently anymore. + */ + for { + if len1 <= 0 || len2 <= 1 { + return errors.New(" len1 > 0 && len2 > 1;") + } + if gr, err := gallopRight(tmp[cursor2], a, base1, len1, len1-1, lt); err == nil { + count1 = len1 - gr + } else { + return err + } + if count1 != 0 { + dest -= count1 + cursor1 -= count1 + len1 -= count1 + copy(a[dest+1:dest+1+count1], a[cursor1+1:cursor1+1+count1]) + if len1 == 0 { + break outer + } + } + a[dest] = tmp[cursor2] + dest-- + cursor2-- + len2-- + if len2 == 1 { + break outer + } + + if gl, err := gallopLeft(a[cursor1], tmp, 0, len2, len2-1, lt); err == nil { + count2 = len2 - gl + } else { + return err + } + if count2 != 0 { + dest -= count2 + cursor2 -= count2 + len2 -= count2 + copy(a[dest+1:dest+1+count2], tmp[cursor2+1:cursor2+1+count2]) + if len2 <= 1 { // len2 == 1 || len2 == 0 + break outer + } + } + a[dest] = a[cursor1] + dest-- + cursor1-- + len1-- + if len1 == 0 { + break outer + } + minGallop-- + + if count1 < _MIN_GALLOP && count2 < _MIN_GALLOP { + break + } + } + if minGallop < 0 { + minGallop = 0 + } + minGallop += 2 // Penalize for leaving gallop mode + } // End of "outer" loop + + if minGallop < 1 { + minGallop = 1 + } + + self.minGallop = minGallop // Write back to field + + if len2 == 1 { + if len1 <= 0 { + return errors.New(" len1 > 0;") + } + dest -= len1 + cursor1 -= len1 + + copy(a[dest+1:dest+1+len1], a[cursor1+1:cursor1+1+len1]) + a[dest] = tmp[cursor2] // Move first elt of run2 to front of merge + } else if len2 == 0 { + return errors.New("Comparison method violates its general contract!") + } else { + if len1 != 0 { + return errors.New("len1 == 0;") + } + + if len2 <= 0 { + return errors.New(" len2 > 0;") + } + + copy(a[dest-(len2-1):dest+1], tmp) + } + return +} + +/** + * Ensures that the external array tmp has at least the specified + * number of elements, increasing its size if necessary. The size + * increases exponentially to ensure amortized linear time complexity. + * + * @param minCapacity the minimum required capacity of the tmp array + * @return tmp, whether or not it grew + */ +func (self *timSortHandler) ensureCapacity(minCapacity int) []interface{} { + if len(self.tmp) < minCapacity { + // Compute smallest power of 2 > minCapacity + newSize := minCapacity + newSize |= newSize >> 1 + newSize |= newSize >> 2 + newSize |= newSize >> 4 + newSize |= newSize >> 8 + newSize |= newSize >> 16 + newSize++ + + if newSize < 0 { // Not bloody likely! + newSize = minCapacity + } else { + ns := len(self.a) / 2 + if ns < newSize { + newSize = ns + } + } + + self.tmp = make([]interface{}, newSize) + } + + return self.tmp +}