| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file | 
|  | 2 // for details. All rights reserved. Use of this source code is governed by a | 
|  | 3 // BSD-style license that can be found in the LICENSE file. | 
|  | 4 | 
|  | 5 library yaml.equality; | 
|  | 6 | 
|  | 7 import 'dart:collection'; | 
|  | 8 | 
|  | 9 import 'package:collection/collection.dart'; | 
|  | 10 | 
|  | 11 import 'yaml_node.dart'; | 
|  | 12 | 
|  | 13 /// Returns a [Map] that compares its keys based on [deepEquals]. | 
|  | 14 Map deepEqualsMap() => new HashMap(equals: deepEquals, hashCode: deepHashCode); | 
|  | 15 | 
|  | 16 /// Returns whether two objects are structurally equivalent. | 
|  | 17 /// | 
|  | 18 /// This considers `NaN` values to be equivalent, handles self-referential | 
|  | 19 /// structures, and considers [YamlScalar]s to be equal to their values. | 
|  | 20 bool deepEquals(obj1, obj2) => new _DeepEquals().equals(obj1, obj2); | 
|  | 21 | 
|  | 22 /// A class that provides access to the list of parent objects used for loop | 
|  | 23 /// detection. | 
|  | 24 class _DeepEquals { | 
|  | 25   final _parents1 = []; | 
|  | 26   final _parents2 = []; | 
|  | 27 | 
|  | 28   /// Returns whether [obj1] and [obj2] are structurally equivalent. | 
|  | 29   bool equals(obj1, obj2) { | 
|  | 30     if (obj1 is YamlScalar) obj1 = obj1.value; | 
|  | 31     if (obj2 is YamlScalar) obj2 = obj2.value; | 
|  | 32 | 
|  | 33     // _parents1 and _parents2 are guaranteed to be the same size. | 
|  | 34     for (var i = 0; i < _parents1.length; i++) { | 
|  | 35       var loop1 = identical(obj1, _parents1[i]); | 
|  | 36       var loop2 = identical(obj2, _parents2[i]); | 
|  | 37       // If both structures loop in the same place, they're equal at that point | 
|  | 38       // in the structure. If one loops and the other doesn't, they're not | 
|  | 39       // equal. | 
|  | 40       if (loop1 && loop2) return true; | 
|  | 41       if (loop1 || loop2) return false; | 
|  | 42     } | 
|  | 43 | 
|  | 44     _parents1.add(obj1); | 
|  | 45     _parents2.add(obj2); | 
|  | 46     try { | 
|  | 47       if (obj1 is List && obj2 is List) { | 
|  | 48         return _listEquals(obj1, obj2); | 
|  | 49       } else if (obj1 is Map && obj2 is Map) { | 
|  | 50         return _mapEquals(obj1, obj2); | 
|  | 51       } else if (obj1 is num && obj2 is num) { | 
|  | 52         return _numEquals(obj1, obj2); | 
|  | 53       } else { | 
|  | 54         return obj1 == obj2; | 
|  | 55       } | 
|  | 56     } finally { | 
|  | 57       _parents1.removeLast(); | 
|  | 58       _parents2.removeLast(); | 
|  | 59     } | 
|  | 60   } | 
|  | 61 | 
|  | 62   /// Returns whether [list1] and [list2] are structurally equal. | 
|  | 63   bool _listEquals(List list1, List list2) { | 
|  | 64     if (list1.length != list2.length) return false; | 
|  | 65 | 
|  | 66     for (var i = 0; i < list1.length; i++) { | 
|  | 67       if (!equals(list1[i], list2[i])) return false; | 
|  | 68     } | 
|  | 69 | 
|  | 70     return true; | 
|  | 71   } | 
|  | 72 | 
|  | 73   /// Returns whether [map1] and [map2] are structurally equal. | 
|  | 74   bool _mapEquals(Map map1, Map map2) { | 
|  | 75     if (map1.length != map2.length) return false; | 
|  | 76 | 
|  | 77     for (var key in map1.keys) { | 
|  | 78       if (!map2.containsKey(key)) return false; | 
|  | 79       if (!equals(map1[key], map2[key])) return false; | 
|  | 80     } | 
|  | 81 | 
|  | 82     return true; | 
|  | 83   } | 
|  | 84 | 
|  | 85   /// Returns whether two numbers are equivalent. | 
|  | 86   /// | 
|  | 87   /// This differs from `n1 == n2` in that it considers `NaN` to be equal to | 
|  | 88   /// itself. | 
|  | 89   bool _numEquals(num n1, num n2) { | 
|  | 90     if (n1.isNaN && n2.isNaN) return true; | 
|  | 91     return n1 == n2; | 
|  | 92   } | 
|  | 93 } | 
|  | 94 | 
|  | 95 /// Returns a hash code for [obj] such that structurally equivalent objects | 
|  | 96 /// will have the same hash code. | 
|  | 97 /// | 
|  | 98 /// This supports deep equality for maps and lists, including those with | 
|  | 99 /// self-referential structures, and returns the same hash code for | 
|  | 100 /// [YamlScalar]s and their values. | 
|  | 101 int deepHashCode(obj) { | 
|  | 102   var parents = []; | 
|  | 103 | 
|  | 104   _deepHashCode(value) { | 
|  | 105     if (parents.any((parent) => identical(parent, value))) return -1; | 
|  | 106 | 
|  | 107     parents.add(value); | 
|  | 108     try { | 
|  | 109       if (value is Map) { | 
|  | 110         var equality = const UnorderedIterableEquality(); | 
|  | 111         return equality.hash(value.keys.map(_deepHashCode)) ^ | 
|  | 112             equality.hash(value.values.map(_deepHashCode)); | 
|  | 113       } else if (value is Iterable) { | 
|  | 114         return const IterableEquality().hash(value.map(deepHashCode)); | 
|  | 115       } else if (value is YamlScalar) { | 
|  | 116         return value.value.hashCode; | 
|  | 117       } else { | 
|  | 118         return value.hashCode; | 
|  | 119       } | 
|  | 120     } finally { | 
|  | 121       parents.removeLast(); | 
|  | 122     } | 
|  | 123   } | 
|  | 124 | 
|  | 125   return _deepHashCode(obj); | 
|  | 126 } | 
| OLD | NEW | 
|---|