binarius
Advanced tools
Comparing version 0.0.1 to 0.0.2
128
benchmark.js
@@ -0,21 +1,59 @@ | ||
/* eslint no-unused-vars: 0 */ | ||
const Benchmark = require('benchmark'); | ||
const binarius = require('./index'); | ||
const BinariusNumber = binarius([{ | ||
a: 8, b: 8, c: 8, d: 8, | ||
}]); // size 32 | ||
const BinariusBigInt = binarius([{ | ||
a: 8, b: 7, c: 8, d: 10, | ||
}]); // size 33 | ||
const BinariusNumber = binarius([ | ||
{ name: 'a', size: 8 }, | ||
{ name: 'b', size: 8 }, | ||
{ name: 'c', size: 8 }, | ||
{ name: 'd', size: 8 }, | ||
]); // size 32 | ||
const BinariusBigInt = binarius([ | ||
{ name: 'a', size: 8 }, | ||
{ name: 'b', size: 8 }, | ||
{ name: 'c', size: 8 }, | ||
{ name: 'd', size: 9 }, | ||
]); // size 33 | ||
const randomArray = () => new Array(4).fill((Math.random() * 100) | 0); | ||
const BinariusBits = binarius(['a', 'b', 'c', 'd']); | ||
const constructionSuite = new Benchmark.Suite('Construction:'); | ||
class Bits { | ||
static get(data, index) { | ||
return (data >> index) & 1; | ||
} | ||
constructionSuite.add('Number', () => { | ||
const result = new BinariusNumber(randomArray()); | ||
static set(data, index, value = 1) { | ||
return (data & ~(1 << index)) | (value << index); | ||
} | ||
static toggle(data, index) { | ||
return data ^ (1 << index); | ||
} | ||
} | ||
const randomArray = new Array(4).fill(1).map(() => (Math.random() * 100) | 0); | ||
const constructionSuite = new Benchmark.Suite('Construct:'); | ||
constructionSuite.add('Binarius Number', () => { | ||
const result = new BinariusNumber(randomArray); | ||
}) | ||
.add('Binarius BigInt', () => { | ||
const result = new BinariusBigInt(randomArray); | ||
}) | ||
.on('start', (event) => { | ||
console.log(event.currentTarget.name); | ||
}) | ||
.on('cycle', (event) => { | ||
console.log(` ${String(event.target)}`); | ||
}) | ||
.run(); | ||
const getSuite = new Benchmark.Suite('Get Field:'); | ||
getSuite.add('Binarius Number', () => { | ||
const result = new BinariusNumber(randomArray); | ||
result.get('a'); | ||
}) | ||
.add('BigInt', () => { | ||
const result = new BinariusBigInt(randomArray()); | ||
.add('Binarius BigInt', () => { | ||
const result = new BinariusBigInt(randomArray); | ||
result.get('a'); | ||
@@ -29,6 +67,66 @@ }) | ||
}) | ||
.on('complete', (event) => { | ||
console.log(` Fastest is ${event.currentTarget.filter('fastest').map('name')}`); | ||
console.log(''); | ||
.run(); | ||
const setSuite = new Benchmark.Suite('Set Field:'); | ||
setSuite.add('Binarius Number', () => { | ||
const result = new BinariusNumber(randomArray); | ||
result.set('a', (Math.random() * 100) | 0); | ||
}) | ||
.add('Binarius BigInt', () => { | ||
const result = new BinariusBigInt(randomArray); | ||
result.set('a', (Math.random() * 100) | 0); | ||
}) | ||
.on('start', (event) => { | ||
console.log(event.currentTarget.name); | ||
}) | ||
.on('cycle', (event) => { | ||
console.log(` ${String(event.target)}`); | ||
}) | ||
.run(); | ||
const constructionBitsSuite = new Benchmark.Suite('Construct for bit flags:'); | ||
constructionBitsSuite.add('Binarius', () => { | ||
const result = new BinariusBits([1, 0, 1, 0]); | ||
}) | ||
.add('parseInt', () => { | ||
const result = 0b1010; | ||
}) | ||
.on('start', (event) => { | ||
console.log(event.currentTarget.name); | ||
}) | ||
.on('cycle', (event) => { | ||
console.log(` ${String(event.target)}`); | ||
}) | ||
.run(); | ||
const getBitsSuite = new Benchmark.Suite('Get bit flag:'); | ||
getBitsSuite.add('Binarius', () => { | ||
const result = new BinariusBits((Math.random() * 15) | 0); | ||
result.get('a'); | ||
}) | ||
.add('Bits', () => { | ||
Bits.get((Math.random() * 15) | 0, 3); | ||
}) | ||
.on('start', (event) => { | ||
console.log(event.currentTarget.name); | ||
}) | ||
.on('cycle', (event) => { | ||
console.log(` ${String(event.target)}`); | ||
}) | ||
.run(); | ||
const setBitsSuite = new Benchmark.Suite('Set bit flag:'); | ||
setBitsSuite.add('Binarius', () => { | ||
const result = new BinariusBits((Math.random() * 15) | 0); | ||
result.set('a'); | ||
}) | ||
.add('Bits', () => { | ||
Bits.set((Math.random() * 15) | 0, 3); | ||
}) | ||
.on('start', (event) => { | ||
console.log(event.currentTarget.name); | ||
}) | ||
.on('cycle', (event) => { | ||
console.log(` ${String(event.target)}`); | ||
}) | ||
.run(); |
122
index.js
@@ -0,1 +1,15 @@ | ||
// fallback to using Number if BigInt is not available | ||
const BigInt = (global || window).BigInt || Number; | ||
/** | ||
* @typedef {Object} FieldDescription | ||
* @property {string} name field name | ||
* @property {number} size size of the field in bits | ||
*/ | ||
/** | ||
* @private | ||
* @param {Array<FieldDescription>|Array<string>} fields | ||
* @returns {Array<FieldDescription>} | ||
*/ | ||
function normalizeFields(fields) { | ||
@@ -7,2 +21,8 @@ return typeof fields[0] === 'string' | ||
/** | ||
* @private | ||
* @param {Array<FieldDescription>} fields | ||
* @param {number} index | ||
* @returns {number} | ||
*/ | ||
function getOffset(fields, index) { | ||
@@ -16,2 +36,9 @@ let offset = 0; | ||
/** | ||
* @private | ||
* @param {Array<FieldDescription>} fields | ||
* @param {number} base | ||
* @param {number} one | ||
* @returns {Array<Object<string, number>>} | ||
*/ | ||
function getMasks(fields, base, one) { | ||
@@ -34,4 +61,24 @@ const masks = {}; | ||
module.exports = function (schema) { | ||
/** | ||
* Creates a new class for storing data in numbers according to a given schema. | ||
* | ||
* @param {Array<FieldDescription>|Array<string>} schema the layout of data being stored | ||
* @returns {Binarius} a new class tailored to the specified data schema | ||
* @example | ||
* | ||
* const Person = BinariusFactory([{ name: 'age', size: 7}, { name: 'gender', size: 1}]); | ||
* const SettingsFlags = BinariusFactory(['notify', 'premium', 'moderator']) | ||
*/ | ||
function BinariusFactory(schema) { | ||
const Binarius = class { | ||
/** | ||
* @param {number|Array<number>} data | ||
* @example | ||
* | ||
* const Person = BinariusFactory([{ name: 'age', size: 7}, { name: 'gender', size: 1}]); | ||
* new Person([20, 1]).value | ||
* //=> 41 | ||
* new Person(41).value | ||
* //=> 41 | ||
*/ | ||
constructor(data) { | ||
@@ -47,2 +94,16 @@ const { zero, fields } = this.constructor; | ||
/** | ||
* Returns the value of a given field. | ||
* | ||
* @param {string} field name of the field | ||
* @returns {number} value value of the field | ||
* @example | ||
* | ||
* const Person = BinariusFactory([{ name: 'age', size: 7}, { name: 'gender', size: 1}]); | ||
* const person = new Person([20, 1]); | ||
* person.get('age'); | ||
* //=> 20 | ||
* person.get('gender'); | ||
* //=> 1 | ||
*/ | ||
get(field) { | ||
@@ -54,2 +115,17 @@ const { offsets, masks } = this.constructor; | ||
/** | ||
* Stores a given value in a field. | ||
* | ||
* @param {string} field name of the field | ||
* @param {number} value value of the field | ||
* @returns {Binarius} the instance | ||
* @example | ||
* | ||
* const Person = BinariusFactory([{ name: 'age', size: 7}, { name: 'gender', size: 1}]); | ||
* const person = new Person([20, 1]); | ||
* person.get('age'); | ||
* //=> 20 | ||
* person.set('age', 30).get('age'); | ||
* //=> 30 | ||
*/ | ||
set(field, value = this.constructor.one) { | ||
@@ -62,11 +138,32 @@ const { offsets, one, masks } = this.constructor; | ||
/** | ||
* Checks if an instance has all the specified fields set to 1. Useful for bit flags. | ||
* | ||
* @param {...string} fields names of the fields to check | ||
* @returns {boolean} whether all the specified fields are set in the instance | ||
* @example | ||
* | ||
* const SettingsFlags = BinariusFactory(['notify', 'premium', 'moderator']); | ||
* const settings = SettingsFlags([1, 0, 1]); | ||
* settings.has('notify', 'moderator'); | ||
* //=> true | ||
* settings.has('notify', 'premium'); | ||
* //=> false | ||
*/ | ||
has(...fields) { | ||
const { offsets, zero, one } = this.constructor; | ||
const mask = this.value | fields.reduce((result, current) => { | ||
result |= one << offsets[current]; | ||
return result; | ||
}, zero); | ||
let mask = zero; | ||
for (let i = 0; i < fields.length; i++) { | ||
mask |= one << offsets[fields[i]]; | ||
} | ||
mask |= this.value; | ||
return this.value === mask; | ||
} | ||
/** | ||
* Returns the numerical value of an instance. | ||
* | ||
* @private | ||
* @returns {*} the numerical value of the instance | ||
*/ | ||
toValue() { | ||
@@ -76,2 +173,13 @@ return this.value; | ||
/** | ||
* Returns the object representation of the instance, | ||
* with field names as properties with corresponding values. | ||
* @returns {Object<string, number>} the object representation of the instance | ||
* @example | ||
* | ||
* const Person = BinariusFactory([{ name: 'age', size: 7}, { name: 'gender', size: 1}]); | ||
* const person = new Person([20, 1]); | ||
* person.toObject(); | ||
* //=> { age: 20, gender: 1 } | ||
*/ | ||
toObject() { | ||
@@ -107,2 +215,4 @@ const { fields, masks } = this.constructor; | ||
return Binarius; | ||
}; | ||
} | ||
module.exports = BinariusFactory; |
@@ -42,2 +42,3 @@ const binarius = require('./index'); | ||
let BinariusNumber; | ||
let BinariusLargestNumber; | ||
let BinariusBigInt; | ||
@@ -48,2 +49,3 @@ let BinariusBits; | ||
BinariusNumber = binarius([{ name: 'age', size: 7 }, { name: 'gender', size: 1 }]); | ||
BinariusLargestNumber = binarius([{ name: 'age', size: 31 }, { name: 'gender', size: 1 }]); | ||
BinariusBigInt = binarius([ | ||
@@ -75,2 +77,4 @@ { name: 'age', size: 7 }, | ||
expect(new BinariusNumber(41).get('age')).toBe(20); | ||
expect(new BinariusLargestNumber([20, 1]).get('age')).toBe(20); | ||
expect(new BinariusLargestNumber(41).get('age')).toBe(20); | ||
expect(new BinariusBigInt([20, 1, 3500, 5]).get('weight')).toBe(3500); | ||
@@ -86,2 +90,3 @@ expect(new BinariusBigInt(BigInt(1375759717)).get('weight')).toBe(3500); | ||
expect(new BinariusNumber([20, 1]).set('age', 30).get('age')).toBe(30); | ||
expect(new BinariusLargestNumber([20, 1]).set('age', 2147483647).get('age')).toBe(2147483647); | ||
expect(new BinariusNumber([20, 0]).set('gender').get('gender')).toBe(1); | ||
@@ -97,8 +102,8 @@ expect(new BinariusNumber(41).set('gender', 0).get('gender')).toBe(0); | ||
it('checks if all specified fields are set in a given bitfield instance', () => { | ||
expect(new BinariusBits([1,0,1]).has('human', 'tall')).toBe(true); | ||
expect(new BinariusBits([1,1,1]).has('human', 'tall')).toBe(true); | ||
expect(new BinariusBits([0,1,1]).has('human', 'tall')).toBe(false); | ||
expect(new BinariusBits([1,1,0]).has('human', 'tall')).toBe(false); | ||
expect(new BinariusBits([0,1,0]).has('human', 'tall')).toBe(false); | ||
expect(new BinariusBits([0,1,0]).has('gender')).toBe(true); | ||
expect(new BinariusBits([1, 0, 1]).has('human', 'tall')).toBe(true); | ||
expect(new BinariusBits([1, 1, 1]).has('human', 'tall')).toBe(true); | ||
expect(new BinariusBits([0, 1, 1]).has('human', 'tall')).toBe(false); | ||
expect(new BinariusBits([1, 1, 0]).has('human', 'tall')).toBe(false); | ||
expect(new BinariusBits([0, 1, 0]).has('human', 'tall')).toBe(false); | ||
expect(new BinariusBits([0, 1, 0]).has('gender')).toBe(true); | ||
}); | ||
@@ -110,3 +115,3 @@ }); | ||
it('returns a plain object representation of an instance', () => { | ||
expect(new BinariusNumber([20, 1]).toObject()).toEqual({ age: 20, gender: 1}); | ||
expect(new BinariusNumber([20, 1]).toObject()).toEqual({ age: 20, gender: 1 }); | ||
expect(new BinariusBigInt([20, 1, 3500, 5]).toObject()).toEqual({ | ||
@@ -131,2 +136,1 @@ age: 20, | ||
}); | ||
{ | ||
"name": "binarius", | ||
"version": "0.0.1", | ||
"description": "", | ||
"version": "0.0.2", | ||
"description": "Store and operate on data in Numbers and BigInts for memory savings, performance, and fun.", | ||
"main": "index.js", | ||
@@ -13,3 +13,5 @@ "keywords": [ | ||
"performance", | ||
"bitwise" | ||
"bitwise", | ||
"integer", | ||
"bigint" | ||
], | ||
@@ -26,3 +28,6 @@ "dependencies": {}, | ||
"scripts": { | ||
"test": "jest" | ||
"test": "jest", | ||
"lint": "eslint *.js", | ||
"coverage:report": "cat ./coverage/lcov.info | codecov", | ||
"benchmark": "node benchmark.js" | ||
}, | ||
@@ -41,4 +46,7 @@ "jest": { | ||
}, | ||
"engines": { | ||
"node": ">=10.4.0" | ||
}, | ||
"author": "Maga D. Zandaqo <denelxan@gmail.com> (http://maga.name)", | ||
"license": "MIT" | ||
} |
@@ -6,2 +6,3 @@ # Binarius | ||
Store and operate on data in Numbers and BigInts for memory savings, performance, and fun. | ||
@@ -16,4 +17,31 @@ ## Installation | ||
## Benchmark | ||
``` | ||
>node benchmark.js | ||
Construct: | ||
Binarius Number x 29,866,474 ops/sec ±8.67% (57 runs sampled) | ||
Binarius BigInt x 674,095 ops/sec ±2.11% (83 runs sampled) | ||
Get Field: | ||
Binarius Number x 8,643,094 ops/sec ±9.13% (59 runs sampled) | ||
Binarius BigInt x 617,815 ops/sec ±6.50% (73 runs sampled) | ||
Set Field: | ||
Binarius Number x 6,918,546 ops/sec ±8.78% (78 runs sampled) | ||
Binarius BigInt x 477,000 ops/sec ±5.86% (84 runs sampled) | ||
Construct for bit flags: | ||
Binarius x 8,019,238 ops/sec ±7.24% (47 runs sampled) | ||
parseInt x 9,128,021 ops/sec ±7.62% (61 runs sampled) | ||
Get bit flag: | ||
Binarius x 26,310,759 ops/sec ±10.21% (59 runs sampled) | ||
Bits x 40,664,455 ops/sec ±2.06% (86 runs sampled) | ||
Set bit flag: | ||
Binarius x 14,740,229 ops/sec ±9.67% (52 runs sampled) | ||
Bits x 30,816,599 ops/sec ±11.43% (51 runs sampled) | ||
``` | ||
## License | ||
MIT © [Maga D. Zandaqo](http://maga.name) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
19078
432
46