public static PhpArray array_map(Context ctx /*, caller*/, IPhpCallable map, [In, Out] params PhpArray[] arrays)
{
//if (!PhpArgument.CheckCallback(map, caller, "map", 0, true)) return null;
if (arrays == null || arrays.Length == 0)
{
//PhpException.InvalidArgument("arrays", LibResources.GetString("arg:null_or_emtpy"));
//return null;
throw new ArgumentException();
}
// if callback has not been specified uses the default one:
if (map == null)
{
map = _mapIdentity;
}
int count = arrays.Length;
bool preserve_keys = count == 1;
var args = new PhpValue[count];
var iterators = new OrderedDictionary.FastEnumerator[count];
PhpArray result;
// initializes iterators and args array, computes length of the longest array:
int max_count = 0;
for (int i = 0; i < arrays.Length; i++)
{
var array = arrays[i];
if (array == null)
{
//PhpException.Throw(PhpError.Warning, LibResources.GetString("argument_not_array", i + 2));// +2 (first arg is callback)
//return null;
throw new ArgumentException();
}
args[i] = PhpValue.CreateAlias();
iterators[i] = array.GetFastEnumerator();
if (array.Count > max_count) max_count = array.Count;
}
// keys are preserved in a case of a single array and re-indexed otherwise:
if (preserve_keys)
result = new PhpArray(arrays[0].IntegerCount, arrays[0].StringCount);
else
result = new PhpArray(max_count, 0);
for (;;)
{
bool hasvalid = false;
// fills args[] with items from arrays:
for (int i = 0; i < arrays.Length; i++)
{
if (iterators[i].IsValid)
{
hasvalid = true;
// note: deep copy is not necessary since a function copies its arguments if needed:
args[i].Alias.Value = iterators[i].CurrentValue.GetValue();
// TODO: throws if the current Value is PhpReference
}
else
{
args[i].Alias.Value = PhpValue.Null;
}
}
if (!hasvalid) break;
// invokes callback:
var return_value = map.Invoke(ctx, args);
// return value is not deeply copied:
if (preserve_keys)
result.Add(iterators[0].CurrentKey, return_value);
else
result.Add(return_value);
// loads new values (callback may modify some by ref arguments):
for (int i = 0; i < arrays.Length; i++)
{
if (iterators[i].IsValid)
{
var item = iterators[i].CurrentValue;
if (item.IsAlias)
{
item.Alias.Value = args[i].Alias.Value;
}
else
{
iterators[i].CurrentValue = args[i].Alias.Value;
}
//
iterators[i].MoveNext();
}
}
}
return result;
}