cbor-x 0.8.2 → 0.9.2

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/index.js CHANGED
@@ -12,6 +12,7 @@
12
12
  let srcEnd;
13
13
  let position = 0;
14
14
  const RECORD_TAG_ID = 0x69;
15
+ const PACKED_REFERENCE_TAG_ID = 6;
15
16
  const STOP_CODE = {};
16
17
  let currentDecoder = {};
17
18
  let currentStructures;
@@ -20,11 +21,15 @@
20
21
  let srcStringEnd = 0;
21
22
  let referenceMap;
22
23
  let currentExtensions = [];
24
+ let currentExtensionRanges = [];
25
+ let packedValues;
23
26
  let dataView;
27
+ let restoreMapsAsObject;
24
28
  let defaultOptions = {
25
29
  useRecords: false,
26
30
  mapsAsObjects: true
27
31
  };
32
+ let sequentialMode = false;
28
33
 
29
34
  class Decoder {
30
35
  constructor(options) {
@@ -36,12 +41,12 @@
36
41
  }
37
42
  Object.assign(this, options);
38
43
  }
39
- decode(source, end, continueReading) {
44
+ decode(source, end) {
40
45
  if (src) {
41
46
  // re-entrant execution, save the state and restore it after we do this decode
42
47
  return saveState(() => {
43
48
  clearSource();
44
- return this ? this.decode(source, end, continueReading) : Decoder.prototype.decode.call(defaultOptions, source, end, continueReading)
49
+ return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
45
50
  })
46
51
  }
47
52
  srcEnd = end > -1 ? end : source.length;
@@ -55,19 +60,12 @@
55
60
  dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
56
61
  if (this) {
57
62
  currentDecoder = this;
63
+ packedValues = this.sharedValues &&
64
+ (this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :
65
+ this.sharedValues);
58
66
  if (this.structures) {
59
67
  currentStructures = this.structures;
60
- try {
61
- return read()
62
- } finally {
63
- if (position >= srcEnd || !continueReading) {
64
- // finished reading this source, cleanup references
65
- currentStructures = null;
66
- src = null;
67
- if (referenceMap)
68
- referenceMap = null;
69
- }
70
- }
68
+ return checkedRead()
71
69
  } else if (!currentStructures || currentStructures.length > 0) {
72
70
  currentStructures = [];
73
71
  }
@@ -75,27 +73,23 @@
75
73
  currentDecoder = defaultOptions;
76
74
  if (!currentStructures || currentStructures.length > 0)
77
75
  currentStructures = [];
76
+ packedValues = null;
78
77
  }
79
- try {
80
- return read()
81
- } finally {
82
- if (position >= srcEnd || !continueReading) {
83
- src = null;
84
- if (referenceMap)
85
- referenceMap = null;
86
- }
87
- }
78
+ return checkedRead()
88
79
  }
89
80
  decodeMultiple(source, forEach) {
81
+ let values, lastPosition = 0;
90
82
  try {
91
- let decoder = this;
92
83
  let size = source.length;
93
- let value = this ? this.decode(source, size, true) : defaultDecoder.decode(source, size, true);
94
- let values;
84
+ sequentialMode = true;
85
+ let value = this ? this.decode(source, size) : defaultDecoder.decode(source, size);
95
86
  if (forEach) {
96
- forEach(value);
87
+ if (forEach(value) === false) {
88
+ return
89
+ }
97
90
  while(position < size) {
98
- if (forEach(read()) === false) {
91
+ lastPosition = position;
92
+ if (forEach(checkedRead()) === false) {
99
93
  return
100
94
  }
101
95
  }
@@ -103,15 +97,48 @@
103
97
  else {
104
98
  values = [ value ];
105
99
  while(position < size) {
106
- values.push(read());
100
+ lastPosition = position;
101
+ values.push(checkedRead());
107
102
  }
108
103
  return values
109
104
  }
105
+ } catch(error) {
106
+ error.lastPosition = lastPosition;
107
+ error.values = values;
108
+ throw error
110
109
  } finally {
110
+ sequentialMode = false;
111
111
  clearSource();
112
112
  }
113
113
  }
114
114
  }
115
+ function checkedRead() {
116
+ try {
117
+ let result = read();
118
+ if (position == srcEnd) {
119
+ // finished reading this source, cleanup references
120
+ currentStructures = null;
121
+ src = null;
122
+ if (referenceMap)
123
+ referenceMap = null;
124
+ } else if (position > srcEnd) {
125
+ // over read
126
+ let error = new Error('Unexpected end of CBOR data');
127
+ error.incomplete = true;
128
+ throw error
129
+ } else if (!sequentialMode) {
130
+ throw new Error('Data read, but end of buffer not reached')
131
+ }
132
+ // else more to read, but we are reading sequentially, so don't clear source yet
133
+ return result
134
+ } catch(error) {
135
+ clearSource();
136
+ if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {
137
+ error.incomplete = true;
138
+ }
139
+ throw error
140
+ }
141
+ }
115
142
 
116
143
  function read() {
117
144
  let token = src[position++];
@@ -176,6 +203,10 @@
176
203
  object[key] = read();
177
204
  return object
178
205
  } else {
206
+ if (restoreMapsAsObject) {
207
+ currentDecoder.mapsAsObjects = true;
208
+ restoreMapsAsObject = false;
209
+ }
179
210
  let map = new Map();
180
211
  while ((key = read()) != STOP_CODE)
181
212
  map.set(key, read());
@@ -222,6 +253,10 @@
222
253
  }
223
254
  return object
224
255
  } else {
256
+ if (restoreMapsAsObject) {
257
+ currentDecoder.mapsAsObjects = true;
258
+ restoreMapsAsObject = false;
259
+ }
225
260
  let map = new Map();
226
261
  for (let i = 0; i < token; i++) {
227
262
  map.set(read(), read());
@@ -261,9 +296,15 @@
261
296
  return extension(read)
262
297
  else
263
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
305
+ }
306
+ return new Tag(input)
264
307
  }
265
- else
266
- return new Tag(read())
267
308
  }
