From e4ecc762c69c41a68a15e2725aaa210277f0e9fe Mon Sep 17 00:00:00 2001 From: Nik Bougalis Date: Mon, 8 Sep 2014 13:20:43 -0700 Subject: [PATCH] Refactor string-to-integer conversions --- beast/module/core/text/LexicalCast.h | 135 +++++++++++++++++---------- 1 file changed, 86 insertions(+), 49 deletions(-) diff --git a/beast/module/core/text/LexicalCast.h b/beast/module/core/text/LexicalCast.h index 8e1f4a471..926b76824 100644 --- a/beast/module/core/text/LexicalCast.h +++ b/beast/module/core/text/LexicalCast.h @@ -39,47 +39,84 @@ namespace detail { #pragma warning(disable: 4804) #endif -template +template bool -parseSigned (IntType& result, char const* begin, char const* end) +parse_integral (Int& num, FwdIt first, FwdIt last, Accumulator accumulator) { - static_assert(std::is_signed::value, ""); - char* ptr; - auto errno_save = errno; - errno = 0; - long long r = std::strtoll(begin, &ptr, 10); - std::swap(errno, errno_save); - errno_save = ptr != end; - if (errno_save == 0) + num = 0; + + if (first == last) + return false; + while (first != last) { - if (std::numeric_limits::min() <= r && - r <= std::numeric_limits::max()) - result = static_cast(r); - else - errno_save = 1; + auto const c = *first++; + if (c < '0' || c > '9') + return false; + if (!accumulator(Int(c - '0'))) + return false; } - return errno_save == 0; + return true; } -template +template bool -parseUnsigned (UIntType& result, char const* begin, char const* end) +parse_negative_integral (Int& num, FwdIt first, FwdIt last) { - static_assert(std::is_unsigned::value, ""); - char* ptr; - auto errno_save = errno; - errno = 0; - unsigned long long r = std::strtoull(begin, &ptr, 10); - std::swap(errno, errno_save); - errno_save = ptr != end; - if (errno_save == 0) - { - if (r <= std::numeric_limits::max()) - result = static_cast(r); - else - errno_save = 1; - } - return errno_save == 0; + Int const limit = std::numeric_limits ::min(); + + return parse_integral (num, first, last, + [&num,&limit](Int n) + { + if ((limit - (10 * num)) > -n) + return false; + num = 10 * num - n; + return true; + }); +} + +template +bool +parse_positive_integral (Int& num, FwdIt first, FwdIt last) +{ + Int const limit = std::numeric_limits ::max(); + + return parse_integral (num, first, last, + [&num,&limit](Int n) + { + if (n > (limit - (10 * num))) + return false; + num = 10 * num + n; + return true; + }); +} + +template +bool +parseSigned (IntType& result, FwdIt first, FwdIt last) +{ + static_assert(std::is_signed::value, + "You may only call parseSigned with a signed integral type."); + + if (first != last && *first == '-') + return parse_negative_integral (result, first + 1, last); + + if (first != last && *first == '+') + return parse_positive_integral (result, first + 1, last); + + return parse_positive_integral (result, first, last); +} + +template +bool +parseUnsigned (UIntType& result, FwdIt first, FwdIt last) +{ + static_assert(std::is_unsigned::value, + "You may only call parseUnsigned with an unsigned integral type."); + + if (first != last && *first == '+') + return parse_positive_integral (result, first + 1, last); + + return parse_positive_integral (result, first, last); } //------------------------------------------------------------------------------ @@ -109,22 +146,22 @@ struct LexicalCast template struct LexicalCast { - bool operator() (short& out, std::string const& in) const { return parseSigned (out, in.data(), in.data()+in.size()); } - bool operator() (int& out, std::string const& in) const { return parseSigned (out, in.data(), in.data()+in.size()); } - bool operator() (long& out, std::string const& in) const { return parseSigned (out, in.data(), in.data()+in.size()); } - bool operator() (long long& out, std::string const& in) const { return parseSigned (out, in.data(), in.data()+in.size()); } - bool operator() (unsigned short& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); } - bool operator() (unsigned int& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); } - bool operator() (unsigned long& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); } - bool operator() (unsigned long long& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); } - bool operator() (float& out, std::string const& in) const { bassertfalse; return false; /* UNIMPLEMENTED! */ } - bool operator() (double& out, std::string const& in) const { bassertfalse; return false; /* UNIMPLEMENTED! */ } - bool operator() (long double& out, std::string const& in) const { bassertfalse; return false; /* UNIMPLEMENTED! */ } -#if 0 - bool operator() (bool& out, std::string const& in) const; -#else - bool operator() (bool& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); } -#endif + static_assert (std::is_integral ::value, + "beast::LexicalCast can only be used with integral types"); + + template + typename std::enable_if ::value, bool>::type + operator () (Integral& out, std::string const& in) const + { + return parseUnsigned (out, std::begin(in), std::end(in)); + } + + template + typename std::enable_if ::value, bool>::type + operator () (Integral& out, std::string const& in) const + { + return parseSigned (out, std::begin(in), std::end(in)); + } }; #if 0