commit a451ac939c64cde8ed34e3755e043668b3bd4823
parent 59ee4d834e0661599af4abced30727f27ee458ce
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 12 Feb 2021 10:38:22 -0500
strconv: expand non-decimal base support
- Use an enum for the valid bases
- Update numeric.ha to support bases
Diffstat:
3 files changed, 77 insertions(+), 41 deletions(-)
diff --git a/strconv/numeric.ha b/strconv/numeric.ha
@@ -1,9 +1,10 @@
use types;
-// Converts any [types::signed] to a string in base 10. The return value is
+// Converts any [types::signed] to a string in a given base. The return value is
// statically allocated and will be overwritten on subsequent calls; see
// [strings::dup] to duplicate the result.
-export fn signedtos(n: types::signed) const str = {
+export fn signedtosb(n: types::signed, b: base) const str = {
+ assert(b == base::DEC); // TODO
return match (n) {
i: int => itos(i),
i: i8 => i8tos(i),
@@ -13,43 +14,68 @@ export fn signedtos(n: types::signed) const str = {
};
};
-// Converts any [types::unsigned] to a string in base 10. The return value is
+// Converts any [types::signed] to a string in base 10. The return value is
// statically allocated and will be overwritten on subsequent calls; see
// [strings::dup] to duplicate the result.
-export fn unsignedtos(n: types::unsigned) const str = {
+export fn signedtos(n: types::signed) const str = signedtosb(n, base::DEC);
+
+// Converts any [types::unsigned] to a string in a given base. The return value
+// is statically allocated and will be overwritten on subsequent calls; see
+// [strings::dup] to duplicate the result.
+export fn unsignedtosb(n: types::unsigned, b: base) const str = {
return match (n) {
- u: size => ztos(u),
- u: uint => utos(u),
- u: u8 => u8tos(u),
- u: u16 => u16tos(u),
- u: u32 => u32tos(u),
- u: u64 => u64tos(u),
+ u: size => ztosb(u, b),
+ u: uint => utosb(u, b),
+ u: u8 => u8tosb(u, b),
+ u: u16 => u16tosb(u, b),
+ u: u32 => u32tosb(u, b),
+ u: u64 => u64tosb(u, b),
};
};
-// Converts any [types::integer] to a string in base 10. The return value is
+// Converts any [types::unsigned] to a string in base 10. The return value is
// statically allocated and will be overwritten on subsequent calls; see
// [strings::dup] to duplicate the result.
-export fn integertos(n: types::integer) const str = {
+export fn unsignedtos(n: types::unsigned) const str = unsignedtosb(n, base::DEC);
+
+// Converts any [types::integer] to a string in a given base, which must be 2,
+// 8, 10, or 16. The return value is statically allocated and will be
+// overwritten on subsequent calls; see [strings::dup] to duplicate the result.
+export fn integertosb(n: types::integer, b: base) const str = {
return match (n) {
- s: types::signed => signedtos(s),
- u: types::unsigned => unsignedtos(u),
+ s: types::signed => signedtosb(s, b),
+ u: types::unsigned => unsignedtosb(u, b),
};
};
-// Converts any [types::floating] to a string in base 10. The return value is
+// Converts any [types::integer] to a string in base 10. The return value is
// statically allocated and will be overwritten on subsequent calls; see
// [strings::dup] to duplicate the result.
-export fn floatingtos(n: types::floating) const str = {
+export fn integertos(n: types::integer) const str = integertosb(n, base::DEC);
+
+// Converts any [types::floating] to a string in a given base. The return value
+// is statically allocated and will be overwritten on subsequent calls; see
+// [strings::dup] to duplicate the result.
+export fn floatingtosb(n: types::floating, b: base) const str = {
abort(); // TODO
};
-// Converts any [types::numeric] to a string in base 10. The return value is
+// Converts any [types::floating] to a string in base 10. The return value is
// statically allocated and will be overwritten on subsequent calls; see
// [strings::dup] to duplicate the result.
-export fn numerictos(n: types::numeric) const str = {
+export fn floatingtos(n: types::floating) const str = floatingtosb(n, base::DEC);
+
+// Converts any [types::numeric] to a string in a given base. The return value
+// is statically allocated and will be overwritten on subsequent calls; see
+// [strings::dup] to duplicate the result.
+export fn numerictosb(n: types::numeric, b: base) const str = {
return match (n) {
- i: types::integer => integertos(i),
- f: types::floating => floatingtos(f),
+ i: types::integer => integertosb(i, b),
+ f: types::floating => floatingtosb(f, b),
};
};
+
+// Converts any [types::numeric] to a string in base 10. The return value is
+// statically allocated and will be overwritten on subsequent calls; see
+// [strings::dup] to duplicate the result.
+export fn numerictos(n: types::numeric) const str = numerictosb(n, base::DEC);
diff --git a/strconv/types.ha b/strconv/types.ha
@@ -4,3 +4,15 @@ export type invalid = void;
// Indicates that the input number is too large to be represented by the
// requested data type
export type overflow = void;
+
+// The valid numeric bases for numeric conversions.
+export type base = enum uint {
+ // Base 2, binary
+ BIN = 2,
+ // Base 8, octal
+ OCT = 8,
+ // Base 10, decimal
+ DEC = 10,
+ // Base 16, hexadecimal
+ HEX = 16,
+};
diff --git a/strconv/utos.ha b/strconv/utos.ha
@@ -3,11 +3,9 @@ use types;
// Converts a u64 to a string, in the given base. The return value is statically
// allocated and will be overwritten on subsequent calls; see [strings::dup] to
-// duplicate the result. Valid bases are 2, 8, 10 and 16.
-export fn u64tosb(u: u64, base: uint) const str = {
+// duplicate the result.
+export fn u64tosb(u: u64, b: base) const str = {
static assert(types::U64_MAX == 18446744073709551615);
- assert(base == 2 || base == 8 || base == 10 || base == 16);
-
static const lut: [_]rune = [
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
@@ -23,9 +21,9 @@ export fn u64tosb(u: u64, base: uint) const str = {
};
for (u > 0u64) {
- buf[s.length] = lut[(u % base: u64)]: u32: u8;
+ buf[s.length] = lut[(u % b: u64)]: u32: u8;
s.length += 1;
- u /= base;
+ u /= b;
};
bytes::reverse(buf[..s.length]);
@@ -35,33 +33,33 @@ export fn u64tosb(u: u64, base: uint) const str = {
// Converts a u32 to a string, in the given base. The return value is statically
// allocated and will be overwritten on subsequent calls; see [strings::dup] to
-// duplicate the result. Valid bases are 2, 8, 10 and 16.
-export fn u32tosb(u: u32, base: uint) const str = u64tosb(u: u32, base);
+// duplicate the result.
+export fn u32tosb(u: u32, b: base) const str = u64tosb(u: u32, b);
// Converts a u16 to a string, in the given base. The return value is statically
// allocated and will be overwritten on subsequent calls; see [strings::dup] to
-// duplicate the result. Valid bases are 2, 8, 10 and 16.
-export fn u16tosb(u: u16, base: uint) const str = u64tosb(u: u16, base);
+// duplicate the result.
+export fn u16tosb(u: u16, b: base) const str = u64tosb(u: u16, b);
// Converts a u8 to a string, in the given base. The return value is statically
// allocated and will be overwritten on subsequent calls; see [strings::dup] to
-// duplicate the result. Valid bases are 2, 8, 10 and 16.
-export fn u8tosb(u: u8, base: uint) const str = u64tosb(u: u8, base);
+// duplicate the result.
+export fn u8tosb(u: u8, b: base) const str = u64tosb(u: u8, b);
// Converts a uint to a string, in the given base. The return value is
// statically allocated and will be overwritten on subsequent calls; see
-// [strings::dup] to duplicate the result. Valid bases are 2, 8, 10 and 16.
-export fn utosb(u: uint, base: uint) const str = u64tosb(u: uint, base);
+// [strings::dup] to duplicate the result.
+export fn utosb(u: uint, b: base) const str = u64tosb(u: uint, b);
// Converts a size to a string, in the given base. The return value is
// statically allocated and will be overwritten on subsequent calls; see
-// [strings::dup] to duplicate the result. Valid bases are 2, 8, 10 and 16.
-export fn ztosb(u: uint, base: uint) const str = u64tosb(u: uint, base);
+// [strings::dup] to duplicate the result.
+export fn ztosb(u: size, b: base) const str = u64tosb(u: uint, b);
// Converts a u64 to a string, in base 10. The return value is statically
// allocated and will be overwritten on subsequent calls; see [strings::dup] to
// duplicate the result.
-export fn u64tos(u: u64) const str = u64tosb(u, 10u);
+export fn u64tos(u: u64) const str = u64tosb(u, base::DEC);
// Converts a u8 to a string, in base 10. The return value is statically
// allocated and will be overwritten on subsequent calls; see [strings::dup] to
@@ -94,10 +92,10 @@ export fn ztos(z: size) const str = u64tos(z: u64);
export fn uptrtos(uptr: uintptr) const str = u64tos(uptr: u64);
@test fn utosb() void = {
- assert("11010" == u64tosb(0b11010, 2));
- assert("1234567" == u64tosb(0o1234567, 8));
- assert("123456789" == u64tosb(123456789, 10));
- assert("123456789ABCDEF" == u64tosb(0x123456789ABCDEF, 16));
+ assert("11010" == u64tosb(0b11010, base::BIN));
+ assert("1234567" == u64tosb(0o1234567, base::OCT));
+ assert("123456789" == u64tosb(123456789, base::DEC));
+ assert("123456789ABCDEF" == u64tosb(0x123456789ABCDEF, base::HEX));
};
@test fn utos() void = {