6

I am comparing two Uint8Array using CRC32 to ensure the accuracy of the data being decompressed. However, I am facing the issue of not having an API like Uint8Array.equal() to compare the arrays. Although there is Buffer.compare() available in Node.js, it is not supported in the browser, which I am also working on.

I have created a basic implementation, but I am unsure if there is a more straightforward approach or if I have overlooked any built-in comparison APIs.

function isEqual(arr1: Uint8Array, arr2: Uint8Array): boolean {
    if (arr1.length !== arr2.length) {
        return false
    }

    return arr1.every((value, index) => value === arr2[index])
}
Filip Seman
  • 1,252
  • 2
  • 15
  • 22
  • Why don't you just install [buffer](https://www.npmjs.com/package/buffer) and use it as in Node.js – Teneff Apr 28 '23 at 07:42
  • Or check it's `.prototype.compare` implementation [here](https://github.com/feross/buffer/blob/master/index.js#L630) – Teneff Apr 28 '23 at 07:45
  • Thank @Teneff for the suggestion, I prefer using native APIs over external libraries to maintain compatibility in my libraries. – Filip Seman Apr 28 '23 at 07:47
  • 1
    I don't think so. This is basically a dupe of [this question](https://stackoverflow.com/questions/21553528/how-to-test-for-equality-in-arraybuffer-dataview-and-typedarray) and as you can see, all answers are essentially the same: check length and use `every`. – kelsny Apr 28 '23 at 14:20
  • 1
    I understand that it's essentially an array because it extends Iterator, but I was hoping for a more expressive method like the `Buffer.compare` API. – Filip Seman Apr 28 '23 at 15:23

2 Answers2

6

You're not missing anything, there isn't currently an equality checking method for typed arrays (or regular arrays), or anything that can be succinctly used like one while remaining efficient with large arrays.

There is a proposal out there, but it doesn't seem to be getting much traction. One of the more contentious issues is that there shouldn't be a dedicated method just for typed arrays, and there should just be a static object equality checking method.

There isn't a standard object equality checking method yet, though proposals have been made in the past. Here's one that was withdrawn. You could of course create your own function like this, probably with a special conditions for ArrayBuffer.isView to compare the length first, before each property. There are many potential edge cases with a function like this, which is perhaps why a generic standard solution remains elusive.

For now the best way to compare 2 typed arrays is to compare the length and loop over the values in your own function. You can do the second part with a method like every or a simple for/while loop (a simple loop is likely faster as it will have less overhead).

Alexander O'Mara
  • 58,688
  • 18
  • 163
  • 171
  • in other words `function isEqualArray(a, b) { if (a.length != b.length) return false; for (let i = 0; i < a.length; i++) if (a[i] != b[i]) return false; return true; }` – milahu Aug 31 '23 at 12:35
0

There is indeed a way to compare two Uint8Arrays that has been built in to the vast majority of browsers for some time:

function areBytewiseEqual(a, b) {
  return indexedDB.cmp(a, b) === 0;
}

This will also work if a and/or b are ArrayBuffers or DataViews.

(It's a weird API to have to get involved with just for this feature, and it's not what this method was directly intended for — but as far as I can tell from reading the spec, there's no logical reason not to use it this way.)

denzquix
  • 1
  • 2
  • You might want to link https://developer.mozilla.org/en-US/docs/Web/API/IDBFactory/cmp and quote the disclaimer: "*Do not use this method for comparing arbitrary JavaScript values, …*" - though of course a typed array is an array with only numeric elements so it indeed will work fine – Bergi Jul 29 '23 at 02:43
  • @Bergi Since IndexedDB 2.0, the API has supported "binary" keys https://w3c.github.io/IndexedDB/#key-construct which are "ArrayBuffer objects (or views on buffers such as Uint8Array)" -- so this is not a case of typed arrays being treated as if they are arrays of numbers, but are in fact specially handled by the comparison algorithm. – denzquix Jul 29 '23 at 08:57
  • Interesting! A couple of things worth noting though: 1. This is currently a browser API, so not natively available in node or deno. 2. There may be some surprise edge-cases with different types, like: `indexedDB.cmp(new Uint8Array([255]), new Int8Array([-1])) === 0` and `indexedDB.cmp(new Uint8Array([0, 0]), new Int16Array([0])) === 0` (not wrong, but maybe confusing to those who don't know what's happening under the hood). – Alexander O'Mara Jul 30 '23 at 00:30
  • @AlexanderO'Mara Yes indeed, and there are even edge cases where the same type can give a surprising result: `indexedDB.cmp(new Float64Array([0]), new Float64Array([-0])) !== 0` – denzquix Aug 02 '23 at 14:00