ordered-binary 1.2.5 → 1.4.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/index.cjs CHANGED
@@ -2,336 +2,365 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- /*
6
- control character types:
7
- 1 - metadata
8
- 2 - symbols
9
- 6 - false
10
- 7 - true
11
- 8- 16 - negative doubles
12
- 16-24 positive doubles
13
- 27 - String starts with a character 27 or less or is an empty string
14
- 0 - multipart separator
15
- > 27 normal string characters
16
- */
17
- /*
18
- * Convert arbitrary scalar values to buffer bytes with type preservation and type-appropriate ordering
19
- */
20
-
21
- const float64Array = new Float64Array(2);
22
- const int32Array = new Int32Array(float64Array.buffer, 0, 4);
23
- let nullTerminate = false;
24
- let textEncoder;
25
- try {
26
- textEncoder = new TextEncoder();
27
- } catch (error) {}
28
-
29
- /*
30
- * Convert arbitrary scalar values to buffer bytes with type preservation and type-appropriate ordering
31
- */
32
- function writeKey(key, target, position, inSequence) {
33
- let targetView = target.dataView;
34
- if (!targetView)
35
- targetView = target.dataView = new DataView(target.buffer, target.byteOffset, ((target.byteLength + 3) >> 2) << 2);
36
- switch (typeof key) {
37
- case 'string':
38
- let strLength = key.length;
39
- let c1 = key.charCodeAt(0);
40
- if (!(c1 >= 28)) // escape character
41
- target[position++] = 27;
42
- if (strLength < 0x40) {
43
- let i, c2;
44
- for (i = 0; i < strLength; i++) {
45
- c1 = key.charCodeAt(i);
46
- if (c1 < 0x80) {
47
- target[position++] = c1;
48
- } else if (c1 < 0x800) {
49
- target[position++] = c1 >> 6 | 0xc0;
50
- target[position++] = c1 & 0x3f | 0x80;
51
- } else if (
52
- (c1 & 0xfc00) === 0xd800 &&
53
- ((c2 = key.charCodeAt(i + 1)) & 0xfc00) === 0xdc00
54
- ) {
55
- c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff);
56
- i++;
57
- target[position++] = c1 >> 18 | 0xf0;
58
- target[position++] = c1 >> 12 & 0x3f | 0x80;
59
- target[position++] = c1 >> 6 & 0x3f | 0x80;
60
- target[position++] = c1 & 0x3f | 0x80;
61
- } else {
62
- target[position++] = c1 >> 12 | 0xe0;
63
- target[position++] = c1 >> 6 & 0x3f | 0x80;
64
- target[position++] = c1 & 0x3f | 0x80;
65
- }
66
- }
67
- } else {
68
- if (target.utf8Write)
69
- position += target.utf8Write(key, position);
70
- else
71
- position += textEncoder.encodeInto(key, target.subarray(position)).written;
72
- if (position > target.length - 4)
73
- throw new RangeError('String does not fit in target buffer')
74
- }
75
- break
76
- case 'number':
77
- float64Array[0] = key;
78
- let lowInt = int32Array[0];
79
- let highInt = int32Array[1];
80
- let length;
81
- if (key < 0) {
82
- targetView.setInt32(position + 4, ~((lowInt >>> 4) | (highInt << 28)));
83
- targetView.setInt32(position + 0, (highInt ^ 0x7fffffff) >>> 4);
84
- targetView.setInt32(position + 8, ((lowInt & 0xf) ^ 0xf) << 4, true); // just always do the null termination here
85
- return position + 9
86
- } else if ((lowInt & 0xf) || inSequence) {
87
- length = 9;
88
- } else if (lowInt & 0xfffff)
89
- length = 8;
90
- else if (lowInt || (highInt & 0xf))
91
- length = 6;
92
- else
93
- length = 4;
94
- // switching order to go to little endian
95
- targetView.setInt32(position + 0, (highInt >>> 4) | 0x10000000);
96
- targetView.setInt32(position + 4, (lowInt >>> 4) | (highInt << 28));
97
- // if (length == 9 || nullTerminate)
98
- targetView.setInt32(position + 8, (lowInt & 0xf) << 4, true);
99
- return position + length;
100
- case 'object':
101
- if (key) {
102
- if (key instanceof Array) {
103
- for (let i = 0, l = key.length; i < l; i++) {
104
- if (i > 0)
105
- target[position++] = 0;
106
- position = writeKey(key[i], target, position, true);
107
- }
108
- break
109
- } else if (key instanceof Uint8Array) {
110
- target.set(key, position);
111
- position += key.length;
112
- break
113
- } else {
114
- throw new Error('Unable to serialize object as a key')
115
- }
116
- } else // null
117
- target[position++] = 0;
118
- break
119
- case 'boolean':
120
- targetView.setUint32(position++, key ? 7 : 6, true);
121
- return position
122
- case 'bigint':
123
- return writeKey(Number(key), target, position, inSequence)
124
- case 'undefined':
125
- return position
126
- // undefined is interpreted as the absence of a key, signified by zero length
127
- case 'symbol':
128
- target[position++] = 2;
129
- return writeKey(key.description, target, position, inSequence)
130
- default:
131
- throw new Error('Can not serialize key of type ' + typeof key)
132
- }
133
- if (nullTerminate && !inSequence)
134
- targetView.setUint32(position, 0);
135
- return position
136
- }
137
-
138
- let position;
139
- function readKey(buffer, start, end, inSequence) {
140
- buffer[end] = 0; // make sure it is null terminated
141
- position = start;
142
- let controlByte = buffer[position];
143
- let value;
144
- if (controlByte < 24) {
145
- if (controlByte < 8) {
146
- position++;
147
- if (controlByte == 6) {
148
- value = false;
149
- } else if (controlByte == 7) {
150
- value = true;
151
- } else if (controlByte == 0) {
152
- value = null;
153
- } else if (controlByte == 2) {
154
- value = Symbol.for(readString(buffer));
155
- } else
156
- return Uint8Array.prototype.slice.call(buffer, start, end)
157
- } else {
158
- let dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2));
159
- let highInt = dataView.getInt32(position) << 4;
160
- let size = end - position;
161
- let lowInt;
162
- if (size > 4) {
163
- lowInt = dataView.getInt32(position + 4);
164
- highInt |= lowInt >>> 28;
165
- if (size <= 6) { // clear the last bits
166
- lowInt &= -0x1000;
167
- }
168
- lowInt = lowInt << 4;
169
- if (size > 8) {
170
- lowInt = lowInt | buffer[position + 8] >> 4;
171
- }
172
- } else
173
- lowInt = 0;
174
- if (controlByte < 16) {
175
- // negative gets negated
176
- highInt = highInt ^ 0x7fffffff;
177
- lowInt = ~lowInt;
178
- }
179
- int32Array[1] = highInt;
180
- int32Array[0] = lowInt;
181
- value = float64Array[0];
182
- position += 9;
183
- }
184
- } else {
185
- if (controlByte == 27) {
186
- position++;
187
- }
188
- value = readString(buffer);
189
- /*let strStart = position
190
- let strEnd = end
191
- for (; position < end; position++) {
192
- if (buffer[position] == 0) {
193
- break
194
- }
195
- }
196
- value = buffer.toString('utf8', strStart, position++)*/
197
- }
198
- while (position < end) {
199
- if (buffer[position] === 0)
200
- position++;
201
- if (inSequence) {
202
- encoder.position = position;
203
- return value
204
- }
205
- let nextValue = readKey(buffer, position, end, true);
206
- if (value instanceof Array) {
207
- value.push(nextValue);
208
- } else
209
- value = [ value, nextValue ];
210
- }
211
- return value
212
- }
213
- const enableNullTermination = () => nullTerminate = true;
214
-
215
- const encoder = {
216
- writeKey,
217
- readKey,
218
- enableNullTermination,
219
- };
220
- const toBufferKey = (key) => {
221
- let buffer = Buffer.alloc(2048);
222
- return buffer.slice(0, writeKey(key, buffer, 0, 2048) + 1)
223
- };
224
- const fromBufferKey = (sourceBuffer) => {
225
- return readKey(sourceBuffer, 0, sourceBuffer.length - 1)
226
- };
227
- const fromCharCode = String.fromCharCode;
228
- function makeStringBuilder() {
229
- let stringBuildCode = '(source) => {';
230
- let previous = [];
231
- for (let i = 0; i < 0x30; i++) {
232
- let v = fromCharCode((i & 0xf) + 97) + fromCharCode((i >> 4) + 97);
233
- stringBuildCode += `
234
- let ${v} = source[position++]
235
- if (${v} === 0)
236
- return fromCharCode(${previous})
237
- else if (${v} >= 0x80)
238
- ${v} = finishUtf8(${v}, source)
239
- `;
240
- previous.push(v);
241
- if (i == 1000000) // this just exists to prevent rollup from doing dead code elimination on finishUtf8
242
- finishUtf8();
243
- }
244
- stringBuildCode += `return fromCharCode(${previous}) + readString(source)}`;
245
- return stringBuildCode
246
- }
247
-
248
- let pendingSurrogate;
249
- function finishUtf8(byte1, src) {
250
- if ((byte1 & 0xe0) === 0xc0) {
251
- // 2 bytes
252
- const byte2 = src[position++] & 0x3f;
253
- return ((byte1 & 0x1f) << 6) | byte2
254
- } else if ((byte1 & 0xf0) === 0xe0) {
255
- // 3 bytes
256
- const byte2 = src[position++] & 0x3f;
257
- const byte3 = src[position++] & 0x3f;
258
- return ((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3
259
- } else if ((byte1 & 0xf8) === 0xf0) {
260
- // 4 bytes
261
- if (pendingSurrogate) {
262
- byte1 = pendingSurrogate;
263
- pendingSurrogate = null;
264
- position += 3;
265
- return byte1
266
- }
267
- const byte2 = src[position++] & 0x3f;
268
- const byte3 = src[position++] & 0x3f;
269
- const byte4 = src[position++] & 0x3f;
270
- let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;
271
- if (unit > 0xffff) {
272
- unit -= 0x10000;
273
- unit = 0xdc00 | (unit & 0x3ff);
274
- pendingSurrogate = ((unit >>> 10) & 0x3ff) | 0xd800;
275
- position -= 4; // reset so we can return the next part of the surrogate pair
276
- }
277
- return unit
278
- } else {
279
- return byte1
280
- }
281
- }
282
-
283
- const readString = eval(makeStringBuilder());
284
-
285
- function compareKeys(a, b) {
286
- // compare with type consistency that matches binary comparison
287
- if (typeof a == 'object') {
288
- if (!a) {
289
- return b == null ? 0 : -1
290
- }
291
- if (a.compare) {
292
- if (b == null) {
293
- return 1
294
- } else if (b.compare) {
295
- return a.compare(b)
296
- } else {
297
- return -1
298
- }
299
- }
300
- let arrayComparison;
301
- if (b instanceof Array) {
302
- let i = 0;
303
- while((arrayComparison = compareKeys(a[i], b[i])) == 0 && i <= a.length) {
304
- i++;
305
- }
306
- return arrayComparison
307
- }
308
- arrayComparison = compareKeys(a[0], b);
309
- if (arrayComparison == 0 && a.length > 1)
310
- return 1
311
- return arrayComparison
312
- } else if (typeof a == typeof b) {
313
- if (typeof a === 'symbol') {
314
- a = Symbol.keyFor(a);
315
- b = Symbol.keyFor(b);
316
- }
317
- return a < b ? -1 : a === b ? 0 : 1
318
- }
319
- else if (typeof b == 'object') {
320
- if (b instanceof Array)
321
- return -compareKeys(b, a)
322
- return 1
323
- } else {
324
- return typeOrder[typeof a] < typeOrder[typeof b] ? -1 : 1
325
- }
326
- }
327
- const typeOrder = {
328
- symbol: 0,
329
- undefined: 1,
330
- boolean: 2,
331
- number: 3,
332
- string: 4
333
- };
334
- const MINIMUM_KEY = null;
5
+ /*
6
+ control character types:
7
+ 1 - metadata
8
+ 2 - symbols
9
+ 6 - false
10
+ 7 - true
11
+ 8- 16 - negative doubles
12
+ 16-24 positive doubles
13
+ 27 - String starts with a character 27 or less or is an empty string
14
+ 0 - multipart separator
15
+ > 27 normal string characters
16
+ */
17
+ /*
18
+ * Convert arbitrary scalar values to buffer bytes with type preservation and type-appropriate ordering
19
+ */
20
+
21
+ const float64Array = new Float64Array(2);
22
+ const int32Array = new Int32Array(float64Array.buffer, 0, 4);
23
+ let nullTerminate = false;
24
+ let textEncoder;
25
+ try {
26
+ textEncoder = new TextEncoder();
27
+ } catch (error) {}
28
+
29
+ /*
30
+ * Convert arbitrary scalar values to buffer bytes with type preservation and type-appropriate ordering
31
+ */
32
+ function writeKey(key, target, position, inSequence) {
33
+ let targetView = target.dataView;
34
+ if (!targetView)
35
+ targetView = target.dataView = new DataView(target.buffer, target.byteOffset, ((target.byteLength + 3) >> 2) << 2);
36
+ switch (typeof key) {
37
+ case 'string':
38
+ let strLength = key.length;
39
+ let c1 = key.charCodeAt(0);
40
+ if (!(c1 >= 28)) // escape character
41
+ target[position++] = 27;
42
+ if (strLength < 0x40) {
43
+ let i, c2;
44
+ for (i = 0; i < strLength; i++) {
45
+ c1 = key.charCodeAt(i);
46
+ if (c1 <= 4) {
47
+ target[position++] = 4;
48
+ target[position++] = c1;
49
+ } else if (c1 < 0x80) {
50
+ target[position++] = c1;
51
+ } else if (c1 < 0x800) {
52
+ target[position++] = c1 >> 6 | 0xc0;
53
+ target[position++] = c1 & 0x3f | 0x80;
54
+ } else if (
55
+ (c1 & 0xfc00) === 0xd800 &&
56
+ ((c2 = key.charCodeAt(i + 1)) & 0xfc00) === 0xdc00
57
+ ) {
58
+ c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff);
59
+ i++;
60
+ target[position++] = c1 >> 18 | 0xf0;
61
+ target[position++] = c1 >> 12 & 0x3f | 0x80;
62
+ target[position++] = c1 >> 6 & 0x3f | 0x80;
63
+ target[position++] = c1 & 0x3f | 0x80;
64
+ } else {
65
+ target[position++] = c1 >> 12 | 0xe0;
66
+ target[position++] = c1 >> 6 & 0x3f | 0x80;
67
+ target[position++] = c1 & 0x3f | 0x80;
68
+ }
69
+ }
70
+ } else {
71
+ if (target.utf8Write)
72
+ position += target.utf8Write(key, position);
73
+ else
74
+ position += textEncoder.encodeInto(key, target.subarray(position)).written;
75
+ if (position > target.length - 4)
76
+ throw new RangeError('String does not fit in target buffer')
77
+ }
78
+ break
79
+ case 'number':
80
+ float64Array[0] = key;
81
+ let lowInt = int32Array[0];
82
+ let highInt = int32Array[1];
83
+ let length;
84
+ if (key < 0) {
85
+ targetView.setInt32(position + 4, ~((lowInt >>> 4) | (highInt << 28)));
86
+ targetView.setInt32(position + 0, (highInt ^ 0x7fffffff) >>> 4);
87
+ targetView.setInt32(position + 8, ((lowInt & 0xf) ^ 0xf) << 4, true); // just always do the null termination here
88
+ return position + 9
89
+ } else if ((lowInt & 0xf) || inSequence) {
90
+ length = 9;
91
+ } else if (lowInt & 0xfffff)
92
+ length = 8;
93
+ else if (lowInt || (highInt & 0xf))
94
+ length = 6;
95
+ else
96
+ length = 4;
97
+ // switching order to go to little endian
98
+ targetView.setInt32(position + 0, (highInt >>> 4) | 0x10000000);
99
+ targetView.setInt32(position + 4, (lowInt >>> 4) | (highInt << 28));
100
+ // if (length == 9 || nullTerminate)
101
+ targetView.setInt32(position + 8, (lowInt & 0xf) << 4, true);
102
+ return position + length;
103
+ case 'object':
104
+ if (key) {
105
+ if (Array.isArray(key)) {
106
+ for (let i = 0, l = key.length; i < l; i++) {
107
+ if (i > 0)
108
+ target[position++] = 0;
109
+ position = writeKey(key[i], target, position, true);
110
+ }
111
+ break
112
+ } else if (key instanceof Uint8Array) {
113
+ target.set(key, position);
114
+ position += key.length;
115
+ break
116
+ } else {
117
+ throw new Error('Unable to serialize object as a key')
118
+ }
119
+ } else // null
120
+ target[position++] = 0;
121
+ break
122
+ case 'boolean':
123
+ targetView.setUint32(position++, key ? 7 : 6, true);
124
+ return position
125
+ case 'bigint':
126
+ return writeKey(Number(key), target, position, inSequence)
127
+ case 'undefined':
128
+ return position
129
+ // undefined is interpreted as the absence of a key, signified by zero length
130
+ case 'symbol':
131
+ target[position++] = 2;
132
+ return writeKey(key.description, target, position, inSequence)
133
+ default:
134
+ throw new Error('Can not serialize key of type ' + typeof key)
135
+ }
136
+ if (nullTerminate && !inSequence)
137
+ targetView.setUint32(position, 0);
138
+ return position
139
+ }
140
+
141
+ let position;
142
+ function readKey(buffer, start, end, inSequence) {
143
+ buffer[end] = 0; // make sure it is null terminated
144
+ position = start;
145
+ let controlByte = buffer[position];
146
+ let value;
147
+ if (controlByte < 24) {
148
+ if (controlByte < 8) {
149
+ position++;
150
+ if (controlByte == 6) {
151
+ value = false;
152
+ } else if (controlByte == 7) {
153
+ value = true;
154
+ } else if (controlByte == 0) {
155
+ value = null;
156
+ } else if (controlByte == 2) {
157
+ value = Symbol.for(readString(buffer));
158
+ } else
159
+ return Uint8Array.prototype.slice.call(buffer, start, end)
160
+ } else {
161
+ let dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2));
162
+ let highInt = dataView.getInt32(position) << 4;
163
+ let size = end - position;
164
+ let lowInt;
165
+ if (size > 4) {
166
+ lowInt = dataView.getInt32(position + 4);
167
+ highInt |= lowInt >>> 28;
168
+ if (size <= 6) { // clear the last bits
169
+ lowInt &= -0x1000;
170
+ }
171
+ lowInt = lowInt << 4;
172
+ if (size > 8) {
173
+ lowInt = lowInt | buffer[position + 8] >> 4;
174
+ }
175
+ } else
176
+ lowInt = 0;
177
+ if (controlByte < 16) {
178
+ // negative gets negated
179
+ highInt = highInt ^ 0x7fffffff;
180
+ lowInt = ~lowInt;
181
+ }
182
+ int32Array[1] = highInt;
183
+ int32Array[0] = lowInt;
184
+ value = float64Array[0];
185
+ position += 9;
186
+ }
187
+ } else {
188
+ if (controlByte == 27) {
189
+ position++;
190
+ }
191
+ value = readString(buffer);
192
+ /*let strStart = position
193
+ let strEnd = end
194
+ for (; position < end; position++) {
195
+ if (buffer[position] == 0) {
196
+ break
197
+ }
198
+ }
199
+ value = buffer.toString('utf8', strStart, position++)*/
200
+ }
201
+ while (position < end) {
202
+ if (buffer[position] === 0)
203
+ position++;
204
+ if (inSequence) {
205
+ encoder.position = position;
206
+ return value
207
+ }
208
+ let nextValue = readKey(buffer, position, end, true);
209
+ if (value instanceof Array) {
210
+ value.push(nextValue);
211
+ } else
212
+ value = [ value, nextValue ];
213
+ }
214
+ return value
215
+ }
216
+ const enableNullTermination = () => nullTerminate = true;
217
+
218
+ const encoder = {
219
+ writeKey,
220
+ readKey,
221
+ enableNullTermination,
222
+ };
223
+ let targetBuffer = [];
224
+ let targetPosition = 0;
225
+ const hasNodeBuffer = typeof Buffer !== 'undefined';
226
+ const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
227
+ const toBufferKey = (key) => {
228
+ let newBuffer;
229
+ if (targetPosition + 100 > targetBuffer.length) {
230
+ targetBuffer = new ByteArrayAllocate(8192);
231
+ targetPosition = 0;
232
+ newBuffer = true;
233
+ }
234
+ try {
235
+ let result = targetBuffer.slice(targetPosition, targetPosition = writeKey(key, targetBuffer, targetPosition));
236
+ if (targetPosition > targetBuffer.length) {
237
+ if (newBuffer)
238
+ throw new Error('Key is too large')
239
+ return toBufferKey(key)
240
+ }
241
+ return result
242
+ } catch(error) {
243
+ if (newBuffer)
244
+ throw error
245
+ targetPosition = targetBuffer.length;
246
+ return toBufferKey(key)
247
+ }
248
+ };
249
+ const fromBufferKey = (sourceBuffer) => {
250
+ return readKey(sourceBuffer, 0, sourceBuffer.length)
251
+ };
252
+ const fromCharCode = String.fromCharCode;
253
+ function makeStringBuilder() {
254
+ let stringBuildCode = '(source) => {';
255
+ let previous = [];
256
+ for (let i = 0; i < 0x30; i++) {
257
+ let v = fromCharCode((i & 0xf) + 97) + fromCharCode((i >> 4) + 97);
258
+ stringBuildCode += `
259
+ let ${v} = source[position++]
260
+ if (${v} > 4) {
261
+ if (${v} >= 0x80) ${v} = finishUtf8(${v}, source)
262
+ } else {
263
+ if (${v} === 4)
264
+ ${v} = source[position++]
265
+ else
266
+ return fromCharCode(${previous})
267
+ }
268
+ `;
269
+ previous.push(v);
270
+ if (i == 1000000) // this just exists to prevent rollup from doing dead code elimination on finishUtf8
271
+ finishUtf8();
272
+ }
273
+ stringBuildCode += `return fromCharCode(${previous}) + readString(source)}`;
274
+ return stringBuildCode
275
+ }
276
+
277
+ let pendingSurrogate;
278
+ function finishUtf8(byte1, src) {
279
+ if ((byte1 & 0xe0) === 0xc0) {
280
+ // 2 bytes
281
+ const byte2 = src[position++] & 0x3f;
282
+ return ((byte1 & 0x1f) << 6) | byte2
283
+ } else if ((byte1 & 0xf0) === 0xe0) {
284
+ // 3 bytes
285
+ const byte2 = src[position++] & 0x3f;
286
+ const byte3 = src[position++] & 0x3f;
287
+ return ((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3
288
+ } else if ((byte1 & 0xf8) === 0xf0) {
289
+ // 4 bytes
290
+ if (pendingSurrogate) {
291
+ byte1 = pendingSurrogate;
292
+ pendingSurrogate = null;
293
+ position += 3;
294
+ return byte1
295
+ }
296
+ const byte2 = src[position++] & 0x3f;
297
+ const byte3 = src[position++] & 0x3f;
298
+ const byte4 = src[position++] & 0x3f;
299
+ let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;
300
+ if (unit > 0xffff) {
301
+ unit -= 0x10000;
302
+ unit = 0xdc00 | (unit & 0x3ff);
303
+ pendingSurrogate = ((unit >>> 10) & 0x3ff) | 0xd800;
304
+ position -= 4; // reset so we can return the next part of the surrogate pair
305
+ }
306
+ return unit
307
+ } else {
308
+ return byte1
309
+ }
310
+ }
311
+
312
+ const readString = eval(makeStringBuilder());
313
+
314
+ function compareKeys(a, b) {
315
+ // compare with type consistency that matches binary comparison
316
+ if (typeof a == 'object') {
317
+ if (!a) {
318
+ return b == null ? 0 : -1
319
+ }
320
+ if (a.compare) {
321
+ if (b == null) {
322
+ return 1
323
+ } else if (b.compare) {
324
+ return a.compare(b)
325
+ } else {
326
+ return -1
327
+ }
328
+ }
329
+ let arrayComparison;
330
+ if (b instanceof Array) {
331
+ let i = 0;
332
+ while((arrayComparison = compareKeys(a[i], b[i])) == 0 && i <= a.length) {
333
+ i++;
334
+ }
335
+ return arrayComparison
336
+ }
337
+ arrayComparison = compareKeys(a[0], b);
338
+ if (arrayComparison == 0 && a.length > 1)
339
+ return 1
340
+ return arrayComparison
341
+ } else if (typeof a == typeof b) {
342
+ if (typeof a === 'symbol') {
343
+ a = Symbol.keyFor(a);
344
+ b = Symbol.keyFor(b);
345
+ }
346
+ return a < b ? -1 : a === b ? 0 : 1
347
+ }
348
+ else if (typeof b == 'object') {
349
+ if (b instanceof Array)
350
+ return -compareKeys(b, a)
351
+ return 1
352
+ } else {
353
+ return typeOrder[typeof a] < typeOrder[typeof b] ? -1 : 1
354
+ }
355
+ }
356
+ const typeOrder = {
357
+ symbol: 0,
358
+ undefined: 1,
359
+ boolean: 2,
360
+ number: 3,
361
+ string: 4
362
+ };
363
+ const MINIMUM_KEY = null;
335
364
  const MAXIMUM_KEY = new Uint8Array([0xff]);
336
365
 
337
366
  exports.MAXIMUM_KEY = MAXIMUM_KEY;