msgpackr 1.4.7 → 1.5.3

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
@@ -20,6 +20,7 @@ var currentStructures;
20
20
  var srcString;
21
21
  var srcStringStart = 0;
22
22
  var srcStringEnd = 0;
23
+ var bundledStrings;
23
24
  var referenceMap;
24
25
  var currentExtensions = [];
25
26
  var dataView;
@@ -60,12 +61,21 @@ class Unpackr {
60
61
  srcStringEnd = 0;
61
62
  srcString = null;
62
63
  strings = EMPTY_ARRAY;
64
+ bundledStrings = null;
63
65
  src = source;
64
66
  // this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
65
67
  // technique for getting data from a database where it can be copied into an existing buffer instead of creating
66
68
  // new ones
67
- dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
68
- if (this) {
69
+ try {
70
+ dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
71
+ } catch(error) {
72
+ // if it doesn't have a buffer, maybe it is the wrong type of object
73
+ src = null;
74
+ if (source instanceof Uint8Array)
75
+ throw error
76
+ throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
77
+ }
78
+ if (this instanceof Unpackr) {
69
79
  currentUnpackr = this;
70
80
  if (this.structures) {
71
81
  currentStructures = this.structures;
@@ -148,6 +158,9 @@ function checkedRead() {
148
158
  currentStructures.length = sharedLength;
149
159
  }
150
160
  let result = read();
161
+ if (bundledStrings) // bundled strings to skip past
162
+ position = bundledStrings.postBundlePosition;
163
+
151
164
  if (position == srcEnd) {
152
165
  // finished reading this source, cleanup references
153
166
  if (currentStructures.restoreStructures)
@@ -242,7 +255,15 @@ function read() {
242
255
  let value;
243
256
  switch (token) {
244
257
  case 0xc0: return null
245
- case 0xc1: return C1; // "never-used", return special object to denote that
258
+ case 0xc1:
259
+ if (bundledStrings) {
260
+ value = read(); // followed by the length of the string in characters (not bytes!)
261
+ if (value > 0)
262
+ return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
263
+ else
264
+ return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 -= value)
265
+ }
266
+ return C1; // "never-used", return special object to denote that
246
267
  case 0xc2: return false
247
268
  case 0xc3: return true
248
269
  case 0xc4:
@@ -297,10 +318,11 @@ function read() {
297
318
  position += 4;
298
319
  return value
299
320
  case 0xcf:
300
- if (currentUnpackr.uint64AsNumber)
301
- return src[position++] * 0x100000000000000 + src[position++] * 0x1000000000000 + src[position++] * 0x10000000000 + src[position++] * 0x100000000 +
302
- src[position++] * 0x1000000 + (src[position++] << 16) + (src[position++] << 8) + src[position++]
303
- value = dataView.getBigUint64(position);
321
+ if (currentUnpackr.int64AsNumber) {
322
+ value = dataView.getUint32(position) * 0x100000000;
323
+ value += dataView.getUint32(position + 4);
324
+ } else
325
+ value = dataView.getBigUint64(position);
304
326
  position += 8;
305
327
  return value
306
328
 
@@ -316,7 +338,11 @@ function read() {
316
338
  position += 4;
317
339
  return value
318
340
  case 0xd3:
319
- value = dataView.getBigInt64(position);
341
+ if (currentUnpackr.int64AsNumber) {
342
+ value = dataView.getInt32(position) * 0x100000000;
343
+ value += dataView.getUint32(position + 4);
344
+ } else
345
+ value = dataView.getBigInt64(position);
320
346
  position += 8;
321
347
  return value
322
348
 
@@ -465,8 +491,10 @@ var readFixedString = readStringJS;
465
491
  var readString8 = readStringJS;
466
492
  var readString16 = readStringJS;
467
493
  var readString32 = readStringJS;
494
+ exports.isNativeAccelerationEnabled = false;
468
495
 
469
496
  function setExtractor(extractStrings) {
497
+ exports.isNativeAccelerationEnabled = true;
470
498
  readFixedString = readString(1);
471
499
  readString8 = readString(2);
472
500
  readString16 = readString(3);
@@ -475,6 +503,8 @@ function setExtractor(extractStrings) {
475
503
  return function readString(length) {
476
504
  let string = strings[stringPosition++];
477
505
  if (string == null) {
506
+ if (bundledStrings)
507
+ return readStringJS(length)
478
508
  let extraction = extractStrings(position - headerLength, srcEnd, src);
479
509
  if (typeof extraction == 'string') {
480
510
  string = extraction;
@@ -733,6 +763,36 @@ function shortStringInJS(length) {
733
763
  }
734
764
  }
735
765
 
766
+ function readOnlyJSString() {
767
+ let token = src[position++];
768
+ let length;
769
+ if (token < 0xc0) {
770
+ // fixstr
771
+ length = token - 0xa0;
772
+ } else {
773
+ switch(token) {
774
+ case 0xd9:
775
+ // str 8
776
+ length = src[position++];
777
+ break
778
+ case 0xda:
779
+ // str 16
780
+ length = dataView.getUint16(position);
781
+ position += 2;
782
+ break
783
+ case 0xdb:
784
+ // str 32
785
+ length = dataView.getUint32(position);
786
+ position += 4;
787
+ break
788
+ default:
789
+ throw new Error('Expected string')
790
+ }
791
+ }
792
+ return readStringJS(length)
793
+ }
794
+
795
+
736
796
  function readBin(length) {
737
797
  return currentUnpackr.copyBuffers ?
738
798
  // specifically use the copying slice (not the node one)
@@ -884,6 +944,19 @@ currentExtensions[0x78] = () => {
884
944
  let data = read();
885
945
  return new RegExp(data[0], data[1])
886
946
  };
947
+ const TEMP_BUNDLE = [];
948
+ currentExtensions[0x62] = (data) => {
949
+ let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
950
+ let dataPosition = position;
951
+ position += dataSize - data.length;
952
+ bundledStrings = TEMP_BUNDLE;
953
+ bundledStrings = [readOnlyJSString(), readOnlyJSString()];
954
+ bundledStrings.position0 = 0;
955
+ bundledStrings.position1 = 0;
956
+ bundledStrings.postBundlePosition = position;
957
+ position = dataPosition;
958
+ return read()
959
+ };
887
960
 
888
961
  currentExtensions[0xff] = (data) => {
889
962
  // 32-bit date extension
@@ -898,7 +971,7 @@ currentExtensions[0xff] = (data) => {
898
971
  ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
899
972
  (((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
900
973
  else
901
- throw new Error('Invalid timestamp length')
974
+ return new Date('invalid')
902
975
  }; // notepack defines extension 0 to mean undefined, so use that as the default here
903
976
  // registration of bulk record definition?
904
977
  // currentExtensions[0x52] = () =>
@@ -912,6 +985,7 @@ function saveState(callback) {
912
985
  let savedSrcString = srcString;
913
986
  let savedStrings = strings;
914
987
  let savedReferenceMap = referenceMap;
988
+ let savedBundledStrings = bundledStrings;
915
989
 
916
990
  // TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
917
991
  let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
@@ -928,6 +1002,7 @@ function saveState(callback) {
928
1002
  srcString = savedSrcString;
929
1003
  strings = savedStrings;
930
1004
  referenceMap = savedReferenceMap;
1005
+ bundledStrings = savedBundledStrings;
931
1006
  src = savedSrc;
932
1007
  sequentialMode = savedSequentialMode;
933
1008
  currentStructures = savedStructures;
@@ -981,10 +1056,13 @@ const hasNodeBuffer = typeof Buffer !== 'undefined';
981
1056
  const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
982
1057
  const ByteArray = hasNodeBuffer ? Buffer : Uint8Array;
983
1058
  const MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000;
984
- let target;
1059
+ let target, keysTarget;
985
1060
  let targetView;
986
1061
  let position$1 = 0;
987
1062
  let safeEnd;
1063
+ let bundledStrings$1 = null;
1064
+ const MAX_BUNDLE_SIZE = 0xf000;
1065
+ const hasNonLatin = /[\u0080-\uFFFF]/;
988
1066
  const RECORD_SYMBOL = Symbol('record-id');
989
1067
  class Packr extends Unpackr {
990
1068
  constructor(options) {
@@ -1046,6 +1124,11 @@ class Packr extends Unpackr {
1046
1124
  position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
1047
1125
  start = position$1;
1048
1126
  referenceMap = packr.structuredClone ? new Map() : null;
1127
+ if (packr.bundleStrings && typeof value !== 'string') {
1128
+ bundledStrings$1 = [];
1129
+ bundledStrings$1.size = Infinity; // force a new bundle start on first string
1130
+ } else
1131
+ bundledStrings$1 = null;
1049
1132
  sharedStructures = packr.structures;
1050
1133
  if (sharedStructures) {
1051
1134
  if (sharedStructures.uninitialized)
@@ -1081,9 +1164,12 @@ class Packr extends Unpackr {
1081
1164
  }
1082
1165
  if (hasSharedUpdate)
1083
1166
  hasSharedUpdate = false;
1084
- structures = sharedStructures || [];
1167
+ structures = sharedStructures || (packr.structures = []);
1085
1168
  try {
1086
1169
  pack(value);
1170
+ if (bundledStrings$1) {
1171
+ writeBundles(start, pack);
1172
+ }
1087
1173
  packr.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
1088
1174
  if (referenceMap && referenceMap.idsToInsert) {
1089
1175
  position$1 += referenceMap.idsToInsert.length * 6;
@@ -1094,7 +1180,7 @@ class Packr extends Unpackr {
1094
1180
  referenceMap = null;
1095
1181
  return serialized
1096
1182
  }
1097
- if (encodeOptions === REUSE_BUFFER_MODE) {
1183
+ if (encodeOptions & REUSE_BUFFER_MODE) {
1098
1184
  target.start = start;
1099
1185
  target.end = position$1;
1100
1186
  return target
@@ -1104,6 +1190,8 @@ class Packr extends Unpackr {
1104
1190
  if (sharedStructures) {
1105
1191
  if (serializationsSinceTransitionRebuild < 10)
1106
1192
  serializationsSinceTransitionRebuild++;
1193
+ if (sharedStructures.length > maxSharedStructures)
1194
+ sharedStructures.length = maxSharedStructures;
1107
1195
  if (transitionsCount > 10000) {
1108
1196
  // force a rebuild occasionally after a lot of transitions so it can get cleaned up
1109
1197
  sharedStructures.transitions = null;
@@ -1133,6 +1221,8 @@ class Packr extends Unpackr {
1133
1221
  return returnBuffer
1134
1222
  }
1135
1223
  }
1224
+ if (encodeOptions & RESET_BUFFER_MODE)
1225
+ position$1 = start;
1136
1226
  }
1137
1227
  };
1138
1228
  const pack = (value) => {
@@ -1143,6 +1233,36 @@ class Packr extends Unpackr {
1143
1233
  var length;
1144
1234
  if (type === 'string') {
1145
1235
  let strLength = value.length;
1236
+ if (bundledStrings$1 && strLength >= 4 && strLength < 0x1000) {
1237
+ if ((bundledStrings$1.size += strLength) > MAX_BUNDLE_SIZE) {
1238
+ let extStart;
1239
+ let maxBytes = (bundledStrings$1[0] ? bundledStrings$1[0].length * 3 + bundledStrings$1[1].length : 0) + 10;
1240
+ if (position$1 + maxBytes > safeEnd)
1241
+ target = makeRoom(position$1 + maxBytes);
1242
+ if (bundledStrings$1.position) { // here we use the 0x62 extension to write the last bundle and reserve sapce for the reference pointer to the next/current bundle
1243
+ target[position$1] = 0xc8; // ext 16
1244
+ position$1 += 3; // reserve for the writing bundle size
1245
+ target[position$1++] = 0x62; // 'b'
1246
+ extStart = position$1 - start;
1247
+ position$1 += 4; // reserve for writing bundle reference
1248
+ writeBundles(start, pack); // write the last bundles
1249
+ targetView.setUint16(extStart + start - 3, position$1 - start - extStart);
1250
+ } else { // here we use the 0x62 extension just to reserve the space for the reference pointer to the bundle (will be updated once the bundle is written)
1251
+ target[position$1++] = 0xd6; // fixext 4
1252
+ target[position$1++] = 0x62; // 'b'
1253
+ extStart = position$1 - start;
1254
+ position$1 += 4; // reserve for writing bundle reference
1255
+ }
1256
+ bundledStrings$1 = ['', '']; // create new ones
1257
+ bundledStrings$1.size = 0;
1258
+ bundledStrings$1.position = extStart;
1259
+ }
1260
+ let twoByte = hasNonLatin.test(value);
1261
+ bundledStrings$1[twoByte ? 0 : 1] += value;
1262
+ target[position$1++] = 0xc1;
1263
+ pack(twoByte ? -strLength : strLength);
1264
+ return
1265
+ }
1146
1266
  let headerSize;
1147
1267
  // first we estimate the header size, so we can write to the correct location
1148
1268
  if (strLength < 0x20) {
@@ -1441,53 +1561,55 @@ class Packr extends Unpackr {
1441
1561
  target[objectOffset++ + start] = size >> 8;
1442
1562
  target[objectOffset + start] = size & 0xff;
1443
1563
  } :
1444
-
1445
- /* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
1564
+ (options.progressiveRecords && !useTwoByteRecords) ? // this is about 2% faster for highly stable structures, since it only requires one for-in loop (but much more expensive when new structure needs to be written)
1446
1565
  (object, safePrototype) => {
1447
- let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
1448
- let objectOffset = position++ - start
1449
- let wroteKeys
1566
+ let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1567
+ let objectOffset = position$1++ - start;
1568
+ let wroteKeys;
1450
1569
  for (let key in object) {
1451
1570
  if (safePrototype || object.hasOwnProperty(key)) {
1452
- nextTransition = transition[key]
1453
- if (!nextTransition) {
1454
- nextTransition = transition[key] = Object.create(null)
1455
- nextTransition.__keys__ = (transition.__keys__ || []).concat([key])
1456
- /*let keys = Object.keys(object)
1457
- if
1458
- let size = 0
1459
- let startBranch = transition.__keys__ ? transition.__keys__.length : 0
1460
- for (let i = 0, l = keys.length; i++) {
1461
- let key = keys[i]
1462
- size += key.length << 2
1463
- if (i >= startBranch) {
1464
- nextTransition = nextTransition[key] = Object.create(null)
1465
- nextTransition.__keys__ = keys.slice(0, i + 1)
1571
+ nextTransition = transition[key];
1572
+ if (nextTransition)
1573
+ transition = nextTransition;
1574
+ else {
1575
+ // record doesn't exist, create full new record and insert it
1576
+ let keys = Object.keys(object);
1577
+ let lastTransition = transition;
1578
+ transition = structures.transitions;
1579
+ let newTransitions = 0;
1580
+ for (let i = 0, l = keys.length; i < l; i++) {
1581
+ let key = keys[i];
1582
+ nextTransition = transition[key];
1583
+ if (!nextTransition) {
1584
+ nextTransition = transition[key] = Object.create(null);
1585
+ newTransitions++;
1466
1586
  }
1587
+ transition = nextTransition;
1467
1588
  }
1468
- makeRoom(position + size)
1469
- nextTransition = transition[key]
1470
- target.copy(target, )
1471
- objectOffset
1589
+ if (objectOffset + start + 1 == position$1) {
1590
+ // first key, so we don't need to insert, we can just write record directly
1591
+ position$1--;
1592
+ newRecord(transition, keys, newTransitions);
1593
+ } else // otherwise we need to insert the record, moving existing data after the record
1594
+ insertNewRecord(transition, keys, objectOffset, newTransitions);
1595
+ wroteKeys = true;
1596
+ transition = lastTransition[key];
1472
1597
  }
1473
- transition = nextTransition
1474
- pack(object[key])
1598
+ pack(object[key]);
1475
1599
  }
1476
1600
  }
1477
- let id = transition.id
1478
- if (!id) {
1479
- id = transition.id = structures.push(transition.__keys__) + 63
1480
- if (sharedStructures.onUpdate)
1481
- sharedStructures.onUpdate(id, transition.__keys__)
1601
+ if (!wroteKeys) {
1602
+ let recordId = transition[RECORD_SYMBOL];
1603
+ if (recordId)
1604
+ target[objectOffset + start] = recordId;
1605
+ else
1606
+ insertNewRecord(transition, Object.keys(object), objectOffset, 0);
1482
1607
  }
1483
- target[objectOffset + start] = id
1484
- }*/
1485
- (object) => {
1486
- let keys = Object.keys(object);
1608
+ } :
1609
+ (object, safePrototype) => {
1487
1610
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1488
1611
  let newTransitions = 0;
1489
- for (let i = 0, l = keys.length; i < l; i++) {
1490
- let key = keys[i];
1612
+ for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
1491
1613
  nextTransition = transition[key];
1492
1614
  if (!nextTransition) {
1493
1615
  nextTransition = transition[key] = Object.create(null);
@@ -1503,57 +1625,12 @@ class Packr extends Unpackr {
1503
1625
  } else
1504
1626
  target[position$1++] = recordId;
1505
1627
  } else {
1506
- recordId = structures.nextId;
1507
- if (!recordId)
1508
- recordId = 0x40;
1509
- if (recordId < sharedLimitId && this.shouldShareStructure && !this.shouldShareStructure(keys)) {
1510
- recordId = structures.nextOwnId;
1511
- if (!(recordId < maxStructureId))
1512
- recordId = sharedLimitId;
1513
- structures.nextOwnId = recordId + 1;
1514
- } else {
1515
- if (recordId >= maxStructureId)// cycle back around
1516
- recordId = sharedLimitId;
1517
- structures.nextId = recordId + 1;
1518
- }
1519
- let highByte = keys.highByte = recordId >= 0x60 && useTwoByteRecords ? (recordId - 0x60) >> 5 : -1;
1520
- transition[RECORD_SYMBOL] = recordId;
1521
- structures[recordId - 0x40] = keys;
1522
-
1523
- if (recordId < sharedLimitId) {
1524
- keys.isShared = true;
1525
- structures.sharedLength = recordId - 0x3f;
1526
- hasSharedUpdate = true;
1527
- if (highByte >= 0) {
1528
- target[position$1++] = (recordId & 0x1f) + 0x60;
1529
- target[position$1++] = highByte;
1530
- } else {
1531
- target[position$1++] = recordId;
1532
- }
1533
- } else {
1534
- if (highByte >= 0) {
1535
- target[position$1++] = 0xd5; // fixext 2
1536
- target[position$1++] = 0x72; // "r" record defintion extension type
1537
- target[position$1++] = (recordId & 0x1f) + 0x60;
1538
- target[position$1++] = highByte;
1539
- } else {
1540
- target[position$1++] = 0xd4; // fixext 1
1541
- target[position$1++] = 0x72; // "r" record defintion extension type
1542
- target[position$1++] = recordId;
1543
- }
1544
-
1545
- if (newTransitions)
1546
- transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
1547
- // record the removal of the id, we can maintain our shared structure
1548
- if (recordIdsToRemove.length >= maxOwnStructures)
1549
- recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
1550
- recordIdsToRemove.push(transition);
1551
- pack(keys);
1552
- }
1628
+ newRecord(transition, transition.__keys__ || Object.keys(object), newTransitions);
1553
1629
  }
1554
1630
  // now write the values
1555
- for (let i = 0, l = keys.length; i < l; i++)
1556
- pack(object[keys[i]]);
1631
+ for (let key in object)
1632
+ if (safePrototype || object.hasOwnProperty(key))
1633
+ pack(object[key]);
1557
1634
  };
1558
1635
  const makeRoom = (end) => {
1559
1636
  let newSize;
@@ -1562,7 +1639,7 @@ class Packr extends Unpackr {
1562
1639
  if ((end - start) > MAX_BUFFER_SIZE)
1563
1640
  throw new Error('Packed buffer would be larger than maximum buffer size')
1564
1641
  newSize = Math.min(MAX_BUFFER_SIZE,
1565
- Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x1000000) / 0x1000) * 0x1000);
1642
+ Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000);
1566
1643
  } else // faster handling for smaller buffers
1567
1644
  newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
1568
1645
  let newBuffer = new ByteArrayAllocate(newSize);
@@ -1576,6 +1653,86 @@ class Packr extends Unpackr {
1576
1653
  safeEnd = newBuffer.length - 10;
1577
1654
  return target = newBuffer
1578
1655
  };
1656
+ const newRecord = (transition, keys, newTransitions) => {
1657
+ let recordId = structures.nextId;
1658
+ if (!recordId)
1659
+ recordId = 0x40;
1660
+ if (recordId < sharedLimitId && this.shouldShareStructure && !this.shouldShareStructure(keys)) {
1661
+ recordId = structures.nextOwnId;
1662
+ if (!(recordId < maxStructureId))
1663
+ recordId = sharedLimitId;
1664
+ structures.nextOwnId = recordId + 1;
1665
+ } else {
1666
+ if (recordId >= maxStructureId)// cycle back around
1667
+ recordId = sharedLimitId;
1668
+ structures.nextId = recordId + 1;
1669
+ }
1670
+ let highByte = keys.highByte = recordId >= 0x60 && useTwoByteRecords ? (recordId - 0x60) >> 5 : -1;
1671
+ transition[RECORD_SYMBOL] = recordId;
1672
+ transition.__keys__ = keys;
1673
+ structures[recordId - 0x40] = keys;
1674
+
1675
+ if (recordId < sharedLimitId) {
1676
+ keys.isShared = true;
1677
+ structures.sharedLength = recordId - 0x3f;
1678
+ hasSharedUpdate = true;
1679
+ if (highByte >= 0) {
1680
+ target[position$1++] = (recordId & 0x1f) + 0x60;
1681
+ target[position$1++] = highByte;
1682
+ } else {
1683
+ target[position$1++] = recordId;
1684
+ }
1685
+ } else {
1686
+ if (highByte >= 0) {
1687
+ target[position$1++] = 0xd5; // fixext 2
1688
+ target[position$1++] = 0x72; // "r" record defintion extension type
1689
+ target[position$1++] = (recordId & 0x1f) + 0x60;
1690
+ target[position$1++] = highByte;
1691
+ } else {
1692
+ target[position$1++] = 0xd4; // fixext 1
1693
+ target[position$1++] = 0x72; // "r" record defintion extension type
1694
+ target[position$1++] = recordId;
1695
+ }
1696
+
1697
+ if (newTransitions)
1698
+ transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
1699
+ // record the removal of the id, we can maintain our shared structure
1700
+ if (recordIdsToRemove.length >= maxOwnStructures)
1701
+ recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
1702
+ recordIdsToRemove.push(transition);
1703
+ pack(keys);
1704
+ }
1705
+ };
1706
+ const insertNewRecord = (transition, keys, insertionOffset, newTransitions) => {
1707
+ let mainTarget = target;
1708
+ let mainPosition = position$1;
1709
+ let mainSafeEnd = safeEnd;
1710
+ let mainStart = start;
1711
+ target = keysTarget;
1712
+ position$1 = 0;
1713
+ start = 0;
1714
+ if (!target)
1715
+ keysTarget = target = new ByteArrayAllocate(8192);
1716
+ safeEnd = target.length - 10;
1717
+ newRecord(transition, keys, newTransitions);
1718
+ keysTarget = target;
1719
+ let keysPosition = position$1;
1720
+ target = mainTarget;
1721
+ position$1 = mainPosition;
1722
+ safeEnd = mainSafeEnd;
1723
+ start = mainStart;
1724
+ if (keysPosition > 1) {
1725
+ let newEnd = position$1 + keysPosition - 1;
1726
+ if (newEnd > safeEnd)
1727
+ makeRoom(newEnd);
1728
+ let insertionPosition = insertionOffset + start;
1729
+ target.copyWithin(insertionPosition + keysPosition, insertionPosition + 1, position$1);
1730
+ target.set(keysTarget.slice(0, keysPosition), insertionPosition);
1731
+ position$1 = newEnd;
1732
+ } else {
1733
+ target[insertionOffset + start] = keysTarget[0];
1734
+ }
1735
+ };
1579
1736
  }
1580
1737
  useBuffer(buffer) {
1581
1738
  // this means we are finished using our own buffer and we can write over it safely
@@ -1583,11 +1740,15 @@ class Packr extends Unpackr {
1583
1740
  targetView = new DataView(target.buffer, target.byteOffset, target.byteLength);
1584
1741
  position$1 = 0;
1585
1742
  }
1743
+ clearSharedData() {
1744
+ if (this.structures)
1745
+ this.structures = [];
1746
+ }
1586
1747
  }
1587
1748
 
1588
1749
  extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
1589
1750
  extensions = [{
1590
- pack(date, allocateForWrite) {
1751
+ pack(date, allocateForWrite, pack) {
1591
1752
  let seconds = date.getTime() / 1000;
1592
1753
  if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
1593
1754
  // Timestamp 32
@@ -1602,6 +1763,16 @@ extensions = [{
1602
1763
  target[position++] = 0xff;
1603
1764
  targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0));
1604
1765
  targetView.setUint32(position + 4, seconds);
1766
+ } else if (isNaN(seconds)) {
1767
+ if (this.onInvalidDate) {
1768
+ allocateForWrite(0);
1769
+ return pack(this.onInvalidDate())
1770
+ }
1771
+ // Intentionally invalid timestamp
1772
+ let { target, targetView, position} = allocateForWrite(3);
1773
+ target[position++] = 0xd4;
1774
+ target[position++] = 0xff;
1775
+ target[position++] = 0xff;
1605
1776
  } else {
1606
1777
  // Timestamp 96
1607
1778
  let { target, targetView, position} = allocateForWrite(15);
@@ -1770,6 +1941,14 @@ function insertIds(serialized, idsToInsert) {
1770
1941
  return serialized
1771
1942
  }
1772
1943
 
1944
+ function writeBundles(start, pack) {
1945
+ targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start);
1946
+ let writeStrings = bundledStrings$1;
1947
+ bundledStrings$1 = null;
1948
+ pack(writeStrings[0]);
1949
+ pack(writeStrings[1]);
1950
+ }
1951
+
1773
1952
  function addExtension$1(extension) {
1774
1953
  if (extension.Class) {
1775
1954
  if (!extension.pack && !extension.write)
@@ -1787,7 +1966,8 @@ const pack = defaultPackr.pack;
1787
1966
  const encode = defaultPackr.pack;
1788
1967
  const Encoder = Packr;
1789
1968
  const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1790
- const REUSE_BUFFER_MODE = 1000;
1969
+ const REUSE_BUFFER_MODE = 512;
1970
+ const RESET_BUFFER_MODE = 1024;
1791
1971
 
1792
1972
  class PackrStream extends stream.Transform {
1793
1973
  constructor(options) {
@@ -1939,9 +2119,7 @@ function tryRequire(moduleId) {
1939
2119
  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)));
1940
2120
  return require$1(moduleId)
1941
2121
  } catch (error) {
1942
- if (typeof window == 'undefined')
1943
- console.warn('Native extraction module not loaded, msgpackr will still run, but with decreased performance. ' + error.message.split('\n')[0]);
1944
- else
2122
+ if (typeof window != 'undefined')
1945
2123
  console.warn('For browser usage, directly use msgpackr/unpack or msgpackr/pack modules. ' + error.message.split('\n')[0]);
1946
2124
  }
1947
2125
  }