1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package types
6
7import "cmd/compile/internal/base"
8
9// AlgKind describes the kind of algorithms used for comparing and
10// hashing a Type.
11type AlgKind int8
12
13//go:generate stringer -type AlgKind -trimprefix A alg.go
14
15const (
16	AUNK   AlgKind = iota
17	ANOEQ          // Types cannot be compared
18	ANOALG         // implies ANOEQ, and in addition has a part that is marked Noalg
19	AMEM           // Type can be compared/hashed as regular memory.
20	AMEM0          // Specific subvariants of AMEM (TODO: move to ../reflectdata?)
21	AMEM8
22	AMEM16
23	AMEM32
24	AMEM64
25	AMEM128
26	ASTRING
27	AINTER
28	ANILINTER
29	AFLOAT32
30	AFLOAT64
31	ACPLX64
32	ACPLX128
33	ASPECIAL // Type needs special comparison/hashing functions.
34)
35
36// Most kinds are priority 0. Higher numbers are higher priority, in that
37// the higher priority kinds override lower priority kinds.
38var algPriority = [ASPECIAL + 1]int8{ASPECIAL: 1, ANOEQ: 2, ANOALG: 3, AMEM: -1}
39
40// setAlg sets the algorithm type of t to a, if it is of higher
41// priority to the current algorithm type.
42func (t *Type) setAlg(a AlgKind) {
43	if t.alg == AUNK {
44		base.Fatalf("setAlg(%v,%s) starting with unknown priority", t, a)
45	}
46	if algPriority[a] > algPriority[t.alg] {
47		t.alg = a
48	} else if a != t.alg && algPriority[a] == algPriority[t.alg] {
49		base.Fatalf("ambiguous priority %s and %s", a, t.alg)
50	}
51}
52
53// AlgType returns the AlgKind used for comparing and hashing Type t.
54func AlgType(t *Type) AlgKind {
55	CalcSize(t)
56	return t.alg
57}
58
59// TypeHasNoAlg reports whether t does not have any associated hash/eq
60// algorithms because t, or some component of t, is marked Noalg.
61func TypeHasNoAlg(t *Type) bool {
62	return AlgType(t) == ANOALG
63}
64
65// IsComparable reports whether t is a comparable type.
66func IsComparable(t *Type) bool {
67	a := AlgType(t)
68	return a != ANOEQ && a != ANOALG
69}
70
71// IncomparableField returns an incomparable Field of struct Type t, if any.
72func IncomparableField(t *Type) *Field {
73	for _, f := range t.Fields() {
74		if !IsComparable(f.Type) {
75			return f
76		}
77	}
78	return nil
79}
80
81// IsPaddedField reports whether the i'th field of struct type t is followed
82// by padding.
83func IsPaddedField(t *Type, i int) bool {
84	if !t.IsStruct() {
85		base.Fatalf("IsPaddedField called non-struct %v", t)
86	}
87	end := t.width
88	if i+1 < t.NumFields() {
89		end = t.Field(i + 1).Offset
90	}
91	return t.Field(i).End() != end
92}
93