diff --git a/bitswap/client/wantlist/wantlist.go b/bitswap/client/wantlist/wantlist.go index a79dbd9fc..20432a2b1 100644 --- a/bitswap/client/wantlist/wantlist.go +++ b/bitswap/client/wantlist/wantlist.go @@ -3,7 +3,8 @@ package wantlist import ( - "sort" + "cmp" + "slices" pb "github.com/ipfs/boxo/bitswap/message/pb" @@ -34,12 +35,6 @@ func NewRefEntry(c cid.Cid, p int32) Entry { } } -type entrySlice []Entry - -func (es entrySlice) Len() int { return len(es) } -func (es entrySlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] } -func (es entrySlice) Less(i, j int) bool { return es[i].Priority > es[j].Priority } - // New generates a new raw Wantlist func New() *Wantlist { return &Wantlist{ @@ -125,7 +120,9 @@ func (w *Wantlist) Entries() []Entry { for _, e := range w.set { es = append(es, e) } - sort.Sort(entrySlice(es)) + slices.SortFunc(es, func(a, b Entry) int { + return cmp.Compare(b.Priority, a.Priority) + }) w.cached = es return es[0:len(es):len(es)] } diff --git a/bitswap/server/server.go b/bitswap/server/server.go index 5bb277dfb..6a2ceb3f9 100644 --- a/bitswap/server/server.go +++ b/bitswap/server/server.go @@ -4,7 +4,7 @@ import ( "context" "errors" "fmt" - "sort" + "slices" "sync" "time" @@ -383,7 +383,7 @@ func (bs *Server) Stat() (Stat, error) { for i, p := range peers { peersStr[i] = p.String() } - sort.Strings(peersStr) + slices.Sort(peersStr) s.Peers = peersStr return s, nil diff --git a/files/serialfile_test.go b/files/serialfile_test.go index 2f08bada0..e07a288b3 100644 --- a/files/serialfile_test.go +++ b/files/serialfile_test.go @@ -6,7 +6,7 @@ import ( "io" "os" "path/filepath" - "sort" + "slices" "strings" "testing" ) @@ -96,7 +96,7 @@ testInputs: } } - sort.Strings(expectedPaths) + slices.Sort(expectedPaths) stat, err := os.Stat(tmppath) if err != nil { diff --git a/filestore/util.go b/filestore/util.go index 80bec61fd..21900f055 100644 --- a/filestore/util.go +++ b/filestore/util.go @@ -1,9 +1,11 @@ package filestore import ( + "cmp" "context" "fmt" - "sort" + "slices" + "strings" pb "github.com/ipfs/boxo/filestore/pb" @@ -177,7 +179,7 @@ func listAllFileOrder(ctx context.Context, fs *Filestore, verify bool) (func(con return nil, err } - var entries listEntries + var entries []*listEntry for { v, ok := qr.NextSync() @@ -199,7 +201,15 @@ func listAllFileOrder(ctx context.Context, fs *Filestore, verify bool) (func(con }) } } - sort.Sort(entries) + slices.SortFunc(entries, func(a, b *listEntry) int { + if a.filePath == b.filePath { + if a.offset == b.offset { + return strings.Compare(a.dsKey, b.dsKey) + } + return cmp.Compare(a.offset, b.offset) + } + return strings.Compare(a.filePath, b.filePath) + }) i := 0 return func(ctx context.Context) *ListRes { @@ -243,20 +253,6 @@ type listEntry struct { err error } -type listEntries []*listEntry - -func (l listEntries) Len() int { return len(l) } -func (l listEntries) Swap(i, j int) { l[i], l[j] = l[j], l[i] } -func (l listEntries) Less(i, j int) bool { - if l[i].filePath == l[j].filePath { - if l[i].offset == l[j].offset { - return l[i].dsKey < l[j].dsKey - } - return l[i].offset < l[j].offset - } - return l[i].filePath < l[j].filePath -} - func mkListRes(m mh.Multihash, d *pb.DataObj, err error) *ListRes { status := StatusOk errorMsg := "" diff --git a/gateway/headers.go b/gateway/headers.go index 66ad5d43a..cb279d456 100644 --- a/gateway/headers.go +++ b/gateway/headers.go @@ -2,7 +2,7 @@ package gateway import ( "net/http" - "sort" + "slices" ) // Headers is an HTTP middleware that sets the configured headers in all requests. @@ -106,7 +106,6 @@ func cleanHeaderSet(headers []string) []string { result = append(result, k) } - // Sort - sort.Strings(result) + slices.Sort(result) return result } diff --git a/ipld/merkledag/coding.go b/ipld/merkledag/coding.go index a455a6a44..fb7d18c3d 100644 --- a/ipld/merkledag/coding.go +++ b/ipld/merkledag/coding.go @@ -3,7 +3,7 @@ package merkledag import ( "errors" "fmt" - "sort" + "slices" "strings" pb "github.com/ipfs/boxo/ipld/merkledag/pb" @@ -24,14 +24,6 @@ const _ = pb.DoNotUpgradeFileEverItWillChangeYourHashes // for now, we use a PBNode intermediate thing. // because native go objects are nice. -// pbLinkSlice is a slice of pb.PBLink, similar to LinkSlice but for sorting the -// PB form -type pbLinkSlice []*pb.PBLink - -func (pbls pbLinkSlice) Len() int { return len(pbls) } -func (pbls pbLinkSlice) Swap(a, b int) { pbls[a], pbls[b] = pbls[b], pbls[a] } -func (pbls pbLinkSlice) Less(a, b int) bool { return *pbls[a].Name < *pbls[b].Name } - // unmarshal decodes raw data into a *Node instance. // The conversion uses an intermediate PBNode. func unmarshal(encodedBytes []byte) (*ProtoNode, error) { @@ -148,7 +140,9 @@ func (n *ProtoNode) GetPBNode() *pb.PBNode { // Ensure links are sorted prior to encode, regardless of `linksDirty`. They // may not have come sorted if we deserialized a badly encoded form that // didn't have links already sorted. - sort.Stable(pbLinkSlice(pbn.Links)) + slices.SortStableFunc(pbn.Links, func(a, b *pb.PBLink) int { + return strings.Compare(*a.Name, *b.Name) + }) if len(n.data) > 0 { pbn.Data = n.data @@ -163,7 +157,7 @@ func (n *ProtoNode) EncodeProtobuf(force bool) ([]byte, error) { if n.linksDirty { // there was a mutation involving links, make sure we sort before we build // and cache a `Node` form that captures the current state - sort.Stable(LinkSlice(n.links)) + n.sortLinks() n.linksDirty = false } n.cached = cid.Undef diff --git a/ipld/merkledag/node.go b/ipld/merkledag/node.go index 782d7c4ef..3ef445198 100644 --- a/ipld/merkledag/node.go +++ b/ipld/merkledag/node.go @@ -6,7 +6,8 @@ import ( "errors" "fmt" "math" - "sort" + "slices" + "strings" blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" @@ -147,13 +148,6 @@ func checkHasher(indicator uint64, sizeHint int) error { return err } -// LinkSlice is a slice of format.Links -type LinkSlice []*format.Link - -func (ls LinkSlice) Len() int { return len(ls) } -func (ls LinkSlice) Swap(a, b int) { ls[a], ls[b] = ls[b], ls[a] } -func (ls LinkSlice) Less(a, b int) bool { return ls[a].Name < ls[b].Name } - // NodeWithData builds a new Protonode with the given data. func NodeWithData(d []byte) *ProtoNode { return &ProtoNode{data: d} @@ -289,7 +283,7 @@ func (n *ProtoNode) Copy() format.Node { // Sort links regardless of linksDirty state, this may have come from a // serialized form that had badly sorted links, in which case linksDirty // will not be true. - sort.Stable(LinkSlice(nnode.links)) + nnode.sortLinks() } nnode.builder = n.builder @@ -424,7 +418,7 @@ func checkLink(lnk *format.Link) error { func (n *ProtoNode) MarshalJSON() ([]byte, error) { if n.linksDirty { // there was a mutation involving links, make sure we sort - sort.Stable(LinkSlice(n.links)) + n.sortLinks() n.linksDirty = false n.encoded = nil } @@ -489,7 +483,7 @@ func (n *ProtoNode) Multihash() mh.Multihash { func (n *ProtoNode) Links() []*format.Link { if n.linksDirty { // there was a mutation involving links, make sure we sort - sort.Stable(LinkSlice(n.links)) + n.sortLinks() n.linksDirty = false n.encoded = nil } @@ -541,7 +535,7 @@ func (n *ProtoNode) Tree(p string, depth int) []string { if n.linksDirty { // there was a mutation involving links, make sure we sort - sort.Stable(LinkSlice(n.links)) + n.sortLinks() n.linksDirty = false n.encoded = nil } @@ -553,6 +547,12 @@ func (n *ProtoNode) Tree(p string, depth int) []string { return out } +func (n *ProtoNode) sortLinks() { + slices.SortStableFunc(n.links, func(a, b *format.Link) int { + return strings.Compare(a.Name, b.Name) + }) +} + func ProtoNodeConverter(b blocks.Block, nd ipld.Node) (legacy.UniversalNode, error) { pbNode, ok := nd.(dagpb.PBNode) if !ok { diff --git a/ipld/unixfs/hamt/hamt_test.go b/ipld/unixfs/hamt/hamt_test.go index 16b325773..009dbc258 100644 --- a/ipld/unixfs/hamt/hamt_test.go +++ b/ipld/unixfs/hamt/hamt_test.go @@ -6,8 +6,9 @@ import ( "fmt" "math/rand" "os" - "sort" + "slices" "strconv" + "strings" "testing" "time" @@ -60,6 +61,12 @@ func makeDirWidth(ds ipld.DAGService, size, width int) ([]string, *Shard, error) return dirs, s, nil } +func sortLinks(links []*ipld.Link) { + slices.SortStableFunc(links, func(a, b *ipld.Link) int { + return strings.Compare(a.Name, b.Name) + }) +} + func assertLink(s *Shard, name string, found bool) error { _, err := s.Find(context.Background(), name) switch err { @@ -85,8 +92,8 @@ func assertLinksEqual(linksA []*ipld.Link, linksB []*ipld.Link) error { return errors.New("links arrays are different sizes") } - sort.Stable(dag.LinkSlice(linksA)) - sort.Stable(dag.LinkSlice(linksB)) + sortLinks(linksA) + sortLinks(linksB) for i, a := range linksA { b := linksB[i] if a.Name != b.Name { @@ -513,7 +520,7 @@ func TestRemoveElemsAfterMarshal(t *testing.T) { } ctx := context.Background() - sort.Strings(dirs) + slices.Sort(dirs) err = s.Remove(ctx, dirs[0]) if err != nil { diff --git a/ipld/unixfs/io/directory_test.go b/ipld/unixfs/io/directory_test.go index e39cd5b3e..480aaa592 100644 --- a/ipld/unixfs/io/directory_test.go +++ b/ipld/unixfs/io/directory_test.go @@ -4,7 +4,7 @@ import ( "context" "fmt" "math" - "sort" + "slices" "strconv" "strings" "sync" @@ -438,9 +438,9 @@ func getAllLinksSortedByName(d Directory) ([]*ipld.Link, error) { return entries, nil } -func sortLinksByName(l []*ipld.Link) { - sort.SliceStable(l, func(i, j int) bool { - return strings.Compare(l[i].Name, l[j].Name) == -1 // FIXME: Is this correct? +func sortLinksByName(links []*ipld.Link) { + slices.SortStableFunc(links, func(a, b *ipld.Link) int { + return strings.Compare(a.Name, b.Name) }) } diff --git a/ipns/record.go b/ipns/record.go index 147190a3b..2c7d4673d 100644 --- a/ipns/record.go +++ b/ipns/record.go @@ -3,9 +3,11 @@ package ipns import ( "bytes" + "cmp" "errors" "fmt" - "sort" + "slices" + "strings" "time" ipns_pb "github.com/ipfs/boxo/ipns/pb" @@ -321,12 +323,12 @@ func createNode(value path.Path, seq uint64, eol time.Time, ttl time.Duration) ( m[cborTTLKey] = basicnode.NewInt(int64(ttl)) keys = append(keys, cborTTLKey) - sort.Slice(keys, func(i, j int) bool { - li, lj := len(keys[i]), len(keys[j]) - if li == lj { - return keys[i] < keys[j] + slices.SortFunc(keys, func(a, b string) int { + la, lb := len(a), len(b) + if la == lb { + return strings.Compare(a, b) } - return li < lj + return cmp.Compare(la, lb) }) newNd := basicnode.Prototype__Map{}.NewBuilder() diff --git a/keystore/keystore_test.go b/keystore/keystore_test.go index 6d9bf6960..dd87baa92 100644 --- a/keystore/keystore_test.go +++ b/keystore/keystore_test.go @@ -6,7 +6,7 @@ import ( "fmt" "os" "path/filepath" - "sort" + "slices" "testing" ci "github.com/libp2p/go-libp2p/core/crypto" @@ -60,7 +60,7 @@ func TestKeystoreBasics(t *testing.T) { t.Fatal(err) } - sort.Strings(l) + slices.Sort(l) if l[0] != "bar" || l[1] != "foo" { t.Fatal("wrong entries listed") } @@ -179,7 +179,7 @@ func TestInvalidKeyFiles(t *testing.T) { t.Fatal(err) } - sort.Strings(l) + slices.Sort(l) if len(l) != 1 { t.Fatal("wrong entry count") } @@ -256,8 +256,8 @@ func assertDirContents(dir string, exp []string) error { names = append(names, decodedName) } - sort.Strings(names) - sort.Strings(exp) + slices.Sort(names) + slices.Sort(exp) if len(names) != len(exp) { return errors.New("directory had wrong number of entries in it") } diff --git a/keystore/memkeystore_test.go b/keystore/memkeystore_test.go index 907cbbd0e..667e09eb8 100644 --- a/keystore/memkeystore_test.go +++ b/keystore/memkeystore_test.go @@ -1,7 +1,7 @@ package keystore import ( - "sort" + "slices" "testing" ) @@ -37,7 +37,7 @@ func TestMemKeyStoreBasics(t *testing.T) { t.Fatal(err) } - sort.Strings(l) + slices.Sort(l) if l[0] != "bar" || l[1] != "foo" { t.Fatal("wrong entries listed") } diff --git a/mfs/mfs_test.go b/mfs/mfs_test.go index ee2726160..cf56f9d73 100644 --- a/mfs/mfs_test.go +++ b/mfs/mfs_test.go @@ -12,7 +12,7 @@ import ( "os" gopath "path" "runtime" - "sort" + "slices" "strings" "sync" "testing" @@ -117,8 +117,8 @@ func assertDirAtPath(root *Directory, pth string, children []string) error { names = append(names, d.Name) } - sort.Strings(children) - sort.Strings(names) + slices.Sort(children) + slices.Sort(names) if !compStrArrs(children, names) { return errors.New("directories children did not match") } @@ -259,7 +259,7 @@ func TestMkdir(t *testing.T) { rootdir := rt.GetDirectory() dirsToMake := []string{"a", "B", "foo", "bar", "cats", "fish"} - sort.Strings(dirsToMake) // sort for easy comparing later + slices.Sort(dirsToMake) // sort for easy comparing later for _, d := range dirsToMake { _, err := rootdir.Mkdir(d) diff --git a/routing/http/client/client.go b/routing/http/client/client.go index 5baacfba2..ca9841946 100644 --- a/routing/http/client/client.go +++ b/routing/http/client/client.go @@ -10,7 +10,7 @@ import ( "mime" "net/http" gourl "net/url" - "sort" + "slices" "strings" "time" @@ -107,7 +107,7 @@ func WithDisabledLocalFiltering(val bool) Option { // The protocols are ordered alphabetically for cache key (url) consistency func WithProtocolFilter(protocolFilter []string) Option { return func(c *Client) error { - sort.Strings(protocolFilter) + slices.Sort(protocolFilter) c.protocolFilter = protocolFilter return nil } @@ -118,7 +118,7 @@ func WithProtocolFilter(protocolFilter []string) Option { // The addresses are ordered alphabetically for cache key (url) consistency func WithAddrFilter(addrFilter []string) Option { return func(c *Client) error { - sort.Strings(addrFilter) + slices.Sort(addrFilter) c.addrFilter = addrFilter return nil }