如何将一组指令块划分为适合JavaScript中特定大小的连续数组的序列?

问题描述

我有这样的项目,其中foobar是简单的指令,而ab是简单的指令 blocks

a:
  foo 1
  foo 2
  bar 10
  bar 20
  foo 1
  bar 30
b:
  foo 20
  bar 30
  foo 10
  foo 100
  bar 31
  ...

相应的数据结构如下:

const blocks = [
  [
    { type: 'foo',val: 1 },{ type: 'foo',val: 2 },{ type: 'bar',val: 10 },val: 20 },...
  ],...
]

目标是从blocks的第一个块开始,迭代所有块并以某种方式将它们布置在内存中:

<foo><1><foo><2>...

或更笼统地说:

<type><val><type><val>...

每个<>尖括号对象都代表一个32位整数(假设foo == 1bar == 2或其他东西)。所以这个:

a:
  foo 1
  foo 2
  bar 10
  bar 20
  foo 1
  bar 30

成为这个:

<foo><1><foo><2><bar><10><bar><20><foo><1><bar><30>
or
32   32 32   32 32   32  32   32  32   32 32   32

请注意,每条指令仅采用一个参数,因此每个“指令调用”的内存布局仅采用2个32位插槽。

问题是,我们必须遵守以下约束:我们只允许包含1、2、4、8、16、32、64或128个32位整数的连续序列。如果指令块不适合这些模式,则可以将其与后续块(的一部分)组合,或将其分成适合连续数组约束的块。但是,您还必须在创建的任何块的末尾添加 4个32位整数(foobar),并且总数必须达到1 ,2、4、8、16、32、64或128个项目。

所以问题是,如何像上面一样开始处理块数组,并最有效地将它们转换为一组连续的那些特定大小的内存分配?“有效地”我并不一定表示对块进行分块的算法的性能,而是最终块会占用理想的空间量(理想情况下可填充128个插槽) ,然后是64,然后是32,依此类推)。目的是我们希望将指令打包到尽可能多的大型连续数组中。

例如,以这个为例:

a:
  foo 1
  foo 2
  bar 10
  bar 20
  foo 1
  bar 30

