-
Notifications
You must be signed in to change notification settings - Fork 0
/
misc.go
117 lines (100 loc) · 2.76 KB
/
misc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package jrutil
import (
"cmp"
crand "crypto/rand"
"math/rand/v2"
)
// MakePtr is useful for making pointers from intrinsic types like int
// for which the address-of operator does not work.
func MakePtr[T any](x T) *T {
return &x
}
// IfElse is similar to C's ternary operator.
func IfElse[T any](b bool, consequent T, alternative T) T {
if b {
return consequent
}
return alternative
}
// MakeRandomBytes returns a slice of bytes initialzed from
// crypto.rand.Read().
func MakeRandomBytes(n uint64) ([]byte, error) {
bs := make([]byte, 32)
_, err := crand.Read(bs)
if err != nil {
return nil, err
}
return bs, nil
}
// NewRand returns a new math.rand.Rand (v2) instance that uses source
// that is seeded with random bytes from crypto.rand.Read().
func NewRand() (*rand.Rand, error) {
bs, err := MakeRandomBytes(32)
if err != nil {
return nil, err
}
return rand.New(rand.NewChaCha8([32]byte(bs))), nil
}
// Merge merges the two sorted slices (xs and ys) and returns a new
// sorted slice that contains all of the elements from the two sorted
// input slices. This function performs a shallow copy when copying
// values from xs and ys to the result. Thus, if complex values are
// being sorted, xs and ys should hold pointers (for which shallow
// copying is correct).
func MergeSlices[T cmp.Ordered](
xs []T,
ys []T,
isLessThan func(x, y T) bool) []T {
// Get the length of both slices.
xLen := uint64(len(xs))
yLen := uint64(len(ys))
// Generate the slice to return.
rLen := uint64(xLen + yLen)
result := make([]T, rLen)
// Merge the lists into the result.
xsIndex := uint64(0)
ysIndex := uint64(0)
for i := uint64(0); i < rLen; i++ {
// When we run out of xs, the next value must come from ys.
if xsIndex >= xLen {
result[i] = ys[ysIndex]
ysIndex++
continue
}
// When we run out of ys, the next value must come from xs.
if ysIndex >= yLen {
result[i] = xs[xsIndex]
xsIndex++
continue
}
// We still have values in both xs and ys. Because xs and ys
// are both sorted, the value at xsIndex is the smallest value
// in xs, and the value at ysIndex is the smallest value in
// ys. We just need to compare the two values at xsIndex and
// ysIndex and copy the smaller to the result.
if isLessThan(xs[xsIndex], ys[ysIndex]) {
result[i] = xs[xsIndex]
xsIndex++
} else {
result[i] = ys[ysIndex]
ysIndex++
}
}
return result
}
// MergeSort returns a new, sorted slice based on the comparison
// function f.
func MergeSortSlices[T cmp.Ordered](
xs []T,
isLessThan func(x1, x2 T) bool) []T {
// Base case.
if len(xs) <= 1 {
return xs
}
// Divide and conquer.
mid := uint64(len(xs) / 2)
return MergeSlices(
MergeSortSlices(xs[:mid], isLessThan),
MergeSortSlices(xs[mid:], isLessThan),
isLessThan)
}