Skip to content

Commit ae88a97

Browse files
Juneezeematloob
authored andcommitted
all: change from sort functions to slices functions
The sorting functions in the slices package are slightly faster as they don't use reflection internally. Change-Id: I3c0ab61336d44c1928ee2a9da12a00d914f5e637 Reviewed-on: https://go-review.googlesource.com/c/mod/+/625635 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Michael Matloob <[email protected]> Reviewed-by: Michael Matloob <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent dc121ce commit ae88a97

File tree

6 files changed

+94
-54
lines changed

6 files changed

+94
-54
lines changed

modfile/rule.go

+23-25
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
package modfile
2121

2222
import (
23+
"cmp"
2324
"errors"
2425
"fmt"
2526
"path/filepath"
26-
"sort"
27+
"slices"
2728
"strconv"
2829
"strings"
2930
"unicode"
@@ -1633,15 +1634,13 @@ func (f *File) SortBlocks() {
16331634
if !ok {
16341635
continue
16351636
}
1636-
less := lineLess
1637+
less := compareLine
16371638
if block.Token[0] == "exclude" && useSemanticSortForExclude {
1638-
less = lineExcludeLess
1639+
less = compareLineExclude
16391640
} else if block.Token[0] == "retract" {
1640-
less = lineRetractLess
1641+
less = compareLineRetract
16411642
}
1642-
sort.SliceStable(block.Line, func(i, j int) bool {
1643-
return less(block.Line[i], block.Line[j])
1644-
})
1643+
slices.SortStableFunc(block.Line, less)
16451644
}
16461645
}
16471646

@@ -1746,39 +1745,38 @@ func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace, to
17461745
syntax.Stmt = stmts
17471746
}
17481747

