Пример #1
0
func init() {
	typ := reflect.TypeOf(composite{})
	alg := reflect.ValueOf(typ).Elem().FieldByName("alg").Elem()
	// Pretty certain that doing this voids your warranty.
	// This overwrites the typeAlg of either alg_NOEQ64 (on 32-bit platforms)
	// or alg_NOEQ128 (on 64-bit platforms), which means that all unhashable
	// types that were using this typeAlg are now suddenly hashable and will
	// attempt to use our equal/hash functions, which will lead to undefined
	// behaviors.  But then these types shouldn't have been hashable in the
	// first place, so no one should have attempted to use them as keys in a
	// map.  The compiler will emit an error if it catches someone trying to
	// do this, but if they do it through a map that uses an interface type as
	// the key, then the compiler can't catch it.
	// To prevent this we could instead override the alg pointer in the type,
	// but it's in a read-only data section in the binary (it's put there by
	// dcommontype() in gc/reflect.go), so changing it is also not without
	// perils.  Basically: Here Be Dragons.
	areflect.ForceExport(alg.FieldByName("hash")).Set(reflect.ValueOf(hash))
	areflect.ForceExport(alg.FieldByName("equal")).Set(reflect.ValueOf(equal))
}
Пример #2
0
func prettyPrintWithType(v reflect.Value, done ptrSet, depth int, showType bool) string {
	if depth < 0 {
		return "<max_depth>"
	}
	switch v.Kind() {
	case reflect.Invalid:
		return "nil"
	case reflect.Bool:
		return fmt.Sprintf("%t", v.Bool())
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Float32, reflect.Float64,
		reflect.Int, reflect.Uint, reflect.Uintptr,
		reflect.Complex64, reflect.Complex128:
		i := areflect.ForceExport(v).Interface()
		if showType {
			return fmt.Sprintf("%s(%v)", v.Type().Name(), i)
		}
		return fmt.Sprintf("%v", i)
	case reflect.String:
		return fmt.Sprintf("%q", v.String())
	case reflect.Ptr:
		return "*" + prettyPrintWithType(v.Elem(), done, depth-1, showType)
	case reflect.Interface:
		return prettyPrintWithType(v.Elem(), done, depth-1, showType)
	case reflect.Map:
		var r []byte
		r = append(r, []byte(v.Type().String())...)
		r = append(r, '{')
		var elems mapEntries
		for _, k := range v.MapKeys() {
			elem := &mapEntry{
				k: prettyPrint(k, done, depth-1),
				v: prettyPrint(v.MapIndex(k), done, depth-1),
			}
			elems.entries = append(elems.entries, elem)
		}
		sort.Sort(&elems)
		for i, e := range elems.entries {
			if i > 0 {
				r = append(r, []byte(", ")...)
			}
			r = append(r, []byte(e.k)...)
			r = append(r, ':')
			r = append(r, []byte(e.v)...)
		}
		r = append(r, '}')
		return string(r)
	case reflect.Struct:
		// Circular dependency?
		if v.CanAddr() {
			ptr := v.UnsafeAddr()
			if _, ok := done[ptr]; ok {
				return fmt.Sprintf("%s{<circular dependency>}", v.Type().String())
			}
			done[ptr] = struct{}{}
		}
		var r []byte
		r = append(r, []byte(v.Type().String())...)
		r = append(r, '{')
		for i := 0; i < v.NumField(); i++ {
			if i > 0 {
				r = append(r, []byte(", ")...)
			}
			sf := v.Type().Field(i)
			r = append(r, sf.Name...)
			r = append(r, ':')
			r = append(r, prettyPrint(v.Field(i), done, depth-1)...)
		}
		r = append(r, '}')
		return string(r)
	case reflect.Chan:
		var ptr, bufsize string
		if v.Pointer() == 0 {
			ptr = "nil"
		} else {
			ptr = fmt.Sprintf("0x%x", v.Pointer())
		}
		if v.Cap() > 0 {
			bufsize = fmt.Sprintf("[%d]", v.Cap())
		}
		return fmt.Sprintf("(%s)(%s)%s", v.Type().String(), ptr, bufsize)
	case reflect.Func:
		return "func(...)"
	case reflect.Array, reflect.Slice:
		l := v.Len()
		var r []byte
		if v.Type().Elem().Kind() == reflect.Uint8 && v.Kind() != reflect.Array {
			b := areflect.ForceExport(v).Interface().([]byte)
			r = append(r, []byte(`[]byte(`)...)
			if b == nil {
				r = append(r, []byte("nil")...)
			} else {
				r = append(r, []byte(fmt.Sprintf("%q", b))...)
			}
			r = append(r, ')')
			return string(r)
		}
		r = append(r, []byte(v.Type().String())...)
		r = append(r, '{')
		for i := 0; i < l; i++ {
			if i > 0 {
				r = append(r, []byte(", ")...)
			}
			r = append(r, prettyPrintWithType(v.Index(i), done, depth-1, false)...)
		}
		r = append(r, '}')
		return string(r)
	case reflect.UnsafePointer:
		var ptr string
		if v.Pointer() == 0 {
			ptr = "nil"
		} else {
			ptr = fmt.Sprintf("0x%x", v.Pointer())
		}
		if showType {
			ptr = fmt.Sprintf("(unsafe.Pointer)(%s)", ptr)
		}
		return ptr
	default:
		panic(fmt.Errorf("Unhandled kind of reflect.Value: %v", v.Kind()))
	}
}
Пример #3
0
func diffImpl(a, b interface{}, seen map[edge]struct{}) string {
	av := reflect.ValueOf(a)
	bv := reflect.ValueOf(b)
	// Check if nil
	if !av.IsValid() {
		if !bv.IsValid() {
			return "" // Both are "nil" with no type
		}
		return fmt.Sprintf("expected nil but got a %T: %#v", b, b)
	} else if !bv.IsValid() {
		return fmt.Sprintf("expected a %T (%#v) but got nil", a, a)
	}
	if av.Type() != bv.Type() {
		return fmt.Sprintf("expected a %T but got a %T", a, b)
	}

	switch a := a.(type) {
	case string, bool,
		int8, int16, int32, int64,
		uint8, uint16, uint32, uint64,
		float32, float64,
		complex64, complex128,
		int, uint, uintptr:
		if a != b {
			typ := reflect.TypeOf(a).Name()
			return fmt.Sprintf("%s(%v) != %s(%v)", typ, a, typ, b)
		}
		return ""
	case []byte:
		if !bytes.Equal(a, b.([]byte)) {
			return fmt.Sprintf("[]byte(%q) != []byte(%q)", a, b)
		}
	}

	if ac, ok := a.(diffable); ok {
		return ac.Diff(b.(diffable))
	}

	if ac, ok := a.(key.Comparable); ok {
		if ac.Equal(b.(key.Comparable)) {
			return ""
		}
		return fmt.Sprintf("Comparable types are different: %s vs %s",
			PrettyPrint(a), PrettyPrint(b))
	}

	switch av.Kind() {
	case reflect.Array, reflect.Slice:
		l := av.Len()
		if l != bv.Len() {
			return fmt.Sprintf("Expected an array of size %d but got %d",
				l, bv.Len())
		}
		for i := 0; i < l; i++ {
			diff := diffImpl(av.Index(i).Interface(), bv.Index(i).Interface(),
				seen)
			if len(diff) > 0 {
				return fmt.Sprintf("In arrays, values are different at index %d: %s", i, diff)
			}
		}

	case reflect.Map:
		if c, d := isNilCheck(av, bv); c {
			return d
		}
		if av.Len() != bv.Len() {
			return fmt.Sprintf("Maps have different size: %d != %d (%s)",
				av.Len(), bv.Len(), diffMapKeys(av, bv))
		}
		for _, ka := range av.MapKeys() {
			ae := av.MapIndex(ka)
			if k := ka.Kind(); k == reflect.Ptr || k == reflect.Interface {
				return diffComplexKeyMap(av, bv, seen)
			}
			be := bv.MapIndex(ka)
			if !be.IsValid() {
				return fmt.Sprintf(
					"key %s in map is missing in the actual map",
					prettyPrint(ka, ptrSet{}, prettyPrintDepth))
			}
			if !ae.CanInterface() {
				return fmt.Sprintf(
					"for key %s in map, value can't become an interface: %s",
					prettyPrint(ka, ptrSet{}, prettyPrintDepth),
					prettyPrint(ae, ptrSet{}, prettyPrintDepth))
			}
			if !be.CanInterface() {
				return fmt.Sprintf(
					"for key %s in map, value can't become an interface: %s",
					prettyPrint(ka, ptrSet{}, prettyPrintDepth),
					prettyPrint(be, ptrSet{}, prettyPrintDepth))
			}
			if diff := diffImpl(ae.Interface(), be.Interface(), seen); len(diff) > 0 {
				return fmt.Sprintf(
					"for key %s in map, values are different: %s",
					prettyPrint(ka, ptrSet{}, prettyPrintDepth), diff)
			}
		}

	case reflect.Ptr, reflect.Interface:
		if c, d := isNilCheck(av, bv); c {
			return d
		}
		av = av.Elem()
		bv = bv.Elem()

		if av.CanAddr() && bv.CanAddr() {
			e := edge{from: av.UnsafeAddr(), to: bv.UnsafeAddr()}
			// Detect and prevent cycles.
			if seen == nil {
				seen = make(map[edge]struct{})
			} else if _, ok := seen[e]; ok {
				return ""
			}
			seen[e] = struct{}{}
		}
		return diffImpl(av.Interface(), bv.Interface(), seen)

	case reflect.Struct:
		typ := av.Type()
		for i, n := 0, av.NumField(); i < n; i++ {
			if typ.Field(i).Tag.Get("deepequal") == "ignore" {
				continue
			}
			af := areflect.ForceExport(av.Field(i))
			bf := areflect.ForceExport(bv.Field(i))
			if diff := diffImpl(af.Interface(), bf.Interface(), seen); len(diff) > 0 {
				return fmt.Sprintf("attributes %q are different: %s",
					av.Type().Field(i).Name, diff)
			}
		}

		// The following cases are here to handle named types (aka type aliases).
	case reflect.String:
		if as, bs := av.String(), bv.String(); as != bs {
			return fmt.Sprintf("%s(%q) != %s(%q)", av.Type().Name(), as, bv.Type().Name(), bs)
		}
	case reflect.Bool:
		if ab, bb := av.Bool(), bv.Bool(); ab != bb {
			return fmt.Sprintf("%s(%t) != %s(%t)", av.Type().Name(), ab, bv.Type().Name(), bb)
		}
	case reflect.Uint, reflect.Uintptr,
		reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if ai, bi := av.Uint(), bv.Uint(); ai != bi {
			return fmt.Sprintf("%s(%d) != %s(%d)", av.Type().Name(), ai, bv.Type().Name(), bi)
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if ai, bi := av.Int(), bv.Int(); ai != bi {
			return fmt.Sprintf("%s(%d) != %s(%d)", av.Type().Name(), ai, bv.Type().Name(), bi)
		}
	case reflect.Float32, reflect.Float64:
		if af, bf := av.Float(), bv.Float(); af != bf {
			return fmt.Sprintf("%s(%f) != %s(%f)", av.Type().Name(), af, bv.Type().Name(), bf)
		}
	case reflect.Complex64, reflect.Complex128:
		if ac, bc := av.Complex(), bv.Complex(); ac != bc {
			return fmt.Sprintf("%s(%f) != %s(%f)", av.Type().Name(), ac, bv.Type().Name(), bc)
		}

	default:
		return fmt.Sprintf("Unknown or unsupported type: %T: %#v", a, a)
	}

	return ""
}
Пример #4
0
func genericDeepEqual(a, b interface{}, seen map[edge]struct{}) bool {
	av := reflect.ValueOf(a)
	bv := reflect.ValueOf(b)
	if avalid, bvalid := av.IsValid(), bv.IsValid(); !avalid || !bvalid {
		return avalid == bvalid
	}
	if bv.Type() != av.Type() {
		return false
	}

	switch av.Kind() {
	case reflect.Ptr:
		if av.IsNil() || bv.IsNil() {
			return a == b
		}

		av = av.Elem()
		bv = bv.Elem()
		if av.CanAddr() && bv.CanAddr() {
			e := edge{from: av.UnsafeAddr(), to: bv.UnsafeAddr()}
			// Detect and prevent cycles.
			if seen == nil {
				seen = make(map[edge]struct{})
			} else if _, ok := seen[e]; ok {
				return true
			}
			seen[e] = struct{}{}
		}

		return deepEqual(av.Interface(), bv.Interface(), seen)
	case reflect.Slice, reflect.Array:
		l := av.Len()
		if l != bv.Len() {
			return false
		}
		for i := 0; i < l; i++ {
			if !deepEqual(av.Index(i).Interface(), bv.Index(i).Interface(), seen) {
				return false
			}
		}
		return true
	case reflect.Map:
		if av.IsNil() != bv.IsNil() {
			return false
		}
		if av.Len() != bv.Len() {
			return false
		}
		if av.Pointer() == bv.Pointer() {
			return true
		}
		for _, k := range av.MapKeys() {
			// Upon finding the first key that's a pointer, we bail out and do
			// a O(N^2) comparison.
			if kk := k.Kind(); kk == reflect.Ptr || kk == reflect.Interface {
				ok, _, _ := complexKeyMapEqual(av, bv, seen)
				return ok
			}
			ea := av.MapIndex(k)
			eb := bv.MapIndex(k)
			if !eb.IsValid() {
				return false
			}
			if !deepEqual(ea.Interface(), eb.Interface(), seen) {
				return false
			}
		}
		return true
	case reflect.Struct:
		typ := av.Type()
		if typ.Implements(comparableType) {
			return av.Interface().(key.Comparable).Equal(bv.Interface())
		}
		for i, n := 0, av.NumField(); i < n; i++ {
			if typ.Field(i).Tag.Get("deepequal") == "ignore" {
				continue
			}
			af := areflect.ForceExport(av.Field(i))
			bf := areflect.ForceExport(bv.Field(i))
			if !deepEqual(af.Interface(), bf.Interface(), seen) {
				return false
			}
		}
		return true
	default:
		// Other the basic types.
		return a == b
	}
}