Represents an array with non-consecutive elements.
예제 #1
0
 /// <summary>
 /// Creates a sparse array from the given dense array.
 /// </summary>
 /// <param name="array"> The array to copy items from. </param>
 /// <param name="length"> The number of items to copy. </param>
 /// <returns> A new sparse array containing the items from the given array. </returns>
 public static SparseArray FromDenseArray(object[] array, int length)
 {
     if (array == null)
         throw new ArgumentNullException("array");
     if (length > array.Length)
         throw new ArgumentOutOfRangeException("length");
     var result = new SparseArray();
     result.CopyTo(array, 0, length);
     return result;
 }
예제 #2
0
        /// <summary>
        /// Creates a new array and initializes it with the given sparse array.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="sparseArray"> The sparse array to use as the backing store. </param>
        /// <param name="length"> The initial value of the length property. </param>
        private ArrayInstance(ObjectInstance prototype, SparseArray sparseArray, uint length)
            : base(prototype)
        {
            if (sparseArray == null)
                throw new ArgumentNullException("sparseArray");
            this.sparse = sparseArray;

            // Create a fake property for length plus initialize the real length property.
            this.length = length;
            FastSetProperty("length", -1, PropertyAttributes.Writable | PropertyAttributes.IsLengthProperty);
        }
예제 #3
0
        //     INITIALIZATION
        //_________________________________________________________________________________________
        /// <summary>
        /// Creates a new array with the given length and capacity.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="length"> The initial value of the length property. </param>
        /// <param name="capacity"> The number of elements to allocate. </param>
        internal ArrayInstance(ObjectInstance prototype, uint length, uint capacity)
            : base(prototype)
        {
            if (length > capacity)
                throw new ArgumentOutOfRangeException("length", "length must be less than or equal to capacity.");
            if (length <= 1000)
            {
                this.dense = new object[(int)capacity];
                this.denseMayContainHoles = length > 0;
            }
            else
            {
                this.sparse = new SparseArray();
            }

            // Create a fake property for length plus initialize the real length property.
            this.length = length;
            FastSetProperty("length", -1, PropertyAttributes.Writable | PropertyAttributes.IsLengthProperty);
        }
예제 #4
0
        public static ArrayInstance Concat(ObjectInstance thisObj, params object[] items)
        {
            // Create a new items array with the thisObject at the beginning.
            var temp = new object[items.Length + 1];
            temp[0] = thisObj;
            Array.Copy(items, 0, temp, 1, items.Length);
            items = temp;

            // Determine if the resulting array should be dense or sparse and calculate the length
            // at the same time.
            bool dense = true;
            uint length = (uint)items.Length;
            foreach (object item in items)
                if (item is ArrayInstance)
                {
                    length += ((ArrayInstance)item).Length - 1;
                    if (((ArrayInstance)item).dense == null)
                        dense = false;
                }

            // This method only supports arrays of length up to 2^31-1, rather than 2^32-1.
            if (length > int.MaxValue)
                throw new JavaScriptException(thisObj.Engine, "RangeError", "The resulting array is too long");

            if (dense == true)
            {
                // Create a dense array.
                var result = new object[length];

                int index = 0;
                foreach (object item in items)
                {
                    if (item is ArrayInstance)
                    {
                        // Add the items in the array to the end of the resulting array.
                        var array = (ArrayInstance)item;
                        Array.Copy(array.dense, 0, result, index, (int)array.Length);
                        if (array.denseMayContainHoles == true && array.Prototype != null)
                        {
                            // Populate holes from the prototype.
                            for (uint i = 0; i < array.length; i++)
                                if (array.dense[i] == null)
                                    result[index + i] = array.Prototype.GetPropertyValue(i);
                        }
                        index += (int)array.Length;
                    }
                    else
                    {
                        // Add the item to the end of the resulting array.
                        result[index ++] = item;
                    }
                }

                // Return the new dense array.
                return new ArrayInstance(thisObj.Engine.Array.InstancePrototype, result);
            }
            else
            {
                // Create a new sparse array.
                var result = new SparseArray();

                int index = 0;
                foreach (object item in items)
                {
                    if (item is ArrayInstance)
                    {
                        // Add the items in the array to the end of the resulting array.
                        var array = (ArrayInstance)item;
                        if (array.dense != null)
                        {
                            result.CopyTo(array.dense, (uint)index, (int)array.Length);
                            if (array.Prototype != null)
                            {
                                // Populate holes from the prototype.
                                for (uint i = 0; i < array.length; i++)
                                    if (array.dense[i] == null)
                                        result[(uint)index + i] = array.Prototype.GetPropertyValue(i);
                            }
                        }
                        else
                        {
                            result.CopyTo(array.sparse, (uint)index);
                            if (array.Prototype != null)
                            {
                                // Populate holes from the prototype.
                                for (uint i = 0; i < array.Length; i++)
                                    if (array.sparse[i] == null)
                                        result[(uint)index + i] = array.Prototype.GetPropertyValue(i);
                            }
                        }
                        index += (int)array.Length;
                    }
                    else
                    {
                        // Add the item to the end of the resulting array.
                        result[(uint)index] = item;
                        index++;
                    }
                }

                // Return the new sparse array.
                return new ArrayInstance(thisObj.Engine.Array.InstancePrototype, result, length);
            }
        }
예제 #5
0
        /// <summary>
        /// Sets the value of the property with the given array index.  If a property with the
        /// given index does not exist, or exists in the prototype chain (and is not a setter) then
        /// a new property is created.
        /// </summary>
        /// <param name="index"> The array index of the property to set. </param>
        /// <param name="value"> The value to set the property to.  This must be a javascript
        /// primitive (double, string, etc) or a class derived from <see cref="ObjectInstance"/>. </param>
        /// <param name="throwOnError"> <c>true</c> to throw an exception if the property could not
        /// be set.  This can happen if the property is read-only or if the object is sealed. </param>
        public override void SetPropertyValue(uint index, object value, bool throwOnError)
        {
            value = value ?? Undefined.Value;
            if (this.dense != null)
            {
                if (index < this.length)
                {
                    // The index is inside the existing bounds of the array.
                    this.dense[index] = value;
                }
                else if (index < this.dense.Length)
                {
                    // The index is outside the bounds of the array but inside the allocated buffer.
                    this.dense[index] = value;
                    this.denseMayContainHoles = this.denseMayContainHoles || index > this.length;
                    this.length = index + 1;
                }
                else
                {
                    // The index is out of range - either enlarge the array or switch to sparse.
                    if (index < this.dense.Length + 10)
                    {
                        // Enlarge the dense array.
                        ResizeDenseArray((uint)(this.dense.Length * 2 + 10), this.length);

                        // Set the value.
                        this.dense[index] = value;
                        this.denseMayContainHoles = this.denseMayContainHoles || index > this.length;
                    }
                    else
                    {
                        // Switch to a sparse array.
                        this.sparse = SparseArray.FromDenseArray(this.dense, (int)this.length);
                        this.dense = null;
                        this.sparse[index] = value;
                    }

                    // Update the length.
                    this.length = index + 1;
                }
            }
            else
            {
                // Set the value and update the length.
                this.sparse[index] = value;
                this.length = Math.Max(this.length, index + 1);
            }
        }
예제 #6
0
        /// <summary>
        /// Copies the elements of the given sparse array to this sparse array, starting at a
        /// particular index.  Existing values are overwritten.
        /// </summary>
        /// <param name="source"> The sparse array to copy. </param>
        /// <param name="start"> The zero-based index at which copying begins. </param>
        public void CopyTo(SparseArray source, uint start)
        {
            foreach (var sourceRange in source.Ranges)
            {
                int sourceOffset = 0;
                uint destIndex = start + sourceRange.StartIndex;

                do
                {
                    // Get a reference to the array to copy to.
                    object[] dest = FindOrCreateArray(start, writeAccess: true);
                    int destOffset = (int)(destIndex & NodeMask);

                    // Copy as much as possible.
                    int copyLength = Math.Min(sourceRange.Length - sourceOffset, dest.Length - destOffset);
                    Array.Copy(sourceRange.Array, sourceOffset, dest, destOffset, copyLength);

                    start += (uint)copyLength;
                    sourceOffset += copyLength;
                } while (sourceOffset < sourceRange.Length);
            }
        }