Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(math): rewrite UnicodeDigits to improve performance #297

Merged
merged 6 commits into from
Oct 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<li><a href="./signal/">Signal</a></li>
<li><a href="./router/">Router</a></li>
<li><a href="./font/">Font</a></li>
<li><a href="./math/">Math</a></li>
</ol>
</body>
</html>
13 changes: 13 additions & 0 deletions demo/math/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@alwatr/math</title>
<script type="module" src="./translate-unicode-digits.js"></script>
</head>

<body>
<h3>Check the console</h3>
</body>
</html>
17 changes: 14 additions & 3 deletions demo/math/translate-unicode-digits.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {translateUnicodeDigits} from '@alwatr/math';
import {UnicodeDigits} from '@alwatr/math';

const unicodeDigits = new UnicodeDigits('all', 'fa');

const list = [
'0123456789',
'٠١٢٣٤٥٦٧٨٩',
'۰۱۲۳۴۵۶۷۸۹',
'߀߁߂߃߄߅߆߇߈߉',
'०१२३४५६७८९',
'০১২৩৪৫৬৭৮৯',
Expand All @@ -14,5 +15,15 @@ const list = [
].join('\n');

console.log(list);
console.log('-----');

console.log(unicodeDigits.translate(list));

const start = Date.now();
const count = 20_000;

for (let i = count; i > 0; i--) {
unicodeDigits.translate(list);
}

console.log(translateUnicodeDigits(list, 'fa'));
console.log(count / (Date.now() - start) * 1000);
72 changes: 49 additions & 23 deletions packages/core/math/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,39 @@ Simple useful Math library written in tiny TypeScript module.

## API

### `UnicodeDigits(fromLanguages: Array<UnicodeLangKeys> | 'all' | 'common', toLanguage: UnicodeLangKeys)`

Translate number.

- **fromLanguages** The source language to be translated.
- **toLanguages** The dest language to be translated.

Example:

```ts
const unicodeDigits = new UnicodeDigits('common', 'en');

const list = [
'0123456789',
'٠١٢٣٤٥٦٧٨٩',
'߀߁߂߃߄߅߆߇߈߉',
'०१२३४५६७८९',
'০১২৩৪৫৬৭৮৯',
'੦੧੨੩੪੫੬੭੮੯',
'૦૧૨૩૪૫૬૭૮૯',
'୦୧୨୩୪୫୬୭୮୯',
'௦௧௨௩௪௫௬௭௮௯',
].join('\n');

console.log(unicodeDigits.translate(list));
```

### `unicodeDigits.translate(str: string): string`

Convert the String of number of the source language to the destination language.

- **str** is String of number of the source language.

@TODO: update from ts files docs

### `isNumber(value: unknown): boolean`
Expand All @@ -12,7 +45,7 @@ Check the value is number or can convert to a number, for example string ' 123 '

#### Why is this needed?

```js
```ts
console.log(typeof '123'); //=> 'string'
console.log(+[]); //=> 0
console.log(+''); //=> 0
Expand All @@ -23,8 +56,7 @@ console.log(typeof Infinity); //=> 'number'

#### True

<!-- prettier-ignore -->
```js
```ts
import {isNumber} from 'https://esm.run/@alwatr/math';

isNumber(5e3); // true
Expand All @@ -33,27 +65,21 @@ isNumber(-1.1); // true
isNumber(0); // true
isNumber(1); // true
isNumber(1.1); // true
isNumber(10); // true
isNumber(10.10); // true
isNumber(100); // true
isNumber('-1.1'); // true
isNumber('0'); // true
isNumber('012'); // true
isNumber('0xff'); // true
isNumber('1'); // true
isNumber('1.1'); // true
isNumber('10'); // true
isNumber('10.10'); // true
isNumber('100'); // true
isNumber('5e3'); // true
isNumber('012'); // true
isNumber(parseInt('012')); // true
isNumber(parseFloat('012')); // true
```

#### False

<!-- prettier-ignore -->
```js
```ts
import {isNumber} from 'https://esm.run/@alwatr/math';

isNumber(Infinity); // false
Expand Down Expand Up @@ -101,19 +127,19 @@ Options:

#### Example

```js
```ts
transformToRange(5, {in: [0, 10], out: [0, 100]}); // => 50
```

Make percentage of any value

```js
```ts
transformToRange(2000, {in: [0, 5000], out: [0, 100]}); // => 40
```

Calculate progress-bar with

```js
```ts
const progressOuterWith = 400; //px
const gap = 5; //px (the visual gap between progressBar and component outer).
const currentProgress = 30; //%
Expand All @@ -133,50 +159,50 @@ this.progressBar.style.width = `${progressBarWith}px`;

Returns a float random number between 0 and 1 (1 Not included).

```js
```ts
console.log(random.value); // 0.7124123
```

### `random.integer(min: number, max: number): number`

Generate a random integer between min and max.

```js
```ts
console.log(random.integer(1, 10)); // somewhere between 1 and 10
```

### `random.float(min: number, max: number): number`

Generate a random float between min and max.

```js
```ts
console.log(random.float(1, 10)); // somewhere between 1 and 10
```

### `string: (min: number, max?: number): string`

Generate a random string with random length.
The string will contain only characters from the characters list.
The length of the string will be between min and max (max included).
Generate a random string with random length.
The string will contain only characters from the characters list.
The length of the string will be between min and max (max included).
If max not specified, the length will be set to min.

```js
```ts
console.log(random.string(6)); // something like 'Aab1V2'
```

### `step(min: number, max: number, step: number): number`

Generate a random integer between min and max with a step.

```js
```ts
console.log(random.step(6, 10, 2)); // 6 or 8 or 10
```

### `shuffle(array: any[]): any[]`

Shuffle an array.

```js
```ts
const array = [1, 2, 3, 4, 5];
random.shuffle(array);
console.log(array); // [2, 4, 3, 1, 5]
Expand Down
99 changes: 7 additions & 92 deletions packages/core/math/src/math.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {TransformRangeOptions} from './type';
export * from './unicode-digits.js';

/**
* Number.isFinite simple polyfill
Expand All @@ -9,6 +10,9 @@ if (typeof Number.isFinite !== 'function') {

/**
* Check the value is number or can convert to a number, for example string ' 123 ' can be converted to 123
*
* @param {unknown} value - the value must check numberic.
* @return {boolean} - is number status.
*/
export function isNumber(value: unknown): boolean {
if (typeof value === 'number') {
Expand All @@ -25,19 +29,19 @@ export function isNumber(value: unknown): boolean {
*
* Example:
*
* ```js
* ```ts
* transformToRange(5, {in: [0, 10], out: [0, 100]}); // => 50
* ```
*
* Make percentage of any value
*
* ```js
* ```ts
* transformToRange(2000, {in: [0, 5000], out: [0, 100]}); // => 40
* ```
*
* Calculate progress-bar with
*
* ```js
* ```ts
* const progressOuterWith = 400; //px
* const gap = 5; //px (the visual gap between progressBar and component outer).
* const currentProgress = 30; //%
Expand Down Expand Up @@ -191,92 +195,3 @@ export function parseDuration(duration: DurationString, toUnit: DurationUnit | '
}
return (durationNumber * unitConversion[durationUnit]) / (toUnit === 'ms' ? 1 : unitConversion[toUnit]);
}

export const unicodeDigits = {
'en': 0x0030,
'ar': 0x0660,
'fa': 0x06f0,
'nko': 0x07c0,
'hi': 0x0966, // devanagari
'bn': 0x09e6, // bengali
'pa': 0x0a66, // gurmukhi, punjabi
'gu': 0x0ae6, // gujarati
'or': 0x0b66, // oriya
'ta': 0x0be6, // tamil
'te': 0x0c66, // telugu
'kn': 0x0ce6, // kannada

'mal': 0x0d66, // malayalam
'sinhala_lith': 0x0de6,
'thai': 0x0e50,
'lao': 0x0ed0,
'tibetan': 0x0f20,
'myanmar': 0x1040,
'myanmar_shan': 0x1090,
'khmer': 0x17e0,
'mongolian': 0x1810,
'limbu': 0x1946,
'new_tai_lue': 0x19d0,
'tai_tham_hora': 0x1a80,
'tai_tham_tham': 0x1a90,
'balinese': 0x1b50,
'sundanese': 0x1bb0,
'lepcha': 0x1c40,
'ol_chiki': 0x1c50,
'vai': 0xa620,
'saurashtra': 0xa8d0,
'kayah_li': 0xa900,
'javanese': 0xa9d0,
'myanmar_tai_laing': 0xa9f0,
'cham': 0xaa50,
'meetei_mayek': 0xabf0,
'fullwidth': 0xff10,
'osmanya': 0x104a0,
'brahmi': 0x11066,
'sora_sompeng': 0x110f0,
'chakma': 0x11136,
'sharada': 0x111d0,
'khudawadi': 0x112f0,
'newa': 0x11450,
'tirhuta': 0x114d0,
'modi': 0x11650,
'takri': 0x116c0,
'ahom': 0x11730,
'warang_citi': 0x118e0,
'bhaiksuki': 0x11c50,
'mro': 0x16a60,
'pahawh_hmong': 0x16b50,
'mathematical_bold': 0x1d7ce,
'mathematical_double-struck': 0x1d7d8,
'mathematical_sans-serif': 0x1d7e2,
'mathematical_sans-serif_bold': 0x1d7ec,
'mathematical_monospace': 0x1d7f6,
'fula': 0x1e950, // adlam script in fula lang
} as const;

export type LangKeys = keyof typeof unicodeDigits;
const allLangKeys: Array<LangKeys> = Object.keys(unicodeDigits) as Array<LangKeys>;

/**
* Replace all digital number in all languages to requested language.
*
* Example:
*
* ```js
* translateUnicodeDigits('123 ߁߂߃ ੧੨੩ ٣٤٦', 'fa'); // ۱۲۳ ۱۲۳ ۱۲۳ ۳۴۶
* ```
*/
export function translateUnicodeDigits(
string: string,
toLanguage: LangKeys = 'en',
fromLanguages: Array<LangKeys> = allLangKeys,
): string {
const toLangZeroCode = unicodeDigits[toLanguage];
for (const langKey of fromLanguages) {
const fromLangZeroCode = unicodeDigits[langKey];
for (let n = 0; n < 10; n++) {
string = string.replaceAll(String.fromCharCode(fromLangZeroCode + n), String.fromCharCode(toLangZeroCode + n));
}
}
return string;
}
Loading