diff --git a/vlib/math/unsigned/uint128.v b/vlib/math/unsigned/uint128.v index a22c0d5100..3195713d8a 100644 --- a/vlib/math/unsigned/uint128.v +++ b/vlib/math/unsigned/uint128.v @@ -423,12 +423,20 @@ pub fn uint128_new(lo u64, hi u64) Uint128 { return Uint128{lo, hi} } -// unint_from_dec_str returns an error or new Uint128 from given string +// unint_from_dec_str returns an error or new Uint128 from given string. +// The `_` character is allowed as a separator. pub fn uint128_from_dec_str(value string) !Uint128 { mut res := unsigned.uint128_zero - for b_ in value.bytes() { - b := b_ - '0'.bytes()[0] + underscore := `_` + + for b_ in value { + b := b_ - `0` if b > 9 { + // allow _ as a separator in decimal strings + if b_ == underscore { + continue + } + return error('invalid character "${b}"') } diff --git a/vlib/math/unsigned/uint128_test.v b/vlib/math/unsigned/uint128_test.v index 5ad59a9eb4..658db896fd 100644 --- a/vlib/math/unsigned/uint128_test.v +++ b/vlib/math/unsigned/uint128_test.v @@ -97,3 +97,76 @@ fn test_leading_zeros() { assert zeros == tc.zeros } } + +fn test_separators() { + // numbers of varying lengths and a random + // scattering of '_' throughout. + test_strings := [ + '_', + '__', + '_0', + '0_', + '_0_', + '_1', + '1_', + '_1_', + '1_2', + '_12', + '12_', + '12_3', + '1_23_4', + '12_345', + '_123_456_', + '1_234_567', + '1234_5678', + '_123456789', + '1234567890_', + '0_123_456_789_0', + '90_12_345_67890', + '8901_234_567890_', + '_7890_123456789_0', + '678901234_567890', + '567890_1234567890', + '4567890123__4567890', + '_34567890123_4567890', + '2345678_90123_4567890', + '123456789_01_234567890', + '01234567_8901234567890', + '9012345678901_234567890__', + '8_90123456_78901234567890', + '78901234567890_123_4567890', + '___67890123_4_5_6_78901234567890___', + '567890123_45678901234567890', + '45_67890123456789_01234567890', + '3456789012_345678901234567890', + '234_567890_1234_5__67890_1234567890_', + '12345678_90123_456789_0123_4567890', + '0_123_456_789_012_345_678_901_234_567_890', + '90_123456__78901__234567_8901_234567890', + '890123456789012345678901234567_890', + '7890_1234567_8901234567890_1234567890', + '67890123_45678_901234567_8901234567890', + '567890_1234567890_12345678901_234567890', + '45678_9012345_6789012345678901234567890_', + '34567890123456_789012345678901234567890', + '234567_890_1234567890_1234567890_1234567890', + '334567890_1234567890_1234567890_1234567890', + '340282360_0000000000_0000000000_0000000000', + '340282366_9209384634_2648111928_4349108225', + '340282366_9209384634_6337460743_1768211455', + ] + + for ts in test_strings { + with := unsigned.uint128_from_dec_str(ts) or { + assert false, 'invalid Uint128 string ${ts}' + panic('') + } + + without := unsigned.uint128_from_dec_str(ts.replace('_', '')) or { + assert false, 'invalid Uint128 string ${ts.replace('_', '')}' + panic('') + } + + assert with == without + } +}