javascript 如何测试 ArrayBuffer、DataView 和 TypedArray 中的相等性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21553528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to test for equality in ArrayBuffer, DataView, and TypedArray
提问by JirkaV
Is there a way how to test if two JavaScript ArrayBuffers are equal? I would like to write test for message composing method. The only way I found is to convert the ArrayBuffer to string and then compare. Did I miss something?
有没有办法测试两个 JavaScript ArrayBuffers 是否相等?我想为消息编写方法编写测试。我发现的唯一方法是将 ArrayBuffer 转换为字符串,然后进行比较。我错过了什么?
Following code is giving false, even if I think that it should be true:
以下代码给出错误,即使我认为它应该是正确的:
(function() {
'use strict';
/* Fill buffer with data of Verse header and user_auth
* command */
var buf_pos = 0;
var name_len = 6
var message_len = 4 + 1 + 1 + 1 + name_len + 1;
var buf = new ArrayBuffer(message_len);
var view = new DataView(buf);
/* Verse header starts with version */
view.setUint8(buf_pos, 1 << 4); /* First 4 bits are reserved for version of protocol */
buf_pos += 2;
/* The lenght of the message */
view.setUint16(buf_pos, message_len);
buf_pos += 2;
buf_pos = 0;
var buf2 = new ArrayBuffer(message_len);
var view2 = new DataView(buf);
/* Verse header starts with version */
view2.setUint8(buf_pos, 1 << 4); /* First 4 bits are reserved for version of protocol */
buf_pos += 2;
/* The lenght of the message */
view2.setUint16(buf_pos, message_len);
buf_pos += 2;
if(buf == buf2){
console.log('true');
}
else{
console.log('false');
}
}());
If I try to compare view and view2 it's false again.
如果我尝试比较 view 和 view2,它又是错误的。
回答by kuroi neko
You cannot compare two objects directly in JavaScript using ==
or ===
.
These operators will only check the equality of references (i.e. if expressions reference the same object).
不能在 JavaScript 中使用==
或直接比较两个对象===
。
这些运算符只会检查引用的相等性(即表达式是否引用了相同的对象)。
You can, however, use DataView
or ArrayView
objects to retrieve values of specific parts of ArrayBuffer
objects and check them.
但是,您可以使用DataView
或ArrayView
对象来检索对象特定部分的值ArrayBuffer
并检查它们。
If you want to check headers:
如果要检查标题:
if ( view1.getUint8 (0) == view2.getUint8 (0)
&& view1.getUint16(2) == view2.getUint16(2)) ...
Or if you want to check the globality of your buffers:
或者,如果您想检查缓冲区的全局性:
function equal (buf1, buf2)
{
if (buf1.byteLength != buf2.byteLength) return false;
var dv1 = new Int8Array(buf1);
var dv2 = new Int8Array(buf2);
for (var i = 0 ; i != buf1.byteLength ; i++)
{
if (dv1[i] != dv2[i]) return false;
}
return true;
}
If you want to implement a complex data structure based on ArrayBuffer
, I suggest creating your own class, or else you will have to resort to cumbersome raw DataView
/ ArrayView
instances each time you will want to move a matchstick in and out of the structure.
如果你想实现一个基于 的复杂数据结构ArrayBuffer
,我建议你创建你自己的类,否则每次你想要将火柴棒移入和移出结构时,你将不得不求助于繁琐的原始DataView
/ArrayView
实例。
回答by AnthumChris
In today's V8, DataView
should now be "usable for performance-critical real-world applications" — https://v8.dev/blog/dataview
在今天的 V8 中,DataView
现在应该“可用于性能关键的实际应用程序” ——https://v8.dev/blog/dataview
The functions below test equality based on the objects you already have instantiated. If you already have TypedArray
objects, you could compare them directly without creating additional DataView
objects for them (someone is welcome to measure performance for both options).
下面的函数基于您已经实例化的对象测试相等性。如果您已经有TypedArray
对象,您可以直接比较它们,而无需DataView
为它们创建额外的对象(欢迎有人来衡量这两个选项的性能)。
// compare ArrayBuffers
function arrayBuffersAreEqual(a, b) {
return dataViewsAreEqual(new DataView(a), new DataView(b));
}
// compare DataViews
function dataViewsAreEqual(a, b) {
if (a.byteLength !== b.byteLength) return false;
for (let i=0; i < a.byteLength; i++) {
if (a.getUint8(i) !== b.getUint8(i)) return false;
}
return true;
}
// compare TypedArrays
function typedArraysAreEqual(a, b) {
if (a.byteLength !== b.byteLength) return false;
return a.every((val, i) => val === b[i]);
}
回答by Meirion Hughes
In general javascript, you currently have to compare two ArrayBuffer objects by wrapping each with a TypedArray, then manually iterating over each element and doing element-wise equality.
在一般的 javascript 中,您目前必须通过用 TypedArray 包装每个对象来比较两个 ArrayBuffer 对象,然后手动迭代每个元素并执行元素相等。
If the underlying buffer is 2 or 4-byte memory-aligned then you can make a significant optimization by employing Uint16 or Uint32 typed-arrays for the comparison.
如果底层缓冲区是 2 或 4 字节内存对齐,那么您可以通过使用 Uint16 或 Uint32 类型化数组进行比较来进行重大优化。
/**
* compare two binary arrays for equality
* @param {(ArrayBuffer|ArrayBufferView)} a
* @param {(ArrayBuffer|ArrayBufferView)} b
*/
function equal(a, b) {
if (a instanceof ArrayBuffer) a = new Uint8Array(a, 0);
if (b instanceof ArrayBuffer) b = new Uint8Array(b, 0);
if (a.byteLength != b.byteLength) return false;
if (aligned32(a) && aligned32(b))
return equal32(a, b);
if (aligned16(a) && aligned16(b))
return equal16(a, b);
return equal8(a, b);
}
function equal8(a, b) {
const ua = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
const ub = new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
return compare(ua, ub);
}
function equal16(a, b) {
const ua = new Uint16Array(a.buffer, a.byteOffset, a.byteLength / 2);
const ub = new Uint16Array(b.buffer, b.byteOffset, b.byteLength / 2);
return compare(ua, ub);
}
function equal32(a, b) {
const ua = new Uint32Array(a.buffer, a.byteOffset, a.byteLength / 4);
const ub = new Uint32Array(b.buffer, b.byteOffset, b.byteLength / 4);
return compare(ua, ub);
}
function compare(a, b) {
for (let i = a.length; -1 < i; i -= 1) {
if ((a[i] !== b[i])) return false;
}
return true;
}
function aligned16(a) {
return (a.byteOffset % 2 === 0) && (a.byteLength % 2 === 0);
}
function aligned32(a) {
return (a.byteOffset % 4 === 0) && (a.byteLength % 4 === 0);
}
and called via:
并通过以下方式调用:
equal(buf1, buf2)
here are the performance testsfor 1-, 2-, 4-byte aligned memory.
Alternatives:
备择方案:
You may also get more performance with WASM, but its possible the cost of transferring the data to the heap may negate the comparison benefit.
您还可以使用 WASM 获得更高的性能,但将数据传输到堆的成本可能会抵消比较优势。
Within Node.JS you may get more performance with Buffer
as it will have native code: Buffer.from(buf1, 0).equals(Buffer.from(buf2, 0))
在 Node.JS 中,您可以获得更高的性能,Buffer
因为它具有本机代码:Buffer.from(buf1, 0).equals(Buffer.from(buf2, 0))
回答by Steve Dixon
You can always convert the arrays into strings and compare them. E.g.
您始终可以将数组转换为字符串并进行比较。例如
let a = new Uint8Array([1, 2, 3, 4]);
let b = new Uint8Array([1, 2, 3, 4]);
if (a.toString() == b.toString()) {
console.log("Yes");
} else {
console.log("No");
}
回答by Jason Dreyzehner
To test for equality between two TypedArrays, consider using the everymethod, which exits as soon as an inconsistency is found:
要测试两个 TypedArray 之间的相等性,请考虑使用every方法,一旦发现不一致就会退出:
const first = Uint8Array.from([0,1,2,3]);
const second = Uint8Array.from([0,1,2,3]);
const areEqual = first.every((value, index) => value === second[index]);
console.log(areEqual);