blob: 63e2ea40b117f0404f50ed74611dff111153eccb [file] [log] [blame]
// 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 int8
//go:generate stringer -type AlgKind -trimprefix A alg.go
const (
AUNK AlgKind = iota
ANOEQ // Types cannot be compared
ANOALG // implies ANOEQ, and in addition has a part that is marked Noalg
AMEM // Type can be compared/hashed as regular memory.
AMEM0 // Specific subvariants of AMEM (TODO: move to ../reflectdata?)
AMEM8
AMEM16
AMEM32
AMEM64
AMEM128
ASTRING
AINTER
ANILINTER
AFLOAT32
AFLOAT64
ACPLX64
ACPLX128
ASPECIAL // Type needs special comparison/hashing functions.
)
// Most kinds are priority 0. Higher numbers are higher priority, in that
// the higher priority kinds override lower priority kinds.
var algPriority = [ASPECIAL + 1]int8{ASPECIAL: 1, ANOEQ: 2, ANOALG: 3, AMEM: -1}
// setAlg sets the algorithm type of t to a, if it is of higher
// priority to the current algorithm type.
func (t *Type) setAlg(a AlgKind) {
if t.alg == AUNK {
base.Fatalf("setAlg(%v,%s) starting with unknown priority", t, a)
}
if algPriority[a] > algPriority[t.alg] {
t.alg = a
} else if a != t.alg && algPriority[a] == algPriority[t.alg] {
base.Fatalf("ambiguous priority %s and %s", a, t.alg)
}
}
// AlgType returns the AlgKind used for comparing and hashing Type t.
func AlgType(t *Type) AlgKind {
CalcSize(t)
return t.alg
}
// 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 {
return AlgType(t) == ANOALG
}
// IsComparable reports whether t is a comparable type.
func IsComparable(t *Type) bool {
a := AlgType(t)
return a != ANOEQ && a != ANOALG
}
// IncomparableField returns an incomparable Field of struct Type t, if any.
func IncomparableField(t *Type) *Field {
for _, f := range t.Fields() {
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
}