fix: use proper phrase decompress algorithm

[deploy]
This commit is contained in:
2023-07-28 17:04:43 +02:00
parent 374e27c7d0
commit c709878d6a
6 changed files with 27 additions and 44 deletions

View File

@@ -2,27 +2,11 @@ import {describe, it, expect} from "vitest"
import {compressActions, decompressActions} from "./actions"
describe("layout", function () {
const actions = [1, 5, 2, 1023, 42, 2, 4, 78]
const actions = [1023, 255, 256, 42, 32, 532, 8000]
describe("compression", function () {
it("should compress back and forth arrays divisible by 4", function () {
expect(decompressActions(compressActions(actions))).toEqual(actions)
})
it("should compress back and forth arrays divisible not divisible by 4", function () {
expect(decompressActions(compressActions([...actions, 1023, 512, 123]))).toEqual([
...actions,
1023,
512,
123,
])
expect(decompressActions(compressActions([...actions, 1023, 512]))).toEqual([...actions, 1023, 512])
expect(decompressActions(compressActions([...actions, 1023]))).toEqual([...actions, 1023])
})
it("should compress alternating 0/1023", function () {
const array = Array.from({length: 128}).map((_, i) => (i % 2 === 0 ? 0 : 1023))
expect(decompressActions(compressActions(array))).toEqual(array)
})
})
})

View File

@@ -1,23 +1,18 @@
/**
* Compresses an action list into a Uint8Array of 10-bit integers, supporting values of up to 1023
* Compresses an action list into a Uint8Array of variable-length 8/13-bit integers.
*
* Action codes <32 are invalid.
*/
export function compressActions(actions: number[]): Uint8Array {
const overflow = actions.length % 4
const array = new Uint8Array(
Math.ceil((actions.length - overflow) * 1.25 + (overflow === 0 ? 0 : overflow + 1)),
)
let arrayOffset = 0
for (let i = 0; i < actions.length; i += 4) {
let final = 0
for (let j = 0; j < 4 && i + j < actions.length; j++) {
const action = actions[i + j]
array[arrayOffset++] = (action >>> 2) & 0xff
final |= (action & 0x03) << (j * 2)
const buffer = new Uint8Array(actions.length * 2)
let i = 0
for (const action of actions) {
if (action > 0xff) {
buffer[i++] = action >>> 8
}
array[arrayOffset++] = final
buffer[i++] = action & 0xff
}
console.assert(arrayOffset === array.length)
return array
return buffer.slice(0, i)
}
/**
@@ -27,12 +22,12 @@ export function compressActions(actions: number[]): Uint8Array {
*/
export function decompressActions(raw: Uint8Array): number[] {
const actions: number[] = []
for (let i = 0; i < raw.length + 4; i += 5) {
const overflow = raw[Math.min(i + 4, raw.length - 1)]
for (let j = 0; j < 4 && i + j < raw.length - 1; j++) {
actions.push((raw[i + j] << 2) | ((overflow >>> (j * 2)) & 0x3))
for (let i = 0; i < raw.length; i++) {
let action = raw[i]
if (action < 32) {
action = (action << 8) | raw[++i]
}
actions.push(action)
}
return actions
}