private static bool MergeRecursiveInternal(PhpArray/*!*/ result, PhpArray/*!*/ array, bool deepCopy)
{
var visited = new HashSet<object>(); // marks arrays that are being visited
using (var iterator = array.GetFastEnumerator())
while (iterator.MoveNext())
{
var entry = iterator.Current;
if (entry.Key.IsString)
{
if (result.ContainsKey(entry.Key))
{
// the result array already contains the item => merging take place
var xv = result[entry.Key];
var y = entry.Value.GetValue();
// source item:
PhpValue x = xv.GetValue();
// if x is not a reference then we can reuse the ax array for the result
// since it has been deeply copied when added to the resulting array:
PhpArray item_result = (deepCopy && x.IsArray && !xv.IsAlias) ? x.Array : new PhpArray();
if (x.IsArray && y.IsArray)
{
var ax = x.Array;
var ay = y.Array;
if (ax != item_result)
ax.AddTo(item_result, deepCopy);
if (visited.Add(ax) == false && visited.Add(ay) == false)
return false;
// merges ay to the item result (may lead to stack overflow,
// but only with both arrays recursively referencing themselves - who cares?):
bool finite = MergeRecursiveInternal(item_result, ay, deepCopy);
visited.Remove(ax);
visited.Remove(ay);
if (!finite) return false;
}
else
{
if (x.IsArray)
{
if (x.Array != item_result)
x.Array.AddTo(item_result, deepCopy);
}
else
{
/*if (x != null)*/
item_result.Add(deepCopy ? x.DeepCopy() : x);
}
if (y.IsArray) y.Array.AddTo(item_result, deepCopy);
else /*if (y != null)*/ item_result.Add(deepCopy ? y.DeepCopy() : y);
}
result[entry.Key] = PhpValue.Create(item_result);
}
else
{
// PHP does no dereferencing when items are not merged:
result.Add(entry.Key, (deepCopy) ? entry.Value.DeepCopy() : entry.Value);
}
}
else
{
// PHP does no dereferencing when items are not merged:
result.Add((deepCopy) ? entry.Value.DeepCopy() : entry.Value);
}
}
return true;
}