268
309
  case 7: // fixed value
269
310
  switch (token) {
@@ -273,6 +314,9 @@
273
314
  case 0x17: return; // undefined
274
315
  case 0x1f:
275
316
  default:
317
+ let packedValue = packedValues[token];
318
+ if (packedValue !== undefined)
319
+ return packedValue
276
320
  throw new Error('Unknown token ' + token)
277
321
  }
278
322
  default: // negative int
@@ -662,6 +706,23 @@
662
706
  currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
663
707
  return (glbl[data[0]] || Error)(data[1], data[2])
664
708
  };
709
+ const packedTable = (read) => {
710
+ if (src[position++] != 0x84)
711
+ throw new Error('Packed values structure must be followed by 4 element array')
712
+ let newPackedValues = read(); // packed values
713
+ packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
714
+ packedValues.prefixes = read();
715
+ packedValues.suffixes = read();
716
+ return read() // read the rump
717
+ };
718
+ packedTable.handlesRead = true;
719
+ currentExtensions[51] = packedTable;
720
+
721
+ currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
722
+ if (typeof data == 'number')
723
+ return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
724
+ throw new Error('No support for non-integer packed references yet')
725
+ };
665
726
 
666
727
  currentExtensions[40009] = (id) => {
667
728
  // id extension (for structured clones)
@@ -693,6 +754,36 @@
693
754
  };
694
755
 
695
756
  currentExtensions[258] = (array) => new Set(array); // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md
757
+ (currentExtensions[259] = (read) => {
758
+ // https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
759
+ // for decoding as a standard Map
760
+ if (currentDecoder.mapsAsObjects) {
761
+ currentDecoder.mapsAsObjects = false;
762
+ restoreMapsAsObject = true;
763
+ }
764
+ return read()
765
+ }).handlesRead = true;
766
+ function combine(a, b) {
767
+ if (typeof a === 'string')
768
+ return a + b
769
+ if (a instanceof Array)
770
+ return a.concat(b)
771
+ return Object.assign({}, a, b)
772
+ }
773
+ currentExtensionRanges.push((tag, input) => {
774
+ if (tag >= 225 && tag <= 255)
775
+ return combine(packedTable.prefixes[tag - 224], input)
776
+ if (tag >= 28704 && tag <= 32767)
777
+ return combine(packedTable.prefixes[tag - 28672], input)
778
+ if (tag >= 1879052288 && tag <= 2147483647)
779
+ return combine(packedTable.prefixes[tag - 1879048192], input)
780
+ if (tag >= 216 && tag <= 223)
781
+ return combine(input, packedTable.suffixes[tag - 216])
782
+ if (tag >= 27647 && tag <= 28671)
783
+ return combine(input, packedTable.suffixes[tag - 27639])
784
+ if (tag >= 1811940352 && tag <= 1879048191)
785
+ return combine(input, packedTable.suffixes[tag - 1811939328])
786
+ });
696
787
 
