aboutsummaryrefslogtreecommitdiff
path: root/core/strconv
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-09-25 14:30:50 +0100
committergingerBill <bill@gingerbill.org>2021-09-25 14:30:50 +0100
commitebc09d5e4ee956e2ffa7e18f9f0c57af6433c64b (patch)
tree53de9ca5bfb15c5c8ab69497a79ced4f4ca7e8e7 /core/strconv
parentbfc92d0aaf4e04b8378266e2ab25a8e381e34874 (diff)
Add `i128` and `u128` parsers to `strconv`
Diffstat (limited to 'core/strconv')
-rw-r--r--core/strconv/strconv.odin223
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,