Skip to content

Commit 203bdc1

Browse files
feat: reimplement parse logic with arbitrary radix support
--- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: na - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent 400acc7 commit 203bdc1

6 files changed

Lines changed: 275 additions & 197 deletions

File tree

lib/node_modules/@stdlib/number/uint64/parse/benchmark/benchmark.js

Lines changed: 19 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
var bench = require( '@stdlib/bench' );
2424
var discreteUniform = require( '@stdlib/random/array/discrete-uniform' );
25-
var format = require( '@stdlib/string/format' );
25+
var floor = require( '@stdlib/math/base/special/floor' );
2626
var MAX_SAFE_INTEGER = require( '@stdlib/constants/float64/max-safe-integer' );
2727
var Uint64 = require( '@stdlib/number/uint64/ctor' );
2828
var pkg = require( './../package.json' ).name;
@@ -32,107 +32,36 @@ var parseUint64 = require( './../lib' );
3232
// MAIN //
3333

3434
bench( pkg, function benchmark( b ) {
35-
var x;
36-
var y;
37-
var z;
35+
var values;
36+
var radix;
37+
var N;
38+
var M;
39+
var a;
3840
var i;
39-
40-
x = discreteUniform( 100, 0, MAX_SAFE_INTEGER );
41-
y = [];
42-
for ( i = 0; i < x.length; i++ ) {
43-
y.push( x[i].toString() );
44-
}
45-
46-
b.tic();
47-
for ( i = 0; i < b.iterations; i++ ) {
48-
z = parseUint64( y[ i % y.length ] );
49-
if ( typeof z !== 'object' ) {
50-
b.fail( 'should return a Uint64 instance' );
51-
}
52-
}
53-
b.toc();
54-
if ( !( z instanceof Uint64 ) ) {
55-
b.fail( 'should return a Uint64 instance' );
56-
}
57-
b.pass( 'benchmark finished' );
58-
b.end();
59-
});
60-
61-
bench( format( '%s:hexadecimal', pkg ), function benchmark( b ) {
62-
var x;
63-
var y;
64-
var z;
65-
var i;
66-
67-
x = discreteUniform( 100, 0, MAX_SAFE_INTEGER );
68-
y = [];
69-
for ( i = 0; i < x.length; i++ ) {
70-
y.push( '0x'+x[i].toString( 16 ) );
71-
}
72-
73-
b.tic();
74-
for ( i = 0; i < b.iterations; i++ ) {
75-
z = parseUint64( y[ i % y.length ] );
76-
if ( typeof z !== 'object' ) {
77-
b.fail( 'should return a Uint64 instance' );
78-
}
79-
}
80-
b.toc();
81-
if ( !( z instanceof Uint64 ) ) {
82-
b.fail( 'should return a Uint64 instance' );
83-
}
84-
b.pass( 'benchmark finished' );
85-
b.end();
86-
});
87-
88-
bench( format( '%s:binary', pkg ), function benchmark( b ) {
41+
var j;
8942
var x;
90-
var y;
91-
var z;
92-
var i;
93-
94-
x = discreteUniform( 100, 0, MAX_SAFE_INTEGER );
95-
y = [];
96-
for ( i = 0; i < x.length; i++ ) {
97-
y.push( '0b'+x[i].toString( 2 ) );
98-
}
9943

100-
b.tic();
101-
for ( i = 0; i < b.iterations; i++ ) {
102-
z = parseUint64( y[ i % y.length ] );
103-
if ( typeof z !== 'object' ) {
104-
b.fail( 'should return a Uint64 instance' );
44+
N = 100;
45+
x = discreteUniform( N, 0, MAX_SAFE_INTEGER );
46+
values = [];
47+
for ( radix = 2; radix <= 36; radix++ ) {
48+
for ( i = 0; i < N; i++ ) {
49+
values.push( x[i].toString( radix ) );
10550
}
10651
}
107-
b.toc();
108-
if ( !( z instanceof Uint64 ) ) {
109-
b.fail( 'should return a Uint64 instance' );
110-
}
111-
b.pass( 'benchmark finished' );
112-
b.end();
113-
});
114-
115-
bench( format( '%s:octal', pkg ), function benchmark( b ) {
116-
var x;
117-
var y;
118-
var z;
119-
var i;
120-
121-
x = discreteUniform( 100, 0, MAX_SAFE_INTEGER );
122-
y = [];
123-
for ( i = 0; i < x.length; i++ ) {
124-
y.push( '0o'+x[i].toString( 8 ) );
125-
}
52+
M = values.length;
12653

12754
b.tic();
12855
for ( i = 0; i < b.iterations; i++ ) {
129-
z = parseUint64( y[ i % y.length ] );
130-
if ( typeof z !== 'object' ) {
56+
j = i % M;
57+
radix = 2 + floor( j / N );
58+
a = parseUint64( values[ j ], radix );
59+
if ( typeof a !== 'object' ) {
13160
b.fail( 'should return a Uint64 instance' );
13261
}
13362
}
13463
b.toc();
135-
if ( !( z instanceof Uint64 ) ) {
64+
if ( !( a instanceof Uint64 ) ) {
13665
b.fail( 'should return a Uint64 instance' );
13766
}
13867
b.pass( 'benchmark finished' );

lib/node_modules/@stdlib/number/uint64/parse/docs/types/index.d.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,17 @@ import Uint64 = require( '@stdlib/number/uint64/ctor' );
2929
* @returns unsigned 64-bit integer
3030
*
3131
* @example
32-
* var v = parseUint64( '5' );
33-
* // returns <Uint64>
32+
* var v = parseUint64( '1234' );
33+
* // returns <Uint64>[ 1234n ]
34+
*
35+
* v = parseUint64( '18446744073709551615' );
36+
* // returns <Uint64>[ 18446744073709551615n ]
37+
*
38+
* v = parseUint64( '0xffffffffffffffff' );
39+
* // returns <Uint64>[ 18446744073709551615n ]
40+
*
41+
* v = parseUint64( '3w5e11264sgsf', 36 );
42+
* // returns <Uint64>[ 18446744073709551615n ]
3443
*/
3544
declare function parseUint64( str: string ): Uint64;
3645

lib/node_modules/@stdlib/number/uint64/parse/lib/index.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,17 @@
2626
* @example
2727
* var parseUint64 = require( '@stdlib/number/uint64/parse' );
2828
*
29-
* var v = parseUint64( '5' );
30-
* // returns <Uint64>
29+
* var v = parseUint64( '1234' );
30+
* // returns <Uint64>[ 1234n ]
31+
*
32+
* v = parseUint64( '18446744073709551615' );
33+
* // returns <Uint64>[ 18446744073709551615n ]
34+
*
35+
* v = parseUint64( '0xffffffffffffffff' );
36+
* // returns <Uint64>[ 18446744073709551615n ]
37+
*
38+
* v = parseUint64( '3w5e11264sgsf', 36 );
39+
* // returns <Uint64>[ 18446744073709551615n ]
3140
*/
3241

3342
// MAIN //

lib/node_modules/@stdlib/number/uint64/parse/lib/main.js

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,44 +20,120 @@
2020

2121
// MODULES //
2222

23+
var isBetween = require( '@stdlib/assert/is-between' );
24+
var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
2325
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
26+
var isEmptyString = require( '@stdlib/assert/is-empty-string' ).isPrimitive;
2427
var Uint64 = require( '@stdlib/number/uint64/ctor' );
2528
var trim = require( '@stdlib/string/base/trim' );
2629
var slice = require( '@stdlib/string/base/slice' );
2730
var format = require( '@stdlib/string/format' );
2831
var parse = require( './parse.js' );
2932

3033

34+
// VARIABLES //
35+
36+
var RE_HEX = /^0[Xx]/;
37+
var RE_BIN = /^0[Bb]/;
38+
var RE_OCT = /^0[Oo]/;
39+
var DIGITS = '0123456789abcdefghijklmnopqrstuvwxyz';
40+
var WORKSPACE = [ 0, 0 ];
41+
42+
3143
// MAIN //
3244

3345
/**
3446
* Parses a string as an unsigned 64-bit integer.
3547
*
3648
* @param {string} str - string representation of a nonnegative integer
37-
* @throws {TypeError} must provide a string encoding a nonnegative integer
49+
* @param {PositiveInteger} [radix=10] - radix (base) to use for string conversion (2-36)
50+
* @throws {TypeError} must provide a string
51+
* @throws {RangeError} must provide an integer on the interval [2, 36]
52+
* @throws {Error} must provide a string encoding a nonnegative integer
3853
* @returns {Uint64} unsigned 64-bit integer
3954
*
4055
* @example
41-
* var v = parseUint64( '5' );
42-
* // returns <Uint64>
56+
* var v = parseUint64( '1234' );
57+
* // returns <Uint64>[ 1234n ]
58+
*
59+
* v = parseUint64( '18446744073709551615' );
60+
* // returns <Uint64>[ 18446744073709551615n ]
61+
*
62+
* v = parseUint64( '0xffffffffffffffff' );
63+
* // returns <Uint64>[ 18446744073709551615n ]
64+
*
65+
* v = parseUint64( '3w5e11264sgsf', 36 );
66+
* // returns <Uint64>[ 18446744073709551615n ]
4367
*/
44-
function parseUint64( str ) {
68+
function parseUint64( str, radix ) {
69+
var validChars;
70+
var reInv;
71+
var rad;
4572
var v;
73+
var i;
74+
4675
if ( !isString( str ) ) {
4776
throw new TypeError( format( 'invalid argument. Must provide a string. Value: `%s`.', str ) );
4877
}
78+
4979
v = trim( str );
50-
if ( v[ 0 ] === '-' ) {
51-
throw new TypeError( format( 'invalid argument. Must provide a string encoding a nonnegative integer. Value: `%s`.', str ) );
80+
if ( v[0] === '-' ) {
81+
throw new Error( format( 'invalid argument. Must provide a string encoding a nonnegative integer. Value: `%s`.', str ) );
5282
}
53-
if ( v[ 0 ] === '+' ) {
83+
84+
if ( v[0] === '+' ) {
5485
v = slice( v, 1 );
5586
}
56-
v = parse( v );
57-
if ( v[ 0 ] === -1 ) {
58-
throw new TypeError( format( 'invalid argument. Must provide a string encoding a nonnegative integer. Value: `%s`.', str ) );
87+
88+
if ( arguments.length < 2 ) {
89+
if ( RE_BIN.test( v ) ) {
90+
rad = 2;
91+
} else if ( RE_OCT.test( v ) ) {
92+
rad = 8;
93+
} else if ( RE_HEX.test( v ) ) {
94+
rad = 16;
95+
} else {
96+
rad = 10;
97+
}
98+
99+
if ( rad !== 10 ) {
100+
v = slice( v, 2 );
101+
}
102+
} else if ( !isInteger( radix ) ) {
103+
throw new TypeError( format( 'invalid argument. Must provide an integer. Value: `%s`.', radix ) );
104+
} else if ( isBetween( radix, 2, 36 ) ) {
105+
rad = radix;
106+
} else {
107+
throw new RangeError( format( 'invalid argument. Must provide an integer on the interval [2, 36]. Value: `%s`.', radix ) );
108+
}
109+
110+
if ( isEmptyString( v ) ) {
111+
throw new Error( format( 'invalid argument. Must provide a non-empty string encoding a nonnegative integer. Value: `%s`.', str ) );
112+
}
113+
114+
// Trim leading zeros
115+
i = 0;
116+
while ( ( i < v.length-1 ) && ( v[i] === '0' ) ) {
117+
i += 1;
118+
}
119+
v = slice( v, i );
120+
121+
// Validate digits with respect to radix
122+
validChars = slice( DIGITS, 0, rad );
123+
reInv = new RegExp( format( '[^%s]', validChars ), 'i' );
124+
if ( reInv.test( v ) ) {
125+
throw new Error( format( 'invalid argument. Cannot parse a string containing invalid characters. Value: `%s`.', str ) );
126+
}
127+
128+
// Reset the workspace:
129+
WORKSPACE[ 0 ] = 0;
130+
WORKSPACE[ 1 ] = 0;
131+
parse( v, rad, WORKSPACE );
132+
133+
if ( WORKSPACE[ 0 ] === -1 ) {
134+
throw new RangeError( format( 'invalid argument. Must provide a string encoding a nonnegative integer smaller than 2^64. Value: `%s`.', str ) );
59135
}
60-
return Uint64.from( v );
136+
return Uint64.from( WORKSPACE );
61137
}
62138

63139

0 commit comments

Comments
 (0)