Index: src/typedarray.js |
diff --git a/src/typedarray.js b/src/typedarray.js |
index d5357b4f2cbdbd3c656041754ac6ea0b863def16..f9e732fa7f8f35bfd13598746c8a02f9af98b2ef 100644 |
--- a/src/typedarray.js |
+++ b/src/typedarray.js |
@@ -144,30 +144,103 @@ function CreateSubArray(elementSize, constructor) { |
} |
} |
+function TypedArraySetFromArrayLike(target, source, sourceLength, offset) { |
+ if (offset > 0) { |
+ for (var i = 0; i < sourceLength; i++) { |
+ target[offset + i] = source[i]; |
+ } |
+ } |
+ else { |
+ for (var i = 0; i < sourceLength; i++) { |
+ target[i] = source[i]; |
+ } |
+ } |
+} |
+ |
+function TypedArraySetFromOverlappingTypedArray(target, source, offset) { |
+ var sourceElementSize = source.BYTES_PER_ELEMENT; |
+ var targetElementSize = target.BYTES_PER_ELEMENT; |
+ var sourceLength = source.length; |
+ |
+ // Copy left part. |
+ function CopyLeftPart() { |
+ // First un-mutated byte after the next write |
+ var targetPtr = target.byteOffset + (offset + 1) * targetElementSize; |
+ // Next read at sourcePtr. We do not care for memory changing before |
+ // sourcePtr - we have already copied it. |
+ var sourcePtr = source.byteOffset; |
+ for (var leftIndex = 0; |
+ leftIndex < sourceLength && targetPtr <= sourcePtr; |
+ leftIndex++) { |
+ target[offset + leftIndex] = source[leftIndex]; |
+ targetPtr += targetElementSize; |
+ sourcePtr += sourceElementSize; |
+ } |
+ return leftIndex; |
+ } |
+ var leftIndex = CopyLeftPart(); |
+ |
+ // Copy rigth part; |
+ function CopyRightPart() { |
+ // First unmutated byte before the next write |
+ var targetPtr = |
+ target.byteOffset + (offset + sourceLength - 1) * targetElementSize; |
+ // Next read before sourcePtr. We do not care for memory changing after |
+ // sourcePtr - we have already copied it. |
+ var sourcePtr = |
+ source.byteOffset + sourceLength * sourceElementSize; |
+ for(var rightIndex = sourceLength - 1; |
+ rightIndex >= leftIndex && targetPtr >= sourcePtr; |
+ rightIndex--) { |
+ target[offset + rightIndex] = source[rightIndex]; |
+ targetPtr -= targetElementSize; |
+ sourcePtr -= sourceElementSize; |
+ } |
+ return rightIndex; |
+ } |
+ var rightIndex = CopyRightPart(); |
+ |
+ var temp = new $Array(rightIndex + 1 - leftIndex); |
+ for (var i = leftIndex; i <= rightIndex; i++) { |
+ temp[i - leftIndex] = source[i]; |
+ } |
+ for (i = leftIndex; i <= rightIndex; i++) { |
+ target[offset + i] = temp[i - leftIndex]; |
+ } |
+} |
+ |
function TypedArraySet(obj, offset) { |
var intOffset = IS_UNDEFINED(offset) ? 0 : TO_INTEGER(offset); |
if (intOffset < 0) { |
throw MakeTypeError("typed_array_set_negative_offset"); |
} |
- if (%TypedArraySetFastCases(this, obj, intOffset)) |
- return; |
- |
- var l = obj.length; |
- if (IS_UNDEFINED(l)) { |
- if (IS_NUMBER(obj)) { |
- // For number as a first argument, throw TypeError |
- // instead of silently ignoring the call, so that |
- // the user knows (s)he did something wrong. |
- // (Consistent with Firefox and Blink/WebKit) |
- throw MakeTypeError("invalid_argument"); |
- } |
- return; |
- } |
- if (intOffset + l > this.length) { |
- throw MakeRangeError("typed_array_set_source_too_large"); |
- } |
- for (var i = 0; i < l; i++) { |
- this[intOffset + i] = obj[i]; |
+ switch (%TypedArraySetFastCases(this, obj, intOffset)) { |
+ // These numbers should be synchronized with runtime.cc. |
+ case 0: // TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE |
+ return; |
+ case 1: // TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING |
+ TypedArraySetFromOverlappingTypedArray(this, obj, intOffset); |
+ return; |
+ case 2: // TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING |
+ TypedArraySetFromArrayLike(this, obj, obj.length, intOffset); |
+ return; |
+ case 3: // TYPED_ARRAY_SET_NON_TYPED_ARRAY |
+ var l = obj.length; |
+ if (IS_UNDEFINED(l)) { |
+ if (IS_NUMBER(obj)) { |
+ // For number as a first argument, throw TypeError |
+ // instead of silently ignoring the call, so that |
+ // the user knows (s)he did something wrong. |
+ // (Consistent with Firefox and Blink/WebKit) |
+ throw MakeTypeError("invalid_argument"); |
+ } |
+ return; |
+ } |
+ if (intOffset + l > this.length) { |
+ throw MakeRangeError("typed_array_set_source_too_large"); |
+ } |
+ TypedArraySetFromArrayLike(this, obj, l, intOffset); |
+ return; |
} |
} |