Pchp.Library.Arrays.array_map C# (CSharp) Method

array_map() public static method

Applies a callback function on specified tuples one by one storing its results to an array.

In the i-th call the j-th parameter of the callback will be the i-th value of the j-the array or a null if that array has less then i entries.

If the callback assigns a value to a parameter passed by reference in the i-the call and the respective array contains at least i elements the assigned value is propagated to the array.

public static array_map ( Context ctx, IPhpCallable map ) : PhpArray
ctx Pchp.Core.Context Current runtime context.
map IPhpCallable /// A callback to be called on tuples. The number of arguments should be the same as /// the number of arrays specified by . /// Arguments passed by reference modifies elements of . /// A null means default callback which makes integer indexed arrays from the tuples is used. ///
return Pchp.Core.PhpArray
        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;
        }