1749-
// lineLess returns whether li should be sorted before lj. It sorts
1750-
// lexicographically without assigning any special meaning to tokens.
1751-
func lineLess(li, lj *Line) bool {
1748+
// compareLine compares li and lj. It sorts lexicographically without assigning
1749+
// any special meaning to tokens.
1750+
func compareLine(li, lj *Line) int {
17521751
for k := 0; k < len(li.Token) && k < len(lj.Token); k++ {
17531752
if li.Token[k] != lj.Token[k] {
1754-
return li.Token[k] < lj.Token[k]
1753+
return cmp.Compare(li.Token[k], lj.Token[k])
17551754
}
17561755
}
1757-
return len(li.Token) < len(lj.Token)
1756+
return cmp.Compare(len(li.Token), len(lj.Token))
17581757
}
17591758

1760-
// lineExcludeLess reports whether li should be sorted before lj for lines in
1761-
// an "exclude" block.
1762-
func lineExcludeLess(li, lj *Line) bool {
1759+
// compareLineExclude compares li and lj for lines in an "exclude" block.
1760+
func compareLineExclude(li, lj *Line) int {
17631761
if len(li.Token) != 2 || len(lj.Token) != 2 {
17641762
// Not a known exclude specification.
17651763
// Fall back to sorting lexicographically.
1766-
return lineLess(li, lj)
1764+
return compareLine(li, lj)
17671765
}
17681766
// An exclude specification has two tokens: ModulePath and Version.
17691767
// Compare module path by string order and version by semver rules.
17701768
if pi, pj := li.Token[0], lj.Token[0]; pi != pj {
1771-
return pi < pj
1769+
return cmp.Compare(pi, pj)
17721770
}
1773-
return semver.Compare(li.Token[1], lj.Token[1]) < 0
1771+
return semver.Compare(li.Token[1], lj.Token[1])
17741772
}
17751773

1776-
// lineRetractLess returns whether li should be sorted before lj for lines in
1777-
// a "retract" block. It treats each line as a version interval. Single versions
1778-
// are compared as if they were intervals with the same low and high version.
1774+
// compareLineRetract compares li and lj for lines in a "retract" block.
1775+
// It treats each line as a version interval. Single versions are compared as
1776+
// if they were intervals with the same low and high version.
17791777
// Intervals are sorted in descending order, first by low version, then by
1780-
// high version, using semver.Compare.
1781-
func lineRetractLess(li, lj *Line) bool {
1778+
// high version, using [semver.Compare].
1779+
func compareLineRetract(li, lj *Line) int {
17821780
interval := func(l *Line) VersionInterval {
17831781
if len(l.Token) == 1 {
17841782
return VersionInterval{Low: l.Token[0], High: l.Token[0]}
@@ -1792,9 +1790,9 @@ func lineRetractLess(li, lj *Line) bool {
17921790
vii := interval(li)
17931791
vij := interval(lj)
17941792
if cmp := semver.Compare(vii.Low, vij.Low); cmp != 0 {
1795-
return cmp > 0
1793+
return -cmp
17961794
}
1797-
return semver.Compare(vii.High, vij.High) > 0
1795+
return -semver.Compare(vii.High, vij.High)
17981796
}
17991797

18001798
// checkCanonicalVersion returns a non-nil error if vers is not a canonical

modfile/work.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ package modfile
66

77
import (
88
"fmt"
9-
"sort"
9+
"slices"
1010
"strings"
1111
)
1212

@@ -315,9 +315,7 @@ func (f *WorkFile) SortBlocks() {
315315
if !ok {
316316
continue
317317
}
318-
sort.SliceStable(block.Line, func(i, j int) bool {
319-
return lineLess(block.Line[i], block.Line[j])
320-
})
318+
slices.SortStableFunc(block.Line, compareLine)
321319
}
322320
}
323321

module/module.go

+9-10
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,11 @@ package module
9696
// Changes to the semantics in this file require approval from rsc.
9797

9898
import (
99+
"cmp"
99100
"errors"
100101
"fmt"
101102
"path"
102-
"sort"
103+
"slices"
103104
"strings"
104105
"unicode"
105106
"unicode/utf8"
@@ -657,17 +658,15 @@ func CanonicalVersion(v string) string {
657658
// optionally followed by a tie-breaking suffix introduced by a slash character,
658659
// like in "v0.0.1/go.mod".
659660
func Sort(list []Version) {
660-
sort.Slice(list, func(i, j int) bool {
661-
mi := list[i]
662-
mj := list[j]
663-
if mi.Path != mj.Path {
664-
return mi.Path < mj.Path
661+
slices.SortFunc(list, func(i, j Version) int {
662+
if i.Path != j.Path {
663+
return strings.Compare(i.Path, j.Path)
665664
}
666665
// To help go.sum formatting, allow version/file.
667666
// Compare semver prefix by semver rules,
668667
// file by string order.
669-
vi := mi.Version
670-
vj := mj.Version
668+
vi := i.Version
669+
vj := j.Version
671670
var fi, fj string
672671
if k := strings.Index(vi, "/"); k >= 0 {
673672
vi, fi = vi[:k], vi[k:]
@@ -676,9 +675,9 @@ func Sort(list []Version) {
676675
vj, fj = vj[:k], vj[k:]
677676
}
678677
if vi != vj {
679-
return semver.Compare(vi, vj) < 0
678+
return semver.Compare(vi, vj)
680679
}
681-
return fi < fj
680+
return cmp.Compare(fi, fj)
682681
})
683682
}
684683

semver/semver.go

+18-12
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
2323
package semver
2424

25-
import "sort"
25+
import (
26+
"slices"
27+
"strings"
28+
)
2629

2730
// parsed returns the parsed form of a semantic version string.
2831
type parsed struct {
@@ -154,19 +157,22 @@ func Max(v, w string) string {
154157
// ByVersion implements [sort.Interface] for sorting semantic version strings.
155158
type ByVersion []string
156159

157-
func (vs ByVersion) Len() int { return len(vs) }
158-
func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
159-
func (vs ByVersion) Less(i, j int) bool {
160-
cmp := Compare(vs[i], vs[j])
161-
if cmp != 0 {
162-
return cmp < 0
163-
}
164-
return vs[i] < vs[j]
165-
}
160+
func (vs ByVersion) Len() int { return len(vs) }
161+
func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
162+
func (vs ByVersion) Less(i, j int) bool { return compareVersion(vs[i], vs[j]) < 0 }
166163

167-
// Sort sorts a list of semantic version strings using [ByVersion].
164+
// Sort sorts a list of semantic version strings using [Compare] and falls back
165+
// to use [strings.Compare] if both versions are considered equal.
168166
func Sort(list []string) {
169-
sort.Sort(ByVersion(list))
167+
slices.SortFunc(list, compareVersion)
168+
}
169+
170+
func compareVersion(a, b string) int {
171+
cmp := Compare(a, b)
172+
if cmp != 0 {
173+
return cmp
174+
}
175+
return strings.Compare(a, b)
170176
}
171177

172178
func parse(v string) (p parsed, ok bool) {

semver/semver_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package semver
66

77
import (
88
"math/rand"
9+
"slices"
910
"sort"
1011
"strings"
1112
"testing"
@@ -166,6 +167,44 @@ func TestSort(t *testing.T) {
166167
if !sort.IsSorted(ByVersion(versions)) {
167168
t.Errorf("list is not sorted:\n%s", strings.Join(versions, "\n"))
168169
}
170+
171+
golden := []string{
172+
"bad",
173+
"v1+meta",
174+
"v1-alpha.beta.gamma",
175+
"v1-pre",
176+
"v1-pre+meta",
177+
"v1.2+meta",
178+
"v1.2-pre",
179+
"v1.2-pre+meta",
180+
"v1.0.0-alpha",
181+
"v1.0.0-alpha.1",
182+
"v1.0.0-alpha.beta",
183+
"v1.0.0-beta",
184+
"v1.0.0-beta.2",
185+
"v1.0.0-beta.11",
186+
"v1.0.0-rc.1",
187+
"v1",
188+
"v1.0",
189+
"v1.0.0",
190+
"v1.2",
191+
"v1.2.0",
192+
"v1.2.3-456",
193+
"v1.2.3-456.789",
194+
"v1.2.3-456-789",
195+
"v1.2.3-456a",
196+
"v1.2.3-pre",
197+
"v1.2.3-pre+meta",
198+
"v1.2.3-pre.1",
199+
"v1.2.3-zzz",
200+
"v1.2.3",
201+
"v1.2.3+meta",
202+
"v1.2.3+meta-pre",
203+
"v1.2.3+meta-pre.sha.256a",
204+
}
205+
if !slices.Equal(versions, golden) {
206+
t.Errorf("list is not sorted correctly\ngot:\n%v\nwant:\n%v", versions, golden)
207+
}
169208
}
170209

171210
func TestMax(t *testing.T) {

sumdb/dirhash/hash.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
"io"
1717
"os"
1818
"path/filepath"
19-
"sort"
19+
"slices"
2020
"strings"
2121
)
2222

@@ -36,15 +36,15 @@ type Hash func(files []string, open func(string) (io.ReadCloser, error)) (string
3636
// sha256sum $(find . -type f | sort) | sha256sum
3737
//
3838
// More precisely, the hashed summary contains a single line for each file in the list,
39-
// ordered by sort.Strings applied to the file names, where each line consists of
39+
// ordered by [slices.Sort] applied to the file names, where each line consists of
4040
// the hexadecimal SHA-256 hash of the file content,
4141
// two spaces (U+0020), the file name, and a newline (U+000A).
4242
//
4343
// File names with newlines (U+000A) are disallowed.
4444
func Hash1(files []string, open func(string) (io.ReadCloser, error)) (string, error) {
4545
h := sha256.New()
4646
files = append([]string(nil), files...)
47-
sort.Strings(files)
47+
slices.Sort(files)
4848
for _, file := range files {
4949
if strings.Contains(file, "\n") {
5050
return "", errors.New("dirhash: filenames with newlines are not supported")

0 commit comments

Comments
 (0)