Exemple #1
0
 /// <summary>
 /// Performs replacements on deeply-copied array. Performs deep copies of replace values.
 /// </summary>
 internal static void ArrayReplaceImpl(PhpArray array, PhpArray replaceWith, bool recursive)
 {
     if (array != null && replaceWith != null)
     {
         var iterator = replaceWith.GetFastEnumerator();
         while (iterator.MoveNext())
         {
             PhpValue tmp;
             var entry = iterator.Current;
             if (recursive && entry.Value.IsArray && (tmp = array[entry.Key]).IsArray)
             {
                 ArrayReplaceImpl(tmp.Array, entry.Value.Array, true);
             }
             else
             {
                 array[entry.Key] = entry.Value.DeepCopy();
             }
         }
     }
 }
Exemple #2
0
        /// <summary>
        /// Returns array which elements are taken from a specified one in reversed order.
        /// </summary>
        /// <param name="array">The array to be reversed.</param>
        /// <param name="preserveKeys">Whether keys should be left untouched. 
        /// If set to <b>false</b> then integer keys are reindexed starting from zero.</param>
        /// <returns>The array <paramref name="array"/> with items in reversed order.</returns>
        public static PhpArray array_reverse(PhpArray array, bool preserveKeys = false)
        {
            if (array == null)
            {
                //PhpException.ReferenceNull("array");
                //return null;
                throw new ArgumentNullException();
            }

            PhpArray result = new PhpArray();

            var e = array.GetFastEnumerator();

            if (preserveKeys)
            {
                // changes only the order of elements:
                while (e.MoveNext())
                {
                    result.Prepend(e.CurrentKey, e.CurrentValue);
                }
            }
            else
            {
                // changes the order of elements and reindexes integer keys:
                int i = array.IntegerCount;
                while (e.MoveNext())
                {
                    var key = e.CurrentKey;
                    result.Prepend(key.IsString ? key : new IntStringKey(--i), e.CurrentValue);
                }
            }

            // if called by PHP languge then all items in the result should be inplace deeply copied:
            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #3
0
        /// <summary>
        /// Retuns the specified array.
        /// see http://php.net/manual/en/function.array-filter.php
        /// </summary>
        /// <remarks>The caller argument is here just because of the second Filter() method. Phalanger shares the function properties over the overloads.</remarks>
        public static PhpArray array_filter(PhpArray array)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException(nameof(array));
            }

            var result = new PhpArray();

            var enumerator = array.GetFastEnumerator();
            while (enumerator.MoveNext())
            {
                var entry = enumerator.Current;
                if (entry.Value.ToBoolean())
                {
                    result.Add(entry);
                }
            }

            return result;
        }
Exemple #4
0
        /// <summary>
        /// Filters an array using a specified callback.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="array">The array to be filtered.</param>
        /// <param name="callback">
        /// The callback called on each value in the <paramref name="array"/>. 
        /// If the callback returns value convertible to <B>true</B> the value is copied to the resulting array.
        /// Otherwise, it is ignored.
        /// </param>
        /// <returns>An array of unfiltered items.</returns>
        //[return: PhpDeepCopy]
        public static PhpArray array_filter(Context ctx /*, caller*/, PhpArray array, IPhpCallable callback)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException(nameof(array));
            }

            if (callback == null)
            {
                //PhpException.ArgumentNull("callback");
                //return null;
                throw new ArgumentNullException(nameof(callback));
            }

            var result = new PhpArray();
            var args = new PhpValue[1];

            var iterator = array.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                var entry = iterator.Current;

                // no deep copying needed because it is done so in callback:
                args[0] = entry.Value;

                // adds entry to the resulting array if callback returns true:
                if (callback.Invoke(ctx, args).ToBoolean())
                {
                    result.Add(entry);
                }
            }

            // values should be inplace deeply copied:
            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #5
0
        static PhpValue preg_replace(Context ctx, string pattern, string replacement, PhpCallable callback, PhpValue subject, int limit, ref long count)
        {
            var regex = new PerlRegex.Regex(pattern);

            // TODO: count
            // TODO: callback

            var subject_array = subject.AsArray();
            if (subject_array == null)
            {
                return PhpValue.Create(regex.Replace(subject.ToStringOrThrow(ctx), replacement, limit));
            }
            else
            {
                var arr = new PhpArray(subject_array, false);
                var enumerator = arr.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    var newvalue = regex.Replace(enumerator.CurrentValue.ToStringOrThrow(ctx), replacement, limit);
                    enumerator.CurrentValue = PhpValue.Create(newvalue);
                }

                return PhpValue.Create(arr);
            }
        }