697
788
  const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array');
698
789
  const typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 81, 82];
@@ -719,6 +810,7 @@
719
810
  let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
720
811
  let savedStructures = currentStructures;
721
812
  let savedDecoder = currentDecoder;
813
+ let savedSequentialMode = sequentialMode;
722
814
  let value = callback();
723
815
  srcEnd = savedSrcEnd;
724
816
  position = savedPosition;
@@ -727,6 +819,7 @@
727
819
  srcString = savedSrcString;
728
820
  referenceMap = savedReferenceMap;
729
821
  src = savedSrc;
822
+ sequentialMode = savedSequentialMode;
730
823
  currentStructures = savedStructures;
731
824
  currentDecoder = savedDecoder;
732
825
  dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
@@ -742,7 +835,7 @@
742
835
  currentExtensions[extension.tag] = extension.decode;
743
836
  }
744
837
 
745
- let mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
838
+ const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
746
839
  for (let i = 0; i < 256; i++) {
747
840
  mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
748
841
  }
@@ -754,7 +847,14 @@
754
847
  ALWAYS: 1,
755
848
  DECIMAL_ROUND: 3,
756
849
  DECIMAL_FIT: 4
757
- };
850
+ };
851
+ let f32Array = new Float32Array(1);
852
+ let u8Array = new Uint8Array(f32Array.buffer, 0, 4);
853
+ function roundFloat32(float32Number) {
854
+ f32Array[0] = float32Number;
855
+ let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
856
+ return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
857
+ }
758
858
 
759
859
  let textEncoder;
