This repository was archived by the owner on Jan 22, 2025. It is now read-only.
forked from msgpack/msgpack-javascript
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwasmFunctions.ts
More file actions
96 lines (82 loc) · 3.18 KB
/
wasmFunctions.ts
File metadata and controls
96 lines (82 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// WASM=never - disable WASM functions
// WASM=force - force to use WASM functions
const WASM: string = process.env.MSGPACK_WASM || process.env.WASM || "";
export const NO_WASM = WASM === "never";
export const FORCE_WASM = WASM === "force";
type pointer = number;
// WM stands for WasmModule, but not the WebAssembly.Module instance but the WebAssembly.Instance.prototype.exports
const wm: any = (() => {
if (NO_WASM) {
return null;
}
try {
return require("../dist/wasm/msgpack.wasm.js");
} catch (e) {
if (FORCE_WASM) {
throw e;
}
return null;
}
})();
export const WASM_AVAILABLE = !!wm;
// A hint of when to use WASM ver.
export const WASM_STR_THRESHOLD = FORCE_WASM ? 0 : 1024;
function setMemoryU8(destPtr: pointer, src: Uint8Array, size: number) {
const destView = new Uint8Array(wm.memory.buffer, destPtr, size);
destView.set(src);
}
function setMemoryStr(destPtr: pointer, destByteLength: number, str: string, strLength: number) {
const inputView = new DataView(wm.memory.buffer, destPtr, destByteLength);
for (let i = 0; i < strLength; i++) {
inputView.setUint16(i * 2, str.charCodeAt(i));
}
}
/**
* It encodes string to MessagePack str family (headByte/size + utf8 bytes).
* @returns The whole byte length including headByte/size.
*/
export function utf8EncodeWasm(str: string, output: Uint8Array, outputOffset: number): number {
const strLength = str.length;
const inputByteLength = strLength * 2;
const inputU16BePtr: pointer = wm.malloc(inputByteLength);
setMemoryStr(inputU16BePtr, inputByteLength, str, strLength);
const maxOutputHeaderSize = 1 + 4; // headByte + u32
const outputPtr: pointer = wm.malloc(maxOutputHeaderSize + strLength * 4);
try {
const outputLength = wm.utf8EncodeUint16Array(outputPtr, inputU16BePtr, strLength);
output.set(new Uint8Array(wm.memory.buffer, outputPtr, outputLength), outputOffset);
return outputLength;
} finally {
wm.free(inputU16BePtr);
wm.free(outputPtr);
}
}
const CHUNK_SIZE = 0x10_000;
function safeStringFromCharCodeU16(units: Uint16Array) {
if (units.length <= CHUNK_SIZE) {
// `String.fromCharCode.apply()` is faster than `String.fromCharCode(...units)`
// in case `units` is a typed array
return String.fromCharCode.apply(String, units as any);
}
let result = "";
for (let i = 0; i < units.length; i++) {
const chunk = units.subarray(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE);
result += String.fromCharCode.apply(String, chunk as any);
}
return result;
}
// A wrapper function for utf8DecodeToUint16Array()
export function utf8DecodeWasm(bytes: Uint8Array, inputOffset: number, byteLength: number): string {
const inputPtr: pointer = wm.malloc(byteLength);
// in worst case, the UTF-16 array uses the same as byteLength * 2
const outputPtr: pointer = wm.malloc(byteLength * 2);
try {
setMemoryU8(inputPtr, bytes.subarray(inputOffset, inputOffset + byteLength), byteLength);
const outputArraySize = wm.utf8DecodeToUint16Array(outputPtr, inputPtr, byteLength);
const units = new Uint16Array(wm.memory.buffer, outputPtr, outputArraySize);
return safeStringFromCharCodeU16(units);
} finally {
wm.free(inputPtr);
wm.free(outputPtr);
}
}