Exemple #6
0
        /// <summary>
        /// Adds items of "array" to "result" merging those whose string keys are the same.
        /// </summary>
        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;
        }
Exemple #7
0
        /// <summary>
        /// Retrieves an array of some keys contained in a given array.
        /// </summary>
        /// <param name="array">An array which keys to get.</param>
        /// <param name="searchValue">Only the keys for this value are returned. 
        /// Values are compared using regular comparison method (<see cref="PhpComparer.CompareEq"/>).</param>
        /// <param name="strict">If true, uses strict comparison method (operator "===").</param>
        /// <returns>An array of keys being associated with specified value. 
        /// Keys in returned array are successive integers starting from zero.</returns>
        /// <exception cref="PhpException"><paramref name="array"/> is a <B>null</B> reference.</exception>
        public static PhpArray array_keys(PhpArray array, PhpValue searchValue, bool strict = false)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException();
            }

            var result = new PhpArray();
            var enumerator = array.GetFastEnumerator();

            if (strict)
            {
                while (enumerator.MoveNext())
                {
                    if (enumerator.CurrentValue.StrictEquals(searchValue))
                        result.AddValue(PhpValue.Create(enumerator.CurrentKey));
                }
            }
            else
            {
                while (enumerator.MoveNext())
                {
                    if (enumerator.CurrentValue.Equals(searchValue))
                        result.AddValue(PhpValue.Create(enumerator.CurrentKey));
                }
            }

            // no need to make a deep copy since keys are immutable objects (strings, ints):
            return result;
        }
Exemple #8
0
        public static PhpArray array_fill_keys(PhpArray keys, PhpValue value)
        {
            if (keys == null)
            {
                // PhpException.ArgumentNull("keys");
                // return null;
                throw new ArgumentNullException();
            }

            var result = new PhpArray(keys.Count);
            var iterator = keys.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                IntStringKey key;
                if (Core.Convert.TryToIntStringKey(iterator.CurrentValue, out key) && !result.ContainsKey(key))
                {
                    result[key] = value;
                }
            }

            // makes deep copies of all added items:
            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #9
0
        /// <summary>
        /// Swaps all keys and their associated values in an array.
        /// </summary>
        /// <param name="array">The array.</param>
        /// <returns>An array containing entries which keys are values from the <paramref name="array"/>
        /// and which values are the corresponding keys.</returns>
        /// <remarks>
        /// <para>
        /// Values which are not of type <see cref="string"/> nor <see cref="int"/> are skipped 
        /// and for each such value a warning is reported. If there are more entries with the same 
        /// value in the <paramref name="array"/> the last key is considered others are ignored.
        /// String keys are converted using <see cref="Core.Convert.StringToArrayKey"/>.
        /// </para>
        /// <para>
        /// Unlike PHP this method doesn't return <B>false</B> on failure but a <B>null</B> reference.
        /// This is because it fails only if <paramref name="array"/> is a <B>null</B> reference.
        /// </para>
        /// </remarks>
        /// <exception cref="PhpException"><paramref name="array"/> is a <B>null</B> reference (Warning).</exception>
        /// <exception cref="PhpException">A value is neither <see cref="string"/> nor <see cref="int"/> (Warning).</exception>     
        public static PhpArray array_flip(PhpArray array)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException();
            }

            PhpArray result = new PhpArray(array.Count);

            var iterator = array.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                var entry = iterator.Current;
                // dereferences value:
                var val = entry.Value.GetValue();
                switch (val.TypeCode)
                {
                    case PhpTypeCode.Int32:
                    case PhpTypeCode.Long:
                    case PhpTypeCode.String:
                    case PhpTypeCode.WritableString:
                        var askey = val.ToIntStringKey();
                        result[askey] = PhpValue.Create(entry.Key);
                        break;
                    default:
                        // PhpException.Throw(PhpError.Warning, LibResources.GetString("neither_string_nor_integer_value", "flip"));
                        throw new ArgumentException();
                }
            }

            // no need to deep copy because values are ints/strings only (<= keys were int/strings only):
            return result;
        }
