Add i128 and u128 parsers to strconv

This commit is contained in:
gingerBill
2021-09-25 14:30:50 +01:00
parent bfc92d0aaf
commit ebc09d5e4e

View File

@@ -300,6 +300,229 @@ parse_uint :: proc(s: string, base := 0) -> (value: uint, ok: bool) {
}
// Parses an integer value from a string, in the given base, without a prefix.
//
// Returns ok=false if no numeric value of the appropriate base could be found,
// or if the input string contained more than just the number.
//
// ```
// n, ok := strconv.parse_i128_of_base("-1234eeee", 10);
// assert(n == -1234 && ok);
// ```
parse_i128_of_base :: proc(str: string, base: int) -> (value: i128, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
if s == "" {
return
}
neg := false
if len(s) > 1 {
switch s[0] {
case '-':
neg = true
s = s[1:]
case '+':
s = s[1:]
}
}
i := 0
for r in s {
if r == '_' {
i += 1
continue
}
v := i128(_digit_value(r))
if v >= i128(base) {
break
}
value *= i128(base)
value += v
i += 1
}
s = s[i:]
if neg {
value = -value
}
ok = len(s) == 0
return
}
// Parses a integer value from a string, in base 10, unless there's a prefix.
//
// Returns ok=false if a valid integer could not be found,
// or if the input string contained more than just the number.
//
// ```
// n, ok := strconv.parse_i128_maybe_prefixed("1234");
// assert(n == 1234 && ok);
//
// n, ok = strconv.parse_i128_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_i128_maybe_prefixed :: proc(str: string) -> (value: i128, ok: bool) {
s := str
if s == "" {
return
}
neg := false
if len(s) > 1 {
switch s[0] {
case '-':
neg = true
s = s[1:]
case '+':
s = s[1:]
}
}
base: i128 = 10
if len(s) > 2 && s[0] == '0' {
switch s[1] {
case 'b': base = 2; s = s[2:]
case 'o': base = 8; s = s[2:]
case 'd': base = 10; s = s[2:]
case 'z': base = 12; s = s[2:]
case 'x': base = 16; s = s[2:]
}
}
i := 0
for r in s {
if r == '_' {
i += 1
continue
}
v := i128(_digit_value(r))
if v >= base {
break
}
value *= base
value += v
i += 1
}
s = s[i:]
if neg {
value = -value
}
ok = len(s) == 0
return
}
parse_i128 :: proc{parse_i128_maybe_prefixed, parse_i128_of_base}
// Parses an unsigned integer value from a string, in the given base, and
// without a prefix.
//
// Returns ok=false if no numeric value of the appropriate base could be found,
// or if the input string contained more than just the number.
//
// ```
// n, ok := strconv.parse_u128_of_base("1234eeee", 10);
// assert(n == 1234 && ok);
//
// n, ok = strconv.parse_u128_of_base("5678eeee", 16);
// assert(n == 0x5678eeee && ok);
// ```
parse_u128_of_base :: proc(str: string, base: int) -> (value: u128, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
if s == "" {
return
}
if len(s) > 1 && s[0] == '+' {
s = s[1:]
}
i := 0
for r in s {
if r == '_' {
i += 1
continue
}
v := u128(_digit_value(r))
if v >= u128(base) {
break
}
value *= u128(base)
value += v
i += 1
}
s = s[i:]
ok = len(s) == 0
return
}
// Parses an unsigned integer value from a string in base 10, unless there's a prefix.
//
// Returns ok=false if a valid integer could not be found, if the value was negative,
// or if the input string contained more than just the number.
//
// ```
// n, ok := strconv.parse_u128_maybe_prefixed("1234");
// assert(n == 1234 && ok);
//
// n, ok = strconv.parse_u128_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_u128_maybe_prefixed :: proc(str: string) -> (value: u128, ok: bool) {
s := str
if s == "" {
return
}
if len(s) > 1 && s[0] == '+' {
s = s[1:]
}
base := u128(10)
if len(s) > 2 && s[0] == '0' {
switch s[1] {
case 'b': base = 2; s = s[2:]
case 'o': base = 8; s = s[2:]
case 'd': base = 10; s = s[2:]
case 'z': base = 12; s = s[2:]
case 'x': base = 16; s = s[2:]
}
}
i := 0
for r in s {
if r == '_' {
i += 1
continue
}
v := u128(_digit_value(r))
if v >= base {
break
}
value *= base
value += v
i += 1
}
s = s[i:]
ok = len(s) == 0
return
}
parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
// Parses a 32-bit floating point number from a string.
//
// Returns ok=false if a base 10 float could not be found,