diff --git a/src/string.cpp b/src/string.cpp index 750ba284..a21a1550 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -31,17 +31,17 @@ stoi(const string& str, size_t* idx, int base) { char* ptr; const char* const p = str.c_str(); + int errno_save = errno; + errno = 0; long r = strtol(p, &ptr, base); - if (r < numeric_limits::min() || numeric_limits::max() < r) - ptr = const_cast(p); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stoi: no conversion"); + if (errno_save == ERANGE || r < numeric_limits::min() || + numeric_limits::max() < r) throw out_of_range("stoi: out of range"); + if (ptr == p) + throw invalid_argument("stoi: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return static_cast(r); @@ -52,17 +52,17 @@ stoi(const wstring& str, size_t* idx, int base) { wchar_t* ptr; const wchar_t* const p = str.c_str(); + int errno_save = errno; + errno = 0; long r = wcstol(p, &ptr, base); - if (r < numeric_limits::min() || numeric_limits::max() < r) - ptr = const_cast(p); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stoi: no conversion"); + if (errno_save == ERANGE || r < numeric_limits::min() || + numeric_limits::max() < r) throw out_of_range("stoi: out of range"); + if (ptr == p) + throw invalid_argument("stoi: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return static_cast(r); @@ -73,15 +73,16 @@ stol(const string& str, size_t* idx, int base) { char* ptr; const char* const p = str.c_str(); + int errno_save = errno; + errno = 0; long r = strtol(p, &ptr, base); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stol: no conversion"); + if (errno_save == ERANGE) throw out_of_range("stol: out of range"); + if (ptr == p) + throw invalid_argument("stol: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return r; @@ -92,15 +93,16 @@ stol(const wstring& str, size_t* idx, int base) { wchar_t* ptr; const wchar_t* const p = str.c_str(); + int errno_save = errno; + errno = 0; long r = wcstol(p, &ptr, base); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stol: no conversion"); + if (errno_save == ERANGE) throw out_of_range("stol: out of range"); + if (ptr == p) + throw invalid_argument("stol: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return r; @@ -111,15 +113,16 @@ stoul(const string& str, size_t* idx, int base) { char* ptr; const char* const p = str.c_str(); + int errno_save = errno; + errno = 0; unsigned long r = strtoul(p, &ptr, base); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stoul: no conversion"); + if (errno_save == ERANGE) throw out_of_range("stoul: out of range"); + if (ptr == p) + throw invalid_argument("stoul: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return r; @@ -130,15 +133,16 @@ stoul(const wstring& str, size_t* idx, int base) { wchar_t* ptr; const wchar_t* const p = str.c_str(); + int errno_save = errno; + errno = 0; unsigned long r = wcstoul(p, &ptr, base); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stoul: no conversion"); + if (errno_save == ERANGE) throw out_of_range("stoul: out of range"); + if (ptr == p) + throw invalid_argument("stoul: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return r; @@ -149,15 +153,16 @@ stoll(const string& str, size_t* idx, int base) { char* ptr; const char* const p = str.c_str(); + int errno_save = errno; + errno = 0; long long r = strtoll(p, &ptr, base); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stoll: no conversion"); + if (errno_save == ERANGE) throw out_of_range("stoll: out of range"); + if (ptr == p) + throw invalid_argument("stoll: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return r; @@ -168,15 +173,16 @@ stoll(const wstring& str, size_t* idx, int base) { wchar_t* ptr; const wchar_t* const p = str.c_str(); + int errno_save = errno; + errno = 0; long long r = wcstoll(p, &ptr, base); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stoll: no conversion"); + if (errno_save == ERANGE) throw out_of_range("stoll: out of range"); + if (ptr == p) + throw invalid_argument("stoll: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return r; @@ -187,15 +193,16 @@ stoull(const string& str, size_t* idx, int base) { char* ptr; const char* const p = str.c_str(); + int errno_save = errno; + errno = 0; unsigned long long r = strtoull(p, &ptr, base); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stoull: no conversion"); + if (errno_save == ERANGE) throw out_of_range("stoull: out of range"); + if (ptr == p) + throw invalid_argument("stoull: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return r; @@ -206,15 +213,16 @@ stoull(const wstring& str, size_t* idx, int base) { wchar_t* ptr; const wchar_t* const p = str.c_str(); + int errno_save = errno; + errno = 0; unsigned long long r = wcstoull(p, &ptr, base); - if (ptr == p) - { + swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS - if (r == 0) - throw invalid_argument("stoull: no conversion"); + if (errno_save == ERANGE) throw out_of_range("stoull: out of range"); + if (ptr == p) + throw invalid_argument("stoull: no conversion"); #endif // _LIBCPP_NO_EXCEPTIONS - } if (idx) *idx = static_cast(ptr - p); return r; @@ -227,7 +235,7 @@ stof(const string& str, size_t* idx) const char* const p = str.c_str(); int errno_save = errno; errno = 0; - double r = strtod(p, &ptr); + float r = strtof(p, &ptr); swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS if (errno_save == ERANGE) @@ -237,7 +245,7 @@ stof(const string& str, size_t* idx) #endif // _LIBCPP_NO_EXCEPTIONS if (idx) *idx = static_cast(ptr - p); - return static_cast(r); + return r; } float @@ -247,7 +255,7 @@ stof(const wstring& str, size_t* idx) const wchar_t* const p = str.c_str(); int errno_save = errno; errno = 0; - double r = wcstod(p, &ptr); + float r = wcstof(p, &ptr); swap(errno, errno_save); #ifndef _LIBCPP_NO_EXCEPTIONS if (errno_save == ERANGE) @@ -257,7 +265,7 @@ stof(const wstring& str, size_t* idx) #endif // _LIBCPP_NO_EXCEPTIONS if (idx) *idx = static_cast(ptr - p); - return static_cast(r); + return r; } double diff --git a/test/strings/string.conversions/stof.pass.cpp b/test/strings/string.conversions/stof.pass.cpp index 749d8672..444a6951 100644 --- a/test/strings/string.conversions/stof.pass.cpp +++ b/test/strings/string.conversions/stof.pass.cpp @@ -32,23 +32,24 @@ int main() idx = 0; assert(std::stof(L"10g", &idx) == 10); assert(idx == 2); + idx = 0; try { assert(std::stof("1.e60", &idx) == INFINITY); - assert(idx == 5); + assert(false); } catch (const std::out_of_range&) { - assert(false); + assert(idx == 0); } try { assert(std::stof(L"1.e60", &idx) == INFINITY); - assert(idx == 5); + assert(false); } catch (const std::out_of_range&) { - assert(false); + assert(idx == 0); } idx = 0; try diff --git a/test/strings/string.conversions/stoll.pass.cpp b/test/strings/string.conversions/stoll.pass.cpp index 217f00d0..3887b7d2 100644 --- a/test/strings/string.conversions/stoll.pass.cpp +++ b/test/strings/string.conversions/stoll.pass.cpp @@ -86,4 +86,13 @@ int main() { assert(idx == 0); } + try + { + std::stoll("99999999999999999999999999", &idx); + assert(false); + } + catch (const std::out_of_range&) + { + assert(idx == 0); + } }