commit fd0359ea21f152be1f82f33db5d3f3b2b297458b
parent 63b409faa151502c7bf219395759986626a9e0c6
Author: Andri Yngvason <andri@yngvason.is>
Date: Sat, 6 Feb 2021 16:45:08 +0000
strconv: add string-to-integer converter
Diffstat:
A | strconv/+test/stoi.ha | | | 55 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | strconv/stoi.ha | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 146 insertions(+), 0 deletions(-)
diff --git a/strconv/+test/stoi.ha b/strconv/+test/stoi.ha
@@ -0,0 +1,55 @@
+fn is_invalid_i64(value: (i64 | invalid | overflow)) bool = {
+ return match (value) {
+ invalid => true,
+ * => false,
+ };
+};
+
+fn is_overflow_i64(value: (i64 | invalid | overflow)) bool = {
+ return match (value) {
+ overflow => true,
+ * => false,
+ };
+};
+
+fn is_number_i64(n: i64, value: (i64 | invalid | overflow)) bool = {
+ return match (value) {
+ v: i64 => v == n,
+ * => false,
+ };
+};
+
+fn is_overflow_i32(value: (i32 | invalid | overflow)) bool = {
+ return match (value) {
+ overflow => true,
+ * => false,
+ };
+};
+
+fn is_number_i32(n: i32, value: (i32 | invalid | overflow)) bool = {
+ return match (value) {
+ v: i32 => v == n,
+ * => false,
+ };
+};
+
+@test fn stoi() void = {
+ assert(is_invalid_i64(stoi64("")));
+ assert(is_invalid_i64(stoi64("abc")));
+ assert(is_invalid_i64(stoi64("1a")));
+
+ assert(is_overflow_i64(stoi64("9223372036854775808")));
+ assert(is_overflow_i64(stoi64("-9223372036854775809")));
+
+ assert(is_number_i64(0i64, stoi64("0")));
+ assert(is_number_i64(1i64, stoi64("1")));
+ assert(is_number_i64(-1i64, stoi64("-1")));
+ assert(is_number_i64(9223372036854775807i64, stoi64("9223372036854775807")));
+ assert(is_number_i64(-9223372036854775808i64, stoi64("-9223372036854775808")));
+
+ assert(is_overflow_i32(stoi32("2147483648")));
+ assert(is_overflow_i32(stoi32("-2147483649")));
+
+ assert(is_number_i32(2147483647i32, stoi32("2147483647")));
+ assert(is_number_i32(-2147483648i32, stoi32("-2147483648")));
+};
diff --git a/strconv/stoi.ha b/strconv/stoi.ha
@@ -0,0 +1,91 @@
+use types;
+use strings;
+
+// Converts a string to an i64 in base 10. If the string contains any
+// non-numeric characters, except '-' at the start, or if it's empty,
+// [strconv::invalid] is returned. If the number is too large to be represented
+// by an i64, [strconv::overflow] is returned.
+export fn stoi64(s: str) (i64 | invalid | overflow) = {
+ if (len(s) == 0z) return invalid;
+ let b = strings::to_utf8(s);
+ let sign = 1i64;
+ let max = types::I64_MAX: u64;
+ if (b[0] == '-': u32: u8) {
+ sign = -1i64;
+ max += 1u64;
+ };
+ let u = if (sign < 0i64) stou64(strings::from_utf8_unsafe(b[1..]))
+ else stou64(s);
+ match(u) {
+ v: (invalid | overflow) => return v,
+ n: u64 => {
+ if (n > max) {
+ return overflow;
+ };
+ return n: i64 * sign;
+ },
+ };
+};
+
+// Converts a string to an i32 in base 10. If the string contains any
+// non-numeric characters, except '-' at the start, or if it's empty,
+// [strconv::invalid] is returned. If the number is too large to be represented
+// by an i32, [strconv::overflow] is returned.
+export fn stoi32(s: str) (i32 | invalid | overflow) = {
+ match (stoi64(s)) {
+ v: (invalid | overflow) => return v,
+ n: i64 => {
+ if (n >= types::I32_MIN: i64 && n <= types::I32_MAX: i64) {
+ return n: i32;
+ };
+ return overflow;
+ },
+ };
+};
+
+// Converts a string to an i16 in base 10. If the string contains any
+// non-numeric characters, except '-' at the start, or if it's empty,
+// [strconv::invalid] is returned. If the number is too large to be represented
+// by an i16, [strconv::overflow] is returned.
+export fn stoi16(s: str) (i16 | invalid | overflow) = {
+ match (stoi64(s)) {
+ v: (invalid | overflow) => return v,
+ n: i64 => {
+ if (n >= types::I16_MIN: i64 && n <= types::I16_MAX: i64) {
+ return n: i16;
+ };
+ return overflow;
+ },
+ };
+};
+
+// Converts a string to an i8 in base 10. If the string contains any
+// non-numeric characters, except '-' at the start, or if it's empty,
+// [strconv::invalid] is returned. If the number is too large to be represented
+// by an i8, [strconv::overflow] is returned.
+export fn stoi8(s: str) (i8 | invalid | overflow) = {
+ match (stoi64(s)) {
+ v: (invalid | overflow) => return v,
+ n: i64 => {
+ if (n >= types::I8_MIN: i64 && n <= types::I8_MAX: i64) {
+ return n: i8;
+ };
+ return overflow;
+ },
+ };
+};
+
+// Converts a string to an int in base 10. If the string contains any
+// non-numeric characters, except '-' at the start, or if it's empty,
+// [strconv::invalid] is returned. If the number is too large to be represented
+// by an int, [strconv::overflow] is returned.
+export fn stoi(s: str) (int | invalid | overflow) = {
+ static assert(size(int) == size(i32) || size(int) == size(i64));
+ return if (size(int) == size(i32)) match (stoi32(s)) {
+ v: (invalid | overflow) => v,
+ n: i32 => n: int,
+ } else match (stoi64(s)) {
+ v: (invalid | overflow) => v,
+ n: i64 => n: int,
+ };
+};