有6条指令,所以有12个32位值。但是12不是1、2、4、8、16、32、64或128。因此,我们需要做的是在某些地方 break 使其成为这6个连续数组大小之一。但是,我们只能在bar之后中断。此外,我们需要考虑连续数组之间的链接。因此,我们添加了一对额外的特殊指令,为方程式(foobar增加了4个32位值。因此,无论我们决定拆分何处,都需要插入4个额外的32位值,这些值将对地址和跳转到下一个连续数组的指令进行编码。

因此在我们的示例中,我们可以这样做:

a_1:
  foo 1 # 2
  foo 2 # 4
  bar 10 # 6
  bar 20 # 8
  foo 1 # 10
  bar 30 # 12
  <ins1> x # 14
  <ins2> y # 16

可以正确平衡到16个项目的连续数组。

这是一个占用10个32位插槽的示例(如果您想将其划分,则为14个)。这些尺寸都不符合约束条件。

x:
  foo 1
  bar 2
  foo 1
  foo 1
  bar 3

如果我们只处理这1个指令块(而不是指令块的集合),那么我们可能会得到以下结果:

foo 1
bar 2
foo 1
foo 1
bar 3
<insert-foo>
<insert-bar>
<empty><empty>

也等于16。可以在连续数组中保留尾随空间。但是您不想创建过多的尾随空白空间哈哈。

最后一个示例包含16个项目:

foo 1 # 2
foo 1 # 4
bar 2 # 6
foo 1 # 8
bar 3 # 10
foo 1 # 12
bar 3 # 14
bar 5 # 16

添加2条额外的指令会使我们增加到20条,这不符合约束条件。

# nopE
foo 1 # 2
foo 1 # 4
bar 2 # 6
foo 1 # 8
bar 3 # 10
foo 1 # 12
bar 3 # 14
bar 5 # 16
<ins-foo> # 18
<ins-bar> # 20

我们可以在末尾添加空白空间:

foo 1 # 2
foo 1 # 4
bar 2 # 6
foo 1 # 8
bar 3 # 10
foo 1 # 12
bar 3 # 14
bar 5 # 16
<ins-foo> # 18
<ins-bar> # 20
<empty-pair> # 22
<empty-pair> # 24
<empty-pair> # 26
<empty-pair> # 28
<empty-pair> # 30
<empty-pair> # 32

但是,如果我们做了很多,那将会浪费很多空间。更好的解决方案是:

# block 1
foo 1 # 2
foo 1 # 4
bar 2 # 6
foo 1 # 8
bar 3 # 10
<ins-foo> # 12
<ins-bar> # 14
<empty-pair> # 16

# block 2
foo 1 # 2
bar 3 # 4
bar 5 # 6
<ins-foo> # 8
<ins-bar> # 10
<empty-pair> # 12
<empty-pair> # 14
<empty-pair> # 16

因为它最小化了空的尾随对。


所以我在这里首先要做的是生成一些要测试的演示数据:一堆具有随机大小的块和foo / bar序列的随机组合。这可以模拟具有各种指令块的生产规模程序,这些指令块可以执行各种操作:

const blocks = rand_block_collection()

function rand_block_collection() {
  let rand_i = rand_int(70,80)
  const blocks = []
  while (rand_i--) {
    blocks.push(rand_block())
  }
  return blocks
}

function rand_block() {
  let rand_i = rand_int(2,40)
  const block = []
  while (rand_i--) {
    let rand_seq = [ rand_seq_0,rand_seq_1,rand_seq_2 ][rand_int(0,2)]
    block.push.apply(block,rand_seq())
  }
  return block
}

function rand_seq_0() {
  return [
    { type: 'bar',val: rand_int(0,255) }
  ]
}

function rand_seq_1() {
  return [
    { type: 'foo',255) },255) }
  ]
}

function rand_seq_2() {
  return [
    { type: 'foo',255) }
  ]
}

function rand_int(min,max) {
  return Math.floor(Math.random() * (max - min + 1)) + min
}

下面提供了一些演示数据。

因此,目标是采用blocks数组,并提出一种算法,以生成长度为2、4、6、8、16、32、64或128个项目的多个连续数组。另外的规则是,您必须在序列中添加4个32位值(一个foo一个bar),这将成为跳转到下一个连续数组的调用

您将如何做? JS中什么是体面的算法或最佳算法?

let xhr = new XMLHttpRequest()
xhr.open('GET','https://gist.githubusercontent.com/lancejpollard/e75e0e5e091064d54a9d9502316b1c4c/raw/9d3276f9a712e6547b8ba44d009475a1b945f684/instblock.json')

xhr.onreadystatechange = function(){
  if (xhr.readyState !== 4) return
  if (xhr.status !== 200) return
  
  const blocks = JSON.parse(xhr.responseText)
  const chunks = divide(blocks)
  console.log('chunks',chunks)
}

xhr.send()

function divide(blocks) {
  const SIZEOF_LINK = 4
  const MAX_CHUNK_SIZE = 128
  let chunk = []
  let seq = []
  let next = []
  let chunks = [chunk]
  blocks.forEach(block => {
    block.forEach(inst => {
      chunk.push(inst)
      if (inst.type == 'bar') {
        const size = chunk.length + SIZEOF_LINK
        if (size >= MAX_CHUNK_SIZE - 3 && size <= MAX_CHUNK_SIZE) {
          // add special instructions
          chunk.push({ type: 'foo',val: 1 })
          chunk.push({ type: 'bar',val: 100 })
          chunk = []
          chunks.push(chunk)
        }
        // divide if it's optimal to divide.
      }
    })
  })
  return chunks
}

我这样做正确吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)