760
860
  try {
@@ -781,6 +881,7 @@
781
881
  let hasSharedUpdate;
782
882
  let structures;
783
883
  let referenceMap;
884
+ options = options || {};
784
885
  let lastSharedStructuresLength = 0;
785
886
  let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position, maxBytes) {
786
887
  return target.utf8Write(string, position, maxBytes)
@@ -791,19 +892,25 @@
791
892
 
792
893
  let encoder = this;
793
894
  let maxSharedStructures = 64;
794
- let isSequential = options && options.sequential;
895
+ let isSequential = options.sequential;
795
896
  if (isSequential) {
796
897
  maxSharedStructures = 0;
797
898
  this.structures = [];
798
899
  }
900
+ let samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues;
901
+ let sharedPackedObjectMap;
902
+ if (sharedValues) {
903
+ sharedPackedObjectMap = Object.create(null);
904
+ for (let i = 0, l = sharedValues.length; i < l; i++) {
905
+ sharedPackedObjectMap[sharedValues[i]] = i;
906
+ }
907
+
908
+ }
799
909
  let recordIdsToRemove = [];
800
910
  let transitionsCount = 0;
801
911
  let serializationsSinceTransitionRebuild = 0;
802
- if (this.structures && this.structures.length > maxSharedStructures) {
803
- throw new Error('Too many shared structures')
804
- }
805
912
 
806
- this.encode = function(value) {
913
+ this.encode = function(value, encodeOptions) {
807
914
  if (!target) {
808
915
  target = new ByteArrayAllocate(8192);
809
916
  targetView = new DataView(target.buffer, 0, 8192);
@@ -816,7 +923,8 @@
816
923
  targetView = new DataView(target.buffer, 0, target.length);
817
924
  safeEnd = target.length - 10;
818
925
  position$1 = 0;
819
- }
926
+ } else if (encodeOptions === REUSE_BUFFER_MODE)
927
+ position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
820
928
  start = position$1;
821
929
  referenceMap = encoder.structuredClone ? new Map() : null;
822
930
  sharedStructures = encoder.structures;
@@ -824,7 +932,7 @@
824
932
  if (sharedStructures.uninitialized)
825
933
  encoder.structures = sharedStructures = encoder.getStructures();
826
934
  let sharedStructuresLength = sharedStructures.length;
827
- if (sharedStructuresLength > maxSharedStructures && !isSequential)
935
+ if (sharedStructuresLength > maxSharedStructures && !isSequential)
828
936
  sharedStructuresLength = maxSharedStructures;
829
937
  if (!sharedStructures.transitions) {
830
938
  // rebuild our structure transitions
@@ -834,8 +942,8 @@
834
942
  if (!keys)
835
943
  continue
836
944
  let nextTransition, transition = sharedStructures.transitions;
837
- for (let i =0, l = keys.length; i < l; i++) {
838
- let key = keys[i];
945
+ for (let j = 0, l = keys.length; j < l; j++) {
946
+ let key = keys[j];
839
947
  nextTransition = transition[key];
840
948
  if (!nextTransition) {
841
949
  nextTransition = transition[key] = Object.create(null);
@@ -852,6 +960,29 @@
852
960
  if (hasSharedUpdate)
853
961
  hasSharedUpdate = false;
854
962
  structures = sharedStructures || [];
963
+ packedObjectMap = sharedPackedObjectMap;
964
+ if (options.pack) {
965
+ let packedValues = new Map();
966
+ packedValues.values = [];
967
+ packedValues.encoder = encoder;
968
+ packedValues.maxValues = options.maxPrivatePackedValues || (sharedPackedObjectMap ? 16 : Infinity);
969
+ packedValues.objectMap = sharedPackedObjectMap || false;
970
+ packedValues.samplingPackedValues = samplingPackedValues;
971
+ findRepetitiveStrings(value, packedValues);
972
+ if (packedValues.values.length > 0) {
973
+ target[position$1++] = 0xd8; // one-byte tag
974
+ target[position$1++] = 51; // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
975
+ writeArrayHeader(4);
976
+ let valuesArray = packedValues.values;
977
+ encode(valuesArray);
978
+ writeArrayHeader(0); // prefixes
979
+ writeArrayHeader(0); // suffixes
980
+ packedObjectMap = Object.create(sharedPackedObjectMap || null);
981
+ for (let i = 0, l = valuesArray.length; i < l; i++) {
982
+ packedObjectMap[valuesArray[i]] = i;
983
+ }
984
+ }
985
+ }
855
986
  try {
856
987
  encode(value);
857
988
  encoder.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
@@ -864,7 +995,12 @@
864
995
  referenceMap = null;
865
996
  return serialized
866
997
  }
867
- return target.subarray(start, position$1) // position can change if we call encode again in saveStructures, so we get the buffer now
998
+ if (encodeOptions === REUSE_BUFFER_MODE) {
999
+ target.start = start;
1000
+ target.end = position$1;
1001
+ return target
1002
+ }
1003
+ return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
868
1004
  } finally {
869
1005
  if (sharedStructures) {
870
1006
  if (serializationsSinceTransitionRebuild < 10)
@@ -878,7 +1014,7 @@
878
1014
  recordIdsToRemove = [];
879
1015
  } else if (recordIdsToRemove.length > 0 && !isSequential) {
880
1016
  for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
881
- recordIdsToRemove[i][RECORD_SYMBOL] = 0;
1017
+ recordIdsToRemove[i][RECORD_SYMBOL] = undefined;
882
1018
  }
883
1019
  recordIdsToRemove = [];
884
1020
  }
@@ -886,15 +1022,41 @@
886
1022
  if (encoder.structures.length > maxSharedStructures) {
887
1023
  encoder.structures = encoder.structures.slice(0, maxSharedStructures);
888
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
+ }
889
1031
 
890
1032
  if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
891
1033
  // get updated structures and try again if the update failed
892
1034
  encoder.structures = encoder.getStructures() || [];
893
1035
  return encoder.encode(value)
894
1036
  }
895
- lastSharedStructuresLength = encoder.structures.length;
1037
+ lastSharedStructuresLength = shared.length;
1038
+ return returnBuffer
1039
+ }
1040
+ }
1041
+ }
1042
+ };
1043
+ this.findCommonStringsToPack = () => {
1044
+ samplingPackedValues = new Map();
1045
+ if (!sharedPackedObjectMap)
1046
+ sharedPackedObjectMap = Object.create(null);
1047
+ return ({ threshold }) => {
1048
+ threshold = threshold || 4;
1049
+ let position = this.pack ? options.maxPrivatePackedValues || 16 : 0;
1050
+ if (!sharedValues)
1051
+ sharedValues = this.sharedValues = [];
1052
+ for (let [ key, status ] of samplingPackedValues) {
1053
+ if (status.count > threshold) {
1054
+ sharedPackedObjectMap[key] = position++;
1055
+ sharedValues.push(key);
1056
+ hasSharedUpdate = true;
896
1057
  }
897
1058
  }
1059
+ samplingPackedValues = null;
898
1060
  }
899
1061
  };
