1/** 2 * @fileoverview Helper methods for typed arrays. 3 */ 4goog.module('protobuf.binary.typedArrays'); 5 6const {assert} = goog.require('goog.asserts'); 7 8/** 9 * @param {!ArrayBuffer} buffer1 10 * @param {!ArrayBuffer} buffer2 11 * @return {boolean} 12 */ 13function arrayBufferEqual(buffer1, buffer2) { 14 if (!buffer1 || !buffer2) { 15 throw new Error('Buffer shouldn\'t be empty'); 16 } 17 18 const array1 = new Uint8Array(buffer1); 19 const array2 = new Uint8Array(buffer2); 20 21 return uint8ArrayEqual(array1, array2); 22} 23 24/** 25 * @param {!Uint8Array} array1 26 * @param {!Uint8Array} array2 27 * @return {boolean} 28 */ 29function uint8ArrayEqual(array1, array2) { 30 if (array1 === array2) { 31 return true; 32 } 33 34 if (array1.byteLength !== array2.byteLength) { 35 return false; 36 } 37 38 for (let i = 0; i < array1.byteLength; i++) { 39 if (array1[i] !== array2[i]) { 40 return false; 41 } 42 } 43 return true; 44} 45 46/** 47 * ArrayBuffer.prototype.slice, but fallback to manual copy if missing. 48 * @param {!ArrayBuffer} buffer 49 * @param {number} start 50 * @param {number=} end 51 * @return {!ArrayBuffer} New array buffer with given the contents of `buffer`. 52 */ 53function arrayBufferSlice(buffer, start, end = undefined) { 54 // The fallback isn't fully compatible with ArrayBuffer.slice, enforce 55 // strict requirements on start/end. 56 // Spec: 57 // https://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer.prototype.slice 58 assert(start >= 0); 59 assert(end === undefined || (end >= 0 && end <= buffer.byteLength)); 60 assert((end === undefined ? buffer.byteLength : end) >= start); 61 if (buffer.slice) { 62 const slicedBuffer = buffer.slice(start, end); 63 // The ArrayBuffer.prototype.slice function was flawed before iOS 12.2. This 64 // causes 0-length results when passing undefined or a number greater 65 // than 32 bits for the optional end value. In these cases, we fall back to 66 // using our own slice implementation. 67 // More details: https://bugs.webkit.org/show_bug.cgi?id=185127 68 if (slicedBuffer.byteLength !== 0 || (start === end)) { 69 return slicedBuffer; 70 } 71 } 72 const realEnd = end == null ? buffer.byteLength : end; 73 const length = realEnd - start; 74 assert(length >= 0); 75 const view = new Uint8Array(buffer, start, length); 76 // A TypedArray constructed from another Typed array copies the data. 77 const clone = new Uint8Array(view); 78 79 return clone.buffer; 80} 81 82/** 83 * Returns a new Uint8Array with the size and contents of the given 84 * ArrayBufferView. ArrayBufferView is an interface implemented by DataView, 85 * Uint8Array and all typed arrays. 86 * @param {!ArrayBufferView} view 87 * @return {!Uint8Array} 88 */ 89function cloneArrayBufferView(view) { 90 return new Uint8Array(arrayBufferSlice( 91 view.buffer, view.byteOffset, view.byteOffset + view.byteLength)); 92} 93 94/** 95 * Returns a 32 bit number for the corresponding Uint8Array. 96 * @param {!Uint8Array} array 97 * @return {number} 98 */ 99function hashUint8Array(array) { 100 const prime = 31; 101 let result = 17; 102 103 for (let i = 0; i < array.length; i++) { 104 // '| 0' ensures signed 32 bits 105 result = (result * prime + array[i]) | 0; 106 } 107 return result; 108} 109 110exports = { 111 arrayBufferEqual, 112 uint8ArrayEqual, 113 arrayBufferSlice, 114 cloneArrayBufferView, 115 hashUint8Array, 116}; 117