@@ -8,35 +8,39 @@ if (NODE_MAJOR_VERSION < 12 || process.env.CAMARO_FORCE_SINGLE_THREAD === 'true'
88 pool = {
99 run ( task , opts ) {
1010 void opts
11- return workerFn ( task )
11+ return workerFn ( task ) . then ( parseCamaroJson )
1212 } ,
13+ destroy ( ) { } ,
1314 }
1415} else {
15- const WorkerPool = require ( 'piscina' )
16- const piscina = new WorkerPool ( { filename : resolve ( __dirname , 'worker.js' ) } )
16+ const { LeanPool } = require ( './lean-pool' )
17+ const { parseCamaroJson } = require ( './json-parse' )
18+ const leanPool = new LeanPool ( resolve ( __dirname , 'pool-worker.js' ) )
1719 pool = {
1820 run ( task , opts ) {
19- if ( opts && opts . transferList && opts . transferList . length > 0 ) {
20- return piscina . run ( task , { transferList : opts . transferList } )
21- }
22- return piscina . run ( task )
21+ return leanPool . run ( task , opts ) . then ( parseCamaroJson )
22+ } ,
23+ destroy ( ) {
24+ return leanPool . destroy ( )
2325 } ,
2426 }
2527}
2628
2729/** Wasm Embind Utf-16 string → std::string is slower than Utf-8 bytes + malloc; reuse the Utf-8 path. */
2830const textEncoderUtf8 =
2931 typeof TextEncoder !== 'undefined' ? new TextEncoder ( ) : null
32+ let xmlUtf8Scratch = null
3033
3134function utf8BytesFromJsString ( xml ) {
32- return textEncoderUtf8
33- ? textEncoderUtf8 . encode ( xml )
34- : Buffer . from ( xml , 'utf8' )
35- }
36-
37- function canTransferUnderlyingBuffer ( view ) {
38- if ( ! ( view instanceof Uint8Array ) || view . byteLength === 0 ) return false
39- return view . byteOffset === 0 && view . byteLength === view . buffer . byteLength
35+ if ( ! textEncoderUtf8 ) {
36+ return Buffer . from ( xml , 'utf8' )
37+ }
38+ const worstCase = xml . length * 3
39+ if ( ! xmlUtf8Scratch || xmlUtf8Scratch . length < worstCase ) {
40+ xmlUtf8Scratch = new Uint8Array ( Math . max ( worstCase , 65536 ) )
41+ }
42+ const { written } = textEncoderUtf8 . encodeInto ( xml , xmlUtf8Scratch )
43+ return xmlUtf8Scratch . subarray ( 0 , written )
4044}
4145
4246/**
@@ -45,16 +49,10 @@ function canTransferUnderlyingBuffer(view) {
4549 */
4650function xmlPayloadForWorkerThread ( xml ) {
4751 if ( typeof xml === 'string' ) {
48- const u8 = utf8BytesFromJsString ( xml )
49- if (
50- NODE_MAJOR_VERSION >= 12 &&
51- process . env . CAMARO_FORCE_SINGLE_THREAD !== 'true' &&
52- canTransferUnderlyingBuffer ( u8 )
53- ) {
54- return { xmlWire : u8 , poolOpts : { transferList : [ u8 . buffer ] } }
55- }
56- return { xmlWire : u8 }
52+ // Reuse scratch + structured clone; transfer detaches and forces re-allocation.
53+ return { xmlWire : utf8BytesFromJsString ( xml ) }
5754 }
55+ // User-supplied binaries: structured clone only (transfer would detach caller's buffer).
5856 return { xmlWire : xml }
5957}
6058
@@ -98,6 +96,17 @@ function isEmptyObject(obj) {
9896 return Object . entries ( obj ) . length === 0 && obj . constructor === Object
9997}
10098
99+ const templateStringCache = new WeakMap ( )
100+
101+ function templateString ( template ) {
102+ let cached = templateStringCache . get ( template )
103+ if ( cached === undefined ) {
104+ cached = JSON . stringify ( template )
105+ templateStringCache . set ( template , cached )
106+ }
107+ return cached
108+ }
109+
101110/**
102111 * convert xml to json base on the template object
103112 * @param {string|Buffer|Uint8Array|ArrayBuffer } xml xml as UTF-8 string or raw bytes
@@ -115,7 +124,7 @@ function transform(xml, template) {
115124 return dispatchPool (
116125 {
117126 fn : 'transform' ,
118- args : [ payload . xmlWire , JSON . stringify ( template ) ] ,
127+ args : [ payload . xmlWire , templateString ( template ) ] ,
119128 } ,
120129 payload . poolOpts ,
121130 )
0 commit comments