/// <summary> /// Internal version of <see cref="Chunk"/> with deep-copy option. /// </summary> internal static PhpArray ChunkInternal(PhpArray array, int size, bool preserveKeys, bool deepCopy) { if (array == null) { PhpException.ArgumentNull("array"); return null; } if (size <= 0) { PhpException.InvalidArgument("array", LibResources.GetString("arg:negative_or_zero")); return null; } // nothing to do: if (array.Count == 0) return new PhpArray(); // number of chunks: int count = (array.Count - 1) / size + 1; // = ceil(Count/size): PhpArray chunk; PhpArray result = new PhpArray(count, 0); IEnumerator<KeyValuePair<IntStringKey, object>> iterator; // if deep-copies are required, wrapp iterator by enumerator making deep copies: if (deepCopy) iterator = PhpVariable.EnumerateDeepCopies(array).GetEnumerator(); else iterator = array.GetEnumerator(); iterator.MoveNext(); // all chunks except for the last one: for (int i = 0; i < count - 1; i++) { chunk = new PhpArray(size, 0); if (preserveKeys) { for (int j = 0; j < size; j++, iterator.MoveNext()) chunk.Add(iterator.Current.Key, iterator.Current.Value); } else { for (int j = 0; j < size; j++, iterator.MoveNext()) chunk.Add(iterator.Current.Value); } result.Add(chunk); } // the last chunk: chunk = new PhpArray((size <= array.Count) ? size : array.Count, 0); if (preserveKeys) { do { chunk.Add(iterator.Current.Key, iterator.Current.Value); } while (iterator.MoveNext()); } else { do { chunk.Add(iterator.Current.Value); } while (iterator.MoveNext()); } result.Add(chunk); // no deep copy is needed since it has already been done on chunks: return result; }
/// <summary> /// Compares two instances of <see cref="PhpArray"/> for strict equality. /// </summary> /// <param name="incomparable">Whether arrays are incomparable /// (no difference is found before both arrays enters an infinite recursion). /// Returns <B>true</B> then.</param> /// <include file='Doc/Common.xml' path='docs/method[@name="Compare(x,y)"]/*'/> private static bool StrictCompareArrays(PhpArray x, PhpArray y, 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 true; // object child_x, child_y; PhpArray array_x, array_y; PhpReference r; IEnumerator<KeyValuePair<IntStringKey, object>> iter_x, iter_y; // if numbers of elements differs: if (x.Count != y.Count) return false; // comparing with the same instance: if (x == y) return true; iter_x = x.GetEnumerator(); iter_y = y.GetEnumerator(); // marks arrays as visited (will be always restored to false value before return): x.Visited = true; y.Visited = true; bool result = true; try { // compares corresponding elements (keys first values then): while (iter_x.MoveNext()) { iter_y.MoveNext(); // compares keys: if (!iter_x.Current.Key.Equals(iter_y.Current.Key)) { result = false; break; } // dereferences x child if it is a reference: child_x = iter_x.Current.Value; if ((r = child_x as PhpReference) != null) child_x = r.Value; // dereferences y child if it is a reference: child_y = iter_y.Current.Value; if ((r = child_y as PhpReference) != null) child_y = r.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 = StrictCompareArrays(array_x, array_y, out incomparable); } else { incomparable = true; } // infinity recursion has been detected: if (incomparable) break; } else { // an array with a non-array comparison: result = false; } } else { // compares unknown item with a non-array: result = Operators.StrictEquality(child_x, child_y); } if (!result) break; } // while } finally { x.Visited = false; y.Visited = false; } return result; }