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