compact-encoding 2.6.0 → 2.8.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/README.md +14 -1
- package/index.js +115 -36
- package/lexint.js +114 -0
- package/package.json +1 -1
- package/test.js +181 -3
package/README.md
CHANGED
|
@@ -79,13 +79,20 @@ to build others on top. Feel free to PR more that are missing.
|
|
|
79
79
|
* `cenc.uint16` - Encodes a fixed size uint16. Useful for things like ports.
|
|
80
80
|
* `cenc.uint24` - Encodes a fixed size uint24. Useful for message framing.
|
|
81
81
|
* `cenc.uint32` - Encodes a fixed size uint32. Useful for very large message framing.
|
|
82
|
+
* `cenc.uint40` - Encodes a fixed size uint40.
|
|
83
|
+
* `cenc.uint48` - Encodes a fixed size uint48.
|
|
84
|
+
* `cenc.uint56` - Encodes a fixed size uint56.
|
|
82
85
|
* `cenc.uint64` - Encodes a fixed size uint64.
|
|
83
86
|
* `cenc.int` - Encodes an int using `cenc.uint` with ZigZag encoding.
|
|
84
87
|
* `cenc.int8` - Encodes a fixed size int8 using `cenc.uint8` with ZigZag encoding.
|
|
85
88
|
* `cenc.int16` - Encodes a fixed size int16 using `cenc.uint16` with ZigZag encoding.
|
|
86
89
|
* `cenc.int24` - Encodes a fixed size int24 using `cenc.uint24` with ZigZag encoding.
|
|
87
90
|
* `cenc.int32` - Encodes a fixed size int32 using `cenc.uint32` with ZigZag encoding.
|
|
91
|
+
* `cenc.int40` - Encodes a fixed size int40 using `cenc.uint40` with ZigZag encoding.
|
|
92
|
+
* `cenc.int48` - Encodes a fixed size int48 using `cenc.uint48` with ZigZag encoding.
|
|
93
|
+
* `cenc.int56` - Encodes a fixed size int56 using `cenc.uint56` with ZigZag encoding.
|
|
88
94
|
* `cenc.int64` - Encodes a fixed size int64 using `cenc.uint64` with ZigZag encoding.
|
|
95
|
+
* `cenc.lexint` - Encodes an int using [lexicographic-integer](https://github.com/substack/lexicographic-integer) encoding so that encoded values are lexicographically sorted in ascending numerical order.
|
|
89
96
|
* `cenc.float32` - Encodes a fixed size float32.
|
|
90
97
|
* `cenc.float64` - Encodes a fixed size float64.
|
|
91
98
|
* `cenc.buffer` - Encodes a buffer with its length uint prefixed. When decoding an empty buffer, `null` is returned.
|
|
@@ -99,11 +106,17 @@ to build others on top. Feel free to PR more that are missing.
|
|
|
99
106
|
* `cenc.float32array` - Encodes a float32array with its element length uint prefixed.
|
|
100
107
|
* `cenc.float64array` - Encodes a float64array with its element length uint prefixed.
|
|
101
108
|
* `cenc.bool` - Encodes a boolean as 1 or 0.
|
|
102
|
-
* `cenc.string` - Encodes a utf-8 string, similar to buffer.
|
|
109
|
+
* `cenc.string`, `cenc.utf8` - Encodes a utf-8 string, similar to buffer.
|
|
110
|
+
* `cenc.ascii` - Encodes an ascii string.
|
|
111
|
+
* `cenc.hex` - Encodes a hex string.
|
|
112
|
+
* `cenc.base64` - Encodes a base64 string.
|
|
113
|
+
* `cenc.utf16le`, `cenc.ucs2` - Encodes a utf16le string.
|
|
103
114
|
* `cenc.fixed32` - Encodes a fixed 32 byte buffer.
|
|
104
115
|
* `cenc.fixed64` - Encodes a fixed 64 byte buffer.
|
|
105
116
|
* `cenc.fixed(n)` - Makes a fixed sized encoder.
|
|
106
117
|
* `cenc.array(enc)` - Makes an array encoder from another encoder. Arrays are uint prefixed with their length.
|
|
118
|
+
* `cenc.json` - Encodes a JSON value as utf-8.
|
|
119
|
+
* `cenc.ndjson` - Encodes a JSON value as newline delimited utf-8.
|
|
107
120
|
* `cenc.from(enc)` - Makes a compact encoder from a [codec](https://github.com/mafintosh/codecs) or [abstract-encoding](https://github.com/mafintosh/abstract-encoding).
|
|
108
121
|
|
|
109
122
|
## License
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const b4a = require('b4a')
|
|
2
2
|
|
|
3
|
-
const LE = (new Uint8Array(new Uint16Array([
|
|
3
|
+
const LE = (new Uint8Array(new Uint16Array([0xff]).buffer))[0] === 0xff
|
|
4
4
|
const BE = !LE
|
|
5
5
|
|
|
6
6
|
exports.state = function () {
|
|
@@ -58,7 +58,7 @@ const uint16 = exports.uint16 = {
|
|
|
58
58
|
if (state.end - state.start < 2) throw new Error('Out of bounds')
|
|
59
59
|
return (
|
|
60
60
|
state.buffer[state.start++] +
|
|
61
|
-
state.buffer[state.start++] *
|
|
61
|
+
state.buffer[state.start++] * 0x100
|
|
62
62
|
)
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -76,8 +76,8 @@ const uint24 = exports.uint24 = {
|
|
|
76
76
|
if (state.end - state.start < 3) throw new Error('Out of bounds')
|
|
77
77
|
return (
|
|
78
78
|
state.buffer[state.start++] +
|
|
79
|
-
state.buffer[state.start++] *
|
|
80
|
-
state.buffer[state.start++] *
|
|
79
|
+
state.buffer[state.start++] * 0x100 +
|
|
80
|
+
state.buffer[state.start++] * 0x10000
|
|
81
81
|
)
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -96,25 +96,70 @@ const uint32 = exports.uint32 = {
|
|
|
96
96
|
if (state.end - state.start < 4) throw new Error('Out of bounds')
|
|
97
97
|
return (
|
|
98
98
|
state.buffer[state.start++] +
|
|
99
|
-
state.buffer[state.start++] *
|
|
100
|
-
state.buffer[state.start++] *
|
|
101
|
-
state.buffer[state.start++] *
|
|
99
|
+
state.buffer[state.start++] * 0x100 +
|
|
100
|
+
state.buffer[state.start++] * 0x10000 +
|
|
101
|
+
state.buffer[state.start++] * 0x1000000
|
|
102
102
|
)
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
const uint40 = exports.uint40 = {
|
|
107
|
+
preencode (state, n) {
|
|
108
|
+
state.end += 5
|
|
109
|
+
},
|
|
110
|
+
encode (state, n) {
|
|
111
|
+
const r = Math.floor(n / 0x100)
|
|
112
|
+
uint8.encode(state, n)
|
|
113
|
+
uint32.encode(state, r)
|
|
114
|
+
},
|
|
115
|
+
decode (state) {
|
|
116
|
+
if (state.end - state.start < 5) throw new Error('Out of bounds')
|
|
117
|
+
return uint8.decode(state) + 0x100 * uint32.decode(state)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const uint48 = exports.uint48 = {
|
|
122
|
+
preencode (state, n) {
|
|
123
|
+
state.end += 6
|
|
124
|
+
},
|
|
125
|
+
encode (state, n) {
|
|
126
|
+
const r = Math.floor(n / 0x10000)
|
|
127
|
+
uint16.encode(state, n)
|
|
128
|
+
uint32.encode(state, r)
|
|
129
|
+
},
|
|
130
|
+
decode (state) {
|
|
131
|
+
if (state.end - state.start < 6) throw new Error('Out of bounds')
|
|
132
|
+
return uint16.decode(state) + 0x10000 * uint32.decode(state)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const uint56 = exports.uint56 = {
|
|
137
|
+
preencode (state, n) {
|
|
138
|
+
state.end += 7
|
|
139
|
+
},
|
|
140
|
+
encode (state, n) {
|
|
141
|
+
const r = Math.floor(n / 0x1000000)
|
|
142
|
+
uint24.encode(state, n)
|
|
143
|
+
uint32.encode(state, r)
|
|
144
|
+
},
|
|
145
|
+
decode (state) {
|
|
146
|
+
if (state.end - state.start < 7) throw new Error('Out of bounds')
|
|
147
|
+
return uint24.decode(state) + 0x1000000 * uint32.decode(state)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
106
151
|
const uint64 = exports.uint64 = {
|
|
107
152
|
preencode (state, n) {
|
|
108
153
|
state.end += 8
|
|
109
154
|
},
|
|
110
155
|
encode (state, n) {
|
|
111
|
-
const r = Math.floor(n /
|
|
156
|
+
const r = Math.floor(n / 0x100000000)
|
|
112
157
|
uint32.encode(state, n)
|
|
113
158
|
uint32.encode(state, r)
|
|
114
159
|
},
|
|
115
160
|
decode (state) {
|
|
116
161
|
if (state.end - state.start < 8) throw new Error('Out of bounds')
|
|
117
|
-
return uint32.decode(state) +
|
|
162
|
+
return uint32.decode(state) + 0x100000000 * uint32.decode(state)
|
|
118
163
|
}
|
|
119
164
|
}
|
|
120
165
|
|
|
@@ -123,8 +168,13 @@ exports.int8 = zigZag(uint8)
|
|
|
123
168
|
exports.int16 = zigZag(uint16)
|
|
124
169
|
exports.int24 = zigZag(uint24)
|
|
125
170
|
exports.int32 = zigZag(uint32)
|
|
171
|
+
exports.int40 = zigZag(uint40)
|
|
172
|
+
exports.int48 = zigZag(uint48)
|
|
173
|
+
exports.int56 = zigZag(uint56)
|
|
126
174
|
exports.int64 = zigZag(uint64)
|
|
127
175
|
|
|
176
|
+
exports.lexint = require('./lexint')
|
|
177
|
+
|
|
128
178
|
exports.float32 = {
|
|
129
179
|
preencode (state, n) {
|
|
130
180
|
state.end += 4
|
|
@@ -173,19 +223,18 @@ exports.buffer = {
|
|
|
173
223
|
decode (state) {
|
|
174
224
|
const len = uint.decode(state)
|
|
175
225
|
if (len === 0) return null
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return b
|
|
226
|
+
if (state.end - state.start < len) throw new Error('Out of bounds')
|
|
227
|
+
return state.buffer.subarray(state.start, (state.start += len))
|
|
179
228
|
}
|
|
180
229
|
}
|
|
181
230
|
|
|
182
231
|
const raw = exports.raw = {
|
|
183
232
|
preencode (state, b) {
|
|
184
|
-
state.end += b.
|
|
233
|
+
state.end += b.byteLength
|
|
185
234
|
},
|
|
186
235
|
encode (state, b) {
|
|
187
236
|
state.buffer.set(b, state.start)
|
|
188
|
-
state.start += b.
|
|
237
|
+
state.start += b.byteLength
|
|
189
238
|
},
|
|
190
239
|
decode (state) {
|
|
191
240
|
const b = state.buffer.subarray(state.start, state.end)
|
|
@@ -237,26 +286,33 @@ exports.int32array = typedarray(Int32Array, b4a.swap32)
|
|
|
237
286
|
exports.float32array = typedarray(Float32Array, b4a.swap32)
|
|
238
287
|
exports.float64array = typedarray(Float64Array, b4a.swap64)
|
|
239
288
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
289
|
+
function string (encoding) {
|
|
290
|
+
return {
|
|
291
|
+
preencode (state, s) {
|
|
292
|
+
const len = b4a.byteLength(s, encoding)
|
|
293
|
+
uint.preencode(state, len)
|
|
294
|
+
state.end += len
|
|
295
|
+
},
|
|
296
|
+
encode (state, s) {
|
|
297
|
+
const len = b4a.byteLength(s, encoding)
|
|
298
|
+
uint.encode(state, len)
|
|
299
|
+
b4a.write(state.buffer, s, state.start, encoding)
|
|
300
|
+
state.start += len
|
|
301
|
+
},
|
|
302
|
+
decode (state) {
|
|
303
|
+
const len = uint.decode(state)
|
|
304
|
+
if (state.end - state.start < len) throw new Error('Out of bounds')
|
|
305
|
+
return b4a.toString(state.buffer, encoding, state.start, (state.start += len))
|
|
306
|
+
}
|
|
257
307
|
}
|
|
258
308
|
}
|
|
259
309
|
|
|
310
|
+
const utf8 = exports.string = exports.utf8 = string('utf-8')
|
|
311
|
+
exports.ascii = string('ascii')
|
|
312
|
+
exports.hex = string('hex')
|
|
313
|
+
exports.base64 = string('base64')
|
|
314
|
+
exports.ucs2 = exports.utf16le = string('utf16le')
|
|
315
|
+
|
|
260
316
|
exports.bool = {
|
|
261
317
|
preencode (state, b) {
|
|
262
318
|
state.end++
|
|
@@ -280,9 +336,8 @@ const fixed = exports.fixed = function fixed (n) {
|
|
|
280
336
|
state.start += n
|
|
281
337
|
},
|
|
282
338
|
decode (state) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
return b
|
|
339
|
+
if (state.end - state.start < n) throw new Error('Out of bounds')
|
|
340
|
+
return state.buffer.subarray(state.start, (state.start += n))
|
|
286
341
|
}
|
|
287
342
|
}
|
|
288
343
|
}
|
|
@@ -314,7 +369,7 @@ exports.array = function array (enc) {
|
|
|
314
369
|
},
|
|
315
370
|
decode (state) {
|
|
316
371
|
const len = uint.decode(state)
|
|
317
|
-
if (len >
|
|
372
|
+
if (len > 0x100000) throw new Error('Array is too big')
|
|
318
373
|
const arr = new Array(len)
|
|
319
374
|
for (let i = 0; i < len; i++) arr[i] = enc.decode(state)
|
|
320
375
|
return arr
|
|
@@ -322,6 +377,30 @@ exports.array = function array (enc) {
|
|
|
322
377
|
}
|
|
323
378
|
}
|
|
324
379
|
|
|
380
|
+
exports.json = {
|
|
381
|
+
preencode (state, v) {
|
|
382
|
+
utf8.preencode(state, JSON.stringify(v))
|
|
383
|
+
},
|
|
384
|
+
encode (state, v) {
|
|
385
|
+
utf8.encode(state, JSON.stringify(v))
|
|
386
|
+
},
|
|
387
|
+
decode (state) {
|
|
388
|
+
return JSON.parse(utf8.decode(state))
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
exports.ndjson = {
|
|
393
|
+
preencode (state, v) {
|
|
394
|
+
utf8.preencode(state, JSON.stringify(v) + '\n')
|
|
395
|
+
},
|
|
396
|
+
encode (state, v) {
|
|
397
|
+
utf8.encode(state, JSON.stringify(v) + '\n')
|
|
398
|
+
},
|
|
399
|
+
decode (state) {
|
|
400
|
+
return JSON.parse(utf8.decode(state))
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
325
404
|
exports.from = function from (enc) {
|
|
326
405
|
if (enc.preencode) return enc
|
|
327
406
|
if (enc.encodingLength) return fromAbstractEncoder(enc)
|
|
@@ -336,7 +415,7 @@ function fromCodec (enc) {
|
|
|
336
415
|
preencode (state, m) {
|
|
337
416
|
tmpM = m
|
|
338
417
|
tmpBuf = enc.encode(m)
|
|
339
|
-
state.end += tmpBuf.
|
|
418
|
+
state.end += tmpBuf.byteLength
|
|
340
419
|
},
|
|
341
420
|
encode (state, m) {
|
|
342
421
|
raw.encode(state, m === tmpM ? tmpBuf : enc.encode(m))
|
package/lexint.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
preencode,
|
|
3
|
+
encode,
|
|
4
|
+
decode
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function preencode (state, num) {
|
|
8
|
+
if (num < 251) {
|
|
9
|
+
state.end++
|
|
10
|
+
} else if (num < 256) {
|
|
11
|
+
state.end += 2
|
|
12
|
+
} else if (num < 0x10000) {
|
|
13
|
+
state.end += 3
|
|
14
|
+
} else if (num < 0x1000000) {
|
|
15
|
+
state.end += 4
|
|
16
|
+
} else if (num < 0x100000000) {
|
|
17
|
+
state.end += 5
|
|
18
|
+
} else {
|
|
19
|
+
state.end++
|
|
20
|
+
const exp = Math.floor(Math.log(num) / Math.log(2)) - 32
|
|
21
|
+
preencode(state, exp)
|
|
22
|
+
state.end += 6
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function encode (state, num) {
|
|
27
|
+
const max = 251
|
|
28
|
+
const x = num - max
|
|
29
|
+
|
|
30
|
+
if (num < max) {
|
|
31
|
+
state.buffer[state.start++] = num
|
|
32
|
+
} else if (num < 256) {
|
|
33
|
+
state.buffer[state.start++] = max
|
|
34
|
+
state.buffer[state.start++] = x
|
|
35
|
+
} else if (num < 0x10000) {
|
|
36
|
+
state.buffer[state.start++] = max + 1
|
|
37
|
+
state.buffer[state.start++] = x >> 8 & 0xff
|
|
38
|
+
state.buffer[state.start++] = x & 0xff
|
|
39
|
+
} else if (num < 0x1000000) {
|
|
40
|
+
state.buffer[state.start++] = max + 2
|
|
41
|
+
state.buffer[state.start++] = x >> 16
|
|
42
|
+
state.buffer[state.start++] = x >> 8 & 0xff
|
|
43
|
+
state.buffer[state.start++] = x & 0xff
|
|
44
|
+
} else if (num < 0x100000000) {
|
|
45
|
+
state.buffer[state.start++] = max + 3
|
|
46
|
+
state.buffer[state.start++] = x >> 24
|
|
47
|
+
state.buffer[state.start++] = x >> 16 & 0xff
|
|
48
|
+
state.buffer[state.start++] = x >> 8 & 0xff
|
|
49
|
+
state.buffer[state.start++] = x & 0xff
|
|
50
|
+
} else {
|
|
51
|
+
// need to use Math here as bitwise ops are 32 bit
|
|
52
|
+
const exp = Math.floor(Math.log(x) / Math.log(2)) - 32
|
|
53
|
+
state.buffer[state.start++] = 0xff
|
|
54
|
+
|
|
55
|
+
encode(state, exp)
|
|
56
|
+
const rem = x / Math.pow(2, exp - 11)
|
|
57
|
+
|
|
58
|
+
for (let i = 5; i >= 0; i--) {
|
|
59
|
+
state.buffer[state.start++] = rem / Math.pow(2, 8 * i) & 0xff
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function decode (state) {
|
|
65
|
+
const max = 251
|
|
66
|
+
|
|
67
|
+
if (state.end - state.start < 1) throw new Error('Out of bounds')
|
|
68
|
+
|
|
69
|
+
const flag = state.buffer[state.start++]
|
|
70
|
+
|
|
71
|
+
if (flag < max) return flag
|
|
72
|
+
|
|
73
|
+
if (state.end - state.start < flag - max + 1) {
|
|
74
|
+
throw new Error('Out of bounds.')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (flag < 252) {
|
|
78
|
+
return state.buffer[state.start++] +
|
|
79
|
+
max
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (flag < 253) {
|
|
83
|
+
return (state.buffer[state.start++] << 8) +
|
|
84
|
+
state.buffer[state.start++] +
|
|
85
|
+
max
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (flag < 254) {
|
|
89
|
+
return (state.buffer[state.start++] << 16) +
|
|
90
|
+
(state.buffer[state.start++] << 8) +
|
|
91
|
+
state.buffer[state.start++] +
|
|
92
|
+
max
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// << 24 result may be interpreted as negative
|
|
96
|
+
if (flag < 255) {
|
|
97
|
+
return (state.buffer[state.start++] * 0x1000000) +
|
|
98
|
+
(state.buffer[state.start++] << 16) +
|
|
99
|
+
(state.buffer[state.start++] << 8) +
|
|
100
|
+
state.buffer[state.start++] +
|
|
101
|
+
max
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const exp = decode(state)
|
|
105
|
+
|
|
106
|
+
if (state.end - state.start < 6) throw new Error('Out of bounds')
|
|
107
|
+
|
|
108
|
+
let rem = 0
|
|
109
|
+
for (let i = 5; i >= 0; i--) {
|
|
110
|
+
rem += state.buffer[state.start++] * Math.pow(2, 8 * i)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (rem * Math.pow(2, exp - 11)) + max
|
|
114
|
+
}
|
package/package.json
CHANGED
package/test.js
CHANGED
|
@@ -170,9 +170,6 @@ tape('buffer', function (t) {
|
|
|
170
170
|
t.is(state.start, state.end)
|
|
171
171
|
|
|
172
172
|
t.exception(() => enc.buffer.decode(state))
|
|
173
|
-
state.buffer = state.buffer.subarray(0, 8)
|
|
174
|
-
state.start = 3
|
|
175
|
-
t.exception(() => enc.buffer.decode(state), 'partial throws')
|
|
176
173
|
})
|
|
177
174
|
|
|
178
175
|
tape('raw', function (t) {
|
|
@@ -410,3 +407,184 @@ tape('array', function (t) {
|
|
|
410
407
|
|
|
411
408
|
t.exception(() => arr.decode(state))
|
|
412
409
|
})
|
|
410
|
+
|
|
411
|
+
tape('json', function (t) {
|
|
412
|
+
const state = enc.state()
|
|
413
|
+
|
|
414
|
+
enc.json.preencode(state, { a: 1, b: 2 })
|
|
415
|
+
t.alike(state, { start: 0, end: 14, buffer: null })
|
|
416
|
+
|
|
417
|
+
state.buffer = Buffer.alloc(state.end)
|
|
418
|
+
enc.json.encode(state, { a: 1, b: 2 })
|
|
419
|
+
t.alike(state, {
|
|
420
|
+
start: 14,
|
|
421
|
+
end: 14,
|
|
422
|
+
buffer: Buffer.concat([
|
|
423
|
+
Buffer.from([13]),
|
|
424
|
+
Buffer.from('{"a":1,"b":2}')
|
|
425
|
+
])
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
state.start = 0
|
|
429
|
+
t.alike(enc.json.decode(state), { a: 1, b: 2 })
|
|
430
|
+
|
|
431
|
+
t.exception(() => enc.json.decode(state))
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
tape('lexint: big numbers', function (t) {
|
|
435
|
+
t.plan(1)
|
|
436
|
+
|
|
437
|
+
let prev = enc.encode(enc.lexint, 0)
|
|
438
|
+
|
|
439
|
+
let n
|
|
440
|
+
let skip = 1
|
|
441
|
+
|
|
442
|
+
for (n = 1; n < Number.MAX_VALUE; n += skip) {
|
|
443
|
+
const cur = enc.encode(enc.lexint, n)
|
|
444
|
+
if (Buffer.compare(cur, prev) < 1) break
|
|
445
|
+
prev = cur
|
|
446
|
+
skip = 1 + Math.pow(245, Math.ceil(Math.log(n) / Math.log(256)))
|
|
447
|
+
}
|
|
448
|
+
t.is(n, Infinity)
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
tape('lexint: range precision', function (t) {
|
|
452
|
+
t.plan(2)
|
|
453
|
+
const a = 1e55
|
|
454
|
+
const b = 1.0000000000001e55
|
|
455
|
+
const ha = enc.encode(enc.lexint, a).toString('hex')
|
|
456
|
+
const hb = enc.encode(enc.lexint, b).toString('hex')
|
|
457
|
+
t.not(a, b)
|
|
458
|
+
t.not(ha, hb)
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
tape('lexint: range precision', function (t) {
|
|
462
|
+
let prev = enc.encode(enc.lexint, 0)
|
|
463
|
+
const skip = 0.000000001e55
|
|
464
|
+
for (let i = 0, n = 1e55; i < 1000; n = 1e55 + skip * ++i) {
|
|
465
|
+
const cur = enc.encode(enc.lexint, n)
|
|
466
|
+
if (Buffer.compare(cur, prev) < 1) t.fail('cur <= prev')
|
|
467
|
+
prev = cur
|
|
468
|
+
}
|
|
469
|
+
t.ok(true)
|
|
470
|
+
t.end()
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
tape('lexint: small numbers', function (t) {
|
|
474
|
+
let prev = enc.encode(enc.lexint, 0)
|
|
475
|
+
for (let n = 1; n < 256 * 256 * 16; n++) {
|
|
476
|
+
const cur = enc.encode(enc.lexint, n)
|
|
477
|
+
if (Buffer.compare(cur, prev) < 1) t.fail('cur <= prev')
|
|
478
|
+
prev = cur
|
|
479
|
+
}
|
|
480
|
+
t.ok(true)
|
|
481
|
+
t.end()
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
tape('lexint: throws', function (t) {
|
|
485
|
+
t.exception(() => {
|
|
486
|
+
enc.decode(enc.lexint, Buffer.alloc(1, 251))
|
|
487
|
+
})
|
|
488
|
+
|
|
489
|
+
let num = 252
|
|
490
|
+
|
|
491
|
+
const state = {
|
|
492
|
+
start: 0,
|
|
493
|
+
end: 0,
|
|
494
|
+
buffer: null
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
enc.lexint.preencode(state, num)
|
|
498
|
+
state.buffer = Buffer.alloc(state.end - state.start)
|
|
499
|
+
enc.lexint.encode(state, num)
|
|
500
|
+
|
|
501
|
+
t.exception(() => {
|
|
502
|
+
enc.decode(enc.lexint, state.buffer.subarray(0, state.buffer.byteLength - 2))
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
num <<= 8
|
|
506
|
+
|
|
507
|
+
state.start = 0
|
|
508
|
+
state.end = 0
|
|
509
|
+
state.buffer = null
|
|
510
|
+
|
|
511
|
+
enc.lexint.preencode(state, num)
|
|
512
|
+
state.buffer = Buffer.alloc(state.end - state.start)
|
|
513
|
+
enc.lexint.encode(state, num)
|
|
514
|
+
|
|
515
|
+
t.exception(() => {
|
|
516
|
+
enc.decode(enc.lexint, state.buffer.subarray(0, state.buffer.byteLength - 2))
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
num <<= 8
|
|
520
|
+
|
|
521
|
+
state.start = 0
|
|
522
|
+
state.end = 0
|
|
523
|
+
state.buffer = null
|
|
524
|
+
|
|
525
|
+
enc.lexint.preencode(state, num)
|
|
526
|
+
state.buffer = Buffer.alloc(state.end - state.start)
|
|
527
|
+
enc.lexint.encode(state, num)
|
|
528
|
+
|
|
529
|
+
t.exception(() => {
|
|
530
|
+
enc.decode(enc.lexint, state.buffer.subarray(0, state.buffer.byteLength - 2))
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
num *= 256
|
|
534
|
+
|
|
535
|
+
state.start = 0
|
|
536
|
+
state.end = 0
|
|
537
|
+
state.buffer = null
|
|
538
|
+
|
|
539
|
+
enc.lexint.preencode(state, num)
|
|
540
|
+
state.buffer = Buffer.alloc(state.end - state.start)
|
|
541
|
+
enc.lexint.encode(state, num)
|
|
542
|
+
|
|
543
|
+
t.exception(() => {
|
|
544
|
+
enc.decode(enc.lexint, state.buffer.subarray(0, state.buffer.byteLength - 2))
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
num *= 256 * 256
|
|
548
|
+
|
|
549
|
+
state.start = 0
|
|
550
|
+
state.end = 0
|
|
551
|
+
state.buffer = null
|
|
552
|
+
|
|
553
|
+
enc.lexint.preencode(state, num)
|
|
554
|
+
state.buffer = Buffer.alloc(state.end - state.start)
|
|
555
|
+
enc.lexint.encode(state, num)
|
|
556
|
+
|
|
557
|
+
t.exception(() => {
|
|
558
|
+
enc.decode(enc.lexint, state.buffer.subarray(0, state.buffer.byteLength - 2))
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
t.end()
|
|
562
|
+
})
|
|
563
|
+
|
|
564
|
+
tape('lexint: unpack', function (t) {
|
|
565
|
+
let n
|
|
566
|
+
let skip = 1
|
|
567
|
+
|
|
568
|
+
for (n = 1; n < Number.MAX_VALUE; n += skip) {
|
|
569
|
+
const cur = enc.encode(enc.lexint, n)
|
|
570
|
+
compare(n, enc.decode(enc.lexint, cur))
|
|
571
|
+
skip = 1 + Math.pow(245, Math.ceil(Math.log(n) / Math.log(256)))
|
|
572
|
+
}
|
|
573
|
+
t.is(n, Infinity)
|
|
574
|
+
t.end()
|
|
575
|
+
|
|
576
|
+
function compare (a, b) {
|
|
577
|
+
const desc = a + ' !=~ ' + b
|
|
578
|
+
if (/e\+\d+$/.test(a) || /e\+\d+$/.test(b)) {
|
|
579
|
+
if (String(a).slice(0, 8) !== String(b).slice(0, 8) ||
|
|
580
|
+
/e\+(\d+)$/.exec(a)[1] !== /e\+(\d+)$/.exec(b)[1]) {
|
|
581
|
+
t.fail(desc)
|
|
582
|
+
}
|
|
583
|
+
} else {
|
|
584
|
+
if (String(a).slice(0, 8) !== String(b).slice(0, 8) ||
|
|
585
|
+
String(a).length !== String(b).length) {
|
|
586
|
+
t.fail(desc)
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
})
|