commit d742e7ff32ec12b64bbc22f06f6151dcbc85406b
parent b8ce13679066591a2630f8b5461de42f8ab11b9a
Author: Andri Yngvason <andri@yngvason.is>
Date: Fri, 5 Feb 2021 00:31:22 +0000
strconv: add string to unsigned integer converters
Diffstat:
2 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/strconv/stou+test.ha b/strconv/stou+test.ha
@@ -0,0 +1,34 @@
+fn is_invalid64(value: (u64 | invalid | overflow)) bool = {
+ return match (value) {
+ invalid => true,
+ * => false,
+ };
+};
+
+fn is_overflow64(value: (u64 | invalid | overflow)) bool = {
+ return match (value) {
+ overflow => true,
+ * => false,
+ };
+};
+
+fn is_number64(n: u64, value: (u64 | invalid | overflow)) bool = {
+ return match (value) {
+ v: u64 => v == n,
+ * => false,
+ };
+};
+
+@test fn stou() void = {
+ assert(is_invalid64(stou64("")));
+ assert(is_invalid64(stou64("abc")));
+ assert(is_invalid64(stou64("1a")));
+ assert(is_invalid64(stou64("-1")));
+
+ assert(is_overflow64(stou64("18446744073709551616")));
+ assert(is_overflow64(stou64("184467440737095516150")));
+
+ assert(is_number64(0u64, stou64("0")));
+ assert(is_number64(1u64, stou64("1")));
+ assert(is_number64(18446744073709551615u64, stou64("18446744073709551615")));
+};
diff --git a/strconv/stou.ha b/strconv/stou.ha
@@ -0,0 +1,117 @@
+use strings;
+use types;
+use ascii;
+use encoding::utf8;
+
+// Indicates that the input string is not an integer
+export type invalid = void;
+
+// Indicates that the input number is too large to be represented by the
+// requested data type
+export type overflow = void;
+
+// Converts a string to a u64 in base 10. If the string contains any non-numeric
+// characters, or if it's empty, [strconv::invalid] is returned. If the number
+// is too large to be represented by a u64, [strconv::overflow] is returned.
+export fn stou64(s: str) (u64 | invalid | overflow) = {
+ if (len(s) == 0z) {
+ return invalid;
+ };
+ let n = 0u64;
+ let iter = strings::iter(s);
+ for (true) {
+ let r: rune = match (strings::next(&iter)) {
+ void => break,
+ r: rune => r,
+ };
+
+ if (!ascii::isascii(r: u32: u8) || !ascii::isdigit(r: u32: u8)) {
+ return invalid;
+ };
+
+ let old = n;
+
+ n *= 10u64;
+ n += (r: u32 - '0': u32): u64;
+
+ if (n < old) {
+ return overflow;
+ };
+ };
+ return n;
+};
+
+// Converts a string to a u32 in base 10. If the string contains any non-numeric
+// characters, or if it's empty, [strconv::invalid] is returned. If the number
+// is too large to be represented by a u32, [strconv::overflow] is returned.
+export fn stou32(s: str) (u32 | invalid | overflow) = {
+ match (stou64(s)) {
+ v: (invalid | overflow) => return v,
+ n: u64 => {
+ if (n <= types::U32_MAX: u64) {
+ return n: u32;
+ };
+ return overflow;
+ },
+ };
+};
+
+// Converts a string to a u16 in base 10. If the string contains any non-numeric
+// characters, or if it's empty, [strconv::invalid] is returned. If the number
+// is too large to be represented by a u16, [strconv::overflow] is returned.
+export fn stou16(s: str) (u16 | invalid | overflow) = {
+ match (stou64(s)) {
+ v: (invalid | overflow) => return v,
+ n: u64 => {
+ if (n <= types::U16_MAX: u64) {
+ return n: u16;
+ };
+ return overflow;
+ },
+ };
+};
+
+// Converts a string to a u8 in base 10. If the string contains any non-numeric
+// characters, or if it's empty, [strconv::invalid] is returned. If the number
+// is too large to be represented by a u8, [strconv::overflow] is returned.
+export fn stou8(s: str) (u8 | invalid | overflow) = {
+ match (stou64(s)) {
+ v: (invalid | overflow) => return v,
+ n: u64 => {
+ if (n <= types::U8_MAX: u64) {
+ return n: u8;
+ };
+ return overflow;
+ },
+ };
+};
+
+// Converts a string to a uint in base 10. If the string contains any
+// non-numeric characters, or if it's empty, [strconv::invalid] is returned. If
+// the number is too large to be represented by a uint, [strconv::overflow] is
+// returned.
+export fn stou(s: str) (uint | invalid | overflow) = {
+ static assert(size(uint) == size(u32) || size(uint) == size(u64));
+ return if (size(uint) == size(u32)) match (stou32(s)) {
+ v: (invalid | overflow) => v,
+ n: u32 => n: uint,
+ } else match (stou64(s)) {
+ v: (invalid | overflow) => v,
+ n: u64 => n: uint,
+ };
+};
+
+// Converts a string to a size in base 10. If the string contains any
+// non-numeric characters, or if it's empty, [strconv::invalid] is returned. If
+// the number is too large to be represented by a size, [strconv::overflow] is
+// returned.
+export fn stoz(s: str) (size | invalid | overflow) = {
+ static assert(size(size) == size(u32) || size(size) == size(u64));
+ return if (size(size) == size(u32)) match (stou32(s)) {
+ v: (invalid | overflow) => v,
+ n: u32 => n: size,
+ } else match (stou64(s)) {
+ v: (invalid | overflow) => v,
+ n: u64 => n: size,
+ };
+};