diff options
| author | gingerBill <bill@gingerbill.org> | 2021-09-25 14:30:50 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-09-25 14:30:50 +0100 |
| commit | ebc09d5e4ee956e2ffa7e18f9f0c57af6433c64b (patch) | |
| tree | 53de9ca5bfb15c5c8ab69497a79ced4f4ca7e8e7 /core/strconv | |
| parent | bfc92d0aaf4e04b8378266e2ab25a8e381e34874 (diff) | |
Add `i128` and `u128` parsers to `strconv`
Diffstat (limited to 'core/strconv')
| -rw-r--r-- | core/strconv/strconv.odin | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 3bd1769d4..6b3a91b4c 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -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, |