900
1062
  const encode = (value) => {
@@ -904,6 +1066,43 @@
904
1066
  var type = typeof value;
905
1067
  var length;
906
1068
  if (type === 'string') {
1069
+ if (packedObjectMap) {
1070
+ let packedPosition = packedObjectMap[value];
1071
+ if (packedPosition >= 0) {
1072
+ if (packedPosition < 16)
1073
+ target[position$1++] = packedPosition + 0xe0; // simple values, defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
1074
+ else {
1075
+ target[position$1++] = 0xc6; // tag 6 defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
1076
+ if (packedPosition & 1)
1077
+ encode((15 - packedPosition) >> 1);
1078
+ else
1079
+ encode((packedPosition - 16) >> 1);
1080
+ }
1081
+ return
1082
+ /* } else if (packedStatus.serializationId != serializationId) {
1083
+ packedStatus.serializationId = serializationId
1084
+ packedStatus.count = 1
1085
+ if (options.sharedPack) {
1086
+ let sharedCount = packedStatus.sharedCount = (packedStatus.sharedCount || 0) + 1
1087
+ if (shareCount > (options.sharedPack.threshold || 5)) {
1088
+ let sharedPosition = packedStatus.position = packedStatus.nextSharedPosition
1089
+ hasSharedUpdate = true
1090
+ if (sharedPosition < 16)
1091
+ target[position++] = sharedPosition + 0xc0
1092
+
1093
+ }
1094
+ }
1095
+ } // else any in-doc incrementation?*/
1096
+ } else if (samplingPackedValues && !options.pack) {
1097
+ let status = samplingPackedValues.get(value);
1098
+ if (status)
1099
+ status.count++;
1100
+ else
1101
+ samplingPackedValues.set(value, {
1102
+ count: 1,
1103
+ });
1104
+ }
1105
+ }
907
1106
  let strLength = value.length;
908
1107
  let headerSize;
909
1108
  // first we estimate the header size, so we can write to the correct location
@@ -1013,7 +1212,7 @@
1013
1212
  targetView.setFloat32(position$1, value);
1014
1213
  let xShifted;
1015
1214
  if (useFloat32 < 4 ||
1016
- // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1215
+ // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1017
1216
  ((xShifted = value * mult10[((target[position$1] & 0x7f) << 1) | (target[position$1 + 1] >> 7)]) >> 0) === xShifted) {
1018
1217
  position$1 += 4;
1019
1218
  return
@@ -1059,6 +1258,12 @@
1059
1258
  encode(value[i]);
1060
1259
  }
1061
1260
  } else if (constructor === Map) {
1261
+ if (this.mapsAsObjects ? this.useTag259ForMaps !== false : this.useTag259ForMaps) {
1262
+ // use Tag 259 (https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) for maps if the user wants it that way
1263
+ target[position$1++] = 0xd9;
1264
+ target[position$1++] = 1;
1265
+ target[position$1++] = 3;
1266
+ }
1062
1267
  length = value.size;
1063
1268
  if (length < 0x18) {
1064
1269
  target[position$1++] = 0xa0 | length;
@@ -1136,10 +1341,9 @@
1136
1341
  }
1137
1342
  position$1 += 8;
1138
1343
  } else if (type === 'undefined') {
1139
- //target[position++] = 0xc1 // this is the "never-used" byte
1140
1344
  target[position$1++] = 0xf7;
1141
1345
  } else {
1142
- throw new Error('Unknown type ' + type)
1346
+ throw new Error('Unknown type: ' + type)
1143
1347
  }
1144
1348
  };
1145
1349
 
@@ -1228,7 +1432,7 @@
1228
1432
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1229
1433
  let newTransitions = 0;
1230
1434
  let length = keys.length;
