commit c8fa5a819a862b7e5b0a2bc5a986ca2b79ff0dcb
parent e7705d104acf25a709e9d873a5bdd54f4a664403
Author: Joe Finney <me@spxtr.net>
Date: Thu, 22 Feb 2024 15:14:29 +0000
strconv: Minor stylistic fixes for stoi/stou.
- Doc string text improved: non-numeric characters are allowed for hex.
- Overflow checks put into a helper function.
- Tests brought into the same file as code. They're simple tests.
Signed-off-by: Joe Finney <me@spxtr.net>
Diffstat:
4 files changed, 168 insertions(+), 217 deletions(-)
diff --git a/strconv/+test/stoi_test.ha b/strconv/+test/stoi_test.ha
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// (c) Hare authors <https://harelang.org>
-
-use types;
-
-@test fn stoi() void = {
- assert(stoi64("") as invalid == 0);
- assert(stoi64("abc") as invalid == 0);
- assert(stoi64("1a") as invalid == 1);
- assert(stoi64("+") as invalid == 1);
- assert(stoi64("-+") as invalid == 1);
- assert(stoi64("-z") as invalid == 1);
-
- assert(stoi64("9223372036854775808") is overflow);
- assert(stoi64("-9223372036854775809") is overflow);
-
- assert(stoi64("0") as i64 == 0);
- assert(stoi64("1") as i64 == 1);
- assert(stoi64("+1") as i64 == 1);
- assert(stoi64("-1") as i64 == -1);
- assert(stoi64("9223372036854775807") as i64 == types::I64_MAX);
- assert(stoi64("-9223372036854775808") as i64 == types::I64_MIN);
-
- assert(stoi32("2147483648") is overflow);
- assert(stoi32("-2147483649") is overflow);
-
- assert(stoi32("2147483647") as i32 == 2147483647);
- assert(stoi32("-2147483648") as i32 == -2147483648);
-};
-
-@test fn stoib() void = {
- assert(stoi64b("-7f", 16) as i64 == -0x7f);
- assert(stoi64b("7F", 16) as i64 == 0x7f);
- assert(stoi64b("37", 8) as i64 == 0o37);
- assert(stoi64b("-110101", 2) as i64 == -0b110101);
-};
diff --git a/strconv/+test/stou_test.ha b/strconv/+test/stou_test.ha
@@ -1,25 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// (c) Hare authors <https://harelang.org>
-
-@test fn stou() void = {
- assert(stou64("") as invalid == 0);
- assert(stou64("+") as invalid == 1);
- assert(stou64("+a") as invalid == 1);
- assert(stou64("abc") as invalid == 0);
- assert(stou64("1a") as invalid == 1);
-
- assert(stou64("18446744073709551616") is overflow);
- assert(stou64("184467440737095516150") is overflow);
- assert(stou64("-1") is overflow);
-
- assert(stou64("0") as u64 == 0);
- assert(stou64("1") as u64 == 1);
- assert(stou64("18446744073709551615") as u64 == 18446744073709551615);
-};
-
-@test fn stoub() void = {
- assert(stou64b("7f", 16) as u64 == 0x7f);
- assert(stou64b("7F", 16) as u64 == 0x7f);
- assert(stou64b("37", 8) as u64 == 0o37);
- assert(stou64b("110101", 2) as u64 == 0b110101);
-};
diff --git a/strconv/stoi.ha b/strconv/stoi.ha
@@ -4,10 +4,9 @@
use strings;
use types;
-// Converts a string to an i64 in the given base. If the string contains any
-// non-numeric characters, except '-' or '+' at the start, or if it's empty,
-// [[invalid]] is returned. If the number is too large to be represented by an
-// i64, [[overflow]] is returned.
+// Converts a string to an i64 in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by an i64.
export fn stoi64b(s: str, base: base) (i64 | invalid | overflow) = {
let (sign, u) = parseint(s, base)?;
// Two's complement: I64_MIN = -I64_MAX - 1
@@ -18,79 +17,96 @@ export fn stoi64b(s: str, base: base) (i64 | invalid | overflow) = {
return u: i64 * (if (sign) -1 else 1);
};
-// Converts a string to an i32 in the given base. If the string contains any
-// non-numeric characters, except '-' or '+' at the start, or if it's empty,
-// [[invalid]] is returned. If the number is too large to be represented by an
-// i32, [[overflow]] is returned.
-export fn stoi32b(s: str, base: base) (i32 | invalid | overflow) = {
- let n = stoi64b(s, base)?;
- if (n >= types::I32_MIN: i64 && n <= types::I32_MAX: i64) {
- return n: i32;
+fn stoiminmax(
+ s: str,
+ base: base,
+ min: i64,
+ max: i64,
+) (i64 | invalid | overflow) = {
+ const n = stoi64b(s, base)?;
+ if (n < min || n > max) {
+ return overflow;
};
- return overflow;
+ return n;
};
-// Converts a string to an i16 in the given base. If the string contains any
-// non-numeric characters, except '-' or '+' at the start, or if it's empty,
-// [[invalid]] is returned. If the number is too large to be represented by an
-// i16, [[overflow]] is returned.
-export fn stoi16b(s: str, base: base) (i16 | invalid | overflow) = {
- let n = stoi64b(s, base)?;
- if (n >= types::I16_MIN: i64 && n <= types::I16_MAX: i64) {
- return n: i16;
- };
- return overflow;
-};
+// Converts a string to an i32 in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by an i32.
+export fn stoi32b(s: str, base: base) (i32 | invalid | overflow) =
+ stoiminmax(s, base, types::I32_MIN, types::I32_MAX)?: i32;
-// Converts a string to an i8 in the given base. If the string contains any
-// non-numeric characters, except '-' or '+' at the start, or if it's empty,
-// [[invalid]] is returned. If the number is too large to be represented by an
-// i8, [[overflow]] is returned.
-export fn stoi8b(s: str, base: base) (i8 | invalid | overflow) = {
- let n= stoi64b(s, base)?;
- if (n >= types::I8_MIN: i64 && n <= types::I8_MAX: i64) {
- return n: i8;
- };
- return overflow;
-};
+// Converts a string to an i16 in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by an i16.
+export fn stoi16b(s: str, base: base) (i16 | invalid | overflow) =
+ stoiminmax(s, base, types::I16_MIN, types::I16_MAX)?: i16;
+
+// Converts a string to an i8 in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by an i8.
+export fn stoi8b(s: str, base: base) (i8 | invalid | overflow) =
+ stoiminmax(s, base, types::I8_MIN, types::I8_MAX)?: i8;
+
+// Converts a string to an int in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by an int.
+export fn stoib(s: str, base: base) (int | invalid | overflow) =
+ stoiminmax(s, base, types::INT_MIN, types::INT_MAX)?: int;
+
+// Converts a string to an i64 in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by an i64.
+export fn stoi64(s: str) (i64 | invalid | overflow) = stoi64b(s, base::DEC);
+
+// Converts a string to an i32 in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by an i32.
+export fn stoi32(s: str) (i32 | invalid | overflow) = stoi32b(s, base::DEC);
-// Converts a string to an int in the given base. If the string contains any
-// non-numeric characters, except '-' or '+' at the start, or if it's empty,
-// [[invalid]] is returned. If the number is too large to be represented by an
-// int, [[overflow]] is returned.
-export fn stoib(s: str, base: base) (int | invalid | overflow) = {
- static assert(size(int) == size(i32) || size(int) == size(i64));
- return
- if (size(int) == size(i32)) stoi32b(s, base)?: int
- else stoi64b(s, base)?: int;
+// Converts a string to an i16 in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by an i16.
+export fn stoi16(s: str) (i16 | invalid | overflow) = stoi16b(s, base::DEC);
+
+// Converts a string to an i8 in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by an i8.
+export fn stoi8(s: str) (i8 | invalid | overflow) = stoi8b(s, base::DEC);
+
+// Converts a string to an int in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by an int.
+export fn stoi(s: str) (int | invalid | overflow) = stoib(s, base::DEC);
+
+@test fn stoi() void = {
+ assert(stoi64("") as invalid == 0);
+ assert(stoi64("abc") as invalid == 0);
+ assert(stoi64("1a") as invalid == 1);
+ assert(stoi64("+") as invalid == 1);
+ assert(stoi64("-+") as invalid == 1);
+ assert(stoi64("-z") as invalid == 1);
+
+ assert(stoi64("9223372036854775808") is overflow);
+ assert(stoi64("-9223372036854775809") is overflow);
+
+ assert(stoi64("0") as i64 == 0);
+ assert(stoi64("1") as i64 == 1);
+ assert(stoi64("+1") as i64 == 1);
+ assert(stoi64("-1") as i64 == -1);
+ assert(stoi64("9223372036854775807") as i64 == types::I64_MAX);
+ assert(stoi64("-9223372036854775808") as i64 == types::I64_MIN);
+
+ assert(stoi32("2147483648") is overflow);
+ assert(stoi32("-2147483649") is overflow);
+
+ assert(stoi32("2147483647") as i32 == 2147483647);
+ assert(stoi32("-2147483648") as i32 == -2147483648);
};
-// Converts a string to an i64 in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by an i64, [[overflow]] is
-// returned.
-export fn stoi64(s: str) (i64 | invalid | overflow) = stoi64b(s, 10);
-
-// Converts a string to an i32 in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by an i32, [[overflow]] is
-// returned.
-export fn stoi32(s: str) (i32 | invalid | overflow) = stoi32b(s, 10);
-
-// Converts a string to an i16 in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by an i16, [[overflow]] is
-// returned.
-export fn stoi16(s: str) (i16 | invalid | overflow) = stoi16b(s, 10);
-
-// Converts a string to an i8 in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by an i8, [[overflow]] is
-// returned.
-export fn stoi8(s: str) (i8 | invalid | overflow) = stoi8b(s, 10);
-
-// Converts a string to an int in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by an int, [[overflow]] is
-// returned.
-export fn stoi(s: str) (int | invalid | overflow) = stoib(s, 10);
+@test fn stoib() void = {
+ assert(stoi64b("-7f", 16) as i64 == -0x7f);
+ assert(stoi64b("7F", 16) as i64 == 0x7f);
+ assert(stoi64b("37", 8) as i64 == 0o37);
+ assert(stoi64b("-110101", 2) as i64 == -0b110101);
+};
diff --git a/strconv/stou.ha b/strconv/stou.ha
@@ -63,9 +63,9 @@ fn parseint(s: str, base: base) ((bool, u64) | invalid | overflow) = {
return (sign, n);
};
-// Converts a string to a u64 in the given base, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a u64, [[overflow]] is returned.
+// Converts a string to a u64 in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by a u64.
export fn stou64b(s: str, base: base) (u64 | invalid | overflow) = {
let (sign, u) = parseint(s, base)?;
if (sign) {
@@ -74,97 +74,93 @@ export fn stou64b(s: str, base: base) (u64 | invalid | overflow) = {
return u;
};
-// Converts a string to a u32 in the given base, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a u32, [[overflow]] is returned.
-export fn stou32b(s: str, base: base) (u32 | invalid | overflow) = {
- let n = stou64b(s, base)?;
- if (n <= types::U32_MAX: u64) {
- return n: u32;
- };
- return overflow;
-};
-
-// Converts a string to a u16 in the given base, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a u16, [[overflow]] is returned.
-export fn stou16b(s: str, base: base) (u16 | invalid | overflow) = {
- let n = stou64b(s, base)?;
- if (n <= types::U16_MAX: u64) {
- return n: u16;
- };
- return overflow;
-};
-
-// Converts a string to a u8 in the given base, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a u8, [[overflow]] is returned.
-export fn stou8b(s: str, base: base) (u8 | invalid | overflow) = {
- let n = stou64b(s, base)?;
- if (n <= types::U8_MAX: u64) {
- return n: u8;
- };
- return overflow;
-};
-
-// Converts a string to a uint in the given base, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a uint, [[overflow]] is returned.
-export fn stoub(s: str, base: base) (uint | invalid | overflow) = {
- static assert(size(uint) == size(u32) || size(uint) == size(u64));
- return
- if (size(uint) == size(u32)) stou32b(s, base)?: uint
- else stou64b(s, base)?: uint;
-};
-
-// Converts a string to a size in the given base, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a size, [[overflow]] is returned.
-export fn stozb(s: str, base: base) (size | invalid | overflow) = {
- static assert(size(size) == size(u32) || size(size) == size(u64));
- if (size(size) == size(u32)) {
- match (stou32b(s, base)) {
- case let v: (invalid | overflow) =>
- return v;
- case let n: u32 =>
- return n: size;
- };
- } else {
- match (stou64b(s, base)) {
- case let v: (invalid | overflow) =>
- return v;
- case let n: u64 =>
- return n: size;
- };
+fn stoumax(s: str, base: base, max: u64) (u64 | invalid | overflow) = {
+ const n = stou64b(s, base)?;
+ if (n > max) {
+ return overflow;
};
+ return n;
};
-// Converts a string to a u64 in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a u64, [[overflow]] is returned.
+// Converts a string to a u32 in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by a u32.
+export fn stou32b(s: str, base: base) (u32 | invalid | overflow) =
+ stoumax(s, base, types::U32_MAX)?: u32;
+
+// Converts a string to a u16 in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by a u16.
+export fn stou16b(s: str, base: base) (u16 | invalid | overflow) =
+ stoumax(s, base, types::U16_MAX)?: u16;
+
+// Converts a string to a u8 in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by a u8.
+export fn stou8b(s: str, base: base) (u8 | invalid | overflow) =
+ stoumax(s, base, types::U8_MAX)?: u8;
+
+// Converts a string to a uint in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by a uint.
+export fn stoub(s: str, base: base) (uint | invalid | overflow) =
+ stoumax(s, base, types::UINT_MAX)?: uint;
+
+// Converts a string to a size in the given base. Returns [[invalid]] if the
+// string is empty or contains invalid characters. Returns [[overflow]] if the
+// number is too large to be represented by a size.
+export fn stozb(s: str, base: base) (size | invalid | overflow) =
+ stoumax(s, base, types::SIZE_MAX)?: size;
+
+// Converts a string to a u64 in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by a u64.
export fn stou64(s: str) (u64 | invalid | overflow) = stou64b(s, base::DEC);
-// Converts a string to a u32 in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a u32, [[overflow]] is returned.
+// Converts a string to a u32 in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by a u32.
export fn stou32(s: str) (u32 | invalid | overflow) = stou32b(s, base::DEC);
-// Converts a string to a u16 in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a u16, [[overflow]] is returned.
+// Converts a string to a u16 in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by a u16.
export fn stou16(s: str) (u16 | invalid | overflow) = stou16b(s, base::DEC);
-// Converts a string to a u8 in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a u8, [[overflow]] is returned.
+// Converts a string to a u8 in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by a u8.
export fn stou8(s: str) (u8 | invalid | overflow) = stou8b(s, base::DEC);
-// Converts a string to a uint in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a uint, [[overflow]] is returned.
+// Converts a string to a uint in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by a uint.
export fn stou(s: str) (uint | invalid | overflow) = stoub(s, base::DEC);
-// Converts a string to a size in base 10, If the string contains any
-// non-numeric characters, or if it's empty, [[invalid]] is returned. If the
-// number is too large to be represented by a size, [[overflow]] is returned.
+// Converts a string to a size in base 10. Returns [[invalid]] if the string is
+// empty or contains invalid characters. Returns [[overflow]] if the number is
+// too large to be represented by a size.
export fn stoz(s: str) (size | invalid | overflow) = stozb(s, base::DEC);
+
+@test fn stou() void = {
+ assert(stou64("") as invalid == 0);
+ assert(stou64("+") as invalid == 1);
+ assert(stou64("+a") as invalid == 1);
+ assert(stou64("abc") as invalid == 0);
+ assert(stou64("1a") as invalid == 1);
+
+ assert(stou64("18446744073709551616") is overflow);
+ assert(stou64("184467440737095516150") is overflow);
+ assert(stou64("-1") is overflow);
+
+ assert(stou64("0") as u64 == 0);
+ assert(stou64("1") as u64 == 1);
+ assert(stou64("18446744073709551615") as u64 == 18446744073709551615);
+};
+
+@test fn stoub() void = {
+ assert(stou64b("7f", 16) as u64 == 0x7f);
+ assert(stou64b("7F", 16) as u64 == 0x7f);
+ assert(stou64b("37", 8) as u64 == 0o37);
+ assert(stou64b("110101", 2) as u64 == 0b110101);
+};