diff options
Diffstat (limited to 'src/array.js')
-rw-r--r-- | src/array.js | 137 |
1 files changed, 127 insertions, 10 deletions
diff --git a/src/array.js b/src/array.js index 6ed14760..df080a76 100644 --- a/src/array.js +++ b/src/array.js @@ -67,6 +67,25 @@ function GetSortedArrayKeys(array, intervals) { } +function SparseJoinWithSeparator(array, len, convert, separator) { + var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); + var totalLength = 0; + var elements = new InternalArray(keys.length * 2); + var previousKey = -1; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (key != previousKey) { // keys may contain duplicates. + var e = array[key]; + if (!IS_STRING(e)) e = convert(e); + elements[i * 2] = key; + elements[i * 2 + 1] = e; + previousKey = key; + } + } + return %SparseJoinWithSeparator(elements, len, separator); +} + + // Optimized for sparse arrays if separator is ''. function SparseJoin(array, len, convert) { var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); @@ -110,8 +129,12 @@ function Join(array, length, separator, convert) { // Attempt to convert the elements. try { - if (UseSparseVariant(array, length, is_array) && (separator.length == 0)) { - return SparseJoin(array, length, convert); + if (UseSparseVariant(array, length, is_array)) { + if (separator.length == 0) { + return SparseJoin(array, length, convert); + } else { + return SparseJoinWithSeparator(array, length, convert, separator); + } } // Fast case for one-element arrays. @@ -129,10 +152,8 @@ function Join(array, length, separator, convert) { var elements_length = 0; for (var i = 0; i < length; i++) { var e = array[i]; - if (!IS_UNDEFINED(e)) { - if (!IS_STRING(e)) e = convert(e); - elements[elements_length++] = e; - } + if (!IS_STRING(e)) e = convert(e); + elements[elements_length++] = e; } elements.length = elements_length; var result = %_FastAsciiArrayJoin(elements, ''); @@ -151,11 +172,12 @@ function Join(array, length, separator, convert) { } else { for (var i = 0; i < length; i++) { var e = array[i]; - if (IS_NUMBER(e)) elements[i] = %_NumberToString(e); - else { - if (!IS_STRING(e)) e = convert(e); + if (IS_NUMBER(e)) { + e = %_NumberToString(e); + } else if (!IS_STRING(e)) { + e = convert(e); + } elements[i] = e; - } } } var result = %_FastAsciiArrayJoin(elements, separator); @@ -375,6 +397,11 @@ function ArrayToLocaleString() { function ArrayJoin(separator) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.join"]); + } + if (IS_UNDEFINED(separator)) { separator = ','; } else if (!IS_STRING(separator)) { @@ -391,6 +418,11 @@ function ArrayJoin(separator) { // Removes the last element from the array and returns it. See // ECMA-262, section 15.4.4.6. function ArrayPop() { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.pop"]); + } + var n = TO_UINT32(this.length); if (n == 0) { this.length = n; @@ -407,6 +439,11 @@ function ArrayPop() { // Appends the arguments to the end of the array and returns the new // length of the array. See ECMA-262, section 15.4.4.7. function ArrayPush() { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.push"]); + } + var n = TO_UINT32(this.length); var m = %_ArgumentsLength(); for (var i = 0; i < m; i++) { @@ -418,6 +455,11 @@ function ArrayPush() { function ArrayConcat(arg1) { // length == 1 + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.concat"]); + } + var arg_count = %_ArgumentsLength(); var arrays = new InternalArray(1 + arg_count); arrays[0] = this; @@ -474,6 +516,11 @@ function SparseReverse(array, len) { function ArrayReverse() { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.reverse"]); + } + var j = TO_UINT32(this.length) - 1; if (UseSparseVariant(this, j, IS_ARRAY(this))) { @@ -505,6 +552,11 @@ function ArrayReverse() { function ArrayShift() { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.shift"]); + } + var len = TO_UINT32(this.length); if (len === 0) { @@ -526,6 +578,11 @@ function ArrayShift() { function ArrayUnshift(arg1) { // length == 1 + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.unshift"]); + } + var len = TO_UINT32(this.length); var num_arguments = %_ArgumentsLength(); @@ -545,6 +602,11 @@ function ArrayUnshift(arg1) { // length == 1 function ArraySlice(start, end) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.slice"]); + } + var len = TO_UINT32(this.length); var start_i = TO_INTEGER(start); var end_i = len; @@ -582,6 +644,11 @@ function ArraySlice(start, end) { function ArraySplice(start, delete_count) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.splice"]); + } + var num_arguments = %_ArgumentsLength(); var len = TO_UINT32(this.length); @@ -653,6 +720,11 @@ function ArraySplice(start, delete_count) { function ArraySort(comparefn) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.sort"]); + } + // In-place QuickSort algorithm. // For short (length <= 22) arrays, insertion sort is used for efficiency. @@ -914,6 +986,11 @@ function ArraySort(comparefn) { // preserving the semantics, since the calls to the receiver function can add // or delete elements from the array. function ArrayFilter(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.filter"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -935,6 +1012,11 @@ function ArrayFilter(f, receiver) { function ArrayForEach(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.forEach"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -953,6 +1035,11 @@ function ArrayForEach(f, receiver) { // Executes the function once for each element present in the // array until it finds one where callback returns true. function ArraySome(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.some"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -970,6 +1057,11 @@ function ArraySome(f, receiver) { function ArrayEvery(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.every"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -986,6 +1078,11 @@ function ArrayEvery(f, receiver) { } function ArrayMap(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.map"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -1006,6 +1103,11 @@ function ArrayMap(f, receiver) { function ArrayIndexOf(element, index) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.indexOf"]); + } + var length = TO_UINT32(this.length); if (length == 0) return -1; if (IS_UNDEFINED(index)) { @@ -1063,6 +1165,11 @@ function ArrayIndexOf(element, index) { function ArrayLastIndexOf(element, index) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.lastIndexOf"]); + } + var length = TO_UINT32(this.length); if (length == 0) return -1; if (%_ArgumentsLength() < 2) { @@ -1116,6 +1223,11 @@ function ArrayLastIndexOf(element, index) { function ArrayReduce(callback, current) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.reduce"]); + } + if (!IS_FUNCTION(callback)) { throw MakeTypeError('called_non_callable', [callback]); } @@ -1145,6 +1257,11 @@ function ArrayReduce(callback, current) { } function ArrayReduceRight(callback, current) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.reduceRight"]); + } + if (!IS_FUNCTION(callback)) { throw MakeTypeError('called_non_callable', [callback]); } |