1231
- for (let i =0; i < length; i++) {
1435
+ for (let i = 0; i < length; i++) {
1232
1436
  let key = keys[i];
1233
1437
  nextTransition = transition[key];
1234
1438
  if (!nextTransition) {
@@ -1238,7 +1442,7 @@
1238
1442
  transition = nextTransition;
1239
1443
  }
1240
1444
  let recordId = transition[RECORD_SYMBOL];
1241
- if (recordId) {
1445
+ if (recordId !== undefined) {
1242
1446
  target[position$1++] = 0xd9; // tag two byte
1243
1447
  target[position$1++] = RECORD_STARTING_ID_PREFIX;
1244
1448
  target[position$1++] = recordId;
@@ -1265,12 +1469,9 @@
1265
1469
  transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
1266
1470
  // record the removal of the id, we can maintain our shared structure
1267
1471
  if (recordIdsToRemove.length >= MAX_STRUCTURES - maxSharedStructures)
1268
- recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
1472
+ recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
1269
1473
  recordIdsToRemove.push(transition);
1270
- if (length < 0x16)
1271
- target[position$1++] = 0x82 + length; // array header, length of values + 2
1272
- else
1273
- writeArrayHeader(length + 2);
1474
+ writeArrayHeader(length + 2);
1274
1475
  encode(keys);
1275
1476
  target[position$1++] = 0x19; // uint16
1276
1477
  target[position$1++] = RECORD_STARTING_ID_PREFIX;
@@ -1320,7 +1521,9 @@
1320
1521
  }
1321
1522
 
1322
1523
  function writeArrayHeader(length) {
1323
- if (length < 0x100) {
1524
+ if (length < 0x18)
1525
+ target[position$1++] = 0x80 | length;
1526
+ else if (length < 0x100) {
1324
1527
  target[position$1++] = 0x98;
1325
1528
  target[position$1++] = length;
1326
1529
  } else if (length < 0x10000) {
@@ -1334,6 +1537,56 @@
1334
1537
  }
1335
1538
  }
1336
1539
 
1540
+ function findRepetitiveStrings(value, packedValues) {
1541
+ switch(typeof value) {
1542
+ case 'string':
1543
+ if (value.length > 3) {
1544
+ if (packedValues.objectMap[value] > -1 || packedValues.values.length >= packedValues.maxValues)
1545
+ return
1546
+ let packedStatus = packedValues.get(value);
1547
+ if (packedStatus) {
1548
+ if (++packedStatus.count == 2) {
1549
+ packedValues.values.push(value);
1550
+ }
1551
+ } else {
1552
+ packedValues.set(value, {
1553
+ count: 1,
1554
+ });
1555
+ if (packedValues.samplingPackedValues) {
1556
+ let status = packedValues.samplingPackedValues.get(value);
1557
+ if (status)
1558
+ status.count++;
1559
+ else
1560
+ packedValues.samplingPackedValues.set(value, {
1561
+ count: 1,
1562
+ });
1563
+ }
1564
+ }
1565
+ }
1566
+ break
1567
+ case 'object':
1568
+ if (value) {
1569
+ if (value instanceof Array) {
1570
+ for (let i = 0, l = value.length; i < l; i++) {
1571
+ findRepetitiveStrings(value[i], packedValues);
1572
+ }
1573
+
1574
+ } else {
1575
+ let includeKeys = !packedValues.encoder.useRecords;
1576
+ for (var key in value) {
1577
+ if (value.hasOwnProperty(key)) {
1578
+ if (includeKeys)
1579
+ findRepetitiveStrings(key, packedValues);
1580
+ findRepetitiveStrings(value[key], packedValues);
1581
+ }
1582
+ }
1583
+ }
1584
+ }
1585
+ break
1586
+ case 'function': console.log(value);
1587
+ }
1588
+ }
1589
+
1337
1590
  extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, ByteArray,
1338
1591
  Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array, BigUint64Array, Int8Array, Int16Array, Int32Array, BigInt64Array,
1339
1592
  Float32Array, Float64Array];
@@ -1405,7 +1658,9 @@
1405
1658
  }
1406
1659
  function writeBuffer(buffer, makeRoom) {
1407
1660
  let length = buffer.byteLength;
1408
- if (length < 0x100) {
1661
+ if (length < 0x18) {
1662
+ target[position$1++] = 0x40 + length;
1663
+ } else if (length < 0x100) {
1409
1664
  target[position$1++] = 0x58;
1410
1665
  target[position$1++] = length;
1411
1666
  } else if (length < 0x10000) {
@@ -1460,7 +1715,91 @@
1460
1715
  }
1461
1716
  let defaultEncoder = new Encoder({ useRecords: false });
1462
1717
  const encode = defaultEncoder.encode;
1463
- const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1718
+ const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1719
+ const REUSE_BUFFER_MODE = 1000;
1720
+
1721
+ /**
1722
+ * Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer
1723
+ * If the argument is only Async Iterable, the return value will be an Async Iterable.
1724
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
1725
+ * @param {options} [options] - cbor-x Encoder options
1726
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator>}
1727
+ */
1728
+ function encodeIter (objectIterator, options = {}) {
1729
+ if (!objectIterator || typeof objectIterator !== 'object') {
1730
+ throw new Error('first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable')
1731
+ } else if (typeof objectIterator[Symbol.iterator] === 'function') {
1732
+ return encodeIterSync(objectIterator, options)
1733
+ } else if (typeof objectIterator.then === 'function' || typeof objectIterator[Symbol.asyncIterator] === 'function') {
1734
+ return encodeIterAsync(objectIterator, options)
1735
+ } else {
1736
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise')
1737
+ }
1738
+ }
1739
+
1740
+ function * encodeIterSync (objectIterator, options) {
1741
+ const encoder = new Encoder(options);
1742
+ for (const value of objectIterator) {
1743
+ yield encoder.encode(value);
1744
+ }
1745
+ }
1746
+
1747
+ async function * encodeIterAsync (objectIterator, options) {
1748
+ const encoder = new Encoder(options);
1749
+ for await (const value of objectIterator) {
1750
+ yield encoder.encode(value);
1751
+ }
1752
+ }
1753
+
1754
+ /**
1755
+ * Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
1756
+ * Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
1757
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
1758
+ * @param {object} [options] - Decoder options
1759
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator}
1760
+ */
1761
+ function decodeIter (bufferIterator, options = {}) {
1762
+ if (!bufferIterator || typeof bufferIterator !== 'object') {
1763
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise')
1764
+ }
1765
+
1766
+ const decoder = new Decoder(options);
1767
+ let incomplete;
1768
+ const parser = (chunk) => {
1769
+ let yields;
1770
+ // if there's incomplete data from previous chunk, concatinate and try again
1771
+ if (incomplete) {
1772
+ chunk = Buffer.concat([incomplete, chunk]);
1773
+ incomplete = undefined;
1774
+ }
1775
+
1776
+ try {
1777
+ yields = decoder.decodeMultiple(chunk);
1778
+ } catch (err) {
1779
+ if (err.incomplete) {
1780
+ incomplete = chunk.slice(err.lastPosition);
1781
+ yields = err.values;
1782
+ } else {
1783
+ throw err
1784
+ }
1785
+ }
1786
+ return yields
1787
+ };
1788
+
1789
+ if (typeof bufferIterator[Symbol.iterator] === 'function') {
1790
+ return (function * iter () {
1791
+ for (const value of bufferIterator) {
1792
+ yield * parser(value);
1793
+ }
1794
+ })()
1795
+ } else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
1796
+ return (async function * iter () {
1797
+ for await (const value of bufferIterator) {
1798
+ yield * parser(value);
1799
+ }
1800
+ })()
1801
+ }
1802
+ }
1464
1803
 
1465
1804
  const useRecords = false;
1466
1805
  const mapsAsObjects = true;
@@ -1474,10 +1813,14 @@
1474
1813
  exports.NEVER = NEVER;
1475
1814
  exports.Tag = Tag;
1476
1815
  exports.addExtension = addExtension$1;
1816
+ exports.clearSource = clearSource;
1477
1817
  exports.decode = decode;
1818
+ exports.decodeIter = decodeIter;
1478
1819
  exports.decodeMultiple = decodeMultiple;
1479
1820
  exports.encode = encode;
1821
+ exports.encodeIter = encodeIter;
1480
1822
  exports.mapsAsObjects = mapsAsObjects;
1823
+ exports.roundFloat32 = roundFloat32;
1481
1824
  exports.useRecords = useRecords;
1482
1825
 
1483
1826
  Object.defineProperty(exports, '__esModule', { value: true });