pkg/semver/identifiers.go (64 lines of code) (raw):
package semver
import "strconv"
// identifier represents a single identifier in a semver version.
// identifiers are dot separated strings or numbers in the pre release
// and build metadata.
type identifier struct {
intValue uint64
strValue string
isNum bool
}
func newIdentifier(s string) identifier {
bi := identifier{}
if num, err := strconv.ParseUint(s, 10, 64); err == nil {
bi.intValue = num
bi.isNum = true
} else {
bi.strValue = s
bi.isNum = false
}
return bi
}
// compare compares v and o.
// -1 == v is less than o.
// 0 == v is equal to o.
// 1 == v is greater than o.
// 2 == v is different than o (it is not possible to identify if lower or greater).
// Number is considered lower than string.
func (v identifier) compare(o identifier) int {
if v.isNum && !o.isNum {
return -1
}
if !v.isNum && o.isNum {
return 1
}
if v.isNum && o.isNum { // both are numbers
switch {
case v.intValue < o.intValue:
return -1
case v.intValue == o.intValue:
return 0
default:
return 1
}
} else { // both are strings
if v.strValue == o.strValue {
return 0
}
// In order to support random identifiers, like commit hashes,
// we return 2 when the strings are different to signal the
// identifiers are different but we can't determine the precedence
return 2
}
}
type identifiers []identifier
func newIdentifiers(ids []string) identifiers {
bis := make(identifiers, 0, len(ids))
for _, id := range ids {
bis = append(bis, newIdentifier(id))
}
return bis
}
// compare compares 2 identifiers v and o.
// -1 == v is less than o.
// 0 == v is equal to o.
// 1 == v is greater than o.
// If everything else is equal the longer identifier is greater.
func (v identifiers) compare(o identifiers) int {
i := 0
for ; i < len(v) && i < len(o); i++ {
comp := v[i].compare(o[i])
if comp != 0 {
return comp
}
}
// if everything is equal until now the longer is greater
if i == len(v) && i == len(o) {
return 0
} else if i == len(v) && i < len(o) {
return -1
}
return 1
}