diff --git a/luna/include/luna/NumberParsing.h b/luna/include/luna/NumberParsing.h index f4a709aa..e7c94bf5 100644 --- a/luna/include/luna/NumberParsing.h +++ b/luna/include/luna/NumberParsing.h @@ -1,7 +1,14 @@ #pragma once #include +// Parse an unsigned integer and advance *str to point to the first non-digit character after the number. usize scan_unsigned_integer(const char** str); + +// Parse a signed integer and advance *str to point to the first non-digit character after the number. isize scan_signed_integer(const char** str); + +// Parse an unsigned integer, similar to strtoull(). usize parse_unsigned_integer(const char* str, const char** endptr, int base); -isize parse_signed_integer(const char* str, const char** endptr, int base); + +// Parse a signed integer, similar to strtoll(). +isize parse_signed_integer(const char* str, const char** endptr, int base); \ No newline at end of file diff --git a/luna/src/NumberParsing.cpp b/luna/src/NumberParsing.cpp index 0938c06b..b9345452 100644 --- a/luna/src/NumberParsing.cpp +++ b/luna/src/NumberParsing.cpp @@ -17,12 +17,13 @@ static bool is_valid_digit_for_base(int base, char c) return true; } -usize parse_unsigned_integer(const char* str, const char** endptr, int base) +static usize do_unsigned_parse(const char* str, const char** endptr, int base) { usize val = 0; - while (_isspace(*str)) str++; - + // 1. If base is zero or 16, the string may then include a "0x" prefix, and the number will be read in base 16; + // otherwise, a zero base is taken as 10 (decimal) unless the next character is '0', in which case it is taken as + // 8 (octal). if ((base == 0 || base == 16) && *str == '0') { str++; @@ -37,17 +38,32 @@ usize parse_unsigned_integer(const char* str, const char** endptr, int base) else if (base == 0) base = 10; + // 2. The remainder of the string is converted to an unsigned long value in + // the obvious manner, stopping at the first character which is not a + // valid digit in the given base. while (is_valid_digit_for_base(base, *str)) { val = ((usize)base * val) + (usize)parse_digit_unchecked(*str); str++; } + // 3. If endptr is not NULL, this function stores the address of the first invalid character in *endptr. if (endptr) *endptr = str; return val; } +usize parse_unsigned_integer(const char* str, const char** endptr, int base) +{ + // The string may begin with an arbitrary amount of white space (as determined by isspace(3)), + while (_isspace(*str)) str++; + + // followed by a single optional '+' or '-' sign. + if (*str == '-' || *str == '+') str++; + + return do_unsigned_parse(str, endptr, base); +} + #define SSIZE_MAX LONG_MAX #define SSIZE_MIN (-SSIZE_MAX - (isize)1) @@ -55,16 +71,19 @@ isize parse_signed_integer(const char* str, const char** endptr, int base) { bool negative = false; + // The string may begin with an arbitrary amount of white space (as determined by isspace(3)), while (_isspace(*str)) str++; + // followed by a single optional '+' or '-' sign. if (*str == '-' || *str == '+') { if (*str == '-') negative = true; str++; } - usize rc = parse_unsigned_integer(str, endptr, base); + usize rc = do_unsigned_parse(str, endptr, base); + // If an underflow occurs, this function returns SSIZE_MIN. If an overflow occurs, this function returns SSIZE_MAX. if (rc > SSIZE_MAX) { return negative ? SSIZE_MIN : SSIZE_MAX; } return negative ? -(isize)rc : (isize)rc;