/// <summary> /// Compares two instances of <see cref="PhpArray"/>. /// </summary> /// <param name="comparer">The comparer.</param> /// <param name="incomparable">Whether arrays are incomparable /// (no difference is found before both arrays enters an infinite recursion). /// Returns zero then.</param> /// <include file='Doc/Common.xml' path='docs/method[@name="Compare(x,y)"]/*'/> private static int CompareArrays(PhpArray x, PhpArray y, IComparer comparer, out bool incomparable) { Debug.Assert(x != null && y != null); incomparable = false; // if both operands point to the same internal dictionary: if (object.ReferenceEquals(x.table, y.table)) return 0; // object child_x, child_y; PhpArray array_x, array_y; PhpArray sorted_x, sorted_y; IEnumerator<KeyValuePair<IntStringKey, object>> iter_x, iter_y; // if numbers of elements differs: int result = x.Count - y.Count; if (result != 0) return result; // comparing with the same instance: if (x == y) return 0; // marks arrays as visited (will be always restored to false value before return): x.Visited = true; y.Visited = true; // it will be more effective to implement OrderedHashtable.ToOrderedList method and use it here (in future version): sorted_x = (PhpArray)x.Clone(); sorted_x.Sort(KeyComparer.ArrayKeys); sorted_y = (PhpArray)y.Clone(); sorted_y.Sort(KeyComparer.ArrayKeys); iter_x = sorted_x.GetEnumerator(); iter_y = sorted_y.GetEnumerator(); result = 0; try { // compares corresponding elements (keys first values then): while (iter_x.MoveNext()) { iter_y.MoveNext(); // compares keys: result = iter_x.Current.Key.CompareTo(iter_y.Current.Key); if (result != 0) break; // dereferences childs if they are references: child_x = PhpVariable.Dereference(iter_x.Current.Value); child_y = PhpVariable.Dereference(iter_y.Current.Value); // compares values: if ((array_x = child_x as PhpArray) != null) { if ((array_y = child_y as PhpArray) != null) { // at least one child has not been visited yet => continue with recursion: if (!array_x.Visited || !array_y.Visited) { result = CompareArrays(array_x, array_y, comparer, out incomparable); } else { incomparable = true; } // infinity recursion has been detected: if (incomparable) break; } else { // compares an array with a non-array: array_x.CompareTo(child_y, comparer); } } else { // compares unknown item with a non-array: result = -comparer.Compare(child_y, child_x); } if (result != 0) break; } // while } finally { x.Visited = false; y.Visited = false; } return result; }