ordered-binary 1.2.5 → 1.3.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,358 @@
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 < 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 (Array.isArray(key)) {
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
+ let targetBuffer = [];
221
+ let targetPosition = 0;
222
+ const hasNodeBuffer = typeof Buffer !== 'undefined';
223
+ const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
224
+ const toBufferKey = (key) => {
225
+ let newBuffer;
226
+ if (targetPosition + 100 > targetBuffer.length) {
227
+ targetBuffer = new ByteArrayAllocate(8192);
228
+ targetPosition = 0;
229
+ newBuffer = true;
230
+ }
231
+ try {
232
+ let result = targetBuffer.slice(targetPosition, targetPosition = writeKey(key, targetBuffer, targetPosition));
233
+ if (targetPosition > targetBuffer.length) {
234
+ if (newBuffer)
235
+ throw new Error('Key is too large')
236
+ return toBufferKey(key)
237
+ }
238
+ return result
239
+ } catch(error) {
240
+ if (newBuffer)
241
+ throw error
242
+ targetPosition = targetBuffer.length;
243
+ return toBufferKey(key)
244
+ }
245
+ };
246
+ const fromBufferKey = (sourceBuffer) => {
247
+ return readKey(sourceBuffer, 0, sourceBuffer.length)
248
+ };
249
+ const fromCharCode = String.fromCharCode;
250
+ function makeStringBuilder() {
251
+ let stringBuildCode = '(source) => {';
252
+ let previous = [];
253
+ for (let i = 0; i < 0x30; i++) {
254
+ let v = fromCharCode((i & 0xf) + 97) + fromCharCode((i >> 4) + 97);
255
+ stringBuildCode += `
256
+ let ${v} = source[position++]
257
+ if (!${v})
258
+ return fromCharCode(${previous})
259
+ else if (${v} >= 0x80)
260
+ ${v} = finishUtf8(${v}, source)
261
+ `;
262
+ previous.push(v);
263
+ if (i == 1000000) // this just exists to prevent rollup from doing dead code elimination on finishUtf8
264
+ finishUtf8();
265
+ }
266
+ stringBuildCode += `return fromCharCode(${previous}) + readString(source)}`;
267
+ return stringBuildCode
268
+ }
269
+
270
+ let pendingSurrogate;
271
+ function finishUtf8(byte1, src) {
272
+ if ((byte1 & 0xe0) === 0xc0) {
273
+ // 2 bytes
274
+ const byte2 = src[position++] & 0x3f;
275
+ return ((byte1 & 0x1f) << 6) | byte2
276
+ } else if ((byte1 & 0xf0) === 0xe0) {
277
+ // 3 bytes
278
+ const byte2 = src[position++] & 0x3f;
279
+ const byte3 = src[position++] & 0x3f;
280
+ return ((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3
281
+ } else if ((byte1 & 0xf8) === 0xf0) {
282
+ // 4 bytes
283
+ if (pendingSurrogate) {
284
+ byte1 = pendingSurrogate;
285
+ pendingSurrogate = null;
286
+ position += 3;
287
+ return byte1
288
+ }
289
+ const byte2 = src[position++] & 0x3f;
290
+ const byte3 = src[position++] & 0x3f;
291
+ const byte4 = src[position++] & 0x3f;
292
+ let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;
293
+ if (unit > 0xffff) {
294
+ unit -= 0x10000;
295
+ unit = 0xdc00 | (unit & 0x3ff);
296
+ pendingSurrogate = ((unit >>> 10) & 0x3ff) | 0xd800;
297
+ position -= 4; // reset so we can return the next part of the surrogate pair
298
+ }
299
+ return unit
300
+ } else {
301
+ return byte1
302
+ }
303
+ }
304
+
305
+ const readString = eval(makeStringBuilder());
306
+
307
+ function compareKeys(a, b) {
308
+ // compare with type consistency that matches binary comparison
309
+ if (typeof a == 'object') {
310
+ if (!a) {
311
+ return b == null ? 0 : -1
312
+ }
313
+ if (a.compare) {
314
+ if (b == null) {
315
+ return 1
316
+ } else if (b.compare) {
317
+ return a.compare(b)
318
+ } else {
319
+ return -1
320
+ }
321
+ }
322
+ let arrayComparison;
323
+ if (b instanceof Array) {
324
+ let i = 0;
325
+ while((arrayComparison = compareKeys(a[i], b[i])) == 0 && i <= a.length) {
326
+ i++;
327
+ }
328
+ return arrayComparison
329
+ }
330
+ arrayComparison = compareKeys(a[0], b);
331
+ if (arrayComparison == 0 && a.length > 1)
332
+ return 1
333
+ return arrayComparison
334
+ } else if (typeof a == typeof b) {
335
+ if (typeof a === 'symbol') {
336
+ a = Symbol.keyFor(a);
337
+ b = Symbol.keyFor(b);
338
+ }
339
+ return a < b ? -1 : a === b ? 0 : 1
340
+ }
341
+ else if (typeof b == 'object') {
342
+ if (b instanceof Array)
343
+ return -compareKeys(b, a)
344
+ return 1
345
+ } else {
346
+ return typeOrder[typeof a] < typeOrder[typeof b] ? -1 : 1
347
+ }
348
+ }
349
+ const typeOrder = {
350
+ symbol: 0,
351
+ undefined: 1,
352
+ boolean: 2,
353
+ number: 3,
354
+ string: 4
355
+ };
356
+ const MINIMUM_KEY = null;
335
357
  const MAXIMUM_KEY = new Uint8Array([0xff]);
336
358
 
337
359
  exports.MAXIMUM_KEY = MAXIMUM_KEY;