From 15956517803051d14fb3672f4066194b412656fe Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 4 Feb 2016 23:55:55 -0800 Subject: [PATCH] Add support for cloning buffers. [closes #1940] --- lodash.js | 59 +++++++++++++++++++++++++++++++++++++++++++--------- test/test.js | 17 +++++++++++++++ 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/lodash.js b/lodash.js index 427d385cc..e4d5a4cf2 100644 --- a/lodash.js +++ b/lodash.js @@ -230,8 +230,8 @@ /** Used to assign default `context` object properties. */ var contextProps = [ - 'Array', 'Date', 'Error', 'Float32Array', 'Float64Array', 'Function', - 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', + 'Array', 'Buffer', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', 'Reflect', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' @@ -1305,7 +1305,8 @@ ); /** Built-in value references. */ - var Reflect = context.Reflect, + var Buffer = moduleExports ? context.Buffer : undefined, + Reflect = context.Reflect, Symbol = context.Symbol, Uint8Array = context.Uint8Array, clearTimeout = context.clearTimeout, @@ -2250,6 +2251,9 @@ var tag = getTag(value), isFunc = tag == funcTag || tag == genTag; + if (isBuffer(value)) { + return cloneBuffer(value); + } if (tag == objectTag || tag == argsTag || (isFunc && !object)) { if (isHostObject(value)) { return object ? value : {}; @@ -3707,18 +3711,33 @@ } /** - * Creates a clone of `buffer`. + * Creates a clone of `buffer`. * * @private - * @param {ArrayBuffer} buffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. + * @param {Buffer} buffer The buffer to clone. + * @returns {Buffer} Returns the cloned buffer. */ function cloneBuffer(buffer) { var Ctor = buffer.constructor, - result = new Ctor(buffer.byteLength), + result = new Ctor(buffer.byteLength); + + buffer.copy(result); + return result; + } + + /** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function cloneArrayBuffer(arrayBuffer) { + var Ctor = arrayBuffer.constructor, + result = new Ctor(arrayBuffer.byteLength), view = new Uint8Array(result); - view.set(new Uint8Array(buffer)); + view.set(new Uint8Array(arrayBuffer)); return result; } @@ -3784,7 +3803,7 @@ var buffer = typedArray.buffer, Ctor = typedArray.constructor; - return new Ctor(isDeep ? cloneBuffer(buffer) : buffer, typedArray.byteOffset, typedArray.length); + return new Ctor(isDeep ? cloneArrayBuffer(buffer) : buffer, typedArray.byteOffset, typedArray.length); } /** @@ -4978,7 +4997,7 @@ var Ctor = object.constructor; switch (tag) { case arrayBufferTag: - return cloneBuffer(object); + return cloneArrayBuffer(object); case boolTag: case dateTag: @@ -9504,6 +9523,26 @@ (isObjectLike(value) && objectToString.call(value) == boolTag); } + /** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ + var isBuffer = !Buffer ? constant(false) : function(value) { + return value instanceof Buffer; + }; + /** * Checks if `value` is classified as a `Date` object. * diff --git a/test/test.js b/test/test.js index 988df5c81..79fc83e26 100644 --- a/test/test.js +++ b/test/test.js @@ -44,6 +44,7 @@ amd = root.define && define.amd, argv = root.process && process.argv, ArrayBuffer = root.ArrayBuffer, + Buffer = root.Buffer, defineProperty = Object.defineProperty, document = !phantom && root.document, body = root.document && root.document.body, @@ -2538,6 +2539,22 @@ assert.strictEqual(actual.lastIndex, 3); }); + QUnit.test('`_.' + methodName + '` should clone buffers', function(assert) { + assert.expect(3); + + if (Buffer) { + var buffer = new Buffer([1, 2, 3]), + actual = func(buffer); + + assert.strictEqual(actual.byteLength, buffer.byteLength); + assert.strictEqual(actual.inspect(), buffer.inspect()); + assert.notStrictEqual(actual, buffer); + } + else { + skipTest(assert, 3); + } + }); + QUnit.test('`_.' + methodName + '` should clone prototype objects', function(assert) { assert.expect(2);