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