return s
}
-/*
- * Returns 1 if t has a reflexive equality operator.
- * That is, if x==x for all x of type t.
- */
+// isreflexive reports whether t has a reflexive equality operator.
+// That is, if x==x for all x of type t.
func isreflexive(t *Type) bool {
switch t.Etype {
case TBOOL,
return false
}
}
-
return true
default:
}
}
+// needkeyupdate reports whether map updates with t as a key
+// need the key to be updated.
+func needkeyupdate(t *Type) bool {
+ switch t.Etype {
+ case TBOOL,
+ TINT,
+ TUINT,
+ TINT8,
+ TUINT8,
+ TINT16,
+ TUINT16,
+ TINT32,
+ TUINT32,
+ TINT64,
+ TUINT64,
+ TUINTPTR,
+ TPTR32,
+ TPTR64,
+ TUNSAFEPTR,
+ TCHAN:
+ return false
+
+ case TFLOAT32, // floats can be +0/-0
+ TFLOAT64,
+ TCOMPLEX64,
+ TCOMPLEX128,
+ TINTER,
+ TSTRING: // strings might have smaller backing stores
+ return true
+
+ case TARRAY:
+ if Isslice(t) {
+ Fatalf("slice can't be a map key: %v", t)
+ }
+ return needkeyupdate(t.Type)
+
+ case TSTRUCT:
+ for t1 := t.Type; t1 != nil; t1 = t1.Down {
+ if needkeyupdate(t1.Type) {
+ return true
+ }
+ }
+ return false
+
+ default:
+ Fatalf("bad type for map key: %v", t)
+ return true
+ }
+}
+
func dtypesym(t *Type) *Sym {
// Replace byte, rune aliases with real type.
// They've been separate internally to make error messages
ot = duint16(s, ot, uint16(mapbucket(t).Width))
ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down))))
+ ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down))))
case TPTR32, TPTR64:
if t.Type.Etype == TANY {
indirectvalue uint8 // store ptr to value instead of value itself
bucketsize uint16 // size of bucket
reflexivekey bool // true if k==k for all keys
+ needkeyupdate bool // true if we need to update key on an overwrite
}
// ptrType represents a pointer type.
}
mt.bucketsize = uint16(mt.bucket.size)
mt.reflexivekey = isReflexive(ktyp)
+ mt.needkeyupdate = needKeyUpdate(ktyp)
mt.uncommonType = nil
mt.ptrToThis = nil
}
}
+// needKeyUpdate reports whether map overwrites require the key to be copied.
+func needKeyUpdate(t *rtype) bool {
+ switch t.Kind() {
+ case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Ptr, UnsafePointer:
+ return false
+ case Float32, Float64, Complex64, Complex128, Interface, String:
+ // Float keys can be updated from +0 to -0.
+ // String keys can be updated to use a smaller backing store.
+ // Interfaces might have floats of strings in them.
+ return true
+ case Array:
+ tt := (*arrayType)(unsafe.Pointer(t))
+ return needKeyUpdate(tt.elem)
+ case Struct:
+ tt := (*structType)(unsafe.Pointer(t))
+ for _, f := range tt.fields {
+ if needKeyUpdate(f.typ) {
+ return true
+ }
+ }
+ return false
+ default:
+ // Func, Map, Slice, Invalid
+ panic("needKeyUpdate called on non-key type " + t.String())
+ }
+}
+
// Make sure these routines stay in sync with ../../runtime/hashmap.go!
// These types exist only for GC, so we only fill out GC relevant info.
// Currently, that's just size and the GC program. We also fill in string