Compare equality of two Uint8Array
Asked Answered
C

4

8

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])
}
Copolymerize answered 28/4, 2023 at 7:31 Comment(6)
Why don't you just install buffer and use it as in Node.jsMimicry
Or check it's .prototype.compare implementation hereMimicry
Thank @Mimicry for the suggestion, I prefer using native APIs over external libraries to maintain compatibility in my libraries.Copolymerize
I don't think so. This is basically a dupe of this question and as you can see, all answers are essentially the same: check length and use every.Billiton
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.Copolymerize
Does this answer your question? How to test for equality in ArrayBuffer, DataView, and TypedArrayResorcinol
S
9

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).

Spherulite answered 3/6, 2023 at 5:5 Comment(1)
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; }Orosco
C
5

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.)

Consummate answered 29/7, 2023 at 2:23 Comment(4)
You might want to link 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 finePoliceman
@Policeman Since IndexedDB 2.0, the API has supported "binary" keys 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.Consummate
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).Felicitation
@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])) !== 0Consummate
Y
0

Here's a naive implementation in TypeScript:

export function isEqualBytes(
  bytes1: Uint8Array,
  bytes2: Uint8Array

): boolean {

  if (bytes1.length !== bytes2.length) {
    return false;
  }

  for (let i = 0; i < bytes1.length; i++) {
    if (bytes1[i] !== bytes2[i]) {
      return false;
    }
  }

  return true;

}
Yourself answered 30/12, 2023 at 13:57 Comment(0)
L
0

In pure JS, just compare the values of the arrays:

const areUnit8ArraysEqual = (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;
}
Luettaluevano answered 10/5 at 18:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.