golang alg 代码
文件路径:/src/cmd/compile/internal/types/alg.go
/ Copyright 2016 The Go Authors. All rights reserved.
/ Use of this source code is governed by a BSD-style
/ license that can be found in the LICENSE file.
package types
import "cmd/compile/internal/base"
/ AlgKind describes the kind of algorithms used for comparing and
/ hashing a Type.
type AlgKind int
/go:generate stringer -type AlgKind -trimprefix A alg.go
const (
/ These values are known by runtime.
ANOEQ AlgKind = iota
AMEM0
AMEM8
AMEM16
AMEM32
AMEM64
AMEM128
ASTRING
AINTER
ANILINTER
AFLOAT32
AFLOAT64
ACPLX64
ACPLX128
/ Type can be compared/hashed as regular memory.
AMEM AlgKind = 100
/ Type needs special comparison/hashing functions.
ASPECIAL AlgKind = -1
)
/ AlgType returns the AlgKind used for comparing and hashing Type t.
/ If it returns ANOEQ, it also returns the component type of t that
/ makes it incomparable.
func AlgType(t *Type) (AlgKind, *Type) {
if t.Noalg() {
return ANOEQ, t
}
switch t.Kind() {
case TANY, TFORW:
/ will be defined later.
return ANOEQ, t
case TINT8, TUINT8, TINT16, TUINT16,
TINT32, TUINT32, TINT64, TUINT64,
TINT, TUINT, TUINTPTR,
TBOOL, TPTR,
TCHAN, TUNSAFEPTR:
return AMEM, nil
case TFUNC, TMAP:
return ANOEQ, t
case TFLOAT32:
return AFLOAT32, nil
case TFLOAT64:
return AFLOAT64, nil
case TCOMPLEX64:
return ACPLX64, nil
case TCOMPLEX128:
return ACPLX128, nil
case TSTRING:
return ASTRING, nil
case TINTER:
if t.IsEmptyInterface() {
return ANILINTER, nil
}
return AINTER, nil
case TSLICE:
return ANOEQ, t
case TARRAY:
a, bad := AlgType(t.Elem())
switch a {
case AMEM:
return AMEM, nil
case ANOEQ:
return ANOEQ, bad
}
switch t.NumElem() {
case 0:
/ We checked above that the element type is comparable.
return AMEM, nil
case 1:
/ Single-element array is same as its lone element.
return a, nil
}
return ASPECIAL, nil
case TSTRUCT:
fields := t.FieldSlice()
/ One-field struct is same as that one field alone.
if len(fields) == 1 && !fields[0].Sym.IsBlank() {
return AlgType(fields[0].Type)
}
ret := AMEM
for i, f := range fields {
/ All fields must be comparable.
a, bad := AlgType(f.Type)
if a == ANOEQ {
return ANOEQ, bad
}
/ Blank fields, padded fields, fields with non-memory
/ equality need special compare.
if a != AMEM || f.Sym.IsBlank() || IsPaddedField(t, i) {
ret = ASPECIAL
}
}
return ret, nil
}
base.Fatalf("AlgType: unexpected type %v", t)
return 0, nil
}
/ TypeHasNoAlg reports whether t does not have any associated hash/eq
/ algorithms because t, or some component of t, is marked Noalg.
func TypeHasNoAlg(t *Type) bool {
a, bad := AlgType(t)
return a == ANOEQ && bad.Noalg()
}
/ IsComparable reports whether t is a comparable type.
func IsComparable(t *Type) bool {
a, _ := AlgType(t)
return a != ANOEQ
}
/ IncomparableField returns an incomparable Field of struct Type t, if any.
func IncomparableField(t *Type) *Field {
for _, f := range t.FieldSlice() {
if !IsComparable(f.Type) {
return f
}
}
return nil
}
/ IsPaddedField reports whether the i'th field of struct type t is followed
/ by padding.
func IsPaddedField(t *Type, i int) bool {
if !t.IsStruct() {
base.Fatalf("IsPaddedField called non-struct %v", t)
}
end := t.width
if i+1 < t.NumFields() {
end = t.Field(i + 1).Offset
}
return t.Field(i).End() != end
}