diff --git a/.gitignore b/.gitignore index 6704566..48a604b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,104 +1,2 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and *not* Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port +/node_modules/ +*-lock.* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8ca64db --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,18 @@ +# CHANGELOG + +## 1.0.2 + +- Added `CHANGELOG.md` +- Added type hint support +- Reduce the probability of duplicate keys +- Improve performace and readability +- Improve Documentation + +## 1.0.1 + +- Improve performace and readability +- Added Documentation + +## 1.0.0 + +- Initial Release diff --git a/README.md b/README.md index 42b7f1e..94b9e4f 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,29 @@ import numesis module on your project directly ```js import Numesis from 'https://deno.land/x/numesis/mod.ts' ``` +## Example +```js +const hex = new Numesis("0123456789ABCDEF"); +const dec = new Numesis("0123456789"); +const bin = new Numesis("01"); +const oct = new Numesis("01234567"); + +console.log(`Hex value of 255 is ${hex.e(255)}`); +// Output: Hex value of 255 is FF + +console.log(`Oct value of 255 is ${oct.e(255)}`); +// Output: Oct value of 255 is 377 + +console.log(`Dec value of 255 is ${dec.e(255)}`); +// Output: Dec value of 255 is 255 + +console.log(`Bin value of 255 is ${bin.e(255)}`); +// Output: Bin value of 255 is 11111111 + +// Convert RGB Color +console.log(`Convert RGB(255,255,255) to HEX is ${hex.e(255,255,255)}`); +// Output: Covert RGB(255,255,255) to HEX is FFFFFFFF +``` ## Usage ### With deno ```js diff --git a/mod.js b/mod.js index 0707530..96cd755 100644 --- a/mod.js +++ b/mod.js @@ -1,30 +1,70 @@ +/** + * @class Numesis + * Create custom Number System + * Compatible with: + * - Deno + * - NodeJS + * - Browser + * - Typescript + * @author Jericho Aquino + * @version 1.0.2 + * @license Apache-2.0 + * @see {@link https://github.com/eru123/numesis} Github Repository + * @see {@link https://www.npmjs.com/package/numesis} NPM Package + */ class Numesis { - c; - constructor(ch = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"){ - this.c = { - s: ch, - l: ch.length, - i: ch.length - 1, - a: ch.split("") - }; + /** + * A non-duplicate character set, that will be use in creating new number system + * @type {Set} + */ + charset; + /** + * @param {String} chartset A non-duplicate character set, that will be use in creating new number system + */ + constructor(chartset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"){ + this.charset = Array.from(new Set(chartset.split(""))); } - ep(n, c = "") { - n = Math.floor(n); - const { l , i , a } = this.c; - if (n <= i) return a[n] + c; - const m = n % l; - c = m > 0 && m <= l ? a[m] + c : a[0] + c; - const d = Math.floor(n / l); - return this.ep(d, c); + /** + * A recursive method that encodes the n variable to custom number system + * @param {number|string} number The number that will be decoded + * @param {string} current The current string in the recursion + * + * @return {String} encoded string + */ + encode_process(number, current = "") { + number = parseInt("" + number); + const length = this.charset.length; + const lastIndex = length - 1; + const set = this.charset; + if (number <= lastIndex) return "" + (set[number] + current); + const m = number % length; + current = m > 0 && m <= length ? set[m] + current : set[0] + current; + const d = parseInt(number / length + ""); + return this.encode_process(d, current); } - e(n) { - const str = String(n); - if (str.includes(".")) { - const st = str.split("."); - return `${this.ep(Number(st[0]) || 0)}.${this.ep(Number(st[1]) || 0)}`; - } - return this.ep(n); + /** + * Alias for encode_process + */ + ep = this.encode_process; + /** + * A public method that encodes n paramenter to custom number system + * @param {number|string} args numbers that will be decoded + * + * @return {String} encoded string + */ + encode(...args) { + return args.map((n)=>{ + const str = String(n); + if (/\./i.test(str)) { + const st = str.split("."); + return `${this.encode_process(+st[0] || 0)}.${this.encode_process(+st[1] || 0)}`; + } + return this.encode_process(n); + }).join(""); } + /** + * Alias for encode + */ + e = this.encode.bind(this); } - -module.exports = Numesis; \ No newline at end of file +module.exports = Numesis; diff --git a/mod.ts b/mod.ts index ac88688..fd99d13 100644 --- a/mod.ts +++ b/mod.ts @@ -1,30 +1,81 @@ -class Numesis { - public readonly c: {s:string,l:number,i:number,a: Array}; - constructor(ch:string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"){ - this.c = { - s: ch, - l: ch.length, - i: ch.length - 1, - a: ch.split("") - } - } - private ep(n:number, c = ""): string { - n = Math.floor(n) - const {l,i,a} = this.c - if(n <= i) return a[n] + c; - const m: number = n % l; - c = m > 0 && m <= l ? a[m] + c : a[0] + c - const d: number = Math.floor(n / l); - return this.ep(d,c) - } - e(n:number): string { - const str = String(n) - if(str.includes(".")) { - const st = str.split(".") - return `${this.ep(Number(st[0]) || 0)}.${this.ep(Number(st[1]) || 0)}` - } - return this.ep(n) - } +/** + * @class Numesis + * Create custom Number System + * Compatible with: + * - Deno + * - NodeJS + * - Browser + * - Typescript + * @author Jericho Aquino + * @version 1.0.2 + * @license Apache-2.0 + * @see {@link https://github.com/eru123/numesis} Github Repository + * @see {@link https://www.npmjs.com/package/numesis} NPM Package + */ + class Numesis { + /** + * A non-duplicate character set, that will be use in creating new number system + * @type {Set} + */ + public readonly charset: Array; + + /** + * @param {String} chartset A non-duplicate character set, that will be use in creating new number system + */ + constructor(chartset: string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") { + // Recreate an array of characters without duplicates + this.charset = Array.from(new Set(chartset.split(""))) + } + + /** + * A recursive method that encodes the n variable to custom number system + * @param {number|string} number The number that will be decoded + * @param {string} current The current string in the recursion + * + * @return {String} encoded string + */ + private encode_process(number: number | string, current = ""): string { + number = parseInt("" + number) // Convert to integer + const length: number = this.charset.length // Get the length of the charset + const lastIndex: number = length - 1 // Get the last index of the charset + const set: Array = this.charset // Get the charset + if (number <= lastIndex) return "" + (set[number] + current); // If the number is less than the length of the charset, return the character + const m: number = number % length; // Get the remainder of the number + current = m > 0 && m <= length ? set[m] + current : set[0] + current // If the remainder is greater than 0 and less than the length of the charset, return the character + const d: number = parseInt((number / length) + ""); // Get the division of the number + return this.encode_process(d, current) // Recursive call + } + + /** + * Alias for encode_process + */ + ep: Function = this.encode_process + + /** + * A public method that encodes n paramenter to custom number system + * @param {number|string} args numbers that will be decoded + * + * @return {String} encoded string + */ + encode(...args: Array): string { + return args + .map((n) => { + const str = String(n) // Convert to string + if (/\./i.test(str)) { // If float + const st = str.split(".") // Split the string + // return the encoded float + return `${this.encode_process(+st[0] || 0)}.${this.encode_process(+st[1] || 0)}` + } + + return this.encode_process(n) + }) + .join("") + } + + /** + * Alias for encode + */ + e: Function = this.encode.bind(this) } -export default Numesis; \ No newline at end of file +export default Numesis \ No newline at end of file diff --git a/package.json b/package.json index 36602ce..43ff64d 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "numesis", - "version": "1.0.1", + "version": "1.0.2", "description": "Custom Number System", "main": "mod.js", "scripts": { - "test": "node test.js" + "test": "node test.js", + "deno-test": "deno run test.ts" }, "keywords": [ "number", @@ -18,8 +19,11 @@ "base", "numerals", "numeral", - "create", - "custom" + "hex", + "hexadecimal", + "decimal", + "binary", + "octal" ], "author": "eru123", "license": "Apache-2.0", diff --git a/test.js b/test.js index c61aa7c..7127cbf 100644 --- a/test.js +++ b/test.js @@ -1,15 +1,47 @@ const Numesis = require('./mod') -const n = new Numesis(); -let ts = Date.now(); -let de = []; -let dp = []; -for(let i = 999999999; i < 1000001999; i++){ - const e = n.e(i); - if (de.includes(e)) dp.push(e); - de.push(e); + +async function test(s) { + const n = new Numesis(); + return new Promise((resolve)=>{ + let ts = Date.now(); + let te = Date.now(); + let de = []; + var stop = false; + for(let i = 0; !stop; i++){ + de.push(n.e(i)); + te = Date.now(); + if (te - ts >= s * 1000) { + stop = true; + return resolve({ + start: ts, + end: te, + id: de + }); + } + } + }); } -let te = Date.now(); -console.log(`\n===========================================`); -console.log("Generated ID's \t\t\t:", de.length); -console.log("Duplicated ID's \t\t:", dp.length); -console.log("Elapsed time \t\t\t:", (te - ts) / 1000, "s"); \ No newline at end of file +async function average(s) { + const id = []; + const dup = []; + for(let i = 0; i < s; i++){ + await test(1).then(({ id: e })=>{ + id.push(e.length); + dup.push(e.length - new Set(e).size); + }); + } + const avg = id.reduce((a, b)=>a + b, 0) / id.length; + const avgDup = dup.reduce((a, b)=>a + b, 0) / dup.length; + console.log(`\n=====================================================`); + console.log("Average ID's:", ~~avg, "/s"); + console.log(`Average duplicated ID's: ${~~avgDup}/s`); + console.log(`Elapsed time: ${s}s`); +} +test(1).then((e)=>{ + console.log(`\n=====================================================`); + console.log("Average Generated ID's \t\t\t:", e?.id?.length); + console.log("Average Duplicated ID's \t\t:", e?.id?.length - new Set(e?.id).size); + console.log("Elapsed time \t\t\t\t:", (e?.end - e?.start) / 1000, "s"); + return 0; +}); +average(10); diff --git a/test.ts b/test.ts index e9366ac..b550762 100644 --- a/test.ts +++ b/test.ts @@ -1,20 +1,55 @@ +// Deno compatible only import Numesis from './mod.ts' -const n = new Numesis(); -const countStart = 999999999 -const countEnd = 1000001999 +async function test(s: number): Promise<{ + id: string[], + start: number, + end: number, +}> { + const n = new Numesis(); + return new Promise((resolve) => { + let ts = Date.now() + let te = Date.now() + let de: string[] = [] + var stop = false -let ts = Date.now() -let de: string[] = [] -let dp: string[] = [] + for (let i = 0; !stop; i++) { + de.push(n.e(i)) + te = Date.now() + if (te - ts >= s * 1000) { + stop = true; + return resolve({ start: ts, end: te, id: de }) + } + } + }) +} -for(let i = countStart;i < countEnd;i++){ - const e = n.e(i) - if(de.includes(e)) dp.push(e) - de.push(e) +async function average(s: number) { + const id: number[] = [] + const dup: number[] = [] + for (let i = 0; i < s; i++) { + await test(1) + .then(({ id: e }) => { + id.push(e.length) + dup.push(e.length - (new Set(e)).size) + }) + } + const avg = id.reduce((a, b) => a + b, 0) / id.length + const avgDup = dup.reduce((a, b) => a + b, 0) / dup.length + console.log(`\n=====================================================`) + console.log("Average ID's:", ~~avg, "/s") + console.log(`Average duplicated ID's: ${~~avgDup}/s`) + console.log(`Elapsed time: ${s}s`) } -let te = Date.now() -console.log(`\n===========================================`) -console.log("Generated ID's \t\t\t:",de.length) -console.log("Duplicated ID's \t\t:",dp.length) // should be 0 to pass -console.log("Elapsed time \t\t\t:", (te - ts)/1000,"s") \ No newline at end of file + +test(1) + .then((e) => { + console.log(`\n=====================================================`) + console.log("Average Generated ID's \t\t\t:", e?.id?.length) + console.log("Average Duplicated ID's \t\t:", e?.id?.length - (new Set(e?.id)).size) + console.log("Elapsed time \t\t\t\t:", (e?.end - e?.start) / 1000, "s") + return 0; + }) + +average(10) +