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.
Files changed (5) hide show
  1. package/README.md +14 -1
  2. package/index.js +115 -36
  3. package/lexint.js +114 -0
  4. package/package.json +1 -1
  5. 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([255]).buffer))[0] === 0xff
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++] * 256
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++] * 256 +
80
- state.buffer[state.start++] * 65536
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++] * 256 +
100
- state.buffer[state.start++] * 65536 +
101
- state.buffer[state.start++] * 16777216
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 / 4294967296)
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) + 4294967296 * 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
- const b = state.buffer.subarray(state.start, state.start += len)
177
- if (b.length !== len) throw new Error('Out of bounds')
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.length
233
+ state.end += b.byteLength
185
234
  },
186
235
  encode (state, b) {
187
236
  state.buffer.set(b, state.start)
188
- state.start += b.length
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
- exports.string = {
241
- preencode (state, s) {
242
- const len = b4a.byteLength(s)
243
- uint.preencode(state, len)
244
- state.end += len
245
- },
246
- encode (state, s) {
247
- const len = b4a.byteLength(s)
248
- uint.encode(state, len)
249
- b4a.write(state.buffer, s, state.start)
250
- state.start += len
251
- },
252
- decode (state) {
253
- const len = uint.decode(state)
254
- const s = b4a.toString(state.buffer, 'utf-8', state.start, state.start += len)
255
- if (b4a.byteLength(s) !== len || state.start > state.end) throw new Error('Out of bounds')
256
- return s
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
- const b = state.buffer.subarray(state.start, state.start += n)
284
- if (b.length !== n) throw new Error('Out of bounds')
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 > 1048576) throw new Error('Array is too big')
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.length
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compact-encoding",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "description": "A series of compact encoding schemes for building small and fast parsers and serializers",
5
5
  "main": "index.js",
6
6
  "dependencies": {
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
+ })