OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [reflect/] [deepequal.go] - Rev 747

Compare with Previous | Blame | View Log

// Copyright 2009 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.

// Deep equality test via reflection

package reflect

// During deepValueEqual, must keep track of checks that are
// in progress.  The comparison algorithm assumes that all
// checks in progress are true when it reencounters them.
// Visited are stored in a map indexed by 17 * a1 + a2;
type visit struct {
        a1   uintptr
        a2   uintptr
        typ  Type
        next *visit
}

// Tests for deep equality using reflected types. The map argument tracks
// comparisons that have already been seen, which allows short circuiting on
// recursive types.
func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool) {
        if !v1.IsValid() || !v2.IsValid() {
                return v1.IsValid() == v2.IsValid()
        }
        if v1.Type() != v2.Type() {
                return false
        }

        // if depth > 10 { panic("deepValueEqual") }    // for debugging

        if v1.CanAddr() && v2.CanAddr() {
                addr1 := v1.UnsafeAddr()
                addr2 := v2.UnsafeAddr()
                if addr1 > addr2 {
                        // Canonicalize order to reduce number of entries in visited.
                        addr1, addr2 = addr2, addr1
                }

                // Short circuit if references are identical ...
                if addr1 == addr2 {
                        return true
                }

                // ... or already seen
                h := 17*addr1 + addr2
                seen := visited[h]
                typ := v1.Type()
                for p := seen; p != nil; p = p.next {
                        if p.a1 == addr1 && p.a2 == addr2 && p.typ == typ {
                                return true
                        }
                }

                // Remember for later.
                visited[h] = &visit{addr1, addr2, typ, seen}
        }

        switch v1.Kind() {
        case Array:
                if v1.Len() != v2.Len() {
                        return false
                }
                for i := 0; i < v1.Len(); i++ {
                        if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
                                return false
                        }
                }
                return true
        case Slice:
                if v1.IsNil() != v2.IsNil() {
                        return false
                }
                if v1.Len() != v2.Len() {
                        return false
                }
                for i := 0; i < v1.Len(); i++ {
                        if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
                                return false
                        }
                }
                return true
        case Interface:
                if v1.IsNil() || v2.IsNil() {
                        return v1.IsNil() == v2.IsNil()
                }
                return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
        case Ptr:
                return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
        case Struct:
                for i, n := 0, v1.NumField(); i < n; i++ {
                        if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) {
                                return false
                        }
                }
                return true
        case Map:
                if v1.IsNil() != v2.IsNil() {
                        return false
                }
                if v1.Len() != v2.Len() {
                        return false
                }
                for _, k := range v1.MapKeys() {
                        if !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
                                return false
                        }
                }
                return true
        default:
                // Normal equality suffices
                return valueInterface(v1, false) == valueInterface(v2, false)
        }

        panic("Not reached")
}

// DeepEqual tests for deep equality. It uses normal == equality where possible
// but will scan members of arrays, slices, and fields of structs. It correctly
// handles recursive types.
func DeepEqual(a1, a2 interface{}) bool {
        if a1 == nil || a2 == nil {
                return a1 == a2
        }
        v1 := ValueOf(a1)
        v2 := ValueOf(a2)
        if v1.Type() != v2.Type() {
                return false
        }
        return deepValueEqual(v1, v2, make(map[uintptr]*visit), 0)
}

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.