Skip to content

Commit

Permalink
No copy - return wasm memory view
Browse files Browse the repository at this point in the history
  • Loading branch information
platypii committed Feb 28, 2024
1 parent fbc903d commit 2abbdb6
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 27 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { snappyUncompress } from 'hysnappy'
const compressed = new Uint8Array([
0x0a, 0x24, 0x68, 0x79, 0x70, 0x65, 0x72, 0x70, 0x61, 0x72, 0x61, 0x6d
])
const output = new Uint8Array(10)
snappyUncompress(compressed, output)
const outputLength = 10
const output = snappyUncompress(compressed, outputLength)
```

## Development
Expand Down
6 changes: 2 additions & 4 deletions benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ const compressed = time(`generate and compress ${fileSize.toLocaleString()}`, ()
})
console.log(`compressed ${fileSize.toLocaleString()} bytes to ${compressed.length.toLocaleString()} bytes`)

const output = new Uint8Array(fileSize)

const snappyUncompress = snappyUncompressor()
timeWithStdDev('uncompress wasm', () => snappyUncompress(compressed, output))
timeWithStdDev('uncompress wasm', () => snappyUncompress(compressed, fileSize))

// time('uncompress snappyjs', () => uncompress(compressed, output))
// time('uncompress snappyjs', () => uncompress(compressed, fileSize))

/**
* @param {string} name
Expand Down
4 changes: 2 additions & 2 deletions hysnappy.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* @param {Uint8Array} input
* @param {Uint8Array} output
*/
export async function snappyUncompress(input: Uint8Array, output: Uint8Array): Promise<void>
export async function snappyUncompress(input: Uint8Array, outputLength: number): Uint8Array

/**
* Load wasm and return uncompressor function.
*/
export function snappyUncompressor(): (input: Uint8Array, output: Uint8Array) => void
export function snappyUncompressor(): (input: Uint8Array, output: number) => Uint8Array
19 changes: 8 additions & 11 deletions hysnappy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@
* Uncompress a snappy compressed buffer.
*
* @param {Uint8Array} input
* @param {Uint8Array} output
* @param {number} outputLength
* @returns {Uint8Array}
*/
export function snappyUncompress(input, output) {
snappyUncompressor()(input, output)
export function snappyUncompress(input, outputLength) {
return snappyUncompressor()(input, outputLength)
}

/**
* Load wasm and return uncompressor function.
*
* @returns {(input: Uint8Array, output: Uint8Array) => void}
* @returns {(input: Uint8Array, outputLength: number) => Uint8Array}
*/
export function snappyUncompressor() {
// Instantiate wasm module
const wasm = instantiateWasm()

return (input, output) => {
return (input, outputLength) => {
/** @type {any} */
const { memory, uncompress } = wasm.exports

Expand All @@ -28,7 +29,7 @@ export function snappyUncompressor() {
const outputStart = inputStart + input.byteLength

// WebAssembly memory
const totalSize = inputStart + input.byteLength + output.byteLength
const totalSize = inputStart + input.byteLength + outputLength
if (memory.buffer.byteLength < totalSize) {
// Calculate the number of pages needed, rounding up
const pageSize = 64 * 1024 // 64KiB per page
Expand All @@ -52,11 +53,7 @@ export function snappyUncompressor() {
if (result) throw new Error(`failed to uncompress data ${result}`)

// Get uncompressed data from WASM memory
const uncompressed = byteArray.slice(outputStart, outputStart + output.byteLength)

// Copy the uncompressed data to the output buffer
// TODO: Return WASM memory buffer instead of copying?
output.set(uncompressed)
return byteArray.slice(outputStart, outputStart + outputLength)
}
}

Expand Down
14 changes: 6 additions & 8 deletions test/decompress.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ describe('snappy uncompress', () => {

testCases.map(({ compressed, expected }, i) => {
it(`decompress test input ${i}`, () => {
const output = new Uint8Array(expected.length)
snappyUncompress(compressed, output)
const output = snappyUncompress(compressed, expected.length)
if (typeof expected === 'string') {
const outputStr = new TextDecoder().decode(output)
expect(outputStr).toBe(expected)
Expand All @@ -52,16 +51,15 @@ describe('snappy uncompress', () => {
})

it('throws for invalid input', () => {
const output = new Uint8Array(10)
expect(() => snappyUncompress(new Uint8Array([]), output))
expect(() => snappyUncompress(new Uint8Array([]), 10))
.toThrow('invalid snappy length header')
expect(() => snappyUncompress(new Uint8Array([0xff]), output))
expect(() => snappyUncompress(new Uint8Array([0xff]), 10))
.toThrow('invalid snappy length header')
expect(() => snappyUncompress(new Uint8Array([0x03, 0x61]), output))
expect(() => snappyUncompress(new Uint8Array([0x03, 0x61]), 10))
.toThrow('missing eof marker')
expect(() => snappyUncompress(new Uint8Array([0x03, 0xf1]), output))
expect(() => snappyUncompress(new Uint8Array([0x03, 0xf1]), 10))
.toThrow('missing eof marker')
expect(() => snappyUncompress(new Uint8Array([0x02, 0x00, 0x68]), output))
expect(() => snappyUncompress(new Uint8Array([0x02, 0x00, 0x68]), 10))
.toThrow('premature end of input')
})
})

0 comments on commit 2abbdb6

Please sign in to comment.