github.com/database64128/shadowsocks-go@v1.7.0/slices/sort.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package slices 6 7 import ( 8 "math/bits" 9 10 "github.com/database64128/shadowsocks-go/constraints" 11 ) 12 13 // Sort sorts a slice of any ordered type in ascending order. 14 // Sort may fail to sort correctly when sorting slices of floating-point 15 // numbers containing Not-a-number (NaN) values. 16 // Use slices.SortFunc(x, func(a, b float64) bool {return a < b || (math.IsNaN(a) && !math.IsNaN(b))}) 17 // instead if the input may contain NaNs. 18 func Sort[E constraints.Ordered](x []E) { 19 n := len(x) 20 pdqsortOrdered(x, 0, n, bits.Len(uint(n))) 21 } 22 23 // SortFunc sorts the slice x in ascending order as determined by the less function. 24 // This sort is not guaranteed to be stable. 25 // 26 // SortFunc requires that less is a strict weak ordering. 27 // See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. 28 func SortFunc[E any](x []E, less func(a, b E) bool) { 29 n := len(x) 30 pdqsortLessFunc(x, 0, n, bits.Len(uint(n)), less) 31 } 32 33 // SortStableFunc sorts the slice x while keeping the original order of equal 34 // elements, using less to compare elements. 35 func SortStableFunc[E any](x []E, less func(a, b E) bool) { 36 stableLessFunc(x, len(x), less) 37 } 38 39 // IsSorted reports whether x is sorted in ascending order. 40 func IsSorted[E constraints.Ordered](x []E) bool { 41 for i := len(x) - 1; i > 0; i-- { 42 if x[i] < x[i-1] { 43 return false 44 } 45 } 46 return true 47 } 48 49 // IsSortedFunc reports whether x is sorted in ascending order, with less as the 50 // comparison function. 51 func IsSortedFunc[E any](x []E, less func(a, b E) bool) bool { 52 for i := len(x) - 1; i > 0; i-- { 53 if less(x[i], x[i-1]) { 54 return false 55 } 56 } 57 return true 58 } 59 60 // BinarySearch searches for target in a sorted slice and returns the position 61 // where target is found, or the position where target would appear in the 62 // sort order; it also returns a bool saying whether the target is really found 63 // in the slice. The slice must be sorted in increasing order. 64 func BinarySearch[E constraints.Ordered](x []E, target E) (int, bool) { 65 // Inlining is faster than calling BinarySearchFunc with a lambda. 66 n := len(x) 67 // Define x[-1] < target and x[n] >= target. 68 // Invariant: x[i-1] < target, x[j] >= target. 69 i, j := 0, n 70 for i < j { 71 h := int(uint(i+j) >> 1) // avoid overflow when computing h 72 // i ≤ h < j 73 if x[h] < target { 74 i = h + 1 // preserves x[i-1] < target 75 } else { 76 j = h // preserves x[j] >= target 77 } 78 } 79 // i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i. 80 return i, i < n && x[i] == target 81 } 82 83 // BinarySearchFunc works like BinarySearch, but uses a custom comparison 84 // function. The slice must be sorted in increasing order, where "increasing" is 85 // defined by cmp. cmp(a, b) is expected to return an integer comparing the two 86 // parameters: 0 if a == b, a negative number if a < b and a positive number if 87 // a > b. 88 func BinarySearchFunc[E, T any](x []E, target T, cmp func(E, T) int) (int, bool) { 89 n := len(x) 90 // Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 . 91 // Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0. 92 i, j := 0, n 93 for i < j { 94 h := int(uint(i+j) >> 1) // avoid overflow when computing h 95 // i ≤ h < j 96 if cmp(x[h], target) < 0 { 97 i = h + 1 // preserves cmp(x[i - 1], target) < 0 98 } else { 99 j = h // preserves cmp(x[j], target) >= 0 100 } 101 } 102 // i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i. 103 return i, i < n && cmp(x[i], target) == 0 104 } 105 106 type sortedHint int // hint for pdqsort when choosing the pivot 107 108 const ( 109 unknownHint sortedHint = iota 110 increasingHint 111 decreasingHint 112 ) 113 114 // xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf 115 type xorshift uint64 116 117 func (r *xorshift) Next() uint64 { 118 *r ^= *r << 13 119 *r ^= *r >> 17 120 *r ^= *r << 5 121 return uint64(*r) 122 } 123 124 func nextPowerOfTwo(length int) uint { 125 return 1 << bits.Len(uint(length)) 126 }