int IComparer.Compare(object left, object right) { float ret; Pair pair = new Pair(left, right, differ); if (left.GetType() != right.GetType()) { ret = 1; } else if (useCache && differ.comparisonCache.ContainsKey(pair)) { ret = (float)differ.comparisonCache[pair]; } else { NodeInterface comparer = differ.GetInterface(left); ret = comparer.Compare(left, right, differ); } if (useCache) { differ.comparisonCache[pair] = ret; } if (ret < minimumDifference && ret > threshold) { minimumDifference = ret; } if (ret <= threshold) { return(0); } else { return(1); } }
private float CompareLists(IList left, IList right, float threshold, bool output) { // Given two lists, find the elements in the list that correspond. // Two elements correspond if their 'difference metric' is less than // or equal to threshold. For the hunks of correspondent items, // recursively descend into items not truly equal. For hunks of // irreconsiliable material, raise the threshold to the next useful // level and rescan the items. if (left.Count == 0 && right.Count == 0) { return(0); } NodeComparerWrapper comparer = new NodeComparerWrapper(threshold, this); Diff diff = new Diff(left, right, comparer, comparer); int nitems = 0, ndiffs = 0; foreach (Diff.Hunk hunk in diff) { if (hunk.Same || (hunk.Left.Count == 1 && hunk.Right.Count == 1)) { // This comprises a block of correspondent items who // differ by no more than the threshold value. nitems += hunk.Left.Count; bool inSameRegion = false; for (int i = 0; i < hunk.Left.Count; i++) { object oleft = hunk.Left[i]; object oright = hunk.Right[i]; NodeInterface ileft = GetInterface(oleft); NodeInterface iright = GetInterface(oright); IList cleft = null, cright = null; cleft = ileft.GetChildren(oleft); cright = iright.GetChildren(oright); float comp = 0; if (ileft == iright) { comp = ileft.Compare(oleft, oright, this); } // If the nodes are equal, emit one node. if (ileft == iright && comp == 0) { if (output) { if (!inSameRegion) { WritePushSame(); inSameRegion = true; } WriteNodeSame(ileft, oleft, oright); } // Recurse into the lists of each node. } else if (ileft == iright && cleft != null && cright != null && cleft.Count > 0 && cright.Count > 0 && comp <= 1.0) { if (output && inSameRegion) { WritePopSame(); inSameRegion = false; } if (output) { WritePushNode(ileft, oleft, oright); } float d = CompareLists(cleft, cright, 0, output); d *= hunk.Left.Count; if (d < 1) { d = 1; } ndiffs += (int)d; if (output) { WritePopNode(); } // The nodes are not equal, so emit removed and added nodes. } else { if (output && inSameRegion) { WritePopSame(); inSameRegion = false; } if (output) { WriteNodeChange(ileft, oleft, iright, oright); } ndiffs += hunk.Left.Count; } } if (output && inSameRegion) { WritePopSame(); } } else { int ct = hunk.Left.Count + hunk.Right.Count; nitems += ct; ndiffs += ct; if (output) { bool noRecurse = comparer.minimumDifference >= 1; if (hunk.Right.Count == 0 || (hunk.Left.Count > 0 && noRecurse)) { WriteNodesRemoved(hunk.Left); } if (hunk.Left.Count == 0 || (hunk.Right.Count > 0 && noRecurse)) { WriteNodesAdded(hunk.Right); } if (hunk.Right.Count != 0 && hunk.Left.Count != 0 && !noRecurse) { CompareLists(hunk.Left, hunk.Right, comparer.minimumDifference, output); } } } } return((float)ndiffs / (float)nitems); }