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  }