diff --git a/packages/util/src/is/ascii.spec.ts b/packages/util/src/is/ascii.spec.ts index 303cd85b9..95a4b25b8 100644 --- a/packages/util/src/is/ascii.spec.ts +++ b/packages/util/src/is/ascii.spec.ts @@ -1,6 +1,7 @@ // Copyright 2017-2022 @polkadot/util authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { performance } from '../test/performance'; import { isAscii } from '.'; describe('isAscii', (): void => { @@ -35,4 +36,6 @@ describe('isAscii', (): void => { it('returns false for hex input, non-ascii', (): void => { expect(isAscii('0x010203')).toEqual(false); }); + + performance('isAscii', 100_000, [[[0x31, 0x32, 0x20, 10, 9, 13, 65, 66, 67, 68, 69, 70]]], isAscii); }); diff --git a/packages/util/src/is/ascii.ts b/packages/util/src/is/ascii.ts index ee65541e3..9c79e18e8 100644 --- a/packages/util/src/is/ascii.ts +++ b/packages/util/src/is/ascii.ts @@ -1,25 +1,42 @@ // Copyright 2017-2022 @polkadot/util authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { U8aLike } from '../types'; +import type { AnyString, U8aLike } from '../types'; import { u8aToU8a } from '../u8a/toU8a'; import { isHex } from './hex'; import { isString } from './string'; -const FORMAT = [9, 10, 13]; - /** @internal */ -function isAsciiByte (b: number): boolean { - return (b < 127) && ( - (b >= 32) || - FORMAT.includes(b) - ); +function isAsciiStr (str: AnyString): boolean { + const count = str.length; + + for (let i = 0; i < count; i++) { + const b = str.charCodeAt(i); + + // check is inlined here, it is faster than making a call + if (!((b < 127) && ((b >= 32) || (b === 10) || (b === 9) || (b === 13)))) { + return false; + } + } + + return true; } /** @internal */ -function isAsciiChar (s: string): boolean { - return isAsciiByte(s.charCodeAt(0)); +function isAsciiU8a (u8a: Uint8Array): boolean { + const count = u8a.length; + + for (let i = 0; i < count; i++) { + const b = u8a[i]; + + // check is inlined here, it is faster than making a call + if (!((b < 127) && ((b >= 32) || (b === 10) || (b === 9) || (b === 13)))) { + return false; + } + } + + return true; } /** @@ -29,13 +46,9 @@ function isAsciiChar (s: string): boolean { * Checks to see if the input string or Uint8Array is printable ASCII, 32-127 + formatters */ export function isAscii (value?: U8aLike | null): boolean { - const isStringIn = isString(value); - - if (value) { - return isStringIn && !isHex(value) - ? value.toString().split('').every(isAsciiChar) - : u8aToU8a(value).every(isAsciiByte); - } - - return isStringIn; + return isString(value) && !isHex(value) + ? isAsciiStr(value) + : value + ? isAsciiU8a(u8aToU8a(value)) + : false; } diff --git a/packages/util/src/u8a/toString.spec.ts b/packages/util/src/u8a/toString.spec.ts index 9370ec093..626b39dd2 100644 --- a/packages/util/src/u8a/toString.spec.ts +++ b/packages/util/src/u8a/toString.spec.ts @@ -1,7 +1,7 @@ // Copyright 2017-2022 @polkadot/util authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { u8aToString } from '..'; +import { u8aToString } from '.'; describe('u8aToString', (): void => { it('decodes to an empty string for undefined', (): void => { @@ -16,11 +16,19 @@ describe('u8aToString', (): void => { ).toEqual(''); }); - it('decodes the buffer correctly', (): void => { + it('decodes the Uint8Array correctly', (): void => { expect( u8aToString( new Uint8Array([208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130, 44, 32, 208, 188, 208, 184, 209, 128, 33]) ) ).toEqual('Привет, мир!'); }); + + it('decodes the Uint8Array correctly', (): void => { + expect( + u8aToString( + new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]) + ) + ).toEqual('hello world'); + }); });