JavaScript-键入存储布尔值的数组-ArrayBuffer:ByteOffset的重点是什么?

发布于 2025-01-22 18:57:26 字数 1331 浏览 0 评论 0原文

我想将布尔值存储到JavaScript键入数组中。最初,我想拥有一个二维阵列(实际上是一场生命的小游戏),但根据这篇文章是不可能的: javaScript多维打字阵列(int8array)示例

我正在像这样填充阵列:

const cols = 16;
const rows = 16;

const buffer = new ArrayBuffer(cols * rows);
const cells = new Uint8Array(buffer);

for (let i = 0; i < cols * rows; i++) {
    cells[i] =  Math.random() < 0.5;
}

返回:

“在此处输入图像描述”

我一直在做一些测试,并且我想知道ArrayBuffer中byteoffset访问者的意义是什么? Mozilla显示了一个例子,但我没有得到用例:

当我添加2个byteoffset 2的时:const cells = new Uint8array(buffer,2);我注意到的唯一区别是我的数组丢失了2个元素:

”在此处输入图像描述

在所有这些旁边,如果您对如何有效存储布尔值有任何建议,我很高兴能为您提供建议!

I would like to store boolean values into a Javascript Typed Array. Originally I wanted to have a bidimensional array (making a small Game of Life actually) but it is not possible according to this post : javascript multidimensional Typed array (Int8Array) example

I'm filling the array like so :

const cols = 16;
const rows = 16;

const buffer = new ArrayBuffer(cols * rows);
const cells = new Uint8Array(buffer);

for (let i = 0; i < cols * rows; i++) {
    cells[i] =  Math.random() < 0.5;
}

Which returns:

enter image description here

Nevertheless, I've been doing some test, and I was wondering what is the point of byteOffset accessor in the ArrayBuffer ? Mozilla shows an example but I don't get the use case :
enter image description here

When I add a byteOffset of 2 for example : const cells = new Uint8Array(buffer, 2); the only difference I've noticed is that my Array has lost 2 elements :

enter image description here

Beside all of this, if you have any suggestions on how to store booleans efficiently, I'd be glad to have your advices !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风蛊 2025-01-29 18:57:26

(只是遇到了这一点,以防人们找到这个问题)
在同一bytearray上创建多个视图时,字节offset可以很有用。例如,您可能有一个bytearray,其中有5个UINT32S,然后是5个UINT8S,例如:

let buffer = new ArrayBuffer(45);
let uint32Ary = new Uint32Array(buffer, 0, 5);
let uint8Ary = new Uint8Array(buffer, 20, 5);
let uint8AryAll = new Uint8Array(buffer, 0);
// setting some values to show how the whole buffer is affected
uint32Ary[1] = 2000;
uint32Ary[2] = 2001;
uint8Ary[4] = 55;
console.log(uint32Ary);
console.log(uint8Ary);
console.log(uint8AryAll);

结果:

> Uint32Array [0, 2000, 2001, 0, 0]
> Uint8Array [0, 0, 0, 0, 55]
> Uint8Array [0, 0, 0, 0, 208, 7, 0, 0, 209, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55]

通过UINT32Array中的Uint8Array视图设置一个字节:

uint8AryAll[4] = 210;
console.log(uint32Ary);

> Uint32Array [0, 2002, 2001, 0, 0]

此示例是人为的,但说明了如何使用包含一个阵列缓冲区的阵列缓冲区几个不同字节的字节数字的背景数据无需复制数据。

要使用一个更接近您所做的示例,您可以设置代表数据矩阵行的键入数组的数组:

const cols = 16;
const rows = 16;
const buffer = new ArrayBuffer(cols * rows);
const cells = new Uint8Array(buffer);
const rowArys = new Array(cols);

for (let i = 0; i < cols; i++) {
    rowArys[i] =  new Uint8Array(buffer, i * rows, rows);
}
let x = 5;
let y = 1;
rowArys[y][x] = 55;
console.log(rowArys[y][x]);
console.log(cells[y * rows + x]);

cells[y * rows + x] = 33;
console.log(rowArys[y][x]);
console.log(cells[y * rows + x]);

结果:

> 55
> 55
> 33
> 33

如您所见,行阵列指向与单元格数组相同的

数据对于存储布尔值,您可以使用 bitwise oterators 存储和检索每个BYTE,BYTE,BYTE,BYTE,BYERIEND,但是,由于JS在进行位操作时不是很有效,因此由于性能较差和更复杂的代码,可能不值得在内存中节省,但根据情况,数据加载和存储可能值得。

也就是说,这是一个代码段的说明,该摘要是使用位置操作员根据您的游戏示例将布尔值紧凑地存储在模拟的2D数组中:

const cols = 16;
const rows = 16;

