-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
713 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
const Benchmark = require('benchmark'); | ||
const toBase64 = require('../../lib').toBase64; | ||
const {bufferToUint8Array} = require('../../lib/util/buffers/bufferToUint8Array'); | ||
const {fromBase64, createFromBase64} = require('../../lib'); | ||
const {toByteArray} = require('base64-js'); | ||
const {decode: decodeJsBase64} = require('js-base64'); | ||
|
||
const fromBase642 = createFromBase64(); | ||
|
||
const generateBlob = (length) => { | ||
const uint8 = new Uint8Array(length); | ||
for (let i = 0; i < length; i++) { | ||
uint8[i] = Math.floor(Math.random() * 256); | ||
} | ||
return uint8; | ||
}; | ||
|
||
const str4 = toBase64(generateBlob(4)); | ||
const str8 = toBase64(generateBlob(8)); | ||
const str16 = toBase64(generateBlob(16)); | ||
const str24 = toBase64(generateBlob(24)); | ||
const str32 = toBase64(generateBlob(32)); | ||
const str64 = toBase64(generateBlob(64)); | ||
const str128 = toBase64(generateBlob(128)); | ||
const str256 = toBase64(generateBlob(256)); | ||
|
||
const suite = new Benchmark.Suite(); | ||
|
||
const encoders = [ | ||
{ | ||
name: `@jsonjoy.com/base64 fromBase64(str)`, | ||
decode: (str) => fromBase64(str), | ||
}, | ||
{ | ||
name: `@jsonjoy.com/base64 createFromBase64()(str)`, | ||
decode: (str) => fromBase642(str), | ||
}, | ||
{ | ||
name: `Buffer.from(str, 'base64')`, | ||
decode: (str) => bufferToUint8Array(Buffer.from(str, 'base64')), | ||
}, | ||
{ | ||
name: `base64-js`, | ||
decode: (str) => toByteArray(str), | ||
}, | ||
{ | ||
name: `js-base64`, | ||
decode: (str) => decodeJsBase64(str), | ||
}, | ||
]; | ||
|
||
for (const encoder of encoders) { | ||
// Warm up | ||
for (let i = 0; i < 100000; i++) { | ||
encoder.decode(str8); | ||
encoder.decode(str256); | ||
} | ||
suite.add(encoder.name, () => { | ||
encoder.decode(str4); | ||
encoder.decode(str8); | ||
encoder.decode(str16); | ||
encoder.decode(str24); | ||
encoder.decode(str32); | ||
encoder.decode(str64); | ||
encoder.decode(str128); | ||
encoder.decode(str256); | ||
}); | ||
} | ||
|
||
suite | ||
.on('cycle', function (event) { | ||
console.log(String(event.target) + `, ${Math.round(1000000000 / event.target.hz)} ns/op`); | ||
}) | ||
.on('complete', function () { | ||
console.log('Fastest is ' + this.filter('fastest').map('name')); | ||
}) | ||
.run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
const Benchmark = require('benchmark'); | ||
const {toBase64, createToBase64} = require('../../lib'); | ||
const {fromByteArray} = require('base64-js'); | ||
const {encode: encodeJsBase64} = require('js-base64'); | ||
|
||
const toBase64Native = createToBase64(); | ||
|
||
const generateBlob = (length) => { | ||
const uint8 = new Uint8Array(length); | ||
for (let i = 0; i < length; i++) { | ||
uint8[i] = Math.floor(Math.random() * 256); | ||
} | ||
return uint8; | ||
}; | ||
|
||
const arr8 = generateBlob(9); | ||
const arr16 = generateBlob(17); | ||
const arr32 = generateBlob(33); | ||
const arr64 = generateBlob(65); | ||
const arr128 = generateBlob(127); | ||
const arr256 = generateBlob(257); | ||
const arr512 = generateBlob(513); | ||
const arr1024 = generateBlob(1025); | ||
|
||
// fast-base64-encode | ||
const table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); | ||
const fastBase64Encode = (source) => { | ||
let out = ''; | ||
let tmp; | ||
const length = source.byteLength; | ||
const extraLength = length % 3; | ||
const baseLength = length - extraLength; | ||
for (let i = 0; i < baseLength; i += 3) { | ||
tmp = ((source[i] & 0xff) << 16) | ((source[i + 1] & 0xff) << 8) | (source[i + 2] & 0xff); | ||
out += table[(tmp >> 18) & 0x3f] + table[(tmp >> 12) & 0x3f] + table[(tmp >> 6) & 0x3f] + table[tmp & 0x3f]; | ||
} | ||
if (extraLength) { | ||
if (extraLength === 1) { | ||
tmp = source[baseLength] & 0xff; | ||
out += table[tmp >> 2] + table[(tmp << 4) & 0x3f] + '=='; | ||
} else { | ||
tmp = ((source[baseLength] & 0xff) << 8) | (source[baseLength + 1] & 0xff); | ||
out += table[tmp >> 10] + table[(tmp >> 4) & 0x3f] + table[(tmp << 2) & 0x3f] + '='; | ||
} | ||
} | ||
return out; | ||
}; | ||
|
||
const suite = new Benchmark.Suite(); | ||
|
||
const encoders = [ | ||
{ | ||
name: `@jsonjoy.com/base64 toBase64(uint8)`, | ||
encode: (uint8) => toBase64(uint8), | ||
}, | ||
{ | ||
name: `@jsonjoy.com/base64 createToBase64()(uint8)`, | ||
encode: (uint8) => toBase64Native(uint8, uint8.length), | ||
}, | ||
{ | ||
name: `js-base64`, | ||
encode: (uint8) => encodeJsBase64(uint8), | ||
}, | ||
{ | ||
name: `fast-base64-encode`, | ||
encode: (uint8) => fastBase64Encode(uint8), | ||
}, | ||
{ | ||
name: `base64-js`, | ||
encode: (uint8) => fromByteArray(uint8), | ||
}, | ||
{ | ||
name: `Buffer.from(uint8).toString('base64');`, | ||
encode: (uint8) => Buffer.from(uint8).toString('base64'), | ||
}, | ||
]; | ||
|
||
for (const encoder of encoders) { | ||
suite.add(encoder.name, () => { | ||
encoder.encode(arr8); | ||
encoder.encode(arr16); | ||
encoder.encode(arr32); | ||
encoder.encode(arr64); | ||
encoder.encode(arr128); | ||
// encoder.encode(arr256); | ||
// encoder.encode(arr512); | ||
// encoder.encode(arr1024); | ||
}); | ||
} | ||
|
||
suite | ||
.on('cycle', function (event) { | ||
console.log(String(event.target) + `, ${Math.round(1000000000 / event.target.hz)} ns/op`); | ||
}) | ||
.on('complete', function () { | ||
console.log('Fastest is ' + this.filter('fastest').map('name')); | ||
}) | ||
.run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import {toBase64} from '../toBase64'; | ||
import {fromBase64Url} from '../fromBase64Url'; | ||
|
||
const generateBlob = (): Uint8Array => { | ||
const length = Math.floor(Math.random() * 100); | ||
const uint8 = new Uint8Array(length); | ||
for (let i = 0; i < length; i++) { | ||
uint8[i] = Math.floor(Math.random() * 256); | ||
} | ||
return uint8; | ||
}; | ||
|
||
test('works', () => { | ||
for (let i = 0; i < 100; i++) { | ||
const blob = generateBlob(); | ||
const encoded = toBase64(blob).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); | ||
const decoded2 = fromBase64Url(encoded); | ||
expect(decoded2).toEqual(blob); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import {toBase64Bin} from '../toBase64Bin'; | ||
import {fromBase64Bin} from '../fromBase64Bin'; | ||
|
||
const generateBlob = (): Uint8Array => { | ||
const length = Math.floor(Math.random() * 100); | ||
const uint8 = new Uint8Array(length); | ||
for (let i = 0; i < length; i++) { | ||
uint8[i] = Math.floor(Math.random() * 256); | ||
} | ||
return uint8; | ||
}; | ||
|
||
test('works', () => { | ||
for (let i = 0; i < 100; i++) { | ||
const blob = generateBlob(); | ||
const dest = new Uint8Array(blob.length * 4); | ||
const length = toBase64Bin(blob, 0, blob.length, new DataView(dest.buffer), 0); | ||
const encoded = dest.subarray(0, length); | ||
const view = new DataView(encoded.buffer); | ||
const decoded = fromBase64Bin(view, 0, encoded.length); | ||
let padding = 0; | ||
if (encoded.length > 0 && view.getUint8(encoded.length - 1) === 0x3d) padding++; | ||
if (encoded.length > 1 && view.getUint8(encoded.length - 2) === 0x3d) padding++; | ||
const decoded2 = fromBase64Bin(view, 0, encoded.length - padding); | ||
// console.log('blob', blob); | ||
// console.log('encoded', encoded); | ||
// console.log('decoded', decoded); | ||
expect(decoded).toEqual(blob); | ||
expect(decoded2).toEqual(blob); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import {toBase64} from '../toBase64'; | ||
import {fromBase64} from '../fromBase64'; | ||
import {createFromBase64} from '../createFromBase64'; | ||
|
||
const fromBase64_2 = createFromBase64(); | ||
|
||
const generateBlob = (): Uint8Array => { | ||
const length = Math.floor(Math.random() * 100); | ||
const uint8 = new Uint8Array(length); | ||
for (let i = 0; i < length; i++) { | ||
uint8[i] = Math.floor(Math.random() * 256); | ||
} | ||
return uint8; | ||
}; | ||
|
||
test('works', () => { | ||
for (let i = 0; i < 100; i++) { | ||
const blob = generateBlob(); | ||
const encoded = toBase64(blob); | ||
const decoded1 = fromBase64_2(encoded); | ||
const decoded2 = fromBase64(encoded); | ||
expect(decoded1).toEqual(blob); | ||
expect(decoded2).toEqual(blob); | ||
} | ||
}); | ||
|
||
test('handles invalid values', () => { | ||
for (let i = 0; i < 100; i++) { | ||
const blob = generateBlob(); | ||
const encoded = toBase64(blob); | ||
expect(() => fromBase64_2(encoded + '!!!!')).toThrowError(new Error('INVALID_BASE64_STRING')); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import {toBase64Url} from '../toBase64Url'; | ||
|
||
const generateBlob = (): Uint8Array => { | ||
const length = Math.floor(Math.random() * 100) + 1; | ||
const uint8 = new Uint8Array(length); | ||
for (let i = 0; i < length; i++) { | ||
uint8[i] = Math.floor(Math.random() * 256); | ||
} | ||
return uint8; | ||
}; | ||
|
||
test('works', () => { | ||
for (let i = 0; i < 100; i++) { | ||
const blob = generateBlob(); | ||
const expected = Buffer.from(blob).toString('base64'); | ||
const base64url = toBase64Url(blob, blob.length); | ||
let encoded = base64url.replace(/-/g, '+').replace(/_/g, '/'); | ||
const mod = encoded.length % 4; | ||
if (mod === 2) encoded += '=='; | ||
else if (mod === 3) encoded += '='; | ||
expect(encoded).toEqual(expected); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import {toBase64} from '../toBase64'; | ||
import {createToBase64Bin} from '../createToBase64Bin'; | ||
import {createToBase64BinUint8} from '../createToBase64BinUint8'; | ||
import {bufferToUint8Array} from '../util/buffers/bufferToUint8Array'; | ||
import {copy} from '../util/buffers/copy'; | ||
|
||
const encode = createToBase64Bin('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', '='); | ||
const encodeUint8 = createToBase64BinUint8('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', '='); | ||
const encodeNoPadding = createToBase64Bin('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'); | ||
|
||
const generateBlob = (): Uint8Array => { | ||
const length = Math.floor(Math.random() * 100) + 1; | ||
const uint8 = new Uint8Array(length); | ||
for (let i = 0; i < length; i++) { | ||
uint8[i] = Math.floor(Math.random() * 256); | ||
} | ||
return uint8; | ||
}; | ||
|
||
test('works', () => { | ||
for (let i = 0; i < 100; i++) { | ||
const blob = generateBlob(); | ||
const result = bufferToUint8Array(Buffer.from(toBase64(blob))); | ||
const binWithBuffer = new Uint8Array(result.length + 3); | ||
encode(blob, 0, blob.length, new DataView(binWithBuffer.buffer), 3); | ||
const dupe = copy(blob); | ||
encodeNoPadding(blob, 0, blob.length, new DataView(binWithBuffer.buffer), 3); | ||
expect(dupe).toEqual(blob); | ||
const dupe2 = copy(blob); | ||
encodeUint8(blob, 0, blob.length, binWithBuffer, 3); | ||
expect(dupe2).toEqual(blob); | ||
const encoded = binWithBuffer.subarray(3); | ||
// console.log(result); | ||
// console.log(binWithBuffer); | ||
// console.log(encoded); | ||
expect(result).toEqual(encoded); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import {toBase64} from '../toBase64'; | ||
import {createToBase64} from '../createToBase64'; | ||
|
||
const encode2 = createToBase64(); | ||
|
||
const generateBlob = (): Uint8Array => { | ||
const length = Math.floor(Math.random() * 100) + 1; | ||
const uint8 = new Uint8Array(length); | ||
for (let i = 0; i < length; i++) { | ||
uint8[i] = Math.floor(Math.random() * 256); | ||
} | ||
return uint8; | ||
}; | ||
|
||
test('works', () => { | ||
for (let i = 0; i < 100; i++) { | ||
const blob = generateBlob(); | ||
const result = toBase64(blob); | ||
const result2 = encode2(blob, blob.byteLength); | ||
const expected = Buffer.from(blob).toString('base64'); | ||
expect(result).toBe(expected); | ||
expect(result2).toBe(expected); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Jest setup. | ||
process.env.JEST = true; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; | ||
export const hasBuffer = typeof Buffer === 'function' && typeof Buffer.from === 'function'; |
Oops, something went wrong.