diff --git a/include/co/str.h b/include/co/str.h index f704e17b1..aaea51605 100644 --- a/include/co/str.h +++ b/include/co/str.h @@ -1,6 +1,7 @@ #pragma once #include "fastring.h" +#include #include #include #include @@ -61,7 +62,7 @@ fastring strip(const fastring& s, const fastring& c, char d='b'); /** * convert string to built-in types - * - An exception of type const char* will be thrown if any error occured. + * - Returns 0 if the conversion failed, and the errno will be ERANGE or EINVAL. */ bool to_bool(const char* s); int32 to_int32(const char* s); diff --git a/src/flag.cc b/src/flag.cc index af06c8ba4..c5e037e02 100644 --- a/src/flag.cc +++ b/src/flag.cc @@ -48,7 +48,7 @@ inline std::map& gFlags() { return flags; } -void flag_set_value(Flag* flag, const fastring& v) { +fastring flag_set_value(Flag* flag, const fastring& v) { switch (flag->type) { case TYPE_string: *static_cast(flag->addr) = v; @@ -72,8 +72,12 @@ void flag_set_value(Flag* flag, const fastring& v) { *static_cast(flag->addr) = str::to_double(v); break; default: - throw "unknown flag type"; + return "unknown flag type"; } + + if (errno == 0) return fastring(); + if (errno == ERANGE) return "out of range"; + return "invalid number"; } template @@ -107,7 +111,7 @@ fastring flag_get_value(const Flag* flag) { case TYPE_double: return str::from(*static_cast(flag->addr)); default: - throw "unknown flag type"; + return "unknown flag type"; } } @@ -143,12 +147,9 @@ fastring set_flag_value(const fastring& name, const fastring& value) { Flag* flag = find_flag(name); if (!flag) return "flag not defined: " + name; - try { - flag_set_value(flag, value); - return fastring(); - } catch (const char* s) { - return fastring(s) + ": " + value; - } + fastring err = flag_set_value(flag, value); + if (!err.empty()) err.append(": ").append(value); + return err; } // set_bool_flags("abc"): -abc -> true or -a, -b, -c -> true diff --git a/src/str.cc b/src/str.cc index 09d64c56e..0fe420bf0 100644 --- a/src/str.cc +++ b/src/str.cc @@ -218,24 +218,27 @@ fastring strip(const fastring& s, const fastring& c, char d) { bool to_bool(const char* s) { if (strcmp(s, "false") == 0 || strcmp(s, "0") == 0) return false; if (strcmp(s, "true") == 0 || strcmp(s, "1") == 0) return true; - throw "invalid value for bool"; + errno = EINVAL; + return false; } int32 to_int32(const char* s) { int64 x = to_int64(s); - if (x > MAX_INT32 || x < MIN_INT32) { - throw "out of range for int32"; + if (unlikely(x > MAX_INT32 || x < MIN_INT32)) { + errno = ERANGE; + return 0; } - return (int32) x; + return (int32)x; } uint32 to_uint32(const char* s) { int64 x = (int64) to_uint64(s); int64 absx = x < 0 ? -x : x; - if (absx > MAX_UINT32) { - throw "out of range for uint32"; + if (unlikely(absx > MAX_UINT32)) { + errno = ERANGE; + return 0; } - return (uint32) x; + return (uint32)x; } inline int _Shift(char c) { @@ -264,12 +267,9 @@ int64 to_int64(const char* s) { if (!*s) return 0; char* end = 0; + errno = 0; int64 x = strtoll(s, &end, 0); - - if (errno == ERANGE && (x == MIN_INT64 || x == MAX_INT64)) { - errno = 0; - throw "out of range for int64"; - } + if (errno != 0) return 0; size_t n = strlen(s); if (end == s + n) return x; @@ -278,63 +278,56 @@ int64 to_int64(const char* s) { int shift = _Shift(s[n - 1]); if (shift != 0) { if (x == 0) return 0; - if (x < (MIN_INT64 >> shift) || x > (MAX_INT64 >> shift)) { - throw "out of range for int64"; + errno = ERANGE; + return 0; } - return x << shift; } } - throw "invalid value for integer"; + errno = EINVAL; + return 0; } uint64 to_uint64(const char* s) { if (!*s) return 0; char* end = 0; - int64 x = (int64) strtoull(s, &end, 0); - - if (errno == ERANGE && static_cast(x) == MAX_UINT64) { - errno = 0; - throw "out of range for uint64"; - } + errno = 0; + uint64 x = strtoull(s, &end, 0); + if (errno != 0) return 0; size_t n = strlen(s); - if (end == s + n) return (uint64) x; + if (end == s + n) return x; if (end == s + n - 1) { int shift = _Shift(s[n - 1]); if (shift != 0) { if (x == 0) return 0; - - int64 absx = x < 0 ? -x : x; + int64 absx = (int64)x; + if (absx < 0) absx = -x; if (absx > static_cast(MAX_UINT64 >> shift)) { - throw "out of range for uint64"; + errno = ERANGE; + return 0; } - - return static_cast(x << shift); + return x << shift; } } - throw "invalid value for integer"; + errno = EINVAL; + return 0; } double to_double(const char* s) { char* end = 0; + errno = 0; double x = strtod(s, &end); + if (errno != 0) return 0; - if (errno == ERANGE && (x == HUGE_VAL || x == -HUGE_VAL)) { - errno = 0; - throw "out of range for double"; - } - - if (end != s + strlen(s)) { - throw "invalid value for double"; - } - - return x; + if (end == s + strlen(s)) return x; + errno = EINVAL; + return 0; } } // namespace str diff --git a/unitest/str.cc b/unitest/str.cc index b6c0c8fdb..9578f7f7e 100644 --- a/unitest/str.cc +++ b/unitest/str.cc @@ -104,6 +104,35 @@ DEF_test(str) { EXPECT_EQ(str::to_uint64("8t"), 8ULL << 40); EXPECT_EQ(str::to_double("3.14159"), 3.14159); + + // convertion failed + EXPECT_EQ(str::to_bool("xxx"), false); + EXPECT_EQ(errno, EINVAL); + + EXPECT_EQ(str::to_int32("-32g"), 0); + EXPECT_EQ(errno, ERANGE); + EXPECT_EQ(str::to_int32("-3a2"), 0); + EXPECT_EQ(errno, EINVAL); + + EXPECT_EQ(str::to_int64("100000P"), 0); + EXPECT_EQ(errno, ERANGE); + EXPECT_EQ(str::to_int64("1di8"), 0); + EXPECT_EQ(errno, EINVAL); + + EXPECT_EQ(str::to_uint32("32g"), 0); + EXPECT_EQ(errno, ERANGE); + EXPECT_EQ(str::to_uint32("3g3"), 0); + EXPECT_EQ(errno, EINVAL); + + EXPECT_EQ(str::to_uint64("100000P"), 0); + EXPECT_EQ(errno, ERANGE); + EXPECT_EQ(str::to_uint64("12d8"), 0); + EXPECT_EQ(errno, EINVAL); + + EXPECT_EQ(str::to_double("3.141d59"), 0); + EXPECT_EQ(errno, EINVAL); + + EXPECT_EQ(str::to_uint32("32"), 32); } DEF_case(from) {