class BooleanArray {
  constructor(height, width) {
    this.height = height;
    this.width = width;
    this.byteWidth = (width >> 3) + ((width & 0b111) > 0 ? 1 : 0);
    this.dataArray = new Uint8Array(height * this.byteWidth);
  }
  getAt(x, y) {
    const xBytes = x >>> 3;
    const bitMask = 1 << (x & 0b111);
    return (this.dataArray[y * this.byteWidth + xBytes] & bitMask) > 0;
  }
  setAt(x, y, value) {
    const xBytes = x >>> 3;
    const xBits = x & 0b111;
    const i = y * this.byteWidth + xBytes;
    if (value) {
      this.dataArray[i] |= 1 << xBits;
    } else {
      this.dataArray[i] &= ~(1 << xBits);
    }
  }
  toString() {
    let result = "";
    for (let y = 0; y < this.height; y++) {
      result += "\n";
      for (let x = 0; x < this.width; x++) {
        result += this.getAt(x, y) ? "1" : "0";
      }
    }
    return result;
  }
}
bools = new BooleanArray(cols, rows);
console.log(bools.dataArray.length);
bools.setAt(13, 1, true);
bools.setAt(3, 0, true);
console.log(bools.getAt(13, 1));
console.log(bools.toString());
bools.setAt(13, 1, false);
console.log(bools.getAt(13, 1));
console.log(bools.toString());

结果:

> 32
> true
>
0001000000000000
0000000000000100
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
> false
>
0001000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000

(just came across this, in case this helps folks finding this question)
The byteOffset can be useful when creating multiple views on the same byteArray. E.g. you might have one byteArray with a section of 5 Uint32s followed by 5 Uint8s, e.g.:

let buffer = new ArrayBuffer(45);
let uint32Ary = new Uint32Array(buffer, 0, 5);
let uint8Ary = new Uint8Array(buffer, 20, 5);
let uint8AryAll = new Uint8Array(buffer, 0);
// setting some values to show how the whole buffer is affected
uint32Ary[1] = 2000;
uint32Ary[2] = 2001;
uint8Ary[4] = 55;
console.log(uint32Ary);
console.log(uint8Ary);
console.log(uint8AryAll);

results in:

> Uint32Array [0, 2000, 2001, 0, 0]
> Uint8Array [0, 0, 0, 0, 55]
> Uint8Array [0, 0, 0, 0, 208, 7, 0, 0, 209, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55]

setting a single byte in a Uint32Array through the Uint8Array view:

uint8AryAll[4] = 210;
console.log(uint32Ary);

> Uint32Array [0, 2002, 2001, 0, 0]

This example is contrived, but illustrates how one could use an array buffer that contains the backing data for several byteArrays of different byteSize without needing to copy the data.

To use an example a little closer to what you are doing, you could set up an array of typed arrays representing rows for your data matrix:

const cols = 16;
const rows = 16;
const buffer = new ArrayBuffer(cols * rows);
const cells = new Uint8Array(buffer);
const rowArys = new Array(cols);

for (let i = 0; i < cols; i++) {
    rowArys[i] =  new Uint8Array(buffer, i * rows, rows);
}
let x = 5;
let y = 1;
rowArys[y][x] = 55;
console.log(rowArys[y][x]);
console.log(cells[y * rows + x]);

cells[y * rows + x] = 33;
console.log(rowArys[y][x]);
console.log(cells[y * rows + x]);

results in:

> 55
> 55
> 33
> 33

As you can see, the row arrays point to the same data as the cells array

As for storing booleans, you could use bitwise operators to store and retrieve 8 booleans per byte, but since JS is not very efficient when doing bit operations, it might not be worth the in-memory savings due to the poorer performance and more complex code, but could be worthwhile for data loading and storing depending on the situation.

That said, here is a code snippet illustration of using bitwise operators for storing booleans compactly in a simulated 2D array based on your game example:

const cols = 16;
const rows = 16;

class BooleanArray {
  constructor(height, width) {
    this.height = height;
    this.width = width;
    this.byteWidth = (width >> 3) + ((width & 0b111) > 0 ? 1 : 0);
    this.dataArray = new Uint8Array(height * this.byteWidth);
  }
  getAt(x, y) {
    const xBytes = x >>> 3;
    const bitMask = 1 << (x & 0b111);
    return (this.dataArray[y * this.byteWidth + xBytes] & bitMask) > 0;
  }
  setAt(x, y, value) {
    const xBytes = x >>> 3;
    const xBits = x & 0b111;
    const i = y * this.byteWidth + xBytes;
    if (value) {
      this.dataArray[i] |= 1 << xBits;
    } else {
      this.dataArray[i] &= ~(1 << xBits);
    }
  }
  toString() {
    let result = "";
    for (let y = 0; y < this.height; y++) {
      result += "\n";
      for (let x = 0; x < this.width; x++) {
        result += this.getAt(x, y) ? "1" : "0";
      }
    }
    return result;
  }
}
bools = new BooleanArray(cols, rows);
console.log(bools.dataArray.length);
bools.setAt(13, 1, true);
bools.setAt(3, 0, true);
console.log(bools.getAt(13, 1));
console.log(bools.toString());
bools.setAt(13, 1, false);
console.log(bools.getAt(13, 1));
console.log(bools.toString());

results in:

> 32
> true
>
0001000000000000
0000000000000100
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
> false
>
0001000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文