2 using System.Collections.Generic;
6 using SiliconStudio.Assets.Visitors;
7 using SiliconStudio.Core.Reflection;
9 namespace SiliconStudio.Assets.Diff
13 private readonly ModelNodeComparer modelNodeComparer;
14 private readonly ModelNodeCanAlign modelNodeCanAlign;
15 private readonly ModelNodeSimilarityComparer modelNodeSimilarityComparer;
16 private readonly Dictionary<NodeKey, DataMatch> matches =
new Dictionary<NodeKey, DataMatch>();
21 if (descriptorFactory == null)
throw new ArgumentNullException(
"descriptorFactory");
22 this.descriptorFactory = descriptorFactory;
23 modelNodeComparer =
new ModelNodeComparer(
this);
24 modelNodeSimilarityComparer =
new ModelNodeSimilarityComparer(
this);
25 modelNodeCanAlign =
new ModelNodeCanAlign(modelNodeSimilarityComparer);
31 var key =
new NodeKey(node1, node2);
32 if (matches.TryGetValue(key, out match))
38 match = MatchInternal(node1, node2);
39 Console.WriteLine(
"Match {0} : {1} vs {2}", node1, node2, match);
48 if ((ReferenceEquals(node1, null) || ReferenceEquals(node2, null) || node1.GetType() != node2.GetType()))
50 return node1 == node2 ? DataMatch.Empty : UnMatched(node1, node2);
53 var match =
new DataMatch();
55 if (node1 is DataVisitRootNode)
59 return ReferenceEquals(node1.
Instance, node2.
Instance) ? DataMatch.MatchOne : UnMatched(node1, node2);
64 match += MatchValue(node1, ((DataVisitMember)node1).Value, node2, ((DataVisitMember)node2).Value);
68 match += MatchValue(node1, ((DataVisitListItem)node1).Item, node2, ((DataVisitListItem)node2).Item);
71 match += MatchValues(node1, node1.
Members, node2, node2.
Members,
true);
72 match += MatchValues(node1, node1.
Items, node2, node2.
Items,
false);
76 private DataMatch MatchValue(IDataVisitNode node1,
object value1, IDataVisitNode node2,
object value2)
79 if (value1 == null || value2 == null || value1.GetType() != value2.GetType())
81 return ReferenceEquals(value1, value2) ? DataMatch.MatchOne : UnMatched(node1, node2);
86 var type = descriptorFactory.Find(value1.GetType());
89 return Equals(value1, value2) ? DataMatch.MatchOne : UnMatched(node1, node2);
93 return DataMatch.Empty;
96 private DataMatch MatchValues(
DataVisitNode node1Parent, List<IDataVisitNode> nodes1,
DataVisitNode node2Parent, List<IDataVisitNode> nodes2,
bool expectSameCount)
98 if (nodes1 == null || nodes2 == null || (expectSameCount && nodes1.Count != nodes2.Count))
100 return ReferenceEquals(nodes1, nodes2) ? DataMatch.Empty : UnMatched(node1Parent, node2Parent);
103 var match =
new DataMatch();
107 for (
int i = 0; i < nodes1.Count; i++)
114 var alignedDiffs = Diff2.CompareAndAlign(nodes1, nodes2, modelNodeComparer, modelNodeSimilarityComparer, modelNodeCanAlign).ToList();
115 foreach (var alignedDiffChange
in alignedDiffs)
117 switch (alignedDiffChange.Change)
119 case ChangeType.Same:
120 case ChangeType.Changed:
123 case ChangeType.Added:
124 match +=
new DataMatch(0, nodes2[alignedDiffChange.Index2].CountNodes());
126 case ChangeType.Deleted:
127 match +=
new DataMatch(0, nodes1[alignedDiffChange.Index1].CountNodes());
136 private static DataMatch UnMatched(IDataVisitNode node1, IDataVisitNode node2)
138 return new DataMatch(0, Math.Max(node1 != null ? node1.CountNodes() : 0, node2 != null ? node2.CountNodes() : 0));
141 private class ModelNodeComparer : IEqualityComparer<IDataVisitNode>
143 private readonly DataMatcher matcher;
145 public ModelNodeComparer(DataMatcher matcher)
147 this.matcher = matcher;
150 public bool Equals(IDataVisitNode x, IDataVisitNode
y)
156 public
int GetHashCode(IDataVisitNode obj)
163 private class ModelNodeSimilarityComparer : ISimilarityComparer<IDataVisitNode>
165 private readonly DataMatcher matcher;
167 public ModelNodeSimilarityComparer(DataMatcher matcher)
169 this.matcher = matcher;
172 public double Compare(IDataVisitNode value1, IDataVisitNode value2)
175 return (
double)result.Count/result.Total;
179 private class ModelNodeCanAlign : IAlignmentFilter<IDataVisitNode>
181 private readonly ModelNodeSimilarityComparer comparer;
183 public ModelNodeCanAlign(ModelNodeSimilarityComparer comparer)
185 this.comparer = comparer;
188 public bool CanAlign(IDataVisitNode value1, IDataVisitNode value2)
190 return comparer.Compare(value1, value2) > 0.1;
194 private struct NodeKey : IEquatable<NodeKey>
205 public bool Equals(NodeKey other)
207 return ReferenceEquals(node1, other.node1) && ReferenceEquals(node2, other.node2);
210 public override bool Equals(
object obj)
212 if (ReferenceEquals(null, obj))
return false;
213 return obj is NodeKey && Equals((NodeKey)obj);
216 public override int GetHashCode()
220 return ((node1 != null ? node1.GetHashCode() : 0) * 397) ^ (node2 != null ? node2.GetHashCode() : 0);
224 public static bool operator ==(NodeKey left, NodeKey right)
226 return left.Equals(right);
229 public static bool operator !=(NodeKey left, NodeKey right)
231 return !left.Equals(right);
A default implementation for the ITypeDescriptorFactory.
A diff element for a member (field or property) of a class.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Defines an item in a list.
List< DataVisitNode > Members
DataMatch Match(DataVisitNode node1, DataVisitNode node2)
List< DataVisitNode > Items
Base class for all items in a collection (array, list or dictionary)
DataMatcher(TypeDescriptorFactory descriptorFactory)