x/model: introduce Name.CompareFold with example

This commit is contained in:
Blake Mizerany 2024-04-05 21:30:46 -07:00
parent 1c04951cac
commit e1de015fbc
2 changed files with 58 additions and 6 deletions

View File

@ -262,6 +262,44 @@ func (r Name) Complete() bool {
return !slices.Contains(r.Parts(), "")
}
// EqualFold reports whether r and o are equivalent model names, ignoring
// case.
func (r Name) EqualFold(o Name) bool {
return r.CompareFold(o) == 0
}
// CompareFold performs a case-insensitive comparison of two Names. It returns
// an integer comparing two Names lexicographically. The result will be 0 if
// r == o, -1 if r < o, and +1 if r > o.
//
// This can be used with [slice.SortFunc].
func (r Name) CompareFold(o Name) int {
return cmp.Or(
compareFold(r.host, o.host),
compareFold(r.namespace, o.namespace),
compareFold(r.model, o.model),
compareFold(r.tag, o.tag),
compareFold(r.build, o.build),
)
}
func compareFold(a, b string) int {
for i := 0; i < len(a) && i < len(b); i++ {
ca, cb := downcase(a[i]), downcase(b[i])
if n := cmp.Compare(ca, cb); n != 0 {
return n
}
}
return cmp.Compare(len(a), len(b))
}
func downcase(c byte) byte {
if c >= 'A' && c <= 'Z' {
return c + 'a' - 'A'
}
return c
}
// TODO(bmizerany): Compare
// TODO(bmizerany): MarshalText/UnmarshalText
// TODO(bmizerany): LogValue
@ -280,12 +318,6 @@ func (r Name) Parts() []string {
}
}
// EqualFold reports whether r and o are equivalent model names, ignoring
// case.
func (r Name) EqualFold(o Name) bool {
return r.MapHash() == o.MapHash()
}
// Parts returns a sequence of the parts of a Name string from most specific
// to least specific.
//

View File

@ -2,6 +2,7 @@ package model
import (
"fmt"
"slices"
"strings"
"testing"
)
@ -339,4 +340,23 @@ func ExampleName_MapHash() {
// 2
}
func ExampleName_CompareFold_sort() {
names := []Name{
ParseName("mistral:latest"),
ParseName("mistRal:7b+q4"),
ParseName("MIstral:7b"),
}
slices.SortFunc(names, Name.CompareFold)
for _, n := range names {
fmt.Println(n)
}
// Output:
// MIstral:7b
// mistRal:7b+q4
// mistral:latest
}
func keep[T any](v T) T { return v }