cbor-x 0.9.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -21
- package/decode.d.ts +5 -0
- package/decode.js +344 -118
- package/dist/index.js +650 -327
- package/dist/index.min.js +100 -107
- package/dist/node-index.js +93 -0
- package/dist/node.cjs +651 -325
- package/dist/test.js +107 -9
- package/encode.d.ts +1 -1
- package/encode.js +302 -144
- package/index.d.ts +1 -1
- package/index.js +2 -4
- package/node-index.js +2 -4
- package/package.json +13 -4
- package/.vscode/launch.json +0 -22
- package/tests/benchmark-stream.cjs +0 -282
- package/tests/benchmark.cjs +0 -245
- package/tests/example.json +0 -52
- package/tests/example2.json +0 -26
- package/tests/example3.json +0 -22
- package/tests/example4.json +0 -1
- package/tests/example5.json +0 -12
- package/tests/floats.json +0 -1
- package/tests/index.html +0 -28
- package/tests/sample-large.json +0 -231
- package/tests/strings2.json +0 -1
- package/tests/test-compatibility.cjs +0 -36
- package/tests/test-incomplete.js +0 -41
- package/tests/test-node-iterators.js +0 -72
- package/tests/test-node-stream.js +0 -60
- package/tests/test.js +0 -586
package/dist/index.js
CHANGED
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
let src;
|
|
12
12
|
let srcEnd;
|
|
13
13
|
let position = 0;
|
|
14
|
-
const
|
|
14
|
+
const LEGACY_RECORD_INLINE_ID = 105;
|
|
15
|
+
const RECORD_DEFINITIONS_ID = 0xdffe;
|
|
16
|
+
const RECORD_INLINE_ID = 0xdfff; // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'
|
|
17
|
+
const BUNDLED_STRINGS_ID = 0xdff9;
|
|
15
18
|
const PACKED_REFERENCE_TAG_ID = 6;
|
|
16
19
|
const STOP_CODE = {};
|
|
17
20
|
let currentDecoder = {};
|
|
@@ -19,6 +22,7 @@
|
|
|
19
22
|
let srcString;
|
|
20
23
|
let srcStringStart = 0;
|
|
21
24
|
let srcStringEnd = 0;
|
|
25
|
+
let bundledStrings;
|
|
22
26
|
let referenceMap;
|
|
23
27
|
let currentExtensions = [];
|
|
24
28
|
let currentExtensionRanges = [];
|
|
@@ -34,13 +38,70 @@
|
|
|
34
38
|
class Decoder {
|
|
35
39
|
constructor(options) {
|
|
36
40
|
if (options) {
|
|
41
|
+
if ((options.keyMap || options._keyMap) && !options.useRecords) {
|
|
42
|
+
options.useRecords = false;
|
|
43
|
+
options.mapsAsObjects = true;
|
|
44
|
+
}
|
|
37
45
|
if (options.useRecords === false && options.mapsAsObjects === undefined)
|
|
38
46
|
options.mapsAsObjects = true;
|
|
39
|
-
if (options.getStructures
|
|
47
|
+
if (options.getStructures)
|
|
48
|
+
options.getShared = options.getStructures;
|
|
49
|
+
if (options.getShared && !options.structures)
|
|
40
50
|
(options.structures = []).uninitialized = true; // this is what we use to denote an uninitialized structures
|
|
51
|
+
if (options.keyMap) {
|
|
52
|
+
this.mapKey = new Map();
|
|
53
|
+
for (let [k,v] of Object.entries(options.keyMap)) this.mapKey.set(v,k);
|
|
54
|
+
}
|
|
41
55
|
}
|
|
42
56
|
Object.assign(this, options);
|
|
43
57
|
}
|
|
58
|
+
/*
|
|
59
|
+
decodeKey(key) {
|
|
60
|
+
return this.keyMap
|
|
61
|
+
? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key
|
|
62
|
+
: key
|
|
63
|
+
}
|
|
64
|
+
*/
|
|
65
|
+
decodeKey(key) {
|
|
66
|
+
return this.keyMap ? this.mapKey.get(key) || key : key
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
encodeKey(key) {
|
|
70
|
+
return this.keyMap && this.keyMap.hasOwnProperty(key) ? this.keyMap[key] : key
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
encodeKeys(rec) {
|
|
74
|
+
if (!this._keyMap) return rec
|
|
75
|
+
let map = new Map();
|
|
76
|
+
for (let [k,v] of Object.entries(rec)) map.set((this._keyMap.hasOwnProperty(k) ? this._keyMap[k] : k), v);
|
|
77
|
+
return map
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
decodeKeys(map) {
|
|
81
|
+
if (!this._keyMap || map.constructor.name != 'Map') return map
|
|
82
|
+
if (!this._mapKey) {
|
|
83
|
+
this._mapKey = new Map();
|
|
84
|
+
for (let [k,v] of Object.entries(this._keyMap)) this._mapKey.set(v,k);
|
|
85
|
+
}
|
|
86
|
+
let res = {};
|
|
87
|
+
//map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)
|
|
88
|
+
map.forEach((v,k) => res[this._mapKey.has(k) ? this._mapKey.get(k) : k] = v);
|
|
89
|
+
return res
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
mapDecode(source, end) {
|
|
93
|
+
|
|
94
|
+
let res = this.decode(source);
|
|
95
|
+
if (this._keyMap) {
|
|
96
|
+
//Experiemntal support for Optimised KeyMap decoding
|
|
97
|
+
switch (res.constructor.name) {
|
|
98
|
+
case 'Array': return res.map(r => this.decodeKeys(r))
|
|
99
|
+
//case 'Map': return this.decodeKeys(res)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return res
|
|
103
|
+
}
|
|
104
|
+
|
|
44
105
|
decode(source, end) {
|
|
45
106
|
if (src) {
|
|
46
107
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
@@ -53,12 +114,21 @@
|
|
|
53
114
|
position = 0;
|
|
54
115
|
srcStringEnd = 0;
|
|
55
116
|
srcString = null;
|
|
117
|
+
bundledStrings = null;
|
|
56
118
|
src = source;
|
|
57
119
|
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
58
120
|
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
59
121
|
// new ones
|
|
60
|
-
|
|
61
|
-
|
|
122
|
+
try {
|
|
123
|
+
dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
|
|
124
|
+
} catch(error) {
|
|
125
|
+
// if it doesn't have a buffer, maybe it is the wrong type of object
|
|
126
|
+
src = null;
|
|
127
|
+
if (source instanceof Uint8Array)
|
|
128
|
+
throw error
|
|
129
|
+
throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
|
|
130
|
+
}
|
|
131
|
+
if (this instanceof Decoder) {
|
|
62
132
|
currentDecoder = this;
|
|
63
133
|
packedValues = this.sharedValues &&
|
|
64
134
|
(this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :
|
|
@@ -115,6 +185,9 @@
|
|
|
115
185
|
function checkedRead() {
|
|
116
186
|
try {
|
|
117
187
|
let result = read();
|
|
188
|
+
if (bundledStrings) // bundled strings to skip past
|
|
189
|
+
position = bundledStrings.postBundlePosition;
|
|
190
|
+
|
|
118
191
|
if (position == srcEnd) {
|
|
119
192
|
// finished reading this source, cleanup references
|
|
120
193
|
currentStructures = null;
|
|
@@ -177,10 +250,15 @@
|
|
|
177
250
|
position += 8;
|
|
178
251
|
return value
|
|
179
252
|
}
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
253
|
+
if (majorType > 1) {
|
|
254
|
+
if (dataView.getUint32(position) > 0)
|
|
255
|
+
throw new Error('JavaScript does not support arrays, maps, or strings with length over 4294967295')
|
|
256
|
+
token = dataView.getUint32(position + 4);
|
|
257
|
+
} else if (currentDecoder.int64AsNumber) {
|
|
258
|
+
token = dataView.getUint32(position) * 0x100000000;
|
|
259
|
+
token += dataView.getUint32(position + 4);
|
|
260
|
+
} else
|
|
261
|
+
token = dataView.getBigUint64(position);
|
|
184
262
|
position += 8;
|
|
185
263
|
break
|
|
186
264
|
case 0x1f:
|
|
@@ -188,6 +266,7 @@
|
|
|
188
266
|
switch(majorType) {
|
|
189
267
|
case 2: // byte string
|
|
190
268
|
case 3: // text string
|
|
269
|
+
throw new Error('Indefinite length not supported for byte or text strings')
|
|
191
270
|
case 4: // array
|
|
192
271
|
let array = [];
|
|
193
272
|
let value, i = 0;
|
|
@@ -199,8 +278,8 @@
|
|
|
199
278
|
let key;
|
|
200
279
|
if (currentDecoder.mapsAsObjects) {
|
|
201
280
|
let object = {};
|
|
202
|
-
|
|
203
|
-
|
|
281
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[currentDecoder.decodeKey(key)] = read();
|
|
282
|
+
else while ((key = read()) != STOP_CODE) object[key] = read();
|
|
204
283
|
return object
|
|
205
284
|
} else {
|
|
206
285
|
if (restoreMapsAsObject) {
|
|
@@ -208,8 +287,8 @@
|
|
|
208
287
|
restoreMapsAsObject = false;
|
|
209
288
|
}
|
|
210
289
|
let map = new Map();
|
|
211
|
-
|
|
212
|
-
|
|
290
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) map.set(currentDecoder.decodeKey(key), read());
|
|
291
|
+
else while ((key = read()) != STOP_CODE) map.set(key, read());
|
|
213
292
|
return map
|
|
214
293
|
}
|
|
215
294
|
case 7:
|
|
@@ -241,16 +320,15 @@
|
|
|
241
320
|
return readFixedString(token)
|
|
242
321
|
case 4: // array
|
|
243
322
|
let array = new Array(token);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
323
|
+
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
324
|
+
//else
|
|
325
|
+
for (let i = 0; i < token; i++) array[i] = read();
|
|
247
326
|
return array
|
|
248
327
|
case 5: // map
|
|
249
328
|
if (currentDecoder.mapsAsObjects) {
|
|
250
329
|
let object = {};
|
|
251
|
-
for (let i = 0; i < token; i++)
|
|
252
|
-
|
|
253
|
-
}
|
|
330
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[currentDecoder.decodeKey(read())] = read();
|
|
331
|
+
else for (let i = 0; i < token; i++) object[read()] = read();
|
|
254
332
|
return object
|
|
255
333
|
} else {
|
|
256
334
|
if (restoreMapsAsObject) {
|
|
@@ -258,63 +336,66 @@
|
|
|
258
336
|
restoreMapsAsObject = false;
|
|
259
337
|
}
|
|
260
338
|
let map = new Map();
|
|
261
|
-
for (let i = 0; i < token; i++)
|
|
262
|
-
|
|
263
|
-
}
|
|
339
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
|
|
340
|
+
else for (let i = 0; i < token; i++) map.set(read(), read());
|
|
264
341
|
return map
|
|
265
342
|
}
|
|
266
343
|
case 6: // extension
|
|
267
|
-
if (
|
|
268
|
-
let structure = currentStructures[token &
|
|
344
|
+
if (token >= BUNDLED_STRINGS_ID) {
|
|
345
|
+
let structure = currentStructures[token & 0x1fff]; // check record structures first
|
|
346
|
+
// At some point we may provide an option for dynamic tag assignment with a range like token >= 8 && (token < 16 || (token > 0x80 && token < 0xc0) || (token > 0x130 && token < 0x4000))
|
|
269
347
|
if (structure) {
|
|
270
|
-
if (!structure.read)
|
|
271
|
-
structure.read = createStructureReader(structure);
|
|
348
|
+
if (!structure.read) structure.read = createStructureReader(structure);
|
|
272
349
|
return structure.read()
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (extension.handlesRead)
|
|
296
|
-
return extension(read)
|
|
297
|
-
else
|
|
298
|
-
return extension(read())
|
|
299
|
-
} else {
|
|
300
|
-
let input = read();
|
|
301
|
-
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
302
|
-
let value = currentExtensionRanges[i](token, input);
|
|
303
|
-
if (value !== undefined)
|
|
304
|
-
return value
|
|
350
|
+
}
|
|
351
|
+
if (token < 0x10000) {
|
|
352
|
+
if (token == RECORD_INLINE_ID) // we do a special check for this so that we can keep the currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)
|
|
353
|
+
return recordDefinition(read())
|
|
354
|
+
else if (token == RECORD_DEFINITIONS_ID) {
|
|
355
|
+
let length = readJustLength();
|
|
356
|
+
let id = read();
|
|
357
|
+
for (let i = 2; i < length; i++) {
|
|
358
|
+
recordDefinition([id++, read()]);
|
|
359
|
+
}
|
|
360
|
+
return read()
|
|
361
|
+
} else if (token == BUNDLED_STRINGS_ID) {
|
|
362
|
+
return readBundleExt()
|
|
363
|
+
}
|
|
364
|
+
if (currentDecoder.getShared) {
|
|
365
|
+
loadShared();
|
|
366
|
+
structure = currentStructures[token & 0x1fff];
|
|
367
|
+
if (structure) {
|
|
368
|
+
if (!structure.read)
|
|
369
|
+
structure.read = createStructureReader(structure);
|
|
370
|
+
return structure.read()
|
|
371
|
+
}
|
|
305
372
|
}
|
|
306
|
-
return new Tag(input)
|
|
307
373
|
}
|
|
308
374
|
}
|
|
375
|
+
let extension = currentExtensions[token];
|
|
376
|
+
if (extension) {
|
|
377
|
+
if (extension.handlesRead)
|
|
378
|
+
return extension(read)
|
|
379
|
+
else
|
|
380
|
+
return extension(read())
|
|
381
|
+
} else {
|
|
382
|
+
let input = read();
|
|
383
|
+
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
384
|
+
let value = currentExtensionRanges[i](token, input);
|
|
385
|
+
if (value !== undefined)
|
|
386
|
+
return value
|
|
387
|
+
}
|
|
388
|
+
return new Tag(input, token)
|
|
389
|
+
}
|
|
309
390
|
case 7: // fixed value
|
|
310
391
|
switch (token) {
|
|
311
392
|
case 0x14: return false
|
|
312
393
|
case 0x15: return true
|
|
313
394
|
case 0x16: return null
|
|
314
395
|
case 0x17: return; // undefined
|
|
315
|
-
case 0x1f:
|
|
396
|
+
case 0x1f:
|
|
316
397
|
default:
|
|
317
|
-
let packedValue = packedValues[token];
|
|
398
|
+
let packedValue = (packedValues || getPackedValues())[token];
|
|
318
399
|
if (packedValue !== undefined)
|
|
319
400
|
return packedValue
|
|
320
401
|
throw new Error('Unknown token ' + token)
|
|
@@ -330,42 +411,59 @@
|
|
|
330
411
|
}
|
|
331
412
|
const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/;
|
|
332
413
|
function createStructureReader(structure) {
|
|
333
|
-
let l = structure.length;
|
|
334
414
|
function readObject() {
|
|
415
|
+
// get the array size from the header
|
|
416
|
+
let length = src[position++];
|
|
417
|
+
//let majorType = token >> 5
|
|
418
|
+
length = length & 0x1f;
|
|
419
|
+
if (length > 0x17) {
|
|
420
|
+
switch (length) {
|
|
421
|
+
case 0x18:
|
|
422
|
+
length = src[position++];
|
|
423
|
+
break
|
|
424
|
+
case 0x19:
|
|
425
|
+
length = dataView.getUint16(position);
|
|
426
|
+
position += 2;
|
|
427
|
+
break
|
|
428
|
+
case 0x1a:
|
|
429
|
+
length = dataView.getUint32(position);
|
|
430
|
+
position += 4;
|
|
431
|
+
break
|
|
432
|
+
default:
|
|
433
|
+
throw new Error('Expected array header, but got ' + src[position - 1])
|
|
434
|
+
}
|
|
435
|
+
}
|
|
335
436
|
// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
437
|
+
let compiledReader = this.compiledReader; // first look to see if we have the fast compiled function
|
|
438
|
+
while(compiledReader) {
|
|
439
|
+
// we have a fast compiled object literal reader
|
|
440
|
+
if (compiledReader.propertyCount === length)
|
|
441
|
+
return compiledReader(read) // with the right length, so we use it
|
|
442
|
+
compiledReader = compiledReader.next; // see if there is another reader with the right length
|
|
339
443
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
444
|
+
if (this.slowReads++ >= 3) { // create a fast compiled reader
|
|
445
|
+
let array = this.length == length ? this : this.slice(0, length);
|
|
446
|
+
compiledReader = currentDecoder.keyMap
|
|
447
|
+
? new Function('r', 'return {' + array.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? k + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')
|
|
448
|
+
: new Function('r', 'return {' + array.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}');
|
|
449
|
+
if (this.compiledReader)
|
|
450
|
+
compiledReader.next = this.compiledReader; // if there is an existing one, we store multiple readers as a linked list because it is usually pretty rare to have multiple readers (of different length) for the same structure
|
|
451
|
+
compiledReader.propertyCount = length;
|
|
452
|
+
this.compiledReader = compiledReader;
|
|
453
|
+
return compiledReader(read)
|
|
345
454
|
}
|
|
455
|
+
let object = {};
|
|
456
|
+
if (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[currentDecoder.decodeKey(this[i])] = read();
|
|
457
|
+
else for (let i = 0; i < length; i++) object[this[i]] = read();
|
|
346
458
|
return object
|
|
347
459
|
}
|
|
348
|
-
|
|
460
|
+
structure.slowReads = 0;
|
|
349
461
|
return readObject
|
|
350
462
|
}
|
|
351
463
|
|
|
352
|
-
function readArrayHeader(expectedLength) {
|
|
353
|
-
// consume the array header, TODO: check expected length
|
|
354
|
-
let token = src[position++];
|
|
355
|
-
//let majorType = token >> 5
|
|
356
|
-
token = token & 0x1f;
|
|
357
|
-
if (token > 0x17) {
|
|
358
|
-
switch (token) {
|
|
359
|
-
case 0x18: position++;
|
|
360
|
-
break
|
|
361
|
-
case 0x19: position += 2;
|
|
362
|
-
break
|
|
363
|
-
case 0x1a: position += 4;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
464
|
let readFixedString = readStringJS;
|
|
465
|
+
|
|
466
|
+
let isNativeAccelerationEnabled = false;
|
|
369
467
|
function readStringJS(length) {
|
|
370
468
|
let result;
|
|
371
469
|
if (length < 16) {
|
|
@@ -594,76 +692,15 @@
|
|
|
594
692
|
}
|
|
595
693
|
|
|
596
694
|
let keyCache = new Array(4096);
|
|
597
|
-
function readKey() {
|
|
598
|
-
let length = src[position++];
|
|
599
|
-
if (length >= 0x60 && length < 0x78) {
|
|
600
|
-
// fixstr, potentially use key cache
|
|
601
|
-
length = length - 0x60;
|
|
602
|
-
if (srcStringEnd >= position) // if it has been extracted, must use it (and faster anyway)
|
|
603
|
-
return srcString.slice(position - srcStringStart, (position += length) - srcStringStart)
|
|
604
|
-
else if (!(srcStringEnd == 0 && srcEnd < 180))
|
|
605
|
-
return readFixedString(length)
|
|
606
|
-
} else { // not cacheable, go back and do a standard read
|
|
607
|
-
position--;
|
|
608
|
-
return read()
|
|
609
|
-
}
|
|
610
|
-
let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position) : length > 0 ? src[position] : 0)) & 0xfff;
|
|
611
|
-
let entry = keyCache[key];
|
|
612
|
-
let checkPosition = position;
|
|
613
|
-
let end = position + length - 3;
|
|
614
|
-
let chunk;
|
|
615
|
-
let i = 0;
|
|
616
|
-
if (entry && entry.bytes == length) {
|
|
617
|
-
while (checkPosition < end) {
|
|
618
|
-
chunk = dataView.getUint32(checkPosition);
|
|
619
|
-
if (chunk != entry[i++]) {
|
|
620
|
-
checkPosition = 0x70000000;
|
|
621
|
-
break
|
|
622
|
-
}
|
|
623
|
-
checkPosition += 4;
|
|
624
|
-
}
|
|
625
|
-
end += 3;
|
|
626
|
-
while (checkPosition < end) {
|
|
627
|
-
chunk = src[checkPosition++];
|
|
628
|
-
if (chunk != entry[i++]) {
|
|
629
|
-
checkPosition = 0x70000000;
|
|
630
|
-
break
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
if (checkPosition === end) {
|
|
634
|
-
position = checkPosition;
|
|
635
|
-
return entry.string
|
|
636
|
-
}
|
|
637
|
-
end -= 3;
|
|
638
|
-
checkPosition = position;
|
|
639
|
-
}
|
|
640
|
-
entry = [];
|
|
641
|
-
keyCache[key] = entry;
|
|
642
|
-
entry.bytes = length;
|
|
643
|
-
while (checkPosition < end) {
|
|
644
|
-
chunk = dataView.getUint32(checkPosition);
|
|
645
|
-
entry.push(chunk);
|
|
646
|
-
checkPosition += 4;
|
|
647
|
-
}
|
|
648
|
-
end += 3;
|
|
649
|
-
while (checkPosition < end) {
|
|
650
|
-
chunk = src[checkPosition++];
|
|
651
|
-
entry.push(chunk);
|
|
652
|
-
}
|
|
653
|
-
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
654
|
-
let string = length < 16 ? shortStringInJS(length) : longStringInJS(length);
|
|
655
|
-
if (string != null)
|
|
656
|
-
return entry.string = string
|
|
657
|
-
return entry.string = readFixedString(length)
|
|
658
|
-
}
|
|
659
695
|
|
|
660
696
|
class Tag {
|
|
661
|
-
constructor(value) {
|
|
697
|
+
constructor(value, tag) {
|
|
662
698
|
this.value = value;
|
|
699
|
+
this.tag = tag;
|
|
663
700
|
}
|
|
664
701
|
}
|
|
665
702
|
|
|
666
|
-
let glbl = typeof
|
|
703
|
+
let glbl = typeof self == 'object' ? self : global;
|
|
667
704
|
|
|
668
705
|
currentExtensions[0] = (dateString) => {
|
|
669
706
|
// string date extension
|
|
@@ -677,38 +714,67 @@
|
|
|
677
714
|
|
|
678
715
|
currentExtensions[2] = (buffer) => {
|
|
679
716
|
// bigint extension
|
|
680
|
-
|
|
717
|
+
let value = BigInt(0);
|
|
718
|
+
for (let i = 0, l = buffer.byteLength; i < l; i++) {
|
|
719
|
+
value = BigInt(buffer[i]) + value << BigInt(8);
|
|
720
|
+
}
|
|
721
|
+
return value
|
|
681
722
|
};
|
|
682
723
|
|
|
683
724
|
currentExtensions[3] = (buffer) => {
|
|
684
725
|
// negative bigint extension
|
|
685
|
-
return BigInt(-1) - (
|
|
726
|
+
return BigInt(-1) - currentExtensions[2](buffer)
|
|
727
|
+
};
|
|
728
|
+
currentExtensions[4] = (fraction) => {
|
|
729
|
+
// best to reparse to maintain accuracy
|
|
730
|
+
return +(fraction[1] + 'e' + fraction[0])
|
|
686
731
|
};
|
|
687
732
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
733
|
+
currentExtensions[5] = (fraction) => {
|
|
734
|
+
// probably not sufficiently accurate
|
|
735
|
+
return fraction[1] * Math.exp(fraction[0] * Math.log(2))
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
// the registration of the record definition extension
|
|
739
|
+
const recordDefinition = (definition) => {
|
|
740
|
+
let id = definition[0] - 0xe000;
|
|
741
|
+
let structure = definition[1];
|
|
742
|
+
let existingStructure = currentStructures[id];
|
|
743
|
+
if (existingStructure && existingStructure.isShared) {
|
|
744
|
+
(currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure;
|
|
745
|
+
}
|
|
746
|
+
currentStructures[id] = structure;
|
|
747
|
+
|
|
694
748
|
structure.read = createStructureReader(structure);
|
|
695
749
|
let object = {};
|
|
696
|
-
for (let i = 2,l = definition.length; i < l; i++) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
750
|
+
if (currentDecoder.keyMap) for (let i = 2,l = definition.length; i < l; i++) {
|
|
751
|
+
let key = currentDecoder.decodeKey(structure[i - 2]);
|
|
752
|
+
object[key] = definition[i];
|
|
753
|
+
}
|
|
754
|
+
else for (let i = 2,l = definition.length; i < l; i++) {
|
|
755
|
+
let key = structure[i - 2];
|
|
756
|
+
object[key] = definition[i];
|
|
757
|
+
}
|
|
700
758
|
return object
|
|
701
759
|
};
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
760
|
+
currentExtensions[LEGACY_RECORD_INLINE_ID] = recordDefinition;
|
|
761
|
+
currentExtensions[14] = (value) => {
|
|
762
|
+
if (bundledStrings)
|
|
763
|
+
return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 += value)
|
|
764
|
+
return new Tag(value, 14)
|
|
765
|
+
};
|
|
766
|
+
currentExtensions[15] = (value) => {
|
|
767
|
+
if (bundledStrings)
|
|
768
|
+
return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
|
|
769
|
+
return new Tag(value, 15)
|
|
770
|
+
};
|
|
705
771
|
|
|
706
772
|
currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
707
773
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
708
774
|
};
|
|
709
775
|
const packedTable = (read) => {
|
|
710
776
|
if (src[position++] != 0x84)
|
|
711
|
-
throw new Error('Packed values structure must be followed by 4 element array')
|
|
777
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
712
778
|
let newPackedValues = read(); // packed values
|
|
713
779
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
714
780
|
packedValues.prefixes = read();
|
|
@@ -719,15 +785,36 @@
|
|
|
719
785
|
currentExtensions[51] = packedTable;
|
|
720
786
|
|
|
721
787
|
currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
788
|
+
if (!packedValues) {
|
|
789
|
+
if (currentDecoder.getShared)
|
|
790
|
+
loadShared();
|
|
791
|
+
else
|
|
792
|
+
return new Tag(data, PACKED_REFERENCE_TAG_ID)
|
|
793
|
+
}
|
|
722
794
|
if (typeof data == 'number')
|
|
723
795
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
724
796
|
throw new Error('No support for non-integer packed references yet')
|
|
725
797
|
};
|
|
798
|
+
currentExtensions[25] = (id) => {
|
|
799
|
+
return stringRefs[id]
|
|
800
|
+
};
|
|
801
|
+
currentExtensions[256] = (read) => {
|
|
802
|
+
stringRefs = [];
|
|
803
|
+
try {
|
|
804
|
+
return read()
|
|
805
|
+
} finally {
|
|
806
|
+
stringRefs = null;
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
currentExtensions[256].handlesRead = true;
|
|
726
810
|
|
|
727
|
-
currentExtensions[
|
|
728
|
-
//
|
|
729
|
-
if (!referenceMap)
|
|
811
|
+
currentExtensions[28] = (read) => {
|
|
812
|
+
// shareable http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
813
|
+
if (!referenceMap) {
|
|
730
814
|
referenceMap = new Map();
|
|
815
|
+
referenceMap.id = 0;
|
|
816
|
+
}
|
|
817
|
+
let id = referenceMap.id++;
|
|
731
818
|
let token = src[position];
|
|
732
819
|
let target;
|
|
733
820
|
// TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
|
|
@@ -745,9 +832,10 @@
|
|
|
745
832
|
refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
|
|
746
833
|
return targetProperties // no cycle, can just use the returned read object
|
|
747
834
|
};
|
|
835
|
+
currentExtensions[28].handlesRead = true;
|
|
748
836
|
|
|
749
|
-
currentExtensions[
|
|
750
|
-
//
|
|
837
|
+
currentExtensions[29] = (id) => {
|
|
838
|
+
// sharedref http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
751
839
|
let refEntry = referenceMap.get(id);
|
|
752
840
|
refEntry.used = true;
|
|
753
841
|
return refEntry.target
|
|
@@ -770,19 +858,38 @@
|
|
|
770
858
|
return a.concat(b)
|
|
771
859
|
return Object.assign({}, a, b)
|
|
772
860
|
}
|
|
861
|
+
function getPackedValues() {
|
|
862
|
+
if (!packedValues) {
|
|
863
|
+
if (currentDecoder.getShared)
|
|
864
|
+
loadShared();
|
|
865
|
+
else
|
|
866
|
+
throw new Error('No packed values available')
|
|
867
|
+
}
|
|
868
|
+
return packedValues
|
|
869
|
+
}
|
|
870
|
+
const SHARED_DATA_TAG_ID = 0x53687264; // ascii 'Shrd'
|
|
773
871
|
currentExtensionRanges.push((tag, input) => {
|
|
774
872
|
if (tag >= 225 && tag <= 255)
|
|
775
|
-
return combine(
|
|
873
|
+
return combine(getPackedValues().prefixes[tag - 224], input)
|
|
776
874
|
if (tag >= 28704 && tag <= 32767)
|
|
777
|
-
return combine(
|
|
875
|
+
return combine(getPackedValues().prefixes[tag - 28672], input)
|
|
778
876
|
if (tag >= 1879052288 && tag <= 2147483647)
|
|
779
|
-
return combine(
|
|
877
|
+
return combine(getPackedValues().prefixes[tag - 1879048192], input)
|
|
780
878
|
if (tag >= 216 && tag <= 223)
|
|
781
|
-
return combine(input,
|
|
879
|
+
return combine(input, getPackedValues().suffixes[tag - 216])
|
|
782
880
|
if (tag >= 27647 && tag <= 28671)
|
|
783
|
-
return combine(input,
|
|
881
|
+
return combine(input, getPackedValues().suffixes[tag - 27639])
|
|
784
882
|
if (tag >= 1811940352 && tag <= 1879048191)
|
|
785
|
-
return combine(input,
|
|
883
|
+
return combine(input, getPackedValues().suffixes[tag - 1811939328])
|
|
884
|
+
if (tag == SHARED_DATA_TAG_ID) {// we do a special check for this so that we can keep the currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)
|
|
885
|
+
return {
|
|
886
|
+
packedValues: packedValues,
|
|
887
|
+
structures: currentStructures.slice(0),
|
|
888
|
+
version: input,
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (tag == 55799) // self-descriptive CBOR tag, just return input value
|
|
892
|
+
return input
|
|
786
893
|
});
|
|
787
894
|
|
|
788
895
|
const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array');
|
|
@@ -799,6 +906,61 @@
|
|
|
799
906
|
};
|
|
800
907
|
}
|
|
801
908
|
|
|
909
|
+
function readBundleExt() {
|
|
910
|
+
let length = readJustLength();
|
|
911
|
+
let bundlePosition = position + read();
|
|
912
|
+
for (let i = 2; i < length; i++) {
|
|
913
|
+
// skip past bundles that were already read
|
|
914
|
+
let bundleLength = readJustLength(); // this will increment position, so must add to position afterwards
|
|
915
|
+
position += bundleLength;
|
|
916
|
+
}
|
|
917
|
+
let dataPosition = position;
|
|
918
|
+
position = bundlePosition;
|
|
919
|
+
bundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())];
|
|
920
|
+
bundledStrings.position0 = 0;
|
|
921
|
+
bundledStrings.position1 = 0;
|
|
922
|
+
bundledStrings.postBundlePosition = position;
|
|
923
|
+
position = dataPosition;
|
|
924
|
+
return read()
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function readJustLength() {
|
|
928
|
+
let token = src[position++] & 0x1f;
|
|
929
|
+
if (token > 0x17) {
|
|
930
|
+
switch (token) {
|
|
931
|
+
case 0x18:
|
|
932
|
+
token = src[position++];
|
|
933
|
+
break
|
|
934
|
+
case 0x19:
|
|
935
|
+
token = dataView.getUint16(position);
|
|
936
|
+
position += 2;
|
|
937
|
+
break
|
|
938
|
+
case 0x1a:
|
|
939
|
+
token = dataView.getUint32(position);
|
|
940
|
+
position += 4;
|
|
941
|
+
break
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return token
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
function loadShared() {
|
|
948
|
+
if (currentDecoder.getShared) {
|
|
949
|
+
let sharedData = saveState(() => {
|
|
950
|
+
// save the state in case getShared modifies our buffer
|
|
951
|
+
src = null;
|
|
952
|
+
return currentDecoder.getShared()
|
|
953
|
+
}) || {};
|
|
954
|
+
let updatedStructures = sharedData.structures || [];
|
|
955
|
+
currentDecoder.sharedVersion = sharedData.version;
|
|
956
|
+
packedValues = currentDecoder.sharedValues = sharedData.packedValues;
|
|
957
|
+
if (currentStructures === true)
|
|
958
|
+
currentDecoder.structures = currentStructures = updatedStructures;
|
|
959
|
+
else
|
|
960
|
+
currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures));
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
802
964
|
function saveState(callback) {
|
|
803
965
|
let savedSrcEnd = srcEnd;
|
|
804
966
|
let savedPosition = position;
|
|
@@ -806,6 +968,8 @@
|
|
|
806
968
|
let savedSrcStringEnd = srcStringEnd;
|
|
807
969
|
let savedSrcString = srcString;
|
|
808
970
|
let savedReferenceMap = referenceMap;
|
|
971
|
+
let savedBundledStrings = bundledStrings;
|
|
972
|
+
|
|
809
973
|
// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
|
|
810
974
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
|
|
811
975
|
let savedStructures = currentStructures;
|
|
@@ -818,6 +982,7 @@
|
|
|
818
982
|
srcStringEnd = savedSrcStringEnd;
|
|
819
983
|
srcString = savedSrcString;
|
|
820
984
|
referenceMap = savedReferenceMap;
|
|
985
|
+
bundledStrings = savedBundledStrings;
|
|
821
986
|
src = savedSrc;
|
|
822
987
|
sequentialMode = savedSequentialMode;
|
|
823
988
|
currentStructures = savedStructures;
|
|
@@ -864,13 +1029,15 @@
|
|
|
864
1029
|
const hasNodeBuffer = typeof Buffer !== 'undefined';
|
|
865
1030
|
const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
|
|
866
1031
|
const ByteArray = hasNodeBuffer ? Buffer : Uint8Array;
|
|
867
|
-
const RECORD_STARTING_ID_PREFIX = 0x69; // tag 105/0x69
|
|
868
1032
|
const MAX_STRUCTURES = 0x100;
|
|
869
1033
|
const MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000;
|
|
870
1034
|
let target;
|
|
871
1035
|
let targetView;
|
|
872
1036
|
let position$1 = 0;
|
|
873
1037
|
let safeEnd;
|
|
1038
|
+
let bundledStrings$1 = null;
|
|
1039
|
+
const MAX_BUNDLE_SIZE = 0xf000;
|
|
1040
|
+
const hasNonLatin = /[\u0080-\uFFFF]/;
|
|
874
1041
|
const RECORD_SYMBOL = Symbol('record-id');
|
|
875
1042
|
class Encoder extends Decoder {
|
|
876
1043
|
constructor(options) {
|
|
@@ -882,7 +1049,6 @@
|
|
|
882
1049
|
let structures;
|
|
883
1050
|
let referenceMap;
|
|
884
1051
|
options = options || {};
|
|
885
|
-
let lastSharedStructuresLength = 0;
|
|
886
1052
|
let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position, maxBytes) {
|
|
887
1053
|
return target.utf8Write(string, position, maxBytes)
|
|
888
1054
|
} : (textEncoder && textEncoder.encodeInto) ?
|
|
@@ -891,12 +1057,20 @@
|
|
|
891
1057
|
} : false;
|
|
892
1058
|
|
|
893
1059
|
let encoder = this;
|
|
894
|
-
let
|
|
1060
|
+
let hasSharedStructures = options.structures || options.saveStructures;
|
|
1061
|
+
let maxSharedStructures = options.maxSharedStructures;
|
|
1062
|
+
if (maxSharedStructures == null)
|
|
1063
|
+
maxSharedStructures = hasSharedStructures ? 128 : 0;
|
|
1064
|
+
if (maxSharedStructures > 8190)
|
|
1065
|
+
throw new Error('Maximum maxSharedStructure is 8190')
|
|
895
1066
|
let isSequential = options.sequential;
|
|
896
1067
|
if (isSequential) {
|
|
897
1068
|
maxSharedStructures = 0;
|
|
898
|
-
this.structures = [];
|
|
899
1069
|
}
|
|
1070
|
+
if (!this.structures)
|
|
1071
|
+
this.structures = [];
|
|
1072
|
+
if (this.saveStructures)
|
|
1073
|
+
this.saveShared = this.saveStructures;
|
|
900
1074
|
let samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues;
|
|
901
1075
|
let sharedPackedObjectMap;
|
|
902
1076
|
if (sharedValues) {
|
|
@@ -904,13 +1078,29 @@
|
|
|
904
1078
|
for (let i = 0, l = sharedValues.length; i < l; i++) {
|
|
905
1079
|
sharedPackedObjectMap[sharedValues[i]] = i;
|
|
906
1080
|
}
|
|
907
|
-
|
|
908
1081
|
}
|
|
909
1082
|
let recordIdsToRemove = [];
|
|
910
1083
|
let transitionsCount = 0;
|
|
911
1084
|
let serializationsSinceTransitionRebuild = 0;
|
|
912
|
-
|
|
913
|
-
this.
|
|
1085
|
+
|
|
1086
|
+
this.mapEncode = function(value, encodeOptions) {
|
|
1087
|
+
// Experimental support for premapping keys using _keyMap instad of keyMap - not optiimised yet)
|
|
1088
|
+
if (this._keyMap && !this._mapped) {
|
|
1089
|
+
//console.log('encoding ', value)
|
|
1090
|
+
switch (value.constructor.name) {
|
|
1091
|
+
case 'Array':
|
|
1092
|
+
value = value.map(r => this.encodeKeys(r));
|
|
1093
|
+
break
|
|
1094
|
+
//case 'Map':
|
|
1095
|
+
// value = this.encodeKeys(value)
|
|
1096
|
+
// break
|
|
1097
|
+
}
|
|
1098
|
+
//this._mapped = true
|
|
1099
|
+
}
|
|
1100
|
+
return this.encode(value, encodeOptions)
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
this.encode = function(value, encodeOptions) {
|
|
914
1104
|
if (!target) {
|
|
915
1105
|
target = new ByteArrayAllocate(8192);
|
|
916
1106
|
targetView = new DataView(target.buffer, 0, 8192);
|
|
@@ -926,11 +1116,30 @@
|
|
|
926
1116
|
} else if (encodeOptions === REUSE_BUFFER_MODE)
|
|
927
1117
|
position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
|
|
928
1118
|
start = position$1;
|
|
1119
|
+
if (encoder.useSelfDescribedHeader) {
|
|
1120
|
+
targetView.setUint32(position$1, 0xd9d9f700); // tag two byte, then self-descriptive tag
|
|
1121
|
+
position$1 += 3;
|
|
1122
|
+
}
|
|
929
1123
|
referenceMap = encoder.structuredClone ? new Map() : null;
|
|
1124
|
+
if (encoder.bundleStrings && typeof value !== 'string') {
|
|
1125
|
+
bundledStrings$1 = [];
|
|
1126
|
+
bundledStrings$1.size = Infinity; // force a new bundle start on first string
|
|
1127
|
+
} else
|
|
1128
|
+
bundledStrings$1 = null;
|
|
1129
|
+
|
|
930
1130
|
sharedStructures = encoder.structures;
|
|
931
1131
|
if (sharedStructures) {
|
|
932
|
-
if (sharedStructures.uninitialized)
|
|
933
|
-
|
|
1132
|
+
if (sharedStructures.uninitialized) {
|
|
1133
|
+
let sharedData = encoder.getShared() || {};
|
|
1134
|
+
encoder.structures = sharedStructures = sharedData.structures || [];
|
|
1135
|
+
encoder.sharedVersion = sharedData.version;
|
|
1136
|
+
let sharedValues = encoder.sharedValues = sharedData.packedValues;
|
|
1137
|
+
if (sharedValues) {
|
|
1138
|
+
sharedPackedObjectMap = {};
|
|
1139
|
+
for (let i = 0, l = sharedValues.length; i < l; i++)
|
|
1140
|
+
sharedPackedObjectMap[sharedValues[i]] = i;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
934
1143
|
let sharedStructuresLength = sharedStructures.length;
|
|
935
1144
|
if (sharedStructuresLength > maxSharedStructures && !isSequential)
|
|
936
1145
|
sharedStructuresLength = maxSharedStructures;
|
|
@@ -939,10 +1148,13 @@
|
|
|
939
1148
|
sharedStructures.transitions = Object.create(null);
|
|
940
1149
|
for (let i = 0; i < sharedStructuresLength; i++) {
|
|
941
1150
|
let keys = sharedStructures[i];
|
|
1151
|
+
//console.log('shared struct keys:', keys)
|
|
942
1152
|
if (!keys)
|
|
943
1153
|
continue
|
|
944
1154
|
let nextTransition, transition = sharedStructures.transitions;
|
|
945
1155
|
for (let j = 0, l = keys.length; j < l; j++) {
|
|
1156
|
+
if (transition[RECORD_SYMBOL] === undefined)
|
|
1157
|
+
transition[RECORD_SYMBOL] = i;
|
|
946
1158
|
let key = keys[j];
|
|
947
1159
|
nextTransition = transition[key];
|
|
948
1160
|
if (!nextTransition) {
|
|
@@ -950,9 +1162,8 @@
|
|
|
950
1162
|
}
|
|
951
1163
|
transition = nextTransition;
|
|
952
1164
|
}
|
|
953
|
-
transition[RECORD_SYMBOL] = i;
|
|
1165
|
+
transition[RECORD_SYMBOL] = i | 0x100000;
|
|
954
1166
|
}
|
|
955
|
-
lastSharedStructuresLength = sharedStructures.length;
|
|
956
1167
|
}
|
|
957
1168
|
if (!isSequential)
|
|
958
1169
|
sharedStructures.nextId = sharedStructuresLength;
|
|
@@ -985,9 +1196,12 @@
|
|
|
985
1196
|
}
|
|
986
1197
|
try {
|
|
987
1198
|
encode(value);
|
|
1199
|
+
if (bundledStrings$1) {
|
|
1200
|
+
writeBundles(start, encode);
|
|
1201
|
+
}
|
|
988
1202
|
encoder.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
989
1203
|
if (referenceMap && referenceMap.idsToInsert) {
|
|
990
|
-
position$1 += referenceMap.idsToInsert.length *
|
|
1204
|
+
position$1 += referenceMap.idsToInsert.length * 2;
|
|
991
1205
|
if (position$1 > safeEnd)
|
|
992
1206
|
makeRoom(position$1);
|
|
993
1207
|
encoder.offset = position$1;
|
|
@@ -995,16 +1209,18 @@
|
|
|
995
1209
|
referenceMap = null;
|
|
996
1210
|
return serialized
|
|
997
1211
|
}
|
|
998
|
-
if (encodeOptions
|
|
1212
|
+
if (encodeOptions & REUSE_BUFFER_MODE) {
|
|
999
1213
|
target.start = start;
|
|
1000
1214
|
target.end = position$1;
|
|
1001
1215
|
return target
|
|
1002
1216
|
}
|
|
1003
|
-
return target.subarray(start, position$1) // position can change if we call
|
|
1217
|
+
return target.subarray(start, position$1) // position can change if we call encode again in saveShared, so we get the buffer now
|
|
1004
1218
|
} finally {
|
|
1005
1219
|
if (sharedStructures) {
|
|
1006
1220
|
if (serializationsSinceTransitionRebuild < 10)
|
|
1007
1221
|
serializationsSinceTransitionRebuild++;
|
|
1222
|
+
if (sharedStructures.length > maxSharedStructures)
|
|
1223
|
+
sharedStructures.length = maxSharedStructures;
|
|
1008
1224
|
if (transitionsCount > 10000) {
|
|
1009
1225
|
// force a rebuild occasionally after a lot of transitions so it can get cleaned up
|
|
1010
1226
|
sharedStructures.transitions = null;
|
|
@@ -1017,35 +1233,29 @@
|
|
|
1017
1233
|
recordIdsToRemove[i][RECORD_SYMBOL] = undefined;
|
|
1018
1234
|
}
|
|
1019
1235
|
recordIdsToRemove = [];
|
|
1236
|
+
//sharedStructures.nextId = maxSharedStructures
|
|
1020
1237
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1026
|
-
let returnBuffer = target.subarray(start, position$1);
|
|
1027
|
-
let shared = encoder.structures || [];
|
|
1028
|
-
if (sharedValues) {
|
|
1029
|
-
shared = shared.concat(sharedValues);
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
|
|
1033
|
-
// get updated structures and try again if the update failed
|
|
1034
|
-
encoder.structures = encoder.getStructures() || [];
|
|
1035
|
-
return encoder.encode(value)
|
|
1036
|
-
}
|
|
1037
|
-
lastSharedStructuresLength = shared.length;
|
|
1038
|
-
return returnBuffer
|
|
1238
|
+
}
|
|
1239
|
+
if (hasSharedUpdate && encoder.saveShared) {
|
|
1240
|
+
if (encoder.structures.length > maxSharedStructures) {
|
|
1241
|
+
encoder.structures = encoder.structures.slice(0, maxSharedStructures);
|
|
1039
1242
|
}
|
|
1243
|
+
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1244
|
+
let returnBuffer = target.subarray(start, position$1);
|
|
1245
|
+
if (encoder.updateSharedData() === false)
|
|
1246
|
+
return encoder.encode(value) // re-encode if it fails
|
|
1247
|
+
return returnBuffer
|
|
1040
1248
|
}
|
|
1249
|
+
if (encodeOptions & RESET_BUFFER_MODE)
|
|
1250
|
+
position$1 = start;
|
|
1041
1251
|
}
|
|
1042
1252
|
};
|
|
1043
1253
|
this.findCommonStringsToPack = () => {
|
|
1044
1254
|
samplingPackedValues = new Map();
|
|
1045
1255
|
if (!sharedPackedObjectMap)
|
|
1046
1256
|
sharedPackedObjectMap = Object.create(null);
|
|
1047
|
-
return (
|
|
1048
|
-
threshold = threshold || 4;
|
|
1257
|
+
return (options) => {
|
|
1258
|
+
let threshold = options && options.threshold || 4;
|
|
1049
1259
|
let position = this.pack ? options.maxPrivatePackedValues || 16 : 0;
|
|
1050
1260
|
if (!sharedValues)
|
|
1051
1261
|
sharedValues = this.sharedValues = [];
|
|
@@ -1056,6 +1266,7 @@
|
|
|
1056
1266
|
hasSharedUpdate = true;
|
|
1057
1267
|
}
|
|
1058
1268
|
}
|
|
1269
|
+
while (this.saveShared && this.updateSharedData() === false) {}
|
|
1059
1270
|
samplingPackedValues = null;
|
|
1060
1271
|
}
|
|
1061
1272
|
};
|
|
@@ -1104,6 +1315,33 @@
|
|
|
1104
1315
|
}
|
|
1105
1316
|
}
|
|
1106
1317
|
let strLength = value.length;
|
|
1318
|
+
if (bundledStrings$1 && strLength >= 4 && strLength < 0x400) {
|
|
1319
|
+
if ((bundledStrings$1.size += strLength) > MAX_BUNDLE_SIZE) {
|
|
1320
|
+
let extStart;
|
|
1321
|
+
let maxBytes = (bundledStrings$1[0] ? bundledStrings$1[0].length * 3 + bundledStrings$1[1].length : 0) + 10;
|
|
1322
|
+
if (position$1 + maxBytes > safeEnd)
|
|
1323
|
+
target = makeRoom(position$1 + maxBytes);
|
|
1324
|
+
target[position$1++] = 0xd9; // tag 16-bit
|
|
1325
|
+
target[position$1++] = 0xdf; // tag 0xdff9
|
|
1326
|
+
target[position$1++] = 0xf9;
|
|
1327
|
+
// TODO: If we only have one bundle with any string data, only write one string bundle
|
|
1328
|
+
target[position$1++] = bundledStrings$1.position ? 0x84 : 0x82; // array of 4 or 2 elements depending on if we write bundles
|
|
1329
|
+
target[position$1++] = 0x1a; // 32-bit unsigned int
|
|
1330
|
+
extStart = position$1 - start;
|
|
1331
|
+
position$1 += 4; // reserve for writing bundle reference
|
|
1332
|
+
if (bundledStrings$1.position) {
|
|
1333
|
+
writeBundles(start, encode); // write the last bundles
|
|
1334
|
+
}
|
|
1335
|
+
bundledStrings$1 = ['', '']; // create new ones
|
|
1336
|
+
bundledStrings$1.size = 0;
|
|
1337
|
+
bundledStrings$1.position = extStart;
|
|
1338
|
+
}
|
|
1339
|
+
let twoByte = hasNonLatin.test(value);
|
|
1340
|
+
bundledStrings$1[twoByte ? 0 : 1] += value;
|
|
1341
|
+
target[position$1++] = twoByte ? 0xce : 0xcf;
|
|
1342
|
+
encode(strLength);
|
|
1343
|
+
return
|
|
1344
|
+
}
|
|
1107
1345
|
let headerSize;
|
|
1108
1346
|
// first we estimate the header size, so we can write to the correct location
|
|
1109
1347
|
if (strLength < 0x20) {
|
|
@@ -1230,16 +1468,16 @@
|
|
|
1230
1468
|
if (referenceMap) {
|
|
1231
1469
|
let referee = referenceMap.get(value);
|
|
1232
1470
|
if (referee) {
|
|
1233
|
-
|
|
1471
|
+
target[position$1++] = 0xd8;
|
|
1472
|
+
target[position$1++] = 29; // http://cbor.schmorp.de/value-sharing
|
|
1473
|
+
target[position$1++] = 0x19; // 16-bit uint
|
|
1474
|
+
if (!referee.references) {
|
|
1234
1475
|
let idsToInsert = referenceMap.idsToInsert || (referenceMap.idsToInsert = []);
|
|
1235
|
-
referee.
|
|
1476
|
+
referee.references = [];
|
|
1477
|
+
idsToInsert.push(referee);
|
|
1236
1478
|
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
target[position$1++] = 40010 & 0xff;
|
|
1240
|
-
target[position$1++] = 0x1a; // uint32
|
|
1241
|
-
targetView.setUint32(position$1, referee.id);
|
|
1242
|
-
position$1 += 4;
|
|
1479
|
+
referee.references.push(position$1 - start);
|
|
1480
|
+
position$1 += 2; // TODO: also support 32-bit
|
|
1243
1481
|
return
|
|
1244
1482
|
} else
|
|
1245
1483
|
referenceMap.set(value, { offset: position$1 - start });
|
|
@@ -1279,16 +1517,23 @@
|
|
|
1279
1517
|
targetView.setUint32(position$1, length);
|
|
1280
1518
|
position$1 += 4;
|
|
1281
1519
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1520
|
+
if (encoder.keyMap) {
|
|
1521
|
+
for (let [ key, entryValue ] of value) {
|
|
1522
|
+
encode(encoder.encodeKey(key));
|
|
1523
|
+
encode(entryValue);
|
|
1524
|
+
}
|
|
1525
|
+
} else {
|
|
1526
|
+
for (let [ key, entryValue ] of value) {
|
|
1527
|
+
encode(key);
|
|
1528
|
+
encode(entryValue);
|
|
1529
|
+
}
|
|
1285
1530
|
}
|
|
1286
|
-
} else {
|
|
1531
|
+
} else {
|
|
1287
1532
|
for (let i = 0, l = extensions.length; i < l; i++) {
|
|
1288
1533
|
let extensionClass = extensionClasses[i];
|
|
1289
1534
|
if (value instanceof extensionClass) {
|
|
1290
1535
|
let extension = extensions[i];
|
|
1291
|
-
let tag = extension.tag;
|
|
1536
|
+
let tag = extension.tag || extension.getTag && extension.getTag(value);
|
|
1292
1537
|
if (tag < 0x18) {
|
|
1293
1538
|
target[position$1++] = 0xc0 | tag;
|
|
1294
1539
|
} else if (tag < 0x100) {
|
|
@@ -1350,6 +1595,7 @@
|
|
|
1350
1595
|
const writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {
|
|
1351
1596
|
// this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
|
|
1352
1597
|
let keys = Object.keys(object);
|
|
1598
|
+
let vals = Object.values(object);
|
|
1353
1599
|
let length = keys.length;
|
|
1354
1600
|
if (length < 0x18) {
|
|
1355
1601
|
target[position$1++] = 0xa0 | length;
|
|
@@ -1365,10 +1611,16 @@
|
|
|
1365
1611
|
targetView.setUint32(position$1, length);
|
|
1366
1612
|
position$1 += 4;
|
|
1367
1613
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1614
|
+
if (encoder.keyMap) {
|
|
1615
|
+
for (let i = 0; i < length; i++) {
|
|
1616
|
+
encode(encodeKey(keys[i]));
|
|
1617
|
+
encode(vals[i]);
|
|
1618
|
+
}
|
|
1619
|
+
} else {
|
|
1620
|
+
for (let i = 0; i < length; i++) {
|
|
1621
|
+
encode(keys[i]);
|
|
1622
|
+
encode(vals[i]);
|
|
1623
|
+
}
|
|
1372
1624
|
}
|
|
1373
1625
|
} :
|
|
1374
1626
|
(object, safePrototype) => {
|
|
@@ -1376,95 +1628,92 @@
|
|
|
1376
1628
|
let objectOffset = position$1 - start;
|
|
1377
1629
|
position$1 += 2;
|
|
1378
1630
|
let size = 0;
|
|
1379
|
-
|
|
1380
|
-
if (safePrototype || object.hasOwnProperty(key)) {
|
|
1381
|
-
encode(key);
|
|
1631
|
+
if (encoder.keyMap) {
|
|
1632
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1633
|
+
encode(encoder.encodeKey(key));
|
|
1382
1634
|
encode(object[key]);
|
|
1383
1635
|
size++;
|
|
1384
1636
|
}
|
|
1637
|
+
} else {
|
|
1638
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1639
|
+
encode(key);
|
|
1640
|
+
encode(object[key]);
|
|
1641
|
+
size++;
|
|
1642
|
+
}
|
|
1385
1643
|
}
|
|
1386
1644
|
target[objectOffset++ + start] = size >> 8;
|
|
1387
1645
|
target[objectOffset + start] = size & 0xff;
|
|
1388
1646
|
} :
|
|
1389
|
-
|
|
1390
|
-
/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
|
|
1391
1647
|
(object, safePrototype) => {
|
|
1392
|
-
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
|
|
1393
|
-
let
|
|
1394
|
-
let
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1648
|
+
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1649
|
+
let newTransitions = 0;
|
|
1650
|
+
let length = 0;
|
|
1651
|
+
let parentRecordId;
|
|
1652
|
+
let keys;
|
|
1653
|
+
if (this.keyMap) {
|
|
1654
|
+
keys = Object.keys(object).map(k => this.encodeKey(k));
|
|
1655
|
+
length = keys.length;
|
|
1656
|
+
for (let i = 0; i < length; i++) {
|
|
1657
|
+
let key = keys[i];
|
|
1658
|
+
nextTransition = transition[key];
|
|
1398
1659
|
if (!nextTransition) {
|
|
1399
|
-
nextTransition = transition[key] = Object.create(null)
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
nextTransition.__keys__ = keys.slice(0, i + 1)
|
|
1411
|
-
}
|
|
1660
|
+
nextTransition = transition[key] = Object.create(null);
|
|
1661
|
+
newTransitions++;
|
|
1662
|
+
}
|
|
1663
|
+
transition = nextTransition;
|
|
1664
|
+
}
|
|
1665
|
+
} else {
|
|
1666
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1667
|
+
nextTransition = transition[key];
|
|
1668
|
+
if (!nextTransition) {
|
|
1669
|
+
if (transition[RECORD_SYMBOL] & 0x100000) {// this indicates it is a brancheable/extendable terminal node, so we will use this record id and extend it
|
|
1670
|
+
parentRecordId = transition[RECORD_SYMBOL] & 0xffff;
|
|
1412
1671
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
target.copy(target, )
|
|
1416
|
-
objectOffset
|
|
1672
|
+
nextTransition = transition[key] = Object.create(null);
|
|
1673
|
+
newTransitions++;
|
|
1417
1674
|
}
|
|
1418
|
-
transition = nextTransition
|
|
1419
|
-
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
let id = transition.id
|
|
1423
|
-
if (!id) {
|
|
1424
|
-
id = transition.id = structures.push(transition.__keys__) + 63
|
|
1425
|
-
if (sharedStructures.onUpdate)
|
|
1426
|
-
sharedStructures.onUpdate(id, transition.__keys__)
|
|
1427
|
-
}
|
|
1428
|
-
target[objectOffset + start] = id
|
|
1429
|
-
}*/
|
|
1430
|
-
(object) => {
|
|
1431
|
-
let keys = Object.keys(object);
|
|
1432
|
-
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1433
|
-
let newTransitions = 0;
|
|
1434
|
-
let length = keys.length;
|
|
1435
|
-
for (let i = 0; i < length; i++) {
|
|
1436
|
-
let key = keys[i];
|
|
1437
|
-
nextTransition = transition[key];
|
|
1438
|
-
if (!nextTransition) {
|
|
1439
|
-
nextTransition = transition[key] = Object.create(null);
|
|
1440
|
-
newTransitions++;
|
|
1675
|
+
transition = nextTransition;
|
|
1676
|
+
length++;
|
|
1441
1677
|
}
|
|
1442
|
-
transition = nextTransition;
|
|
1443
1678
|
}
|
|
1444
1679
|
let recordId = transition[RECORD_SYMBOL];
|
|
1445
1680
|
if (recordId !== undefined) {
|
|
1446
|
-
|
|
1447
|
-
target[position$1++] =
|
|
1448
|
-
target[position$1++] = recordId;
|
|
1681
|
+
recordId &= 0xffff;
|
|
1682
|
+
target[position$1++] = 0xd9;
|
|
1683
|
+
target[position$1++] = (recordId >> 8) | 0xe0;
|
|
1684
|
+
target[position$1++] = recordId & 0xff;
|
|
1449
1685
|
} else {
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
structures.nextId
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1686
|
+
if (!keys)
|
|
1687
|
+
keys = transition.__keys__ || (transition.__keys__ = Object.keys(object));
|
|
1688
|
+
if (parentRecordId === undefined) {
|
|
1689
|
+
recordId = structures.nextId++;
|
|
1690
|
+
if (!recordId) {
|
|
1691
|
+
recordId = 0;
|
|
1692
|
+
structures.nextId = 1;
|
|
1693
|
+
}
|
|
1694
|
+
if (recordId >= MAX_STRUCTURES) {// cycle back around
|
|
1695
|
+
structures.nextId = (recordId = maxSharedStructures) + 1;
|
|
1696
|
+
}
|
|
1697
|
+
} else {
|
|
1698
|
+
recordId = parentRecordId;
|
|
1457
1699
|
}
|
|
1458
|
-
transition[RECORD_SYMBOL] = recordId;
|
|
1459
1700
|
structures[recordId] = keys;
|
|
1460
|
-
if (
|
|
1461
|
-
target[position$1++] = 0xd9;
|
|
1462
|
-
target[position$1++] =
|
|
1463
|
-
target[position$1++] = recordId
|
|
1701
|
+
if (recordId < maxSharedStructures) {
|
|
1702
|
+
target[position$1++] = 0xd9;
|
|
1703
|
+
target[position$1++] = (recordId >> 8) | 0xe0;
|
|
1704
|
+
target[position$1++] = recordId & 0xff;
|
|
1705
|
+
transition = structures.transitions;
|
|
1706
|
+
for (let i = 0; i < length; i++) {
|
|
1707
|
+
if (transition[RECORD_SYMBOL] === undefined || (transition[RECORD_SYMBOL] & 0x100000))
|
|
1708
|
+
transition[RECORD_SYMBOL] = recordId;
|
|
1709
|
+
transition = transition[keys[i]];
|
|
1710
|
+
}
|
|
1711
|
+
transition[RECORD_SYMBOL] = recordId | 0x100000; // indicates it is a extendable terminal
|
|
1464
1712
|
hasSharedUpdate = true;
|
|
1465
1713
|
} else {
|
|
1466
|
-
|
|
1467
|
-
|
|
1714
|
+
transition[RECORD_SYMBOL] = recordId;
|
|
1715
|
+
targetView.setUint32(position$1, 0xd9dfff00); // tag two byte, then record definition id
|
|
1716
|
+
position$1 += 3;
|
|
1468
1717
|
if (newTransitions)
|
|
1469
1718
|
transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
|
|
1470
1719
|
// record the removal of the id, we can maintain our shared structure
|
|
@@ -1472,13 +1721,9 @@
|
|
|
1472
1721
|
recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
|
|
1473
1722
|
recordIdsToRemove.push(transition);
|
|
1474
1723
|
writeArrayHeader(length + 2);
|
|
1724
|
+
encode(0xe000 + recordId);
|
|
1475
1725
|
encode(keys);
|
|
1476
|
-
|
|
1477
|
-
target[position$1++] = RECORD_STARTING_ID_PREFIX;
|
|
1478
|
-
target[position$1++] = recordId;
|
|
1479
|
-
// now write the values
|
|
1480
|
-
for (let i =0; i < length; i++)
|
|
1481
|
-
encode(object[keys[i]]);
|
|
1726
|
+
for (let v of Object.values(object)) encode(v);
|
|
1482
1727
|
return
|
|
1483
1728
|
}
|
|
1484
1729
|
}
|
|
@@ -1487,8 +1732,9 @@
|
|
|
1487
1732
|
} else {
|
|
1488
1733
|
writeArrayHeader(length);
|
|
1489
1734
|
}
|
|
1490
|
-
for (let
|
|
1491
|
-
|
|
1735
|
+
for (let key in object)
|
|
1736
|
+
if (safePrototype || object.hasOwnProperty(key))
|
|
1737
|
+
encode(object[key]);
|
|
1492
1738
|
};
|
|
1493
1739
|
const makeRoom = (end) => {
|
|
1494
1740
|
let newSize;
|
|
@@ -1497,7 +1743,7 @@
|
|
|
1497
1743
|
if ((end - start) > MAX_BUFFER_SIZE)
|
|
1498
1744
|
throw new Error('Encoded buffer would be larger than maximum buffer size')
|
|
1499
1745
|
newSize = Math.min(MAX_BUFFER_SIZE,
|
|
1500
|
-
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2),
|
|
1746
|
+
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000);
|
|
1501
1747
|
} else // faster handling for smaller buffers
|
|
1502
1748
|
newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
|
|
1503
1749
|
let newBuffer = new ByteArrayAllocate(newSize);
|
|
@@ -1518,6 +1764,40 @@
|
|
|
1518
1764
|
targetView = new DataView(target.buffer, target.byteOffset, target.byteLength);
|
|
1519
1765
|
position$1 = 0;
|
|
1520
1766
|
}
|
|
1767
|
+
clearSharedData() {
|
|
1768
|
+
if (this.structures)
|
|
1769
|
+
this.structures = [];
|
|
1770
|
+
if (this.sharedValues)
|
|
1771
|
+
this.sharedValues = undefined;
|
|
1772
|
+
}
|
|
1773
|
+
updateSharedData() {
|
|
1774
|
+
let lastVersion = this.sharedVersion || 0;
|
|
1775
|
+
this.sharedVersion = lastVersion + 1;
|
|
1776
|
+
let structuresCopy = this.structures.slice(0);
|
|
1777
|
+
let sharedData = new SharedData(structuresCopy, this.sharedValues, this.sharedVersion);
|
|
1778
|
+
let saveResults = this.saveShared(sharedData,
|
|
1779
|
+
existingShared => (existingShared && existingShared.version || 0) == lastVersion);
|
|
1780
|
+
if (saveResults === false) {
|
|
1781
|
+
// get updated structures and try again if the update failed
|
|
1782
|
+
sharedData = this.getShared() || {};
|
|
1783
|
+
this.structures = sharedData.structures || [];
|
|
1784
|
+
this.sharedValues = sharedData.packedValues;
|
|
1785
|
+
this.sharedVersion = sharedData.version;
|
|
1786
|
+
this.structures.nextId = this.structures.length;
|
|
1787
|
+
} else {
|
|
1788
|
+
// restore structures
|
|
1789
|
+
structuresCopy.forEach((structure, i) => this.structures[i] = structure);
|
|
1790
|
+
}
|
|
1791
|
+
// saveShared may fail to write and reload, or may have reloaded to check compatibility and overwrite saved data, either way load the correct shared data
|
|
1792
|
+
return saveResults
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
class SharedData {
|
|
1796
|
+
constructor(structures, values, version) {
|
|
1797
|
+
this.structures = structures;
|
|
1798
|
+
this.packedValues = values;
|
|
1799
|
+
this.version = version;
|
|
1800
|
+
}
|
|
1521
1801
|
}
|
|
1522
1802
|
|
|
1523
1803
|
function writeArrayHeader(length) {
|
|
@@ -1587,9 +1867,11 @@
|
|
|
1587
1867
|
}
|
|
1588
1868
|
}
|
|
1589
1869
|
|
|
1590
|
-
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, ByteArray,
|
|
1591
|
-
Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,
|
|
1592
|
-
|
|
1870
|
+
extensionClasses = [ Date, Set, Error, RegExp, Tag, ArrayBuffer, ByteArray,
|
|
1871
|
+
Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,
|
|
1872
|
+
typeof BigUint64Array == 'undefined' ? function() {} : BigUint64Array, Int8Array, Int16Array, Int32Array,
|
|
1873
|
+
typeof BigInt64Array == 'undefined' ? function() {} : BigInt64Array,
|
|
1874
|
+
Float32Array, Float64Array, SharedData];
|
|
1593
1875
|
|
|
1594
1876
|
//Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/
|
|
1595
1877
|
extensions = [{
|
|
@@ -1624,6 +1906,13 @@
|
|
|
1624
1906
|
encode(regex, encode) {
|
|
1625
1907
|
encode([ 'RegExp', regex.source, regex.flags ]);
|
|
1626
1908
|
}
|
|
1909
|
+
}, {
|
|
1910
|
+
getTag(tag) {
|
|
1911
|
+
return tag.tag
|
|
1912
|
+
},
|
|
1913
|
+
encode(tag, encode) {
|
|
1914
|
+
encode(tag.value);
|
|
1915
|
+
}
|
|
1627
1916
|
}, {
|
|
1628
1917
|
encode(arrayBuffer, encode, makeRoom) {
|
|
1629
1918
|
writeBuffer(arrayBuffer, makeRoom);
|
|
@@ -1642,7 +1931,35 @@
|
|
|
1642
1931
|
typedArrayEncoder(78),
|
|
1643
1932
|
typedArrayEncoder(79),
|
|
1644
1933
|
typedArrayEncoder(81),
|
|
1645
|
-
typedArrayEncoder(82)
|
|
1934
|
+
typedArrayEncoder(82),
|
|
1935
|
+
{
|
|
1936
|
+
encode(sharedData, encode) { // write SharedData
|
|
1937
|
+
let packedValues = sharedData.packedValues || [];
|
|
1938
|
+
let sharedStructures = sharedData.structures || [];
|
|
1939
|
+
if (packedValues.values.length > 0) {
|
|
1940
|
+
target[position$1++] = 0xd8; // one-byte tag
|
|
1941
|
+
target[position$1++] = 51; // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
|
|
1942
|
+
writeArrayHeader(4);
|
|
1943
|
+
let valuesArray = packedValues.values;
|
|
1944
|
+
encode(valuesArray);
|
|
1945
|
+
writeArrayHeader(0); // prefixes
|
|
1946
|
+
writeArrayHeader(0); // suffixes
|
|
1947
|
+
packedObjectMap = Object.create(sharedPackedObjectMap || null);
|
|
1948
|
+
for (let i = 0, l = valuesArray.length; i < l; i++) {
|
|
1949
|
+
packedObjectMap[valuesArray[i]] = i;
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
if (sharedStructures) {
|
|
1953
|
+
targetView.setUint32(position$1, 0xd9dffe00);
|
|
1954
|
+
position$1 += 3;
|
|
1955
|
+
let definitions = sharedStructures.slice(0);
|
|
1956
|
+
definitions.unshift(0xe000);
|
|
1957
|
+
definitions.push(new Tag(sharedData.version, 0x53687264));
|
|
1958
|
+
encode(definitions);
|
|
1959
|
+
} else
|
|
1960
|
+
encode(new Tag(sharedData.version, 0x53687264));
|
|
1961
|
+
}
|
|
1962
|
+
}];
|
|
1646
1963
|
|
|
1647
1964
|
function typedArrayEncoder(tag) {
|
|
1648
1965
|
return {
|
|
@@ -1682,27 +1999,35 @@
|
|
|
1682
1999
|
function insertIds(serialized, idsToInsert) {
|
|
1683
2000
|
// insert the ids that need to be referenced for structured clones
|
|
1684
2001
|
let nextId;
|
|
1685
|
-
let distanceToMove = idsToInsert.length *
|
|
2002
|
+
let distanceToMove = idsToInsert.length * 2;
|
|
1686
2003
|
let lastEnd = serialized.length - distanceToMove;
|
|
1687
2004
|
idsToInsert.sort((a, b) => a.offset > b.offset ? 1 : -1);
|
|
2005
|
+
for (let id = 0; id < idsToInsert.length; id++) {
|
|
2006
|
+
let referee = idsToInsert[id];
|
|
2007
|
+
referee.id = id;
|
|
2008
|
+
for (let position of referee.references) {
|
|
2009
|
+
serialized[position++] = id >> 8;
|
|
2010
|
+
serialized[position] = id & 0xff;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
1688
2013
|
while (nextId = idsToInsert.pop()) {
|
|
1689
2014
|
let offset = nextId.offset;
|
|
1690
|
-
let id = nextId.id;
|
|
1691
2015
|
serialized.copyWithin(offset + distanceToMove, offset, lastEnd);
|
|
1692
|
-
distanceToMove -=
|
|
2016
|
+
distanceToMove -= 2;
|
|
1693
2017
|
let position = offset + distanceToMove;
|
|
1694
|
-
serialized[position++] =
|
|
1695
|
-
serialized[position++] =
|
|
1696
|
-
serialized[position++] = 40009 & 0xff;
|
|
1697
|
-
serialized[position++] = 0x1a; // uint32
|
|
1698
|
-
serialized[position++] = id >> 24;
|
|
1699
|
-
serialized[position++] = (id >> 16) & 0xff;
|
|
1700
|
-
serialized[position++] = (id >> 8) & 0xff;
|
|
1701
|
-
serialized[position++] = id & 0xff;
|
|
2018
|
+
serialized[position++] = 0xd8;
|
|
2019
|
+
serialized[position++] = 28; // http://cbor.schmorp.de/value-sharing
|
|
1702
2020
|
lastEnd = offset;
|
|
1703
2021
|
}
|
|
1704
2022
|
return serialized
|
|
1705
2023
|
}
|
|
2024
|
+
function writeBundles(start, encode) {
|
|
2025
|
+
targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start + 1); // the offset to bundle
|
|
2026
|
+
let writeStrings = bundledStrings$1;
|
|
2027
|
+
bundledStrings$1 = null;
|
|
2028
|
+
encode(writeStrings[0]);
|
|
2029
|
+
encode(writeStrings[1]);
|
|
2030
|
+
}
|
|
1706
2031
|
|
|
1707
2032
|
function addExtension$1(extension) {
|
|
1708
2033
|
if (extension.Class) {
|
|
@@ -1716,7 +2041,8 @@
|
|
|
1716
2041
|
let defaultEncoder = new Encoder({ useRecords: false });
|
|
1717
2042
|
const encode = defaultEncoder.encode;
|
|
1718
2043
|
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1719
|
-
const REUSE_BUFFER_MODE =
|
|
2044
|
+
const REUSE_BUFFER_MODE = 512;
|
|
2045
|
+
const RESET_BUFFER_MODE = 1024;
|
|
1720
2046
|
|
|
1721
2047
|
/**
|
|
1722
2048
|
* Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer
|
|
@@ -1801,9 +2127,6 @@
|
|
|
1801
2127
|
}
|
|
1802
2128
|
}
|
|
1803
2129
|
|
|
1804
|
-
const useRecords = false;
|
|
1805
|
-
const mapsAsObjects = true;
|
|
1806
|
-
|
|
1807
2130
|
exports.ALWAYS = ALWAYS;
|
|
1808
2131
|
exports.DECIMAL_FIT = DECIMAL_FIT;
|
|
1809
2132
|
exports.DECIMAL_ROUND = DECIMAL_ROUND;
|
|
@@ -1811,6 +2134,7 @@
|
|
|
1811
2134
|
exports.Encoder = Encoder;
|
|
1812
2135
|
exports.FLOAT32_OPTIONS = FLOAT32_OPTIONS;
|
|
1813
2136
|
exports.NEVER = NEVER;
|
|
2137
|
+
exports.REUSE_BUFFER_MODE = REUSE_BUFFER_MODE;
|
|
1814
2138
|
exports.Tag = Tag;
|
|
1815
2139
|
exports.addExtension = addExtension$1;
|
|
1816
2140
|
exports.clearSource = clearSource;
|
|
@@ -1819,9 +2143,8 @@
|
|
|
1819
2143
|
exports.decodeMultiple = decodeMultiple;
|
|
1820
2144
|
exports.encode = encode;
|
|
1821
2145
|
exports.encodeIter = encodeIter;
|
|
1822
|
-
exports.
|
|
2146
|
+
exports.isNativeAccelerationEnabled = isNativeAccelerationEnabled;
|
|
1823
2147
|
exports.roundFloat32 = roundFloat32;
|
|
1824
|
-
exports.useRecords = useRecords;
|
|
1825
2148
|
|
|
1826
2149
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1827
2150
|
|