Exemple #10
0
        /// <summary>
        /// Retrieves an array of keys contained in a given array.
        /// </summary>
        /// <param name="array">An array which keys to get.</param>
        /// <returns><see cref="PhpArray"/> of <paramref name="array"/>'s keys.
        /// Keys in returned array are successive integers starting from zero.</returns>
        /// <exception cref="PhpException"><paramref name="array"/> is a <B>null</B> reference.</exception>
        public static PhpArray array_keys(PhpArray array)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException();
            }

            // no need to make a deep copy since keys are immutable objects (strings, ints):
            var result = new PhpArray(array.Count);

            var enumerator = array.GetFastEnumerator();
            while (enumerator.MoveNext())
            {
                result.Add(PhpValue.Create(enumerator.CurrentKey));
            }

            return result;
        }
Exemple #11
0
        /// <summary>
        /// Removes duplicate values from an array.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="array">The array which duplicate values to remove.</param>
        /// <param name="sortFlags">Specifies how the values are compared to be identical.</param>
        /// <returns>A copy of <paramref name="array"/> without duplicated values.</returns>
        /// <remarks>
        /// Values are compared using string comparison method (<see cref="ValueComparer.String"/>).  
        /// </remarks>
        /// <exception cref="PhpException"><paramref name="array"/> is a <B>null</B> reference.</exception>
        //[return: PhpDeepCopy]
        public static PhpArray array_unique(Context ctx, PhpArray array, ComparisonMethod sortFlags = ComparisonMethod.String)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException();
            }

            IComparer<PhpValue> comparer;
            switch (sortFlags)
            {
                case ComparisonMethod.Regular:
                    comparer = PhpComparer.Default; break;
                case ComparisonMethod.Numeric:
                    comparer = PhpNumericComparer.Default; break;
                case ComparisonMethod.String:
                    comparer = new PhpStringComparer(ctx); break;
                case ComparisonMethod.LocaleString:
                //comparer = new PhpLocaleStringComparer(ctx); break;
                default:
                    //PhpException.ArgumentValueNotSupported("sortFlags", (int)sortFlags);
                    //return null;
                    throw new ArgumentException(nameof(sortFlags));
            }

            var result = new PhpArray(array.Count);

            var/*!*/identitySet = new HashSet<object>();

            // get only unique values - first found
            using (var enumerator = array.GetFastEnumerator())
                while (enumerator.MoveNext())
                {
                    if (identitySet.Add(enumerator.CurrentValue.GetValue()))
                    {
                        result.Add(enumerator.Current);
                    }
                }

            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #12
0
        /// <summary>
        /// Counts frequency of each value in an array.
        /// </summary>
        /// <param name="array">The array which values to count.</param>
        /// <returns>The array which keys are values of <paramref name="array"/> and values are their frequency.</returns>
        /// <remarks>
        /// Only <see cref="string"/> and <see cref="int"/> values are counted.
        /// Note, string numbers (e.g. "10") and their integer equivalents (e.g. 10) are counted separately.
        /// </remarks>
        /// <exception cref="PhpException"><paramref name="array"/> is a <B>null</B> reference.</exception>
        /// <exception cref="PhpException">A value is neither <see cref="string"/> nor <see cref="int"/>.</exception>
        public static PhpArray array_count_values(PhpArray array)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException();
            }

            PhpArray result = new PhpArray();

            var iterator = array.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                // dereferences value:
                var val = iterator.CurrentValue.GetValue();
                IntStringKey askey;

                switch (val.TypeCode)
                {
                    case PhpTypeCode.Int32:
                    case PhpTypeCode.Long:
                    case PhpTypeCode.String:
                    case PhpTypeCode.WritableString:
                        askey = val.ToIntStringKey();
                        break;
                    default:
                        // TODO: PhpException.Throw(PhpError.Warning, LibResources.GetString("neither_string_nor_integer_value", "count"));
                        throw new ArgumentException();
                }

                var countval = result[askey].ToLong();  // 0 for nonexisting entry
                result[askey] = PhpValue.Create(countval + 1L);
            }

            // no need to deep copy (values are ints):
            return result;
        }
Exemple #13
0
        /// <summary>
        /// Converts string keys in <see cref="PhpArray"/> to upper case.
        /// </summary>
        /// <param name="array">The <see cref="PhpArray"/> to be converted.</param>
        /// <returns>The copy of <paramref name="array"/> with all string keys upper cased.</returns>
        /// <remarks>Integer keys as well as all values remain unchanged.</remarks>
        internal static PhpArray StringKeysToUpper(PhpArray/*!*/ array)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException();
            }

            var textInfo = System.Globalization.CultureInfo.CurrentCulture.TextInfo; // cache current culture to avoid repetitious CurrentCulture.get

            PhpArray result = new PhpArray(array.Count);
            using (var iterator = array.GetFastEnumerator())
                while (iterator.MoveNext())
                {
                    var entry = iterator.Current;
                    if (entry.Key.IsString)
                        result[textInfo.ToUpper(entry.Key.String)] = entry.Value;
                    else
                        result[entry.Key] = entry.Value;
                }
            return result;
        }
Exemple #14
0
        /// <summary>
        /// Retrieves a slice of specified array.
        /// </summary>
        /// <param name="array">The array which slice to get.</param>
        /// <param name="offset">The relativized offset of the first item of the slice.</param>
        /// <param name="length">The relativized length of the slice.</param>
        /// <param name="preserveKeys">Whether to preserve integer keys. If <B>false</B>, the integer keys are reset.</param>
        /// <returns>The slice of <paramref name="array"/>.</returns>
        /// <remarks>
        /// See <see cref="PhpMath.AbsolutizeRange"/> for details about <paramref name="offset"/> and <paramref name="length"/>.
        /// </remarks>
        public static PhpArray array_slice(PhpArray array, int offset, int length = int.MaxValue, bool preserveKeys = false)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException();
            }

            // absolutizes range:
            PhpMath.AbsolutizeRange(ref offset, ref length, array.Count);

            var iterator = array.GetFastEnumerator();

            // moves iterator to the first item of the slice;
            // starts either from beginning or from the end (which one is more efficient):
            if (offset < array.Count - offset)
            {
                for (int i = -1; i < offset; i++)
                    if (iterator.MoveNext() == false)
                        break;
            }
            else
            {
                for (int i = array.Count; i > offset; i--)
                    if (iterator.MovePrevious() == false)
                        break;
            }

            // copies the slice:
            PhpArray result = new PhpArray(length);
            int ikey = 0;
            for (int i = 0; i < length; i++)
            {
                var entry = iterator.Current;

                // integer keys are reindexed if preserveKeys is false, string keys are not touched:
                if (preserveKeys || entry.Key.IsString)
                {
                    result.Add(entry.Key, entry.Value);
                }
                else
                {
                    result.Add(ikey++, entry.Value);
                }

                iterator.MoveNext();
            }

            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #15
0
        /// <summary>
        /// Retrieves an array of values contained in a given array.
        /// </summary>
        /// <param name="array">An array which values to get.</param>
        /// <returns>A copy of <paramref name="array"/> with all keys indexed starting from zero.</returns>
        /// <exception cref="PhpException"><paramref name="array"/> is a <B>null</B> reference.</exception>
        /// <remarks>Doesn't dereference PHP references.</remarks>
        //[return: PhpDeepCopy]
        public static PhpArray array_values(PhpArray array)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException(nameof(array));
            }

            // references are not dereferenced:
            PhpArray result = new PhpArray(array.Count);
            var enumerator = array.GetFastEnumerator();
            while (enumerator.MoveNext())
            {
                result.Add(enumerator.CurrentValue);
            }

            // result is inplace deeply copied on return to PHP code:
            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #16
0
        /// <summary>
        /// Searches the array for a given value and returns the corresponding key if successful.
        /// </summary>
        /// <param name="needle">The value to search for.</param>
        /// <param name="haystack">The <see cref="PhpArray"/> where to search.</param>
        /// <param name="strict">Whether strict comparison method (operator ===) is used for comparing values.</param>
        /// <returns>The key associated with the <paramref name="needle"/> or <B>false</B> if there is no such key.</returns>
        /// <exception cref="PhpException"><paramref name="haystack"/> is a <B>null</B> reference (Warning).</exception>
        public static PhpValue array_search(PhpValue needle, PhpArray haystack, bool strict = false)
        {
            // result needn't to be deeply copied because it is a key of an array //

            if (haystack == null)
            {
                // TODO: PhpException.ArgumentNull("haystack");
                return PhpValue.False;
            }

            // using operator ===:
            if (strict)
            {
                using (var enumerator = haystack.GetFastEnumerator())
                    while (enumerator.MoveNext())
                    {
                        // TODO: dereferences value (because of StrictEquality operator):
                        if (needle.StrictEquals(enumerator.CurrentValue))
                            return PhpValue.Create(enumerator.CurrentKey);
                    }
            }
            else
            {
                // using operator ==:

                using (var enumerator = haystack.GetFastEnumerator())
                    while (enumerator.MoveNext())
                    {
                        // note: comparator manages references well:
                        if (needle.Equals(enumerator.CurrentValue))
                            return PhpValue.Create(enumerator.CurrentKey);
                    }
            }

            // not found:
            return PhpValue.False;
        }
Exemple #17
0
        /// <summary>
        /// Creates an array using one array for its keys and the second for its values.
        /// </summary>
        /// <param name="keys">The keys of resulting array.</param>
        /// <param name="values">The values of resulting array.</param>
        /// <returns>An array with keys from <paramref name="keys"/> values and values 
        /// from <paramref name="values"/> values.</returns>
        /// <remarks>
        /// <paramref name="keys"/> and <paramref name="values"/> should have the same length (zero is 
        /// adminssible - an empty array is returned).
        /// Keys are converted using <see cref="PHP.Core.Convert.ObjectToArrayKey"/> before hashed to resulting array.
        /// If more keys has the same value after conversion the last one is used.
        /// If a key is not a legal array key it is skipped.
        /// </remarks>
        /// <exception cref="PhpException"><paramref name="keys"/> or <paramref name="values"/> is a <B>null</B> reference.</exception>
        /// <exception cref="PhpException"><paramref name="keys"/> and <paramref name="values"/> has different length.</exception>
        /// <remarks>Doesn't dereference PHP references.</remarks>
        //[return: PhpDeepCopy]
        public static PhpArray array_combine(PhpArray keys, PhpArray values)
        {
            if (keys == null)
            {
                //PhpException.ArgumentNull("keys");
                //return null;
                throw new ArgumentNullException(nameof(keys));
            }

            if (values == null)
            {
                //PhpException.ArgumentNull("values");
                //return null;
                throw new ArgumentNullException(nameof(values));
            }

            if (keys.Count != values.Count)
            {
                //PhpException.Throw(PhpError.Warning, CoreResources.GetString("lengths_are_different", "keys", "values"));
                //return null;
                throw new ArgumentException();
            }

            IntStringKey key;

            PhpArray result = new PhpArray();
            var k_iterator = keys.GetFastEnumerator();
            var v_iterator = values.GetFastEnumerator();
            while (k_iterator.MoveNext())
            {
                v_iterator.MoveNext();

                // invalid keys are skipped, values are not dereferenced:
                if (Core.Convert.TryToIntStringKey(k_iterator.CurrentValue, out key))
                {
                    result[key] = v_iterator.CurrentValue;
                }
            }

            // result is inplace deeply copied on return to PHP code:
            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #18
0
        /// <summary>
        /// Pads array to the specified length with a value.
        /// If the length is negative adds |length| elements at beginning otherwise adds elements at the end.
        /// Values with integer keys that are contained in the source array are inserted to the resulting one with new 
        /// integer keys counted from zero (or from |length| if length negative).
        /// </summary>
        /// <param name="array">The source array.</param>
        /// <param name="length">The length of the resulting array.</param>
        /// <param name="value">The value to add in array.</param>
        /// <returns>Padded array.</returns>
        /// <exception cref="PhpException">The <paramref name="array"/> argument is a <B>null</B> reference.</exception>
        public static PhpArray array_pad(PhpArray array, int length, PhpValue value)
        {
            if (array == null)
            {
                // PhpException.ArgumentNull("array");
                // return null;
                throw new ArgumentNullException();
            }

            // number of items to add:
            int remains = Math.Abs(length) - array.Count;

            // returns unchanged array (or its deep copy if called from PHP):
            if (remains <= 0) return array;

            PhpArray result = new PhpArray(array.Count + remains);

            // prepends items:
            if (length < 0)
            {
                while (remains-- > 0) result.Add(value);
            }

            // inserts items from source array
            // if a key is a string inserts it unchanged otherwise inserts value with max. integer key:  
            var iterator = array.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                var key = iterator.CurrentKey;
                if (key.IsString)
                    result.Add(key, iterator.CurrentValue);
                else
                    result.Add(iterator.CurrentValue);
            }

            // appends items:
            if (length > 0)
            {
                while (remains-- > 0) result.Add(value);
            }

            // the result is inplace deeply copied on return to PHP code:
            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #19
0
        /// <summary>
        /// Computes a product of all values in an array. 
        /// Each value is converted to a number in the same way it is done by PHP.
        /// </summary>
        /// <exception cref="PhpException">Thrown if the <paramref name="array"/> argument is null.</exception>
        /// <returns>
        /// An integer, if all items are integers or strings converted to integers and the result is in integer range.
        /// A double, otherwise.
        /// </returns>
        public static PhpNumber array_product(PhpArray array)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return 0;
                throw new ArgumentNullException(nameof(array));
            }

            if (array.Count == 0)
            {
                return PhpNumber.Default;
            }

            PhpNumber result = PhpNumber.Create(1L);
            PhpNumber num;

            var iterator = array.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                iterator.CurrentValue.ToNumber(out num);

                result *= num;
            }

            //
            return result;
        }
Exemple #20
0
        public static PhpArray preg_grep(Context ctx, string pattern, PhpArray input, int flags = 0)
        {
            if (input == null)
            {
                return null;
            }

            var result = new PhpArray(input.Count);

            if (input.Count != 0)
            {
                var regex = new PerlRegex.Regex(pattern);

                var enumerator = input.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    var str = enumerator.CurrentValue.ToStringOrThrow(ctx);
                    var m = regex.Match(str);

                    // move a copy to return array if success and not invert or
                    // not success and invert
                    if (m.Success ^ (flags & PREG_GREP_INVERT) != 0)
                    {
                        result.Add(enumerator.CurrentKey, enumerator.CurrentValue.DeepCopy());
                    }
                }
            }

            //
            return result;
        }
Exemple #21
0
        /// <summary>
        /// Compares two instances of <see cref="PhpArray"/> for strict equality.
        /// </summary>
        /// <param name="x">First operand. Cannot be <c>null</c>.</param>
        /// <param name="y">Second operand. Cannot be <c>null</c>.</param>
        /// <param name="incomparable">Whether arrays are incomparable
        /// (no difference is found before both arrays enters an infinite recursion).
        /// Returns <B>true</B> then.</param>
        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 (ReferenceEquals(x.table, y.table))
            {
                return(true);                                   // => x == y
            }
            // if numbers of elements differs:
            if (x.Count != y.Count)
            {
                return(false);
            }

            var iter_x = x.GetFastEnumerator();
            var iter_y = y.GetFastEnumerator();

            PhpArray array_x, array_y;

            // marks arrays as visited (will be always restored to false value before return):
            x._visited++;
            y._visited++;

            bool result = true;

            try
            {
                // compares corresponding elements (keys first values then):
                while (result && iter_x.MoveNext())
                {
                    iter_y.MoveNext();

                    // compares keys:
                    if (!iter_x.Current.Key.Equals(iter_y.Current.Key))
                    {
                        result = false;
                        break;
                    }

                    var child_x = iter_x.CurrentValue;
                    var child_y = iter_y.CurrentValue;

                    // compares values:
                    if ((array_x = child_x.ArrayOrNull()) != null)
                    {
                        if ((array_y = child_y.ArrayOrNull()) != null)
                        {
                            // at least one child has not been visited yet => continue with recursion:
                            if (array_x._visited == 0 || array_y._visited == 0)
                            {
                                result = StrictCompareArrays(array_x, array_y, out incomparable);
                            }
                            else
                            {
                                incomparable = true;
                                break;
                            }
                        }
                        else
                        {
                            // an array with a non-array comparison:
                            result = false;
                        }
                    }
                    else
                    {
                        // compares unknown item with a non-array:
                        result = child_x.GetValue().StrictEquals(child_y.GetValue());
                    }
                } // while
            }
            finally
            {
                x._visited--;
                y._visited--;
            }
            return(result);
        }