hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Astrconv/stou+test.ha | 34++++++++++++++++++++++++++++++++++
Astrconv/stou.ha | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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, + }; +};