this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

all: replace sort.Sort and sort.Slice with slices.SortFunc

In the case of sort.Sort, we avoid having to implement three methods.
In both cases, we compare via ints (-1, 0, -1) rather than a less bool,
meaning that we don't need a separate "equal" check logic
and we also need to make fewer comparisons as part of the sorting.

The code is less verbose too, as we don't need to index into the slice.

While here, fix a couple of broken links I spotted along the way.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: Ib687da2cc357ea784a51f3a832cf3265376fbef0
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1189331
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Reviewed-by: Roger Peppe <rogpeppe@gmail.com>

+98 -172
+22 -21
cue/decode.go
··· 16 16 17 17 import ( 18 18 "bytes" 19 + "cmp" 19 20 "encoding" 20 21 "encoding/json" 21 22 "reflect" 22 - "sort" 23 + "slices" 23 24 "strconv" 24 25 "strings" 25 26 "sync" ··· 488 489 omitEmpty bool 489 490 } 490 491 491 - // byIndex sorts goField by index sequence. 492 - type byIndex []goField 493 - 494 - func (x byIndex) Less(i, j int) bool { 495 - for k, xik := range x[i].index { 496 - if k >= len(x[j].index) { 497 - return false 492 + func compareFieldByIndex(a, b goField) int { 493 + for i, x := range a.index { 494 + if i >= len(b.index) { 495 + break 498 496 } 499 - if xik != x[j].index[k] { 500 - return xik < x[j].index[k] 497 + if c := cmp.Compare(x, b.index[i]); c != 0 { 498 + return c 501 499 } 502 500 } 503 - return len(x[i].index) < len(x[j].index) 501 + return cmp.Compare(len(a.index), len(b.index)) 504 502 } 505 503 506 504 // typeFields returns a list of fields that JSON should recognize for the given type. ··· 614 612 } 615 613 } 616 614 617 - sort.Slice(fields, func(i, j int) bool { 618 - x := fields 615 + slices.SortFunc(fields, func(a, b goField) int { 619 616 // sort field by name, breaking ties with depth, then 620 617 // breaking ties with "name came from json tag", then 621 618 // breaking ties with index sequence. 622 - if x[i].name != x[j].name { 623 - return x[i].name < x[j].name 619 + if c := cmp.Compare(a.name, b.name); c != 0 { 620 + return c 624 621 } 625 - if len(x[i].index) != len(x[j].index) { 626 - return len(x[i].index) < len(x[j].index) 622 + if c := cmp.Compare(len(a.index), len(b.index)); c != 0 { 623 + return c 627 624 } 628 - if x[i].tag != x[j].tag { 629 - return x[i].tag 625 + if a.tag != b.tag { 626 + if a.tag { 627 + return 1 628 + } else { 629 + return -1 630 + } 630 631 } 631 - return byIndex(x).Less(i, j) 632 + return compareFieldByIndex(a, b) 632 633 }) 633 634 634 635 // Delete all fields that are hidden by the Go rules for embedded fields, ··· 660 661 } 661 662 662 663 fields = out 663 - sort.Slice(fields, byIndex(fields).Less) 664 + slices.SortFunc(fields, compareFieldByIndex) 664 665 665 666 nameIndex := make(map[string]int, len(fields)) 666 667 for i, field := range fields {
+24 -46
cue/errors/errors.go
··· 26 26 "io" 27 27 "path/filepath" 28 28 "slices" 29 - "sort" 30 29 "strings" 31 30 32 31 "cuelang.org/go/cue/token" ··· 356 355 // Reset resets an List to no errors. 357 356 func (p *list) Reset() { *p = (*p)[:0] } 358 357 359 - // List implements the sort Interface. 360 - func (p list) Len() int { return len(p) } 361 - func (p list) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 362 - 363 - func (p list) Less(i, j int) bool { 364 - if c := comparePos(p[i].Position(), p[j].Position()); c != 0 { 365 - return c == -1 366 - } 367 - // Note that it is not sufficient to simply compare file offsets because 368 - // the offsets do not reflect modified line information (through //line 369 - // comments). 370 - 371 - if !equalPath(p[i].Path(), p[j].Path()) { 372 - return lessPath(p[i].Path(), p[j].Path()) 373 - } 374 - return p[i].Error() < p[j].Error() 375 - } 376 - 377 358 func comparePos(a, b token.Pos) int { 378 - if a.Filename() != b.Filename() { 379 - return cmp.Compare(a.Filename(), b.Filename()) 359 + if c := cmp.Compare(a.Filename(), b.Filename()); c != 0 { 360 + return c 380 361 } 381 - if a.Line() != b.Line() { 382 - return cmp.Compare(a.Line(), b.Line()) 362 + if c := cmp.Compare(a.Line(), b.Line()); c != 0 { 363 + return c 383 364 } 384 - if a.Column() != b.Column() { 385 - return cmp.Compare(a.Column(), b.Column()) 386 - } 387 - return 0 365 + return cmp.Compare(a.Column(), b.Column()) 388 366 } 389 367 390 - func lessPath(a, b []string) bool { 368 + func comparePath(a, b []string) int { 391 369 for i, x := range a { 392 370 if i >= len(b) { 393 - return false 371 + break 394 372 } 395 - if x != b[i] { 396 - return x < b[i] 373 + if c := cmp.Compare(x, b[i]); c != 0 { 374 + return c 397 375 } 398 376 } 399 - return len(a) < len(b) 400 - } 401 - 402 - func equalPath(a, b []string) bool { 403 - if len(a) != len(b) { 404 - return false 405 - } 406 - for i, x := range a { 407 - if x != b[i] { 408 - return false 409 - } 410 - } 411 - return true 377 + return cmp.Compare(len(a), len(b)) 412 378 } 413 379 414 380 // Sanitize sorts multiple errors and removes duplicates on a best effort basis. ··· 441 407 // other errors are sorted by error message, and before any *posError 442 408 // entry. 443 409 func (p list) Sort() { 444 - sort.Sort(p) 410 + slices.SortFunc(p, func(a, b Error) int { 411 + if c := comparePos(a.Position(), b.Position()); c != 0 { 412 + return c 413 + } 414 + // Note that it is not sufficient to simply compare file offsets because 415 + // the offsets do not reflect modified line information (through //line 416 + // comments). 417 + if c := comparePath(a.Path(), b.Path()); c != 0 { 418 + return c 419 + } 420 + return cmp.Compare(a.Error(), b.Error()) 421 + 422 + }) 445 423 } 446 424 447 425 // RemoveMultiples sorts an List and removes all but the first error per line. ··· 468 446 return aPos.Filename() == bPos.Filename() && 469 447 aPos.Line() == bPos.Line() && 470 448 aPos.Column() == bPos.Column() && 471 - equalPath(a.Path(), b.Path()) 449 + comparePath(a.Path(), b.Path()) == 0 472 450 } 473 451 474 452 // An List implements the error interface.
-52
cue/errors/errors_test.go
··· 66 66 } 67 67 } 68 68 69 - func TestErrorList_Len(t *testing.T) { 70 - tests := []struct { 71 - name string 72 - p list 73 - want int 74 - }{ 75 - // TODO: Add test cases. 76 - } 77 - for _, tt := range tests { 78 - if got := tt.p.Len(); got != tt.want { 79 - t.Errorf("%q. list.Len() = %v, want %v", tt.name, got, tt.want) 80 - } 81 - } 82 - } 83 - 84 - func TestErrorList_Swap(t *testing.T) { 85 - type args struct { 86 - i int 87 - j int 88 - } 89 - tests := []struct { 90 - name string 91 - p list 92 - args args 93 - }{ 94 - // TODO: Add test cases. 95 - } 96 - for _, tt := range tests { 97 - tt.p.Swap(tt.args.i, tt.args.j) 98 - } 99 - } 100 - 101 - func TestErrorList_Less(t *testing.T) { 102 - type args struct { 103 - i int 104 - j int 105 - } 106 - tests := []struct { 107 - name string 108 - p list 109 - args args 110 - want bool 111 - }{ 112 - // TODO: Add test cases. 113 - } 114 - for _, tt := range tests { 115 - if got := tt.p.Less(tt.args.i, tt.args.j); got != tt.want { 116 - t.Errorf("%q. list.Less() = %v, want %v", tt.name, got, tt.want) 117 - } 118 - } 119 - } 120 - 121 69 func TestErrorList_Sort(t *testing.T) { 122 70 tests := []struct { 123 71 name string
+4 -3
cue/load/fs.go
··· 16 16 17 17 import ( 18 18 "bytes" 19 + "cmp" 19 20 "fmt" 20 21 "io" 21 22 iofs "io/fs" 22 23 "os" 23 24 "path/filepath" 24 - "sort" 25 + "slices" 25 26 "strings" 26 27 "time" 27 28 ··· 177 178 items = append(items, iofs.FileInfoToDirEntry(o)) 178 179 } 179 180 } 180 - sort.Slice(items, func(i, j int) bool { 181 - return items[i].Name() < items[j].Name() 181 + slices.SortFunc(items, func(a, b iofs.DirEntry) int { 182 + return cmp.Compare(a.Name(), b.Name()) 182 183 }) 183 184 return items, nil 184 185 }
+4 -3
cue/load/import.go
··· 15 15 package load 16 16 17 17 import ( 18 + "cmp" 18 19 "fmt" 19 20 "os" 20 21 pathpkg "path" 21 22 "path/filepath" 22 - "sort" 23 + "slices" 23 24 "strings" 24 25 25 26 "cuelang.org/go/cue/ast" ··· 199 200 l.addFiles(cfg.ModuleRoot, p) 200 201 _ = p.Complete() 201 202 } 202 - sort.Slice(all, func(i, j int) bool { 203 - return all[i].Dir < all[j].Dir 203 + slices.SortFunc(all, func(a, b *build.Instance) int { 204 + return cmp.Compare(a.Dir, b.Dir) 204 205 }) 205 206 return all 206 207 }
+11 -9
cue/load/loader_common.go
··· 16 16 17 17 import ( 18 18 "bytes" 19 + "cmp" 19 20 pathpkg "path" 20 21 "path/filepath" 22 + "slices" 21 23 "sort" 22 24 "strconv" 23 25 "strings" ··· 58 60 // normalizeFiles sorts the files so that files contained by a parent directory 59 61 // always come before files contained in sub-directories, and that filenames in 60 62 // the same directory are sorted lexically byte-wise, like Go's `<` operator. 61 - func normalizeFiles(a []*build.File) { 62 - sort.Slice(a, func(i, j int) bool { 63 - fi := a[i].Filename 64 - fj := a[j].Filename 65 - ci := strings.Count(fi, string(filepath.Separator)) 66 - cj := strings.Count(fj, string(filepath.Separator)) 67 - if ci != cj { 68 - return ci < cj 63 + func normalizeFiles(files []*build.File) { 64 + slices.SortFunc(files, func(a, b *build.File) int { 65 + fa := a.Filename 66 + fb := b.Filename 67 + ca := strings.Count(fa, string(filepath.Separator)) 68 + cb := strings.Count(fb, string(filepath.Separator)) 69 + if c := cmp.Compare(ca, cb); c != 0 { 70 + return c 69 71 } 70 - return fi < fj 72 + return cmp.Compare(fa, fb) 71 73 }) 72 74 } 73 75
+1 -1
cue/load/loader_test.go
··· 441 441 func TestLoadInstancesConcurrent(t *testing.T) { 442 442 // This test is designed to fail when run with the race detector 443 443 // if there's an underlying race condition. 444 - // See https:/cuelang.org/issue/1746 444 + // See https://cuelang.org/issue/1746 445 445 race(func() { 446 446 Instances([]string{"."}, nil) 447 447 })
+1 -1
cue/testdata/eval/issue2235.txtar
··· 1 1 // Test various orders 2 - // https//cuelang.org/issues/2235 2 + // https://cuelang.org/issues/2235 3 3 4 4 -- reductions.cue -- 5 5 // Each of these tests triggers a slightly different path.
+11 -16
internal/mod/semver/semver.go
··· 22 22 // as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0. 23 23 package semver 24 24 25 - import "sort" 25 + import ( 26 + "cmp" 27 + "slices" 28 + ) 26 29 27 30 // parsed returns the parsed form of a semantic version string. 28 31 type parsed struct { ··· 151 154 return w 152 155 } 153 156 154 - // ByVersion implements sort.Interface for sorting semantic version strings. 155 - type ByVersion []string 156 - 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 - } 166 - 167 - // Sort sorts a list of semantic version strings using ByVersion. 157 + // Sort sorts a list of semantic version strings. 168 158 func Sort(list []string) { 169 - sort.Sort(ByVersion(list)) 159 + slices.SortFunc(list, func(a, b string) int { 160 + if c := Compare(a, b); c != 0 { 161 + return c 162 + } 163 + return cmp.Compare(a, b) 164 + }) 170 165 } 171 166 172 167 func parse(v string) (p parsed, ok bool) {
+5 -4
internal/mod/semver/semver_test.go
··· 6 6 7 7 import ( 8 8 "math/rand" 9 - "sort" 9 + "slices" 10 10 "strings" 11 11 "testing" 12 12 ) ··· 16 16 out string 17 17 }{ 18 18 {"bad", ""}, 19 + {"v1+meta", ""}, 19 20 {"v1-alpha.beta.gamma", ""}, 20 21 {"v1-pre", ""}, 21 - {"v1+meta", ""}, 22 22 {"v1-pre+meta", ""}, 23 - {"v1.2-pre", ""}, 24 23 {"v1.2+meta", ""}, 24 + {"v1.2-pre", ""}, 25 25 {"v1.2-pre+meta", ""}, 26 26 {"v1.0.0-alpha", "v1.0.0-alpha"}, 27 27 {"v1.0.0-alpha.1", "v1.0.0-alpha.1"}, ··· 161 161 for i, test := range tests { 162 162 versions[i] = test.in 163 163 } 164 + sortedVersions := slices.Clone(versions) 164 165 rand.Shuffle(len(versions), func(i, j int) { versions[i], versions[j] = versions[j], versions[i] }) 165 166 Sort(versions) 166 - if !sort.IsSorted(ByVersion(versions)) { 167 + if !slices.Equal(versions, sortedVersions) { 167 168 t.Errorf("list is not sorted:\n%s", strings.Join(versions, "\n")) 168 169 } 169 170 }
+15 -16
mod/module/module.go
··· 80 80 // security, network, and file system representations. 81 81 82 82 import ( 83 + "cmp" 83 84 "fmt" 84 - "sort" 85 + "slices" 85 86 "strings" 86 87 87 88 "cuelang.org/go/internal/mod/semver" ··· 246 247 // optionally followed by a tie-breaking suffix introduced by a slash character, 247 248 // like in "v0.0.1/module.cue". 248 249 func Sort(list []Version) { 249 - sort.Slice(list, func(i, j int) bool { 250 - mi := list[i] 251 - mj := list[j] 252 - if mi.path != mj.path { 253 - return mi.path < mj.path 250 + slices.SortFunc(list, func(a, b Version) int { 251 + if c := cmp.Compare(a.path, b.path); c != 0 { 252 + return c 254 253 } 255 254 // To help go.sum formatting, allow version/file. 256 255 // Compare semver prefix by semver rules, 257 256 // file by string order. 258 - vi := mi.version 259 - vj := mj.version 260 - var fi, fj string 261 - if k := strings.Index(vi, "/"); k >= 0 { 262 - vi, fi = vi[:k], vi[k:] 257 + va := a.version 258 + vb := b.version 259 + var fa, fb string 260 + if k := strings.Index(va, "/"); k >= 0 { 261 + va, fa = va[:k], va[k:] 263 262 } 264 - if k := strings.Index(vj, "/"); k >= 0 { 265 - vj, fj = vj[:k], vj[k:] 263 + if k := strings.Index(vb, "/"); k >= 0 { 264 + vb, fb = vb[:k], vb[k:] 266 265 } 267 - if vi != vj { 268 - return semver.Compare(vi, vj) < 0 266 + if c := semver.Compare(va, vb); c != 0 { 267 + return c 269 268 } 270 - return fi < fj 269 + return cmp.Compare(fa, fb) 271 270 }) 272 271 }