From d135b846db2aba08ebfdf59bc34d5a50c37be80a Mon Sep 17 00:00:00 2001 From: Dan Levy Date: Sat, 26 Mar 2016 17:08:16 -0600 Subject: [PATCH] Adding support for cloning and comparing DataView. --- lodash.js | 58 +++++++++++++++++++++++++++----------- test/test.js | 78 +++++++++++++++++++++++++++------------------------- 2 files changed, 83 insertions(+), 53 deletions(-) diff --git a/lodash.js b/lodash.js index aa248e222..a0f010760 100644 --- a/lodash.js +++ b/lodash.js @@ -86,6 +86,7 @@ weakSetTag = '[object WeakSet]'; var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', @@ -232,7 +233,7 @@ /** Used to assign default `context` object properties. */ var contextProps = [ - 'Array', 'Buffer', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', 'Promise', 'Reflect', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', @@ -251,25 +252,26 @@ typedArrayTags[uint32Tag] = true; typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dateTag] = typedArrayTags[errorTag] = - typedArrayTags[funcTag] = typedArrayTags[mapTag] = - typedArrayTags[numberTag] = typedArrayTags[objectTag] = - typedArrayTags[regexpTag] = typedArrayTags[setTag] = - typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; + typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = + typedArrayTags[errorTag] = typedArrayTags[funcTag] = + typedArrayTags[mapTag] = typedArrayTags[numberTag] = + typedArrayTags[objectTag] = typedArrayTags[regexpTag] = + typedArrayTags[setTag] = typedArrayTags[stringTag] = + typedArrayTags[weakMapTag] = false; /** Used to identify `toStringTag` values supported by `_.clone`. */ var cloneableTags = {}; cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = - cloneableTags[dateTag] = cloneableTags[float32Tag] = - cloneableTags[float64Tag] = cloneableTags[int8Tag] = - cloneableTags[int16Tag] = cloneableTags[int32Tag] = - cloneableTags[mapTag] = cloneableTags[numberTag] = - cloneableTags[objectTag] = cloneableTags[regexpTag] = - cloneableTags[setTag] = cloneableTags[stringTag] = - cloneableTags[symbolTag] = cloneableTags[uint8Tag] = - cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = - cloneableTags[uint32Tag] = true; + cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = + cloneableTags[boolTag] = cloneableTags[dateTag] = + cloneableTags[float32Tag] = cloneableTags[float64Tag] = + cloneableTags[int8Tag] = cloneableTags[int16Tag] = + cloneableTags[int32Tag] = cloneableTags[mapTag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[setTag] = + cloneableTags[stringTag] = cloneableTags[symbolTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false; @@ -3969,6 +3971,19 @@ return result; } + /** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ + function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); + } + /** * Creates a clone of `map`. * @@ -4909,6 +4924,14 @@ */ function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) { switch (tag) { + case dataViewTag: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + case arrayBufferTag: if ((object.byteLength != other.byteLength) || !equalFunc(new Uint8Array(object), new Uint8Array(other))) { @@ -5363,6 +5386,9 @@ case dateTag: return new Ctor(+object); + case dataViewTag: + return cloneDataView(object, isDeep); + case float32Tag: case float64Tag: case int8Tag: case int16Tag: case int32Tag: case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: diff --git a/test/test.js b/test/test.js index 3c4f9196a..9ebfcc7ff 100644 --- a/test/test.js +++ b/test/test.js @@ -62,6 +62,7 @@ var ArrayBuffer = root.ArrayBuffer, Buffer = root.Buffer, + DataView = root.DataView, Promise = root.Promise, Map = root.Map, Set = root.Set, @@ -179,6 +180,9 @@ 'Uint32Array' ]; + /** Used to check whether methods support array views. */ + var arrayViews = typedArrays.concat('DataView'); + /** The file path of the lodash file to test. */ var filePath = (function() { var min = 2, @@ -606,7 +610,7 @@ " 'weakSet': root.WeakSet ? new root.WeakSet : undefined", ' };', '', - " ['" + typedArrays.join("', '") + "'].forEach(function(type) {", + " ['" + arrayViews.join("', '") + "'].forEach(function(type) {", ' var Ctor = root[type]', ' object[type.toLowerCase()] = Ctor ? new Ctor(new ArrayBuffer(24)) : undefined;', ' });', @@ -655,7 +659,7 @@ " 'weakSet': root.WeakSet ? new root.WeakSet : undefined", '};', '', - "_.each(['" + typedArrays.join("', '") + "'], function(type) {", + "_.each(['" + arrayViews.join("', '") + "'], function(type) {", ' var Ctor = root[type];', ' object[type.toLowerCase()] = Ctor ? new Ctor(new ArrayBuffer(24)) : undefined;', '});', @@ -2884,8 +2888,8 @@ } }); - lodashStable.each(typedArrays, function(type) { - QUnit.test('`_.' + methodName + '` should clone ' + type + ' arrays', function(assert) { + lodashStable.each(arrayViews, function(type) { + QUnit.test('`_.' + methodName + '` should clone ' + type + ' values', function(assert) { assert.expect(10); var Ctor = root[type]; @@ -2893,14 +2897,14 @@ lodashStable.times(2, function(index) { if (Ctor) { var buffer = new ArrayBuffer(24), - array = index ? new Ctor(buffer, 8, 1) : new Ctor(buffer), - actual = func(array); + view = index ? new Ctor(buffer, 8, 1) : new Ctor(buffer), + actual = func(view); - assert.deepEqual(actual, array); - assert.notStrictEqual(actual, array); - assert.strictEqual(actual.buffer === array.buffer, !isDeep); - assert.strictEqual(actual.byteOffset, array.byteOffset); - assert.strictEqual(actual.length, array.length); + assert.deepEqual(actual, view); + assert.notStrictEqual(actual, view); + assert.strictEqual(actual.buffer === view.buffer, !isDeep); + assert.strictEqual(actual.byteOffset, view.byteOffset); + assert.strictEqual(actual.length, view.length); } else { skipAssert(assert, 5); @@ -9210,6 +9214,29 @@ } }); + QUnit.test('should compare array views', function(assert) { + assert.expect(1); + + var pairs = lodashStable.map(arrayViews, function(type, index) { + var otherType = arrayViews[(index + 1) % arrayViews.length], + CtorA = root[type] || function(n) { this.n = n; }, + CtorB = root[otherType] || function(n) { this.n = n; }, + bufferA = root[type] ? new ArrayBuffer(8) : 8, + bufferB = root[otherType] ? new ArrayBuffer(8) : 8, + bufferC = root[otherType] ? new ArrayBuffer(16) : 16; + + return [new CtorA(bufferA), new CtorA(bufferA), new CtorB(bufferB), new CtorB(bufferC)]; + }); + + var expected = lodashStable.map(pairs, lodashStable.constant([true, false, false])); + + var actual = lodashStable.map(pairs, function(pair) { + return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; + }); + + assert.deepEqual(actual, expected); + }); + QUnit.test('should compare date objects', function(assert) { assert.expect(4); @@ -9390,29 +9417,6 @@ } }); - QUnit.test('should compare typed arrays', function(assert) { - assert.expect(1); - - var pairs = lodashStable.map(typedArrays, function(type, index) { - var otherType = typedArrays[(index + 1) % typedArrays.length], - CtorA = root[type] || function(n) { this.n = n; }, - CtorB = root[otherType] || function(n) { this.n = n; }, - bufferA = root[type] ? new ArrayBuffer(8) : 8, - bufferB = root[otherType] ? new ArrayBuffer(8) : 8, - bufferC = root[otherType] ? new ArrayBuffer(16) : 16; - - return [new CtorA(bufferA), new CtorA(bufferA), new CtorB(bufferB), new CtorB(bufferC)]; - }); - - var expected = lodashStable.map(pairs, lodashStable.constant([true, false, false])); - - var actual = lodashStable.map(pairs, function(pair) { - return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; - }); - - assert.deepEqual(actual, expected); - }); - QUnit.test('should work as an iteratee for `_.every`', function(assert) { assert.expect(1); @@ -9825,14 +9829,14 @@ assert.strictEqual(_.isFunction(generator), typeof generator == 'function'); }); - QUnit.test('should return `true` for typed array constructors', function(assert) { + QUnit.test('should return `true` for array view constructors', function(assert) { assert.expect(1); - var expected = lodashStable.map(typedArrays, function(type) { + var expected = lodashStable.map(arrayViews, function(type) { return objToString.call(root[type]) == funcTag; }); - var actual = lodashStable.map(typedArrays, function(type) { + var actual = lodashStable.map(arrayViews, function(type) { return _.isFunction(root[type]); });