Ejemplo n.º 1
0
		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 == null) throw new ArgumentNullException("left");
			if (right == null) throw new ArgumentNullException("right");

			if (left.Count == 0 && right.Count == 0)
				return 0;
			
			NodeComparerWrapper comparer = new NodeComparerWrapper(threshold, this);
			
			Diff diff = new Diff(left, right, comparer, new HashCodeProvider(this));
			
			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 one-to-one 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 {
					// We have some arbitrary sets on the left and right side.
					// Try to match nodes on the left with nodes on the right.
					
					ArrayList leftitems = new ArrayList(hunk.Left);
					ArrayList rightitems = new ArrayList(hunk.Right);
					
					while (leftitems.Count > 0 && rightitems.Count > 0) {
						// Find the first node on the left side that matches
						// a node on the right side.
						
						int li = -1, ri = -1;
						float bestD = 1;
							
						for (int lii = 0; lii < leftitems.Count; lii++) {
							object oleft = leftitems[lii];
							NodeInterface ileft = GetInterface(oleft);

							for (int rii = 0; rii < rightitems.Count; rii++) {
								object oright = rightitems[rii];
								NodeInterface iright = GetInterface(oright);
								
								float d = 1;
								if (ileft == iright)
									d = ileft.Compare(oleft, oright, this);
								
								if (d < bestD) {
									bestD = d;
									li = lii;
									ri = rii;
								}
							}
							
						}
						
						if (li == -1) break;
							
						// Try to extend the correspondence further down the right list.
						int count = 1;
						for (int ri2 = ri+1; ri2 < rightitems.Count && (li+(ri2-ri)) < leftitems.Count; ri2++) {
							object oleft2 = leftitems[li+(ri2-ri)];
							object oright2 = rightitems[ri2];
							NodeInterface ileft2 = GetInterface(oleft2);
							NodeInterface iright2 = GetInterface(oright2);
							
							float d2 = 1;
							if (ileft2 == iright2)
								d2 = ileft2.Compare(oleft2, oright2, this);
							
							if (d2 <= bestD)
								count++;
							else
								break;
						}
								
						// We have a correspondence starting at li and ri
						// over count items.
						
						// First, recurse on the first portion of the list that had no matches.
						CompareLists(leftitems.GetRange(0, li), rightitems.GetRange(0, ri), comparer.minimumDifference, output);
						
						// Then recurse on the correspondence range.
						CompareLists(leftitems.GetRange(li, count), rightitems.GetRange(ri, count), comparer.minimumDifference, output);
						
						// Lastly remove the items we just considered and do it again for the rest of the hunk.
						leftitems.RemoveRange(0, li+count);
						rightitems.RemoveRange(0, ri+count);
					}
					
					int ct = leftitems.Count + rightitems.Count;
					nitems += ct;
					ndiffs += ct;
					
					if (output) {
						bool noRecurse = comparer.minimumDifference >= 1;
						if (rightitems.Count == 0 || (leftitems.Count > 0 && noRecurse))
							WriteNodesRemoved(leftitems);
						if (leftitems.Count == 0 || (rightitems.Count > 0 && noRecurse))
							WriteNodesAdded(rightitems);
						if (rightitems.Count != 0 && leftitems.Count != 0 && !noRecurse)
							CompareLists(leftitems, rightitems, comparer.minimumDifference, output);
					}
				}
			}
			
			return (float)ndiffs / (float)nitems;
		}
Ejemplo n.º 2
0
        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 == null)
            {
                throw new ArgumentNullException("left");
            }
            if (right == null)
            {
                throw new ArgumentNullException("right");
            }

            if (left.Count == 0 && right.Count == 0)
            {
                return(0);
            }

            NodeComparerWrapper comparer = new NodeComparerWrapper(threshold, this);

            Diff diff = new Diff(left, right, comparer, new HashCodeProvider(this));

            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);
        }
        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, new HashCodeProvider(this));

            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;
        }