forked from ava-labs/avalanchego
-
Notifications
You must be signed in to change notification settings - Fork 5
/
sorting.go
102 lines (88 loc) · 2.28 KB
/
sorting.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
// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package utils
import (
"bytes"
"golang.org/x/exp/constraints"
"golang.org/x/exp/slices"
"github.com/MetalBlockchain/metalgo/utils/hashing"
)
// TODO can we handle sorting where the Less function relies on a codec?
type Sortable[T any] interface {
Less(T) bool
}
// Sorts the elements of [s].
func Sort[T Sortable[T]](s []T) {
slices.SortFunc(s, T.Less)
}
// Sorts the elements of [s] based on their hashes.
func SortByHash[T ~[]byte](s []T) {
slices.SortFunc(s, func(i, j T) bool {
iHash := hashing.ComputeHash256(i)
jHash := hashing.ComputeHash256(j)
return bytes.Compare(iHash, jHash) == -1
})
}
// Sorts a 2D byte slice.
// Each byte slice is not sorted internally; the byte slices are sorted relative
// to one another.
func SortBytes[T ~[]byte](s []T) {
slices.SortFunc(s, func(i, j T) bool {
return bytes.Compare(i, j) == -1
})
}
// Returns true iff the elements in [s] are sorted.
func IsSortedBytes[T ~[]byte](s []T) bool {
for i := 0; i < len(s)-1; i++ {
if bytes.Compare(s[i], s[i+1]) == 1 {
return false
}
}
return true
}
// Returns true iff the elements in [s] are unique and sorted.
func IsSortedAndUnique[T Sortable[T]](s []T) bool {
for i := 0; i < len(s)-1; i++ {
if !s[i].Less(s[i+1]) {
return false
}
}
return true
}
// Returns true iff the elements in [s] are unique and sorted.
func IsSortedAndUniqueOrdered[T constraints.Ordered](s []T) bool {
for i := 0; i < len(s)-1; i++ {
if s[i] >= s[i+1] {
return false
}
}
return true
}
// Returns true iff the elements in [s] are unique and sorted
// based by their hashes.
func IsSortedAndUniqueByHash[T ~[]byte](s []T) bool {
if len(s) <= 1 {
return true
}
rightHash := hashing.ComputeHash256(s[0])
for i := 1; i < len(s); i++ {
leftHash := rightHash
rightHash = hashing.ComputeHash256(s[i])
if bytes.Compare(leftHash, rightHash) != -1 {
return false
}
}
return true
}
// Returns true iff the elements in [s] are unique.
func IsUnique[T comparable](s []T) bool {
// Can't use set.Set because it'd be a circular import.
asMap := make(map[T]struct{}, len(s))
for _, elt := range s {
if _, ok := asMap[elt]; ok {
return false
}
asMap[elt] = struct{}{}
}
return true
}