The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ ArrayPrototype

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using Microsoft.JScript.Vsa;
  19.     using System;
  20.     using System.Reflection;
  21.     using System.Text;
  22.    
  23.     public class ArrayPrototype : ArrayObject
  24.     {
  25.         static internal readonly ArrayPrototype ob = new ArrayPrototype(ObjectPrototype.ob);
  26.         static internal ArrayConstructor _constructor;
  27.        
  28.         internal ArrayPrototype(ObjectPrototype parent) : base(parent)
  29.         {
  30.             this.noExpando = true;
  31.         }
  32.        
  33.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs | JSFunctionAttributeEnum.HasEngine, JSBuiltin.Array_concat)]
  34.         public static ArrayObject concat(object thisob, VsaEngine engine, params object[] args)
  35.         {
  36.             ArrayObject arrayObj = engine.GetOriginalArrayConstructor().Construct();
  37.             if (thisob is ArrayObject)
  38.                 arrayObj.Concat((ArrayObject)thisob);
  39.             else
  40.                 arrayObj.Concat(thisob);
  41.             for (int i = 0; i < args.Length; i++) {
  42.                 object arg = args[i];
  43.                 if (arg is ArrayObject)
  44.                     arrayObj.Concat((ArrayObject)arg);
  45.                 else
  46.                     arrayObj.Concat(arg);
  47.             }
  48.             return arrayObj;
  49.         }
  50.        
  51.         public static ArrayConstructor constructor {
  52.             get { return ArrayPrototype._constructor; }
  53.         }
  54.        
  55.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_join)]
  56.         public static string join(object thisob, object separator)
  57.         {
  58.             if (separator is Missing)
  59.                 return Join(thisob, ",", false);
  60.             else
  61.                 return Join(thisob, Convert.ToString(separator), false);
  62.         }
  63.        
  64.         static internal string Join(object thisob, string separator, bool localize)
  65.         {
  66.             StringBuilder str = new StringBuilder();
  67.             uint thisLength = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  68.             if (thisLength > int.MaxValue)
  69.                 throw new JScriptException(JSError.OutOfMemory);
  70.             // Small optimization so we're not doing a bunch of reallocs for large arrays.
  71.             if (thisLength > str.Capacity)
  72.                 str.Capacity = (int)thisLength;
  73.             for (uint i = 0; i < thisLength; i++) {
  74.                 object value = LateBinding.GetValueAtIndex(thisob, i);
  75.                 if (value != null && !(value is Missing)) {
  76.                     if (localize)
  77.                         str.Append(Convert.ToLocaleString(value));
  78.                     else
  79.                         str.Append(Convert.ToString(value));
  80.                 }
  81.                 if (i < thisLength - 1)
  82.                     str.Append(separator);
  83.             }
  84.             return str.ToString();
  85.         }
  86.        
  87.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_pop)]
  88.         public static object pop(object thisob)
  89.         {
  90.             uint thisLength = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  91.             if (thisLength == 0) {
  92.                 LateBinding.SetMemberValue(thisob, "length", 0);
  93.                 return null;
  94.             }
  95.             object result = LateBinding.GetValueAtIndex(thisob, thisLength - 1);
  96.             LateBinding.DeleteValueAtIndex(thisob, thisLength - 1);
  97.             LateBinding.SetMemberValue(thisob, "length", thisLength - 1);
  98.             return result;
  99.         }
  100.        
  101.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs, JSBuiltin.Array_push)]
  102.         public static long push(object thisob, params object[] args)
  103.         {
  104.             uint length = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  105.             for (uint i = 0; i < args.Length; i++)
  106.                 LateBinding.SetValueAtIndex(thisob, i + (ulong)length, args[i]);
  107.             long newLength = length + args.Length;
  108.             LateBinding.SetMemberValue(thisob, "length", newLength);
  109.             return newLength;
  110.         }
  111.        
  112.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_reverse)]
  113.         public static object reverse(object thisob)
  114.         {
  115.             uint thisLength = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  116.             uint halfSize = thisLength / 2;
  117.             for (uint low = 0uint high = thisLength - 1; low < halfSize; low++,high--)
  118.                 LateBinding.SwapValues(thisob, low, high);
  119.             return thisob;
  120.         }
  121.        
  122.         internal override void SetMemberValue(string name, object value)
  123.         {
  124.             if (this.noExpando)
  125.                 //This the fast prototype
  126.                 throw new JScriptException(JSError.OLENoPropOrMethod);
  127.             base.SetMemberValue(name, value);
  128.         }
  129.        
  130.         internal override void SetValueAtIndex(uint index, object value)
  131.         {
  132.             if (this.noExpando)
  133.                 //This the fast prototype
  134.                 throw new JScriptException(JSError.OLENoPropOrMethod);
  135.             base.SetValueAtIndex(index, value);
  136.         }
  137.        
  138.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_shift)]
  139.         public static object shift(object thisob)
  140.         {
  141.             object res = null;
  142.             if (thisob is ArrayObject)
  143.                 return ((ArrayObject)thisob).Shift();
  144.             uint length = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  145.             if (length == 0) {
  146.                 LateBinding.SetMemberValue(thisob, "length", 0);
  147.                 return res;
  148.             }
  149.             res = LateBinding.GetValueAtIndex(thisob, 0);
  150.             for (uint i = 1; i < length; i++) {
  151.                 object val = LateBinding.GetValueAtIndex(thisob, i);
  152.                 if (val is Missing)
  153.                     LateBinding.DeleteValueAtIndex(thisob, i - 1);
  154.                 else
  155.                     LateBinding.SetValueAtIndex(thisob, i - 1, val);
  156.             }
  157.             LateBinding.DeleteValueAtIndex(thisob, length - 1);
  158.             LateBinding.SetMemberValue(thisob, "length", length - 1);
  159.             return res;
  160.         }
  161.        
  162.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine, JSBuiltin.Array_slice)]
  163.         public static ArrayObject slice(object thisob, VsaEngine engine, double start, object end)
  164.         {
  165.             ArrayObject array = engine.GetOriginalArrayConstructor().Construct();
  166.             uint length = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  167.             // compute the start index
  168.             long startIndex = Runtime.DoubleToInt64(Convert.ToInteger(start));
  169.             if (startIndex < 0) {
  170.                 startIndex = length + startIndex;
  171.                 if (startIndex < 0)
  172.                     startIndex = 0;
  173.             }
  174.             else if (startIndex > length)
  175.                 startIndex = length;
  176.             // compute the end index
  177.             long endIndex = length;
  178.             if (end != null && !(end is Missing)) {
  179.                 endIndex = Runtime.DoubleToInt64(Convert.ToInteger(end));
  180.                 if (endIndex < 0) {
  181.                     endIndex = length + endIndex;
  182.                     if (endIndex < 0)
  183.                         endIndex = 0;
  184.                 }
  185.                 else if (endIndex > length)
  186.                     endIndex = length;
  187.             }
  188.             // slice
  189.             if (endIndex > startIndex) {
  190.                 array.length = endIndex - startIndex;
  191.                 for (ulong i = (ulong)startIndexulong j = 0; i < (ulong)endIndex; i++,j++) {
  192.                     object val = LateBinding.GetValueAtIndex(thisob, i);
  193.                     if (!(val is Missing))
  194.                         LateBinding.SetValueAtIndex(array, j, val);
  195.                 }
  196.             }
  197.             return array;
  198.         }
  199.        
  200.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_sort)]
  201.         public static object sort(object thisob, object function)
  202.         {
  203.             ScriptFunction func = null;
  204.             if (function is ScriptFunction)
  205.                 func = (ScriptFunction)function;
  206.             uint length = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  207.             if (thisob is ArrayObject)
  208.                 ((ArrayObject)thisob).Sort(func);
  209.             else if (length <= Int32.MaxValue) {
  210.                 QuickSort qs = new QuickSort(thisob, func);
  211.                 qs.SortObject(0, length);
  212.             }
  213.             return thisob;
  214.         }
  215.        
  216.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs | JSFunctionAttributeEnum.HasEngine, JSBuiltin.Array_splice)]
  217.         public static ArrayObject splice(object thisob, VsaEngine engine, double start, double deleteCnt, params object[] args)
  218.         {
  219.             uint oldLength = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  220.             // compute the start index
  221.             long startIndex = Runtime.DoubleToInt64(Convert.ToInteger(start));
  222.             if (startIndex < 0) {
  223.                 startIndex = oldLength + startIndex;
  224.                 if (startIndex < 0)
  225.                     startIndex = 0;
  226.             }
  227.             else if (startIndex > oldLength)
  228.                 startIndex = oldLength;
  229.            
  230.             // compute the number of items to delete
  231.             long deleteCount = Runtime.DoubleToInt64(Convert.ToInteger(deleteCnt));
  232.             if (deleteCount < 0)
  233.                 deleteCount = 0;
  234.             else if (deleteCount > oldLength - startIndex)
  235.                 deleteCount = oldLength - startIndex;
  236.             long newLength = oldLength + args.Length - deleteCount;
  237.            
  238.             // create an array for the result
  239.             ArrayObject result = engine.GetOriginalArrayConstructor().Construct();
  240.             result.length = deleteCount;
  241.            
  242.             // special case array objects (nice speedup if dense)
  243.             if (thisob is ArrayObject) {
  244.                 ((ArrayObject)thisob).Splice((uint)startIndex, (uint)deleteCount, args, result, (uint)oldLength, (uint)newLength);
  245.                 return result;
  246.             }
  247.            
  248.             // copy the deleted items to the result array
  249.             for (ulong i = 0; i < (ulong)deleteCount; i++)
  250.                 result.SetValueAtIndex((uint)i, LateBinding.GetValueAtIndex(thisob, i + (ulong)startIndex));
  251.            
  252.             // shift the remaining elements left or right
  253.             long n = oldLength - startIndex - deleteCount;
  254.             if (newLength < oldLength) {
  255.                 for (long i = 0; i < n; i++)
  256.                     LateBinding.SetValueAtIndex(thisob, (ulong)(i + startIndex + args.Length), LateBinding.GetValueAtIndex(thisob, (ulong)(i + startIndex + deleteCount)));
  257.                 LateBinding.SetMemberValue(thisob, "length", newLength);
  258.             }
  259.             else {
  260.                 LateBinding.SetMemberValue(thisob, "length", newLength);
  261.                 for (long i = n - 1; i >= 0; i--)
  262.                     LateBinding.SetValueAtIndex(thisob, (ulong)(i + startIndex + args.Length), LateBinding.GetValueAtIndex(thisob, (ulong)(i + startIndex + deleteCount)));
  263.             }
  264.            
  265.             // splice in the arguments
  266.             int m = args == null ? 0 : args.Length;
  267.             for (uint i = 0; i < m; i++)
  268.                 LateBinding.SetValueAtIndex(thisob, i + (ulong)startIndex, args[i]);
  269.            
  270.             return result;
  271.         }
  272.        
  273.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_toLocaleString)]
  274.         public static string toLocaleString(object thisob)
  275.         {
  276.             if (thisob is ArrayObject) {
  277.                 StringBuilder sep = new StringBuilder(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator);
  278.                 if (sep[sep.Length - 1] != ' ')
  279.                     sep.Append(' ');
  280.                 return ArrayPrototype.Join(thisob, sep.ToString(), true);
  281.             }
  282.             throw new JScriptException(JSError.NeedArrayObject);
  283.         }
  284.        
  285.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_toString)]
  286.         public static string toString(object thisob)
  287.         {
  288.             if (thisob is ArrayObject)
  289.                 return ArrayPrototype.Join(thisob, ",", false);
  290.             throw new JScriptException(JSError.NeedArrayObject);
  291.         }
  292.        
  293.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs, JSBuiltin.Array_unshift)]
  294.         public static object unshift(object thisob, params object[] args)
  295.         {
  296.             if (args == null || args.Length == 0)
  297.                 return thisob;
  298.             if (thisob is ArrayObject)
  299.                 return ((ArrayObject)thisob).Unshift(args);
  300.             uint oldLength = Convert.ToUint32(LateBinding.GetMemberValue(thisob, "length"));
  301.             long newLength = oldLength + args.Length;
  302.             LateBinding.SetMemberValue(thisob, "length", newLength);
  303.             // shift the array
  304.             for (long i = oldLength - 1; i >= 0; i--) {
  305.                 object val = LateBinding.GetValueAtIndex(thisob, (ulong)i);
  306.                 if (val is Missing)
  307.                     LateBinding.DeleteValueAtIndex(thisob, (ulong)(i + args.Length));
  308.                 else
  309.                     LateBinding.SetValueAtIndex(thisob, (ulong)(i + args.Length), val);
  310.             }
  311.             // copy the input args
  312.             for (uint i = 0; i < args.Length; i++)
  313.                 LateBinding.SetValueAtIndex(thisob, i, args[i]);
  314.             return thisob;
  315.         }
  316.        
  317.     }
  318. }

Developer Fusion