cbor-x 0.9.1 → 1.0.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/dist/node.cjs CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- require('fs');
6
5
  var stream = require('stream');
7
6
  var module$1 = require('module');
8
7
 
@@ -14,7 +13,10 @@ let src;
14
13
  let srcEnd;
15
14
  let position = 0;
16
15
  const EMPTY_ARRAY = [];
17
- const RECORD_TAG_ID = 0x69;
16
+ const LEGACY_RECORD_INLINE_ID = 105;
17
+ const RECORD_DEFINITIONS_ID = 0xdffe;
18
+ const RECORD_INLINE_ID = 0xdfff; // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'
19
+ const BUNDLED_STRINGS_ID = 0xdff9;
18
20
  const PACKED_REFERENCE_TAG_ID = 6;
19
21
  const STOP_CODE = {};
20
22
  let strings = EMPTY_ARRAY;
@@ -24,6 +26,7 @@ let currentStructures;
24
26
  let srcString;
25
27
  let srcStringStart = 0;
26
28
  let srcStringEnd = 0;
29
+ let bundledStrings;
27
30
  let referenceMap;
28
31
  let currentExtensions = [];
29
32
  let currentExtensionRanges = [];
@@ -39,13 +42,70 @@ let sequentialMode = false;
39
42
  class Decoder {
40
43
  constructor(options) {
41
44
  if (options) {
45
+ if ((options.keyMap || options._keyMap) && !options.useRecords) {
46
+ options.useRecords = false;
47
+ options.mapsAsObjects = true;
48
+ }
42
49
  if (options.useRecords === false && options.mapsAsObjects === undefined)
43
50
  options.mapsAsObjects = true;
44
- if (options.getStructures && !options.structures)
51
+ if (options.getStructures)
52
+ options.getShared = options.getStructures;
53
+ if (options.getShared && !options.structures)
45
54
  (options.structures = []).uninitialized = true; // this is what we use to denote an uninitialized structures
55
+ if (options.keyMap) {
56
+ this.mapKey = new Map();
57
+ for (let [k,v] of Object.entries(options.keyMap)) this.mapKey.set(v,k);
58
+ }
46
59
  }
47
60
  Object.assign(this, options);
48
61
  }
62
+ /*
63
+ decodeKey(key) {
64
+ return this.keyMap
65
+ ? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key
66
+ : key
67
+ }
68
+ */
69
+ decodeKey(key) {
70
+ return this.keyMap ? this.mapKey.get(key) || key : key
71
+ }
72
+
73
+ encodeKey(key) {
74
+ return this.keyMap && this.keyMap.hasOwnProperty(key) ? this.keyMap[key] : key
75
+ }
76
+
77
+ encodeKeys(rec) {
78
+ if (!this._keyMap) return rec
79
+ let map = new Map();
80
+ for (let [k,v] of Object.entries(rec)) map.set((this._keyMap.hasOwnProperty(k) ? this._keyMap[k] : k), v);
81
+ return map
82
+ }
83
+
84
+ decodeKeys(map) {
85
+ if (!this._keyMap || map.constructor.name != 'Map') return map
86
+ if (!this._mapKey) {
87
+ this._mapKey = new Map();
88
+ for (let [k,v] of Object.entries(this._keyMap)) this._mapKey.set(v,k);
89
+ }
90
+ let res = {};
91
+ //map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)
92
+ map.forEach((v,k) => res[this._mapKey.has(k) ? this._mapKey.get(k) : k] = v);
93
+ return res
94
+ }
95
+
96
+ mapDecode(source, end) {
97
+
98
+ let res = this.decode(source);
99
+ if (this._keyMap) {
100
+ //Experiemntal support for Optimised KeyMap decoding
101
+ switch (res.constructor.name) {
102
+ case 'Array': return res.map(r => this.decodeKeys(r))
103
+ //case 'Map': return this.decodeKeys(res)
104
+ }
105
+ }
106
+ return res
107
+ }
108
+
49
109
  decode(source, end) {
50
110
  if (src) {
51
111
  // re-entrant execution, save the state and restore it after we do this decode
@@ -60,12 +120,21 @@ class Decoder {
60
120
  srcStringEnd = 0;
61
121
  srcString = null;
62
122
  strings = EMPTY_ARRAY;
123
+ bundledStrings = null;
63
124
  src = source;
64
125
  // this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
65
126
  // technique for getting data from a database where it can be copied into an existing buffer instead of creating
66
127
  // new ones
67
- dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
68
- if (this) {
128
+ try {
129
+ dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
130
+ } catch(error) {
131
+ // if it doesn't have a buffer, maybe it is the wrong type of object
132
+ src = null;
133
+ if (source instanceof Uint8Array)
134
+ throw error
135
+ throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
136
+ }
137
+ if (this instanceof Decoder) {
69
138
  currentDecoder = this;
70
139
  packedValues = this.sharedValues &&
71
140
  (this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :
@@ -122,6 +191,9 @@ class Decoder {
122
191
  function checkedRead() {
123
192
  try {
124
193
  let result = read();
194
+ if (bundledStrings) // bundled strings to skip past
195
+ position = bundledStrings.postBundlePosition;
196
+
125
197
  if (position == srcEnd) {
126
198
  // finished reading this source, cleanup references
127
199
  currentStructures = null;
@@ -184,10 +256,11 @@ function read() {
184
256
  position += 8;
185
257
  return value
186
258
  }
187
- if (currentDecoder.uint64AsNumber)
188
- return src[position++] * 0x100000000000000 + src[position++] * 0x1000000000000 + src[position++] * 0x10000000000 + src[position++] * 0x100000000 +
189
- src[position++] * 0x1000000 + (src[position++] << 16) + (src[position++] << 8) + src[position++]
190
- token = dataView.getBigUint64(position);
259
+ if (currentDecoder.int64AsNumber) {
260
+ token = dataView.getUint32(position) * 0x100000000;
261
+ token += dataView.getUint32(position + 4);
262
+ } else
263
+ token = dataView.getBigUint64(position);
191
264
  position += 8;
192
265
  break
193
266
  case 0x1f:
@@ -195,6 +268,7 @@ function read() {
195
268
  switch(majorType) {
196
269
  case 2: // byte string
197
270
  case 3: // text string
271
+ throw new Error('Indefinite length not supported for byte or text strings')
198
272
  case 4: // array
199
273
  let array = [];
200
274
  let value, i = 0;
@@ -206,8 +280,8 @@ function read() {
206
280
  let key;
207
281
  if (currentDecoder.mapsAsObjects) {
208
282
  let object = {};
209
- while ((key = readKey()) != STOP_CODE)
210
- object[key] = read();
283
+ if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[currentDecoder.decodeKey(key)] = read();
284
+ else while ((key = read()) != STOP_CODE) object[key] = read();
211
285
  return object
212
286
  } else {
213
287
  if (restoreMapsAsObject) {
@@ -215,8 +289,8 @@ function read() {
215
289
  restoreMapsAsObject = false;
216
290
  }
217
291
  let map = new Map();
218
- while ((key = read()) != STOP_CODE)
219
- map.set(key, read());
292
+ if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) map.set(currentDecoder.decodeKey(key), read());
293
+ else while ((key = read()) != STOP_CODE) map.set(key, read());
220
294
  return map
221
295
  }
222
296
  case 7:
@@ -248,16 +322,15 @@ function read() {
248
322
  return readFixedString(token)
249
323
  case 4: // array
250
324
  let array = new Array(token);
251
- for (let i = 0; i < token; i++) {
252
- array[i] = read();
253
- }
325
+ //if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
326
+ //else
327
+ for (let i = 0; i < token; i++) array[i] = read();
254
328
  return array
255
329
  case 5: // map
256
330
  if (currentDecoder.mapsAsObjects) {
257
331
  let object = {};
258
- for (let i = 0; i < token; i++) {
259
- object[readKey()] = read();
260
- }
332
+ if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[currentDecoder.decodeKey(read())] = read();
333
+ else for (let i = 0; i < token; i++) object[read()] = read();
261
334
  return object
262
335
  } else {
263
336
  if (restoreMapsAsObject) {
@@ -265,63 +338,66 @@ function read() {
265
338
  restoreMapsAsObject = false;
266
339
  }
267
340
  let map = new Map();
268
- for (let i = 0; i < token; i++) {
269
- map.set(read(), read());
270
- }
341
+ if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
342
+ else for (let i = 0; i < token; i++) map.set(read(), read());
271
343
  return map
272
344
  }
273
345
  case 6: // extension
274
- if ((token >> 8) == RECORD_TAG_ID) { // record structures
275
- let structure = currentStructures[token & 0xff];
346
+ if (token >= BUNDLED_STRINGS_ID) {
347
+ let structure = currentStructures[token & 0x1fff]; // check record structures first
348
+ // 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))
276
349
  if (structure) {
277
- if (!structure.read)
278
- structure.read = createStructureReader(structure);
350
+ if (!structure.read) structure.read = createStructureReader(structure);
279
351
  return structure.read()
280
- } else if (currentDecoder.getStructures) {
281
- let updatedStructures = saveState(() => {
282
- // save the state in case getStructures modifies our buffer
283
- src = null;
284
- return currentDecoder.getStructures()
285
- });
286
- if (currentStructures === true)
287
- currentDecoder.structures = currentStructures = updatedStructures;
288
- else
289
- currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures));
290
- structure = currentStructures[token & 0xff];
291
- if (structure) {
292
- if (!structure.read)
293
- structure.read = createStructureReader(structure);
294
- return structure.read()
295
- } else
296
- return token
297
- } else
298
- return token
299
- } else {
300
- let extension = currentExtensions[token];
301
- if (extension) {
302
- if (extension.handlesRead)
303
- return extension(read)
304
- else
305
- return extension(read())
306
- } else {
307
- let input = read();
308
- for (let i = 0; i < currentExtensionRanges.length; i++) {
309
- let value = currentExtensionRanges[i](token, input);
310
- if (value !== undefined)
311
- return value
352
+ }
353
+ if (token < 0x10000) {
354
+ 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)
355
+ return recordDefinition(read())
356
+ else if (token == RECORD_DEFINITIONS_ID) {
357
+ let length = readJustLength();
358
+ let id = read();
359
+ for (let i = 2; i < length; i++) {
360
+ recordDefinition([id++, read()]);
361
+ }
362
+ return read()
363
+ } else if (token == BUNDLED_STRINGS_ID) {
364
+ return readBundleExt()
365
+ }
366
+ if (currentDecoder.getShared) {
367
+ loadShared();
368
+ structure = currentStructures[token & 0x1fff];
369
+ if (structure) {
370
+ if (!structure.read)
371
+ structure.read = createStructureReader(structure);
372
+ return structure.read()
373
+ }
312
374
  }
313
- return new Tag(input)
314
375
  }
315
376
  }
377
+ let extension = currentExtensions[token];
378
+ if (extension) {
379
+ if (extension.handlesRead)
380
+ return extension(read)
381
+ else
382
+ return extension(read())
383
+ } else {
384
+ let input = read();
385
+ for (let i = 0; i < currentExtensionRanges.length; i++) {
386
+ let value = currentExtensionRanges[i](token, input);
387
+ if (value !== undefined)
388
+ return value
389
+ }
390
+ return new Tag(input, token)
391
+ }
316
392
  case 7: // fixed value
317
393
  switch (token) {
318
394
  case 0x14: return false
319
395
  case 0x15: return true
320
396
  case 0x16: return null
321
397
  case 0x17: return; // undefined
322
- case 0x1f:
398
+ case 0x1f:
323
399
  default:
324
- let packedValue = packedValues[token];
400
+ let packedValue = (packedValues || getPackedValues())[token];
325
401
  if (packedValue !== undefined)
326
402
  return packedValue
327
403
  throw new Error('Unknown token ' + token)
@@ -337,49 +413,59 @@ function read() {
337
413
  }
338
414
  const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/;
339
415
  function createStructureReader(structure) {
340
- let l = structure.length;
341
416
  function readObject() {
417
+ // get the array size from the header
418
+ let length = src[position++];
419
+ //let majorType = token >> 5
420
+ length = length & 0x1f;
421
+ if (length > 0x17) {
422
+ switch (length) {
423
+ case 0x18:
424
+ length = src[position++];
425
+ break
426
+ case 0x19:
427
+ length = dataView.getUint16(position);
428
+ position += 2;
429
+ break
430
+ case 0x1a:
431
+ length = dataView.getUint32(position);
432
+ position += 4;
433
+ break
434
+ default:
435
+ throw new Error('Expected array header, but got ' + src[position - 1])
436
+ }
437
+ }
342
438
  // This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
343
- if (readObject.count++ > 2) {
344
- this.read = (new Function('a', 'r', 'return function(){a();return {' + structure.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}}'))(readArrayHeader, read);
345
- return this.read()
439
+ if (this.objectLiteralSize === length) // we have a fast object literal reader, use it (assuming it is the right length)
440
+ return this.objectLiteral(read)
441
+ if (this.count++ == 3) { // create a fast reader
442
+ this.objectLiteralSize = length;
443
+ this.objectLiteral = currentDecoder.keyMap
444
+ ? new Function('r', 'return {' + this.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? k + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')
445
+ : new Function('r', 'return {' + this.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}');
446
+ return this.objectLiteral(read)
346
447
  }
347
- readArrayHeader();
348
448
  let object = {};
349
- for (let i = 0; i < l; i++) {
350
- let key = structure[i];
351
- object[key] = read();
352
- }
449
+ if (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[currentDecoder.decodeKey(this[i])] = read();
450
+ else for (let i = 0; i < length; i++) object[this[i]] = read();
353
451
  return object
354
452
  }
355
- readObject.count = 0;
453
+ structure.count = 0;
356
454
  return readObject
357
455
  }
358
456
 
359
- function readArrayHeader(expectedLength) {
360
- // consume the array header, TODO: check expected length
361
- let token = src[position++];
362
- //let majorType = token >> 5
363
- token = token & 0x1f;
364
- if (token > 0x17) {
365
- switch (token) {
366
- case 0x18: position++;
367
- break
368
- case 0x19: position += 2;
369
- break
370
- case 0x1a: position += 4;
371
- }
372
- }
373
- }
374
-
375
457
  let readFixedString = readStringJS;
376
458
 
459
+ exports.isNativeAccelerationEnabled = false;
377
460
  function setExtractor(extractStrings) {
461
+ exports.isNativeAccelerationEnabled = true;
378
462
  readFixedString = readString();
379
463
  function readString(headerLength) {
380
464
  return function readString(length) {
381
465
  let string = strings[stringPosition++];
382
466
  if (string == null) {
467
+ if (bundledStrings)
468
+ return readStringJS(length)
383
469
  let extraction = extractStrings(position, srcEnd, length, src);
384
470
  if (typeof extraction == 'string') {
385
471
  string = extraction;
@@ -634,76 +720,15 @@ function getFloat16() {
634
720
  }
635
721
 
636
722
  let keyCache = new Array(4096);
637
- function readKey() {
638
- let length = src[position++];
639
- if (length >= 0x60 && length < 0x78) {
640
- // fixstr, potentially use key cache
641
- length = length - 0x60;
642
- if (srcStringEnd >= position) // if it has been extracted, must use it (and faster anyway)
643
- return srcString.slice(position - srcStringStart, (position += length) - srcStringStart)
644
- else if (!(srcStringEnd == 0 && srcEnd < 180))
645
- return readFixedString(length)
646
- } else { // not cacheable, go back and do a standard read
647
- position--;
648
- return read()
649
- }
650
- let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position) : length > 0 ? src[position] : 0)) & 0xfff;
651
- let entry = keyCache[key];
652
- let checkPosition = position;
653
- let end = position + length - 3;
654
- let chunk;
655
- let i = 0;
656
- if (entry && entry.bytes == length) {
657
- while (checkPosition < end) {
658
- chunk = dataView.getUint32(checkPosition);
659
- if (chunk != entry[i++]) {
660
- checkPosition = 0x70000000;
661
- break
662
- }
663
- checkPosition += 4;
664
- }
665
- end += 3;
666
- while (checkPosition < end) {
667
- chunk = src[checkPosition++];
668
- if (chunk != entry[i++]) {
669
- checkPosition = 0x70000000;
670
- break
671
- }
672
- }
673
- if (checkPosition === end) {
674
- position = checkPosition;
675
- return entry.string
676
- }
677
- end -= 3;
678
- checkPosition = position;
679
- }
680
- entry = [];
681
- keyCache[key] = entry;
682
- entry.bytes = length;
683
- while (checkPosition < end) {
684
- chunk = dataView.getUint32(checkPosition);
685
- entry.push(chunk);
686
- checkPosition += 4;
687
- }
688
- end += 3;
689
- while (checkPosition < end) {
690
- chunk = src[checkPosition++];
691
- entry.push(chunk);
692
- }
693
- // for small blocks, avoiding the overhead of the extract call is helpful
694
- let string = length < 16 ? shortStringInJS(length) : longStringInJS(length);
695
- if (string != null)
696
- return entry.string = string
697
- return entry.string = readFixedString(length)
698
- }
699
723
 
700
724
  class Tag {
701
- constructor(value) {
725
+ constructor(value, tag) {
702
726
  this.value = value;
727
+ this.tag = tag;
703
728
  }
704
729
  }
705
730
 
706
- let glbl = typeof window == 'object' ? window : global;
731
+ let glbl = typeof self == 'object' ? self : global;
707
732
 
708
733
  currentExtensions[0] = (dateString) => {
709
734
  // string date extension
@@ -717,38 +742,62 @@ currentExtensions[1] = (epochSec) => {
717
742
 
718
743
  currentExtensions[2] = (buffer) => {
719
744
  // bigint extension
720
- return new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getBigUint64(0)
745
+ let value = BigInt(0);
746
+ for (let i = 0, l = buffer.byteLength; i < l; i++) {
747
+ value = BigInt(buffer[i]) + value << BigInt(8);
748
+ }
749
+ return value
721
750
  };
722
751
 
723
752
  currentExtensions[3] = (buffer) => {
724
753
  // negative bigint extension
725
- return BigInt(-1) - (new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getBigUint64(0))
754
+ return BigInt(-1) - currentExtensions[2](buffer)
755
+ };
756
+ currentExtensions[4] = (fraction) => {
757
+ // best to reparse to maintain accuracy
758
+ return +(fraction[1] + 'e' + fraction[0])
759
+ };
760
+
761
+ currentExtensions[5] = (fraction) => {
762
+ // probably not sufficiently accurate
763
+ return fraction[1] * Math.exp(fraction[0] * Math.log(2))
726
764
  };
727
765
 
728
766
  // the registration of the record definition extension (tag 105)
729
- const recordDefinition = () => {
730
- let definition = read();
731
- let structure = definition[0];
732
- let id = definition[1];
733
- currentStructures[id & 0xff] = structure;
767
+ const recordDefinition = (definition) => {
768
+ let id = definition[0] - 0xe000;
769
+ let structure = definition[1];
770
+ currentStructures[id] = structure;
734
771
  structure.read = createStructureReader(structure);
735
772
  let object = {};
736
- for (let i = 2,l = definition.length; i < l; i++) {
737
- let key = structure[i - 2];
738
- object[key] = definition[i];
739
- }
773
+ if (currentDecoder.keyMap) for (let i = 2,l = definition.length; i < l; i++) {
774
+ let key = currentDecoder.decodeKey(structure[i - 2]);
775
+ object[key] = definition[i];
776
+ }
777
+ else for (let i = 2,l = definition.length; i < l; i++) {
778
+ let key = structure[i - 2];
779
+ object[key] = definition[i];
780
+ }
740
781
  return object
741
782
  };
742
-
743
- recordDefinition.handlesRead = true;
744
- currentExtensions[RECORD_TAG_ID] = recordDefinition;
783
+ currentExtensions[LEGACY_RECORD_INLINE_ID] = recordDefinition;
784
+ currentExtensions[14] = (value) => {
785
+ if (bundledStrings)
786
+ return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 += value)
787
+ return new Tag(value, 14)
788
+ };
789
+ currentExtensions[15] = (value) => {
790
+ if (bundledStrings)
791
+ return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
792
+ return new Tag(value, 15)
793
+ };
745
794
 
746
795
  currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
747
796
  return (glbl[data[0]] || Error)(data[1], data[2])
748
797
  };
749
798
  const packedTable = (read) => {
750
799
  if (src[position++] != 0x84)
751
- throw new Error('Packed values structure must be followed by 4 element array')
800
+ throw new Error('Packed values structure must be followed by a 4 element array')
752
801
  let newPackedValues = read(); // packed values
753
802
  packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
754
803
  packedValues.prefixes = read();
@@ -759,15 +808,36 @@ packedTable.handlesRead = true;
759
808
  currentExtensions[51] = packedTable;
760
809
 
761
810
  currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
811
+ if (!packedValues) {
812
+ if (currentDecoder.getShared)
813
+ loadShared();
814
+ else
815
+ return new Tag(data, PACKED_REFERENCE_TAG_ID)
816
+ }
762
817
  if (typeof data == 'number')
763
818
  return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
764
819
  throw new Error('No support for non-integer packed references yet')
765
820
  };
821
+ currentExtensions[25] = (id) => {
822
+ return stringRefs[id]
823
+ };
824
+ currentExtensions[256] = (read) => {
825
+ stringRefs = [];
826
+ try {
827
+ return read()
828
+ } finally {
829
+ stringRefs = null;
830
+ }
831
+ };
832
+ currentExtensions[256].handlesRead = true;
766
833
 
767
- currentExtensions[40009] = (id) => {
768
- // id extension (for structured clones)
769
- if (!referenceMap)
834
+ currentExtensions[28] = (read) => {
835
+ // shareable http://cbor.schmorp.de/value-sharing (for structured clones)
836
+ if (!referenceMap) {
770
837
  referenceMap = new Map();
838
+ referenceMap.id = 0;
839
+ }
840
+ let id = referenceMap.id++;
771
841
  let token = src[position];
772
842
  let target;
773
843
  // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
@@ -785,9 +855,10 @@ currentExtensions[40009] = (id) => {
785
855
  refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
786
856
  return targetProperties // no cycle, can just use the returned read object
787
857
  };
858
+ currentExtensions[28].handlesRead = true;
788
859
 
789
- currentExtensions[40010] = (id) => {
790
- // pointer extension (for structured clones)
860
+ currentExtensions[29] = (id) => {
861
+ // sharedref http://cbor.schmorp.de/value-sharing (for structured clones)
791
862
  let refEntry = referenceMap.get(id);
792
863
  refEntry.used = true;
793
864
  return refEntry.target
@@ -810,19 +881,36 @@ function combine(a, b) {
810
881
  return a.concat(b)
811
882
  return Object.assign({}, a, b)
812
883
  }
884
+ function getPackedValues() {
885
+ if (!packedValues) {
886
+ if (currentDecoder.getShared)
887
+ loadShared();
888
+ else
889
+ throw new Error('No packed values available')
890
+ }
891
+ return packedValues
892
+ }
893
+ const SHARED_DATA_TAG_ID = 0x53687264; // ascii 'Shrd'
813
894
  currentExtensionRanges.push((tag, input) => {
814
895
  if (tag >= 225 && tag <= 255)
815
- return combine(packedTable.prefixes[tag - 224], input)
896
+ return combine(getPackedValues().prefixes[tag - 224], input)
816
897
  if (tag >= 28704 && tag <= 32767)
817
- return combine(packedTable.prefixes[tag - 28672], input)
898
+ return combine(getPackedValues().prefixes[tag - 28672], input)
818
899
  if (tag >= 1879052288 && tag <= 2147483647)
819
- return combine(packedTable.prefixes[tag - 1879048192], input)
900
+ return combine(getPackedValues().prefixes[tag - 1879048192], input)
820
901
  if (tag >= 216 && tag <= 223)
821
- return combine(input, packedTable.suffixes[tag - 216])
902
+ return combine(input, getPackedValues().suffixes[tag - 216])
822
903
  if (tag >= 27647 && tag <= 28671)
823
- return combine(input, packedTable.suffixes[tag - 27639])
904
+ return combine(input, getPackedValues().suffixes[tag - 27639])
824
905
  if (tag >= 1811940352 && tag <= 1879048191)
825
- return combine(input, packedTable.suffixes[tag - 1811939328])
906
+ return combine(input, getPackedValues().suffixes[tag - 1811939328])
907
+ 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)
908
+ return {
909
+ packedValues: packedValues,
910
+ structures: currentStructures.slice(0),
911
+ version: input,
912
+ }
913
+ }
826
914
  });
827
915
 
828
916
  const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array');
@@ -839,6 +927,61 @@ function registerTypedArray(typedArrayName, tag) {
839
927
  };
840
928
  }
841
929
 
930
+ function readBundleExt() {
931
+ let length = readJustLength();
932
+ let bundlePosition = position + read();
933
+ for (let i = 2; i < length; i++) {
934
+ // skip past bundles that were already read
935
+ let bundleLength = readJustLength(); // this will increment position, so must add to position afterwards
936
+ position += bundleLength;
937
+ }
938
+ let dataPosition = position;
939
+ position = bundlePosition;
940
+ bundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())];
941
+ bundledStrings.position0 = 0;
942
+ bundledStrings.position1 = 0;
943
+ bundledStrings.postBundlePosition = position;
944
+ position = dataPosition;
945
+ return read()
946
+ }
947
+
948
+ function readJustLength() {
949
+ let token = src[position++] & 0x1f;
950
+ if (token > 0x17) {
951
+ switch (token) {
952
+ case 0x18:
953
+ token = src[position++];
954
+ break
955
+ case 0x19:
956
+ token = dataView.getUint16(position);
957
+ position += 2;
958
+ break
959
+ case 0x1a:
960
+ token = dataView.getUint32(position);
961
+ position += 4;
962
+ break
963
+ }
964
+ }
965
+ return token
966
+ }
967
+
968
+ function loadShared() {
969
+ if (currentDecoder.getShared) {
970
+ let sharedData = saveState(() => {
971
+ // save the state in case getShared modifies our buffer
972
+ src = null;
973
+ return currentDecoder.getShared()
974
+ }) || {};
975
+ let updatedStructures = sharedData.structures || [];
976
+ currentDecoder.sharedVersion = sharedData.version;
977
+ packedValues = currentDecoder.sharedValues = sharedData.packedValues;
978
+ if (currentStructures === true)
979
+ currentDecoder.structures = currentStructures = updatedStructures;
980
+ else
981
+ currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures));
982
+ }
983
+ }
984
+
842
985
  function saveState(callback) {
843
986
  let savedSrcEnd = srcEnd;
844
987
  let savedPosition = position;
@@ -848,6 +991,8 @@ function saveState(callback) {
848
991
  let savedSrcString = srcString;
849
992
  let savedStrings = strings;
850
993
  let savedReferenceMap = referenceMap;
994
+ let savedBundledStrings = bundledStrings;
995
+
851
996
  // TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
852
997
  let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
853
998
  let savedStructures = currentStructures;
@@ -862,6 +1007,7 @@ function saveState(callback) {
862
1007
  srcString = savedSrcString;
863
1008
  strings = savedStrings;
864
1009
  referenceMap = savedReferenceMap;
1010
+ bundledStrings = savedBundledStrings;
865
1011
  src = savedSrc;
866
1012
  sequentialMode = savedSequentialMode;
867
1013
  currentStructures = savedStructures;
@@ -908,13 +1054,15 @@ let extensions, extensionClasses;
908
1054
  const hasNodeBuffer = typeof Buffer !== 'undefined';
909
1055
  const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
910
1056
  const ByteArray = hasNodeBuffer ? Buffer : Uint8Array;
911
- const RECORD_STARTING_ID_PREFIX = 0x69; // tag 105/0x69
912
1057
  const MAX_STRUCTURES = 0x100;
913
1058
  const MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000;
914
1059
  let target;
915
1060
  let targetView;
916
1061
  let position$1 = 0;
917
1062
  let safeEnd;
1063
+ let bundledStrings$1 = null;
1064
+ const MAX_BUNDLE_SIZE = 0xf000;
1065
+ const hasNonLatin = /[\u0080-\uFFFF]/;
918
1066
  const RECORD_SYMBOL = Symbol('record-id');
919
1067
  class Encoder extends Decoder {
920
1068
  constructor(options) {
@@ -926,7 +1074,6 @@ class Encoder extends Decoder {
926
1074
  let structures;
927
1075
  let referenceMap;
928
1076
  options = options || {};
929
- let lastSharedStructuresLength = 0;
930
1077
  let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position, maxBytes) {
931
1078
  return target.utf8Write(string, position, maxBytes)
932
1079
  } : (textEncoder && textEncoder.encodeInto) ?
@@ -935,12 +1082,14 @@ class Encoder extends Decoder {
935
1082
  } : false;
936
1083
 
937
1084
  let encoder = this;
938
- let maxSharedStructures = 64;
1085
+ let maxSharedStructures = options.maxSharedStructures || 128;
939
1086
  let isSequential = options.sequential;
940
1087
  if (isSequential) {
941
1088
  maxSharedStructures = 0;
942
1089
  this.structures = [];
943
1090
  }
1091
+ if (this.saveStructures)
1092
+ this.saveShared = this.saveStructures;
944
1093
  let samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues;
945
1094
  let sharedPackedObjectMap;
946
1095
  if (sharedValues) {
@@ -948,13 +1097,29 @@ class Encoder extends Decoder {
948
1097
  for (let i = 0, l = sharedValues.length; i < l; i++) {
949
1098
  sharedPackedObjectMap[sharedValues[i]] = i;
950
1099
  }
951
-
952
1100
  }
953
1101
  let recordIdsToRemove = [];
954
1102
  let transitionsCount = 0;
955
1103
  let serializationsSinceTransitionRebuild = 0;
956
-
957
- this.encode = function(value, encodeOptions) {
1104
+
1105
+ this.mapEncode = function(value, encodeOptions) {
1106
+ // Experimental support for premapping keys using _keyMap instad of keyMap - not optiimised yet)
1107
+ if (this._keyMap && !this._mapped) {
1108
+ //console.log('encoding ', value)
1109
+ switch (value.constructor.name) {
1110
+ case 'Array':
1111
+ value = value.map(r => this.encodeKeys(r));
1112
+ break
1113
+ //case 'Map':
1114
+ // value = this.encodeKeys(value)
1115
+ // break
1116
+ }
1117
+ //this._mapped = true
1118
+ }
1119
+ return this.encode(value, encodeOptions)
1120
+ };
1121
+
1122
+ this.encode = function(value, encodeOptions) {
958
1123
  if (!target) {
959
1124
  target = new ByteArrayAllocate(8192);
960
1125
  targetView = new DataView(target.buffer, 0, 8192);
@@ -971,10 +1136,25 @@ class Encoder extends Decoder {
971
1136
  position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
972
1137
  start = position$1;
973
1138
  referenceMap = encoder.structuredClone ? new Map() : null;
1139
+ if (encoder.bundleStrings && typeof value !== 'string') {
1140
+ bundledStrings$1 = [];
1141
+ bundledStrings$1.size = Infinity; // force a new bundle start on first string
1142
+ } else
1143
+ bundledStrings$1 = null;
1144
+
974
1145
  sharedStructures = encoder.structures;
975
1146
  if (sharedStructures) {
976
- if (sharedStructures.uninitialized)
977
- encoder.structures = sharedStructures = encoder.getStructures();
1147
+ if (sharedStructures.uninitialized) {
1148
+ let sharedData = encoder.getShared() || {};
1149
+ encoder.structures = sharedStructures = sharedData.structures || [];
1150
+ encoder.sharedVersion = sharedData.version;
1151
+ let sharedValues = encoder.sharedValues = sharedData.packedValues;
1152
+ if (sharedValues) {
1153
+ sharedPackedObjectMap = {};
1154
+ for (let i = 0, l = sharedValues.length; i < l; i++)
1155
+ sharedPackedObjectMap[sharedValues[i]] = i;
1156
+ }
1157
+ }
978
1158
  let sharedStructuresLength = sharedStructures.length;
979
1159
  if (sharedStructuresLength > maxSharedStructures && !isSequential)
980
1160
  sharedStructuresLength = maxSharedStructures;
@@ -983,6 +1163,7 @@ class Encoder extends Decoder {
983
1163
  sharedStructures.transitions = Object.create(null);
984
1164
  for (let i = 0; i < sharedStructuresLength; i++) {
985
1165
  let keys = sharedStructures[i];
1166
+ //console.log('shared struct keys:', keys)
986
1167
  if (!keys)
987
1168
  continue
988
1169
  let nextTransition, transition = sharedStructures.transitions;
@@ -996,7 +1177,6 @@ class Encoder extends Decoder {
996
1177
  }
997
1178
  transition[RECORD_SYMBOL] = i;
998
1179
  }
999
- lastSharedStructuresLength = sharedStructures.length;
1000
1180
  }
1001
1181
  if (!isSequential)
1002
1182
  sharedStructures.nextId = sharedStructuresLength;
@@ -1029,9 +1209,12 @@ class Encoder extends Decoder {
1029
1209
  }
1030
1210
  try {
1031
1211
  encode(value);
1212
+ if (bundledStrings$1) {
1213
+ writeBundles(start, encode);
1214
+ }
1032
1215
  encoder.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
1033
1216
  if (referenceMap && referenceMap.idsToInsert) {
1034
- position$1 += referenceMap.idsToInsert.length * 8;
1217
+ position$1 += referenceMap.idsToInsert.length * 2;
1035
1218
  if (position$1 > safeEnd)
1036
1219
  makeRoom(position$1);
1037
1220
  encoder.offset = position$1;
@@ -1039,12 +1222,12 @@ class Encoder extends Decoder {
1039
1222
  referenceMap = null;
1040
1223
  return serialized
1041
1224
  }
1042
- if (encodeOptions === REUSE_BUFFER_MODE) {
1225
+ if (encodeOptions & REUSE_BUFFER_MODE) {
1043
1226
  target.start = start;
1044
1227
  target.end = position$1;
1045
1228
  return target
1046
1229
  }
1047
- return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
1230
+ return target.subarray(start, position$1) // position can change if we call pack again in saveShared, so we get the buffer now
1048
1231
  } finally {
1049
1232
  if (sharedStructures) {
1050
1233
  if (serializationsSinceTransitionRebuild < 10)
@@ -1062,34 +1245,27 @@ class Encoder extends Decoder {
1062
1245
  }
1063
1246
  recordIdsToRemove = [];
1064
1247
  }
1065
- if (hasSharedUpdate && encoder.saveStructures) {
1066
- if (encoder.structures.length > maxSharedStructures) {
1067
- encoder.structures = encoder.structures.slice(0, maxSharedStructures);
1068
- }
1069
- // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
1070
- let returnBuffer = target.subarray(start, position$1);
1071
- let shared = encoder.structures || [];
1072
- if (sharedValues) {
1073
- shared = shared.concat(sharedValues);
1074
- }
1075
-
1076
- if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
1077
- // get updated structures and try again if the update failed
1078
- encoder.structures = encoder.getStructures() || [];
1079
- return encoder.encode(value)
1080
- }
1081
- lastSharedStructuresLength = shared.length;
1082
- return returnBuffer
1248
+ }
1249
+ if (hasSharedUpdate && encoder.saveShared) {
1250
+ if (encoder.structures.length > maxSharedStructures) {
1251
+ encoder.structures = encoder.structures.slice(0, maxSharedStructures);
1083
1252
  }
1253
+ // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
1254
+ let returnBuffer = target.subarray(start, position$1);
1255
+ if (encoder.updateSharedData() === false)
1256
+ return encoder.encode(value) // re-encode if it fails
1257
+ return returnBuffer
1084
1258
  }
1259
+ if (encodeOptions & RESET_BUFFER_MODE)
1260
+ position$1 = start;
1085
1261
  }
1086
1262
  };
1087
1263
  this.findCommonStringsToPack = () => {
1088
1264
  samplingPackedValues = new Map();
1089
1265
  if (!sharedPackedObjectMap)
1090
1266
  sharedPackedObjectMap = Object.create(null);
1091
- return ({ threshold }) => {
1092
- threshold = threshold || 4;
1267
+ return (options) => {
1268
+ let threshold = options && options.threshold || 4;
1093
1269
  let position = this.pack ? options.maxPrivatePackedValues || 16 : 0;
1094
1270
  if (!sharedValues)
1095
1271
  sharedValues = this.sharedValues = [];
@@ -1100,6 +1276,7 @@ class Encoder extends Decoder {
1100
1276
  hasSharedUpdate = true;
1101
1277
  }
1102
1278
  }
1279
+ while (this.saveShared && this.updateSharedData() === false) {}
1103
1280
  samplingPackedValues = null;
1104
1281
  }
1105
1282
  };
@@ -1148,6 +1325,33 @@ class Encoder extends Decoder {
1148
1325
  }
1149
1326
  }
1150
1327
  let strLength = value.length;
1328
+ if (bundledStrings$1 && strLength >= 4 && strLength < 0x400) {
1329
+ if ((bundledStrings$1.size += strLength) > MAX_BUNDLE_SIZE) {
1330
+ let extStart;
1331
+ let maxBytes = (bundledStrings$1[0] ? bundledStrings$1[0].length * 3 + bundledStrings$1[1].length : 0) + 10;
1332
+ if (position$1 + maxBytes > safeEnd)
1333
+ target = makeRoom(position$1 + maxBytes);
1334
+ target[position$1++] = 0xd9; // tag 16-bit
1335
+ target[position$1++] = 0xdf; // tag 0xdff9
1336
+ target[position$1++] = 0xf9;
1337
+ // TODO: If we only have one bundle with any string data, only write one string bundle
1338
+ target[position$1++] = bundledStrings$1.position ? 0x84 : 0x82; // array of 4 or 2 elements depending on if we write bundles
1339
+ target[position$1++] = 0x1a; // 32-bit unsigned int
1340
+ extStart = position$1 - start;
1341
+ position$1 += 4; // reserve for writing bundle reference
1342
+ if (bundledStrings$1.position) {
1343
+ writeBundles(start, encode); // write the last bundles
1344
+ }
1345
+ bundledStrings$1 = ['', '']; // create new ones
1346
+ bundledStrings$1.size = 0;
1347
+ bundledStrings$1.position = extStart;
1348
+ }
1349
+ let twoByte = hasNonLatin.test(value);
1350
+ bundledStrings$1[twoByte ? 0 : 1] += value;
1351
+ target[position$1++] = twoByte ? 0xce : 0xcf;
1352
+ encode(strLength);
1353
+ return
1354
+ }
1151
1355
  let headerSize;
1152
1356
  // first we estimate the header size, so we can write to the correct location
1153
1357
  if (strLength < 0x20) {
@@ -1274,16 +1478,16 @@ class Encoder extends Decoder {
1274
1478
  if (referenceMap) {
1275
1479
  let referee = referenceMap.get(value);
1276
1480
  if (referee) {
1277
- if (!referee.id) {
1481
+ target[position$1++] = 0xd8;
1482
+ target[position$1++] = 29; // http://cbor.schmorp.de/value-sharing
1483
+ target[position$1++] = 0x19; // 16-bit uint
1484
+ if (!referee.references) {
1278
1485
  let idsToInsert = referenceMap.idsToInsert || (referenceMap.idsToInsert = []);
1279
- referee.id = idsToInsert.push(referee);
1486
+ referee.references = [];
1487
+ idsToInsert.push(referee);
1280
1488
  }
1281
- target[position$1++] = 0xd9;
1282
- target[position$1++] = 40010 >> 8;
1283
- target[position$1++] = 40010 & 0xff;
1284
- target[position$1++] = 0x1a; // uint32
1285
- targetView.setUint32(position$1, referee.id);
1286
- position$1 += 4;
1489
+ referee.references.push(position$1 - start);
1490
+ position$1 += 2; // TODO: also support 32-bit
1287
1491
  return
1288
1492
  } else
1289
1493
  referenceMap.set(value, { offset: position$1 - start });
@@ -1323,16 +1527,23 @@ class Encoder extends Decoder {
1323
1527
  targetView.setUint32(position$1, length);
1324
1528
  position$1 += 4;
1325
1529
  }
1326
- for (let [ key, entryValue ] of value) {
1327
- encode(key);
1328
- encode(entryValue);
1530
+ if (encoder.keyMap) {
1531
+ for (let [ key, entryValue ] of value) {
1532
+ encode(encoder.encodeKey(key));
1533
+ encode(entryValue);
1534
+ }
1535
+ } else {
1536
+ for (let [ key, entryValue ] of value) {
1537
+ encode(key);
1538
+ encode(entryValue);
1539
+ }
1329
1540
  }
1330
- } else {
1541
+ } else {
1331
1542
  for (let i = 0, l = extensions.length; i < l; i++) {
1332
1543
  let extensionClass = extensionClasses[i];
1333
1544
  if (value instanceof extensionClass) {
1334
1545
  let extension = extensions[i];
1335
- let tag = extension.tag;
1546
+ let tag = extension.tag || extension.getTag && extension.getTag(value);
1336
1547
  if (tag < 0x18) {
1337
1548
  target[position$1++] = 0xc0 | tag;
1338
1549
  } else if (tag < 0x100) {
@@ -1394,6 +1605,7 @@ class Encoder extends Decoder {
1394
1605
  const writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {
1395
1606
  // this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
1396
1607
  let keys = Object.keys(object);
1608
+ let vals = Object.values(object);
1397
1609
  let length = keys.length;
1398
1610
  if (length < 0x18) {
1399
1611
  target[position$1++] = 0xa0 | length;
@@ -1409,10 +1621,16 @@ class Encoder extends Decoder {
1409
1621
  targetView.setUint32(position$1, length);
1410
1622
  position$1 += 4;
1411
1623
  }
1412
- let key;
1413
- for (let i = 0; i < length; i++) {
1414
- encode(key = keys[i]);
1415
- encode(object[key]);
1624
+ if (encoder.keyMap) {
1625
+ for (let i = 0; i < length; i++) {
1626
+ encode(encodeKey(keys[i]));
1627
+ encode(vals[i]);
1628
+ }
1629
+ } else {
1630
+ for (let i = 0; i < length; i++) {
1631
+ encode(keys[i]);
1632
+ encode(vals[i]);
1633
+ }
1416
1634
  }
1417
1635
  } :
1418
1636
  (object, safePrototype) => {
@@ -1420,12 +1638,18 @@ class Encoder extends Decoder {
1420
1638
  let objectOffset = position$1 - start;
1421
1639
  position$1 += 2;
1422
1640
  let size = 0;
1423
- for (let key in object) {
1424
- if (safePrototype || object.hasOwnProperty(key)) {
1425
- encode(key);
1641
+ if (encoder.keyMap) {
1642
+ for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1643
+ encode(encoder.encodeKey(key));
1426
1644
  encode(object[key]);
1427
1645
  size++;
1428
1646
  }
1647
+ } else {
1648
+ for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1649
+ encode(key);
1650
+ encode(object[key]);
1651
+ size++;
1652
+ }
1429
1653
  }
1430
1654
  target[objectOffset++ + start] = size >> 8;
1431
1655
  target[objectOffset + start] = size & 0xff;
@@ -1473,11 +1697,16 @@ class Encoder extends Decoder {
1473
1697
  }*/
1474
1698
  (object) => {
1475
1699
  let keys = Object.keys(object);
1700
+ let vals = Object.values(object);
1701
+ if (this.keyMap) keys = keys.map(k => this.encodeKey(k));
1476
1702
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1477
1703
  let newTransitions = 0;
1478
1704
  let length = keys.length;
1705
+ //let parentRecordId
1479
1706
  for (let i = 0; i < length; i++) {
1707
+ //if (!parentRecordId)
1480
1708
  let key = keys[i];
1709
+ // parentRecordId = transition[RECORD_SYMBOL]
1481
1710
  nextTransition = transition[key];
1482
1711
  if (!nextTransition) {
1483
1712
  nextTransition = transition[key] = Object.create(null);
@@ -1487,9 +1716,9 @@ class Encoder extends Decoder {
1487
1716
  }
1488
1717
  let recordId = transition[RECORD_SYMBOL];
1489
1718
  if (recordId !== undefined) {
1490
- target[position$1++] = 0xd9; // tag two byte
1491
- target[position$1++] = RECORD_STARTING_ID_PREFIX;
1492
- target[position$1++] = recordId;
1719
+ target[position$1++] = 0xd9;
1720
+ target[position$1++] = (recordId >> 8) | 0xe0;
1721
+ target[position$1++] = recordId & 0xff;
1493
1722
  } else {
1494
1723
  recordId = structures.nextId++;
1495
1724
  if (!recordId) {
@@ -1502,13 +1731,13 @@ class Encoder extends Decoder {
1502
1731
  transition[RECORD_SYMBOL] = recordId;
1503
1732
  structures[recordId] = keys;
1504
1733
  if (sharedStructures && sharedStructures.length <= maxSharedStructures) {
1505
- target[position$1++] = 0xd9; // tag two byte
1506
- target[position$1++] = RECORD_STARTING_ID_PREFIX;
1507
- target[position$1++] = recordId; // tag number
1734
+ target[position$1++] = 0xd9;
1735
+ target[position$1++] = (recordId >> 8) | 0xe0;
1736
+ target[position$1++] = recordId & 0xff;
1508
1737
  hasSharedUpdate = true;
1509
1738
  } else {
1510
- target[position$1++] = 0xd8;
1511
- target[position$1++] = RECORD_STARTING_ID_PREFIX;
1739
+ targetView.setUint32(position$1, 0xd9dfff00); // tag two byte, then record definition id
1740
+ position$1 += 3;
1512
1741
  if (newTransitions)
1513
1742
  transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
1514
1743
  // record the removal of the id, we can maintain our shared structure
@@ -1516,13 +1745,9 @@ class Encoder extends Decoder {
1516
1745
  recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
1517
1746
  recordIdsToRemove.push(transition);
1518
1747
  writeArrayHeader(length + 2);
1748
+ encode(0xe000 + recordId);
1519
1749
  encode(keys);
1520
- target[position$1++] = 0x19; // uint16
1521
- target[position$1++] = RECORD_STARTING_ID_PREFIX;
1522
- target[position$1++] = recordId;
1523
- // now write the values
1524
- for (let i =0; i < length; i++)
1525
- encode(object[keys[i]]);
1750
+ for (let v of Object.values(object)) encode(v);
1526
1751
  return
1527
1752
  }
1528
1753
  }
@@ -1531,8 +1756,7 @@ class Encoder extends Decoder {
1531
1756
  } else {
1532
1757
  writeArrayHeader(length);
1533
1758
  }
1534
- for (let i =0; i < length; i++)
1535
- encode(object[keys[i]]);
1759
+ for (let i =0; i < length; i++) encode(vals[i]);
1536
1760
  };
1537
1761
  const makeRoom = (end) => {
1538
1762
  let newSize;
@@ -1541,7 +1765,7 @@ class Encoder extends Decoder {
1541
1765
  if ((end - start) > MAX_BUFFER_SIZE)
1542
1766
  throw new Error('Encoded buffer would be larger than maximum buffer size')
1543
1767
  newSize = Math.min(MAX_BUFFER_SIZE,
1544
- Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x1000000) / 0x1000) * 0x1000);
1768
+ Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000);
1545
1769
  } else // faster handling for smaller buffers
1546
1770
  newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
1547
1771
  let newBuffer = new ByteArrayAllocate(newSize);
@@ -1562,6 +1786,33 @@ class Encoder extends Decoder {
1562
1786
  targetView = new DataView(target.buffer, target.byteOffset, target.byteLength);
1563
1787
  position$1 = 0;
1564
1788
  }
1789
+ clearSharedData() {
1790
+ if (this.structures)
1791
+ this.structures = [];
1792
+ if (this.sharedValues)
1793
+ this.sharedValues = undefined;
1794
+ }
1795
+ updateSharedData() {
1796
+ let lastVersion = this.sharedVersion || 0;
1797
+ this.sharedVersion = lastVersion + 1;
1798
+ let saveResults = this.saveShared(new SharedData(this.structures, this.sharedValues, this.sharedVersion),
1799
+ existingShared => (existingShared && existingShared.version || 0) == lastVersion);
1800
+ if (saveResults === false) {
1801
+ // get updated structures and try again if the update failed
1802
+ let sharedData = this.getShared() || {};
1803
+ this.structures = sharedData.structures || [];
1804
+ this.sharedValues = sharedData.packedValues;
1805
+ this.sharedVersion = sharedData.version;
1806
+ }
1807
+ return saveResults
1808
+ }
1809
+ }
1810
+ class SharedData {
1811
+ constructor(structures, values, version) {
1812
+ this.structures = structures;
1813
+ this.packedValues = values;
1814
+ this.version = version;
1815
+ }
1565
1816
  }
1566
1817
 
1567
1818
  function writeArrayHeader(length) {
@@ -1631,9 +1882,11 @@ function findRepetitiveStrings(value, packedValues) {
1631
1882
  }
1632
1883
  }
1633
1884
 
1634
- extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, ByteArray,
1635
- Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array, BigUint64Array, Int8Array, Int16Array, Int32Array, BigInt64Array,
1636
- Float32Array, Float64Array];
1885
+ extensionClasses = [ Date, Set, Error, RegExp, Tag, ArrayBuffer, ByteArray,
1886
+ Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,
1887
+ typeof BigUint64Array == 'undefined' ? function() {} : BigUint64Array, Int8Array, Int16Array, Int32Array,
1888
+ typeof BigInt64Array == 'undefined' ? function() {} : BigInt64Array,
1889
+ Float32Array, Float64Array, SharedData];
1637
1890
 
1638
1891
  //Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/
1639
1892
  extensions = [{
@@ -1668,6 +1921,13 @@ extensions = [{
1668
1921
  encode(regex, encode) {
1669
1922
  encode([ 'RegExp', regex.source, regex.flags ]);
1670
1923
  }
1924
+ }, {
1925
+ getTag(tag) {
1926
+ return tag.tag
1927
+ },
1928
+ encode(tag, encode) {
1929
+ encode(tag.value);
1930
+ }
1671
1931
  }, {
1672
1932
  encode(arrayBuffer, encode, makeRoom) {
1673
1933
  writeBuffer(arrayBuffer, makeRoom);
@@ -1686,7 +1946,35 @@ extensions = [{
1686
1946
  typedArrayEncoder(78),
1687
1947
  typedArrayEncoder(79),
1688
1948
  typedArrayEncoder(81),
1689
- typedArrayEncoder(82)];
1949
+ typedArrayEncoder(82),
1950
+ {
1951
+ encode(sharedData, encode) { // write SharedData
1952
+ let packedValues = sharedData.packedValues || [];
1953
+ let sharedStructures = sharedData.structures || [];
1954
+ if (packedValues.values.length > 0) {
1955
+ target[position$1++] = 0xd8; // one-byte tag
1956
+ target[position$1++] = 51; // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
1957
+ writeArrayHeader(4);
1958
+ let valuesArray = packedValues.values;
1959
+ encode(valuesArray);
1960
+ writeArrayHeader(0); // prefixes
1961
+ writeArrayHeader(0); // suffixes
1962
+ packedObjectMap = Object.create(sharedPackedObjectMap || null);
1963
+ for (let i = 0, l = valuesArray.length; i < l; i++) {
1964
+ packedObjectMap[valuesArray[i]] = i;
1965
+ }
1966
+ }
1967
+ if (sharedStructures) {
1968
+ targetView.setUint32(position$1, 0xd9dffe00);
1969
+ position$1 += 3;
1970
+ let definitions = sharedStructures.slice(0);
1971
+ definitions.unshift(0xe000);
1972
+ definitions.push(new Tag(sharedData.version, 0x53687264));
1973
+ encode(definitions);
1974
+ } else
1975
+ encode(new Tag(sharedData.version, 0x53687264));
1976
+ }
1977
+ }];
1690
1978
 
1691
1979
  function typedArrayEncoder(tag) {
1692
1980
  return {
@@ -1726,27 +2014,35 @@ function writeBuffer(buffer, makeRoom) {
1726
2014
  function insertIds(serialized, idsToInsert) {
1727
2015
  // insert the ids that need to be referenced for structured clones
1728
2016
  let nextId;
1729
- let distanceToMove = idsToInsert.length * 8;
2017
+ let distanceToMove = idsToInsert.length * 2;
1730
2018
  let lastEnd = serialized.length - distanceToMove;
1731
2019
  idsToInsert.sort((a, b) => a.offset > b.offset ? 1 : -1);
2020
+ for (let id = 0; id < idsToInsert.length; id++) {
2021
+ let referee = idsToInsert[id];
2022
+ referee.id = id;
2023
+ for (let position of referee.references) {
2024
+ serialized[position++] = id >> 8;
2025
+ serialized[position] = id & 0xff;
2026
+ }
2027
+ }
1732
2028
  while (nextId = idsToInsert.pop()) {
1733
2029
  let offset = nextId.offset;
1734
- let id = nextId.id;
1735
2030
  serialized.copyWithin(offset + distanceToMove, offset, lastEnd);
1736
- distanceToMove -= 8;
2031
+ distanceToMove -= 2;
1737
2032
  let position = offset + distanceToMove;
1738
- serialized[position++] = 0xd9;
1739
- serialized[position++] = 40009 >> 8;
1740
- serialized[position++] = 40009 & 0xff;
1741
- serialized[position++] = 0x1a; // uint32
1742
- serialized[position++] = id >> 24;
1743
- serialized[position++] = (id >> 16) & 0xff;
1744
- serialized[position++] = (id >> 8) & 0xff;
1745
- serialized[position++] = id & 0xff;
2033
+ serialized[position++] = 0xd8;
2034
+ serialized[position++] = 28; // http://cbor.schmorp.de/value-sharing
1746
2035
  lastEnd = offset;
1747
2036
  }
1748
2037
  return serialized
1749
2038
  }
2039
+ function writeBundles(start, encode) {
2040
+ targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start + 1); // the offset to bundle
2041
+ let writeStrings = bundledStrings$1;
2042
+ bundledStrings$1 = null;
2043
+ encode(writeStrings[0]);
2044
+ encode(writeStrings[1]);
2045
+ }
1750
2046
 
1751
2047
  function addExtension$1(extension) {
1752
2048
  if (extension.Class) {
@@ -1760,7 +2056,8 @@ function addExtension$1(extension) {
1760
2056
  let defaultEncoder = new Encoder({ useRecords: false });
1761
2057
  const encode = defaultEncoder.encode;
1762
2058
  const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1763
- const REUSE_BUFFER_MODE = 1000;
2059
+ const REUSE_BUFFER_MODE = 512;
2060
+ const RESET_BUFFER_MODE = 1024;
1764
2061
 
1765
2062
  class EncoderStream extends stream.Transform {
1766
2063
  constructor(options) {
@@ -1910,9 +2207,7 @@ function tryRequire(moduleId) {
1910
2207
  let require$1 = module$1.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('node.cjs', document.baseURI).href)));
1911
2208
  return require$1(moduleId)
1912
2209
  } catch (error) {
1913
- if (typeof window == 'undefined')
1914
- console.warn('Native extraction module not loaded, cbor-x will still run, but with decreased performance. ' + error.message.split('\n')[0]);
1915
- else
2210
+ if (typeof window != 'undefined')
1916
2211
  console.warn('For browser usage, directly use cbor-x/decode or cbor-x/encode modules. ' + error.message.split('\n')[0]);
1917
2212
  }
1918
2213
  }