Skip to content

Commit

Permalink
fix(copy): add support for ArrayBuffer, handle multiple references to…
Browse files Browse the repository at this point in the history
… ArrayBuffer

Closes: angular#13640
  • Loading branch information
jbedard authored and lgalfaso committed Dec 31, 2015
1 parent 7b51243 commit 986647a
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 2 deletions.
17 changes: 15 additions & 2 deletions src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,10 @@ function isTypedArray(value) {
return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
}

function isArrayBuffer(obj) {
return toString.call(obj) === '[object ArrayBuffer]';
}


var trim = function(value) {
return isString(value) ? value.trim() : value;
Expand Down Expand Up @@ -807,7 +811,7 @@ function copy(source, destination) {
var stackDest = [];

if (destination) {
if (isTypedArray(destination)) {
if (isTypedArray(destination) || isArrayBuffer(destination)) {
throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
}
if (source === destination) {
Expand Down Expand Up @@ -907,7 +911,16 @@ function copy(source, destination) {
case '[object Uint8ClampedArray]':
case '[object Uint16Array]':
case '[object Uint32Array]':
return new source.constructor(source);
return new source.constructor(copyElement(source.buffer));

case '[object ArrayBuffer]':
//Support: IE10
if (!source.slice) {
var copied = new ArrayBuffer(source.byteLength);
new Uint8Array(copied).set(new Uint8Array(source));
return copied;
}
return source.slice(0);

case '[object Boolean]':
case '[object Number]':
Expand Down
60 changes: 60 additions & 0 deletions test/AngularSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ describe('angular', function() {
expect(copy(src) instanceof Uint8Array).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

Expand All @@ -97,6 +98,7 @@ describe('angular', function() {
expect(copy(src) instanceof Uint8ClampedArray).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

Expand All @@ -108,6 +110,7 @@ describe('angular', function() {
expect(copy(src) instanceof Uint16Array).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

Expand All @@ -119,6 +122,7 @@ describe('angular', function() {
expect(copy(src) instanceof Uint32Array).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

Expand All @@ -130,6 +134,7 @@ describe('angular', function() {
expect(copy(src) instanceof Int8Array).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

Expand All @@ -141,6 +146,7 @@ describe('angular', function() {
expect(copy(src) instanceof Int16Array).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

Expand All @@ -152,6 +158,7 @@ describe('angular', function() {
expect(copy(src) instanceof Int32Array).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

Expand All @@ -163,6 +170,7 @@ describe('angular', function() {
expect(copy(src) instanceof Float32Array).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

Expand All @@ -174,6 +182,49 @@ describe('angular', function() {
expect(copy(src) instanceof Float64Array).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst.buffer).not.toBe(src.buffer);
}
});

it('should copy an ArrayBuffer with no destination', function() {
if (typeof ArrayBuffer !== 'undefined') {
var src = new ArrayBuffer(8);
new Int32Array(src).set([1, 2]);

var dst = copy(src);
expect(dst instanceof ArrayBuffer).toBeTruthy();
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
}
});

it('should handle ArrayBuffer objects with multiple references', function() {
if (typeof ArrayBuffer !== 'undefined') {
var buffer = new ArrayBuffer(8);
var src = [new Int32Array(buffer), new Float32Array(buffer)];
src[0].set([1, 2]);

var dst = copy(src);
expect(dst).toEqual(src);
expect(dst[0]).not.toBe(src[0]);
expect(dst[1]).not.toBe(src[1]);
expect(dst[0].buffer).toBe(dst[1].buffer);
expect(dst[0].buffer).not.toBe(buffer);
}
});

it('should handle Int32Array objects with multiple references', function() {
if (typeof Int32Array !== 'undefined') {
var arr = new Int32Array(2);
var src = [arr, arr];
arr.set([1, 2]);

var dst = copy(src);
expect(dst).toEqual(src);
expect(dst).not.toBe(src);
expect(dst[0]).not.toBe(src[0]);
expect(dst[0]).toBe(dst[1]);
expect(dst[0].buffer).toBe(dst[1].buffer);
}
});

Expand Down Expand Up @@ -258,6 +309,15 @@ describe('angular', function() {
}
});

it("should throw an exception if an ArrayBuffer is the destination", function() {
if (typeof ArrayBuffer !== 'undefined') {
var src = new ArrayBuffer(5);
var dst = new ArrayBuffer(5);
expect(function() { copy(src, dst); })
.toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated.");
}
});

it("should deeply copy an array into an existing array", function() {
var src = [1, {name:"value"}];
var dst = [{key:"v"}];
Expand Down

0 comments on commit 986647a

Please sign in to comment.