From a9211f8b116c387d1f3ef0dc735383bffa2a3f9e Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Tue, 27 Jun 2023 02:50:03 -0400 Subject: [PATCH] refactor: replace hand-rolled lexicalCast (#4473) Replace hand-rolled code with std::from_chars for better maintainability. The C++ std::from_chars function is intended to be as fast as possible, so it is unlikely to be slower than the code it replaces. This change is a net gain because it reduces the amount of hand-rolled code. --- .../app/rdb/backend/detail/impl/Node.cpp | 13 +- src/ripple/beast/core/LexicalCast.h | 140 +++--------------- 2 files changed, 22 insertions(+), 131 deletions(-) diff --git a/src/ripple/app/rdb/backend/detail/impl/Node.cpp b/src/ripple/app/rdb/backend/detail/impl/Node.cpp index b3b354ebe72..8948360a3ad 100644 --- a/src/ripple/app/rdb/backend/detail/impl/Node.cpp +++ b/src/ripple/app/rdb/backend/detail/impl/Node.cpp @@ -518,7 +518,7 @@ getHashByIndex(soci::session& session, LedgerIndex ledgerIndex) std::string sql = "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='"; - sql.append(beast::lexicalCastThrow(ledgerIndex)); + sql.append(std::to_string(ledgerIndex)); sql.append("';"); std::string hash; @@ -581,9 +581,9 @@ getHashesByIndex( { std::string sql = "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= "; - sql.append(beast::lexicalCastThrow(minSeq)); + sql.append(std::to_string(minSeq)); sql.append(" AND LedgerSeq <= "); - sql.append(beast::lexicalCastThrow(maxSeq)); + sql.append(std::to_string(maxSeq)); sql.append(";"); std::uint64_t ls; @@ -761,8 +761,7 @@ transactionsSQL( boost::format("SELECT %s FROM AccountTransactions " "WHERE Account = '%s' %s %s LIMIT %u, %u;") % selection % toBase58(options.account) % maxClause % minClause % - beast::lexicalCastThrow(options.offset) % - beast::lexicalCastThrow(numberOfResults)); + options.offset % numberOfResults); else sql = boost::str( boost::format( @@ -775,9 +774,7 @@ transactionsSQL( "LIMIT %u, %u;") % selection % toBase58(options.account) % maxClause % minClause % (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") % - (descending ? "DESC" : "ASC") % - beast::lexicalCastThrow(options.offset) % - beast::lexicalCastThrow(numberOfResults)); + (descending ? "DESC" : "ASC") % options.offset % numberOfResults); JLOG(j.trace()) << "txSQL query: " << sql; return sql; } diff --git a/src/ripple/beast/core/LexicalCast.h b/src/ripple/beast/core/LexicalCast.h index de1a6a396e9..f4c78341b91 100644 --- a/src/ripple/beast/core/LexicalCast.h +++ b/src/ripple/beast/core/LexicalCast.h @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -32,111 +32,10 @@ #include #include -#include - namespace beast { namespace detail { -#if BOOST_COMP_MSVC -#pragma warning(push) -#pragma warning(disable : 4800) -#pragma warning(disable : 4804) -#endif - -template -bool -parse_integral(Int& num, FwdIt first, FwdIt last, Accumulator accumulator) -{ - num = 0; - - if (first == last) - return false; - - while (first != last) - { - auto const c = *first++; - if (c < '0' || c > '9') - return false; - if (!accumulator(num, Int(c - '0'))) - return false; - } - - return true; -} - -template -bool -parse_negative_integral(Int& num, FwdIt first, FwdIt last) -{ - Int limit_value = std::numeric_limits::min() / 10; - Int limit_digit = std::numeric_limits::min() % 10; - - if (limit_digit < 0) - limit_digit = -limit_digit; - - return parse_integral( - num, first, last, [limit_value, limit_digit](Int& value, Int digit) { - assert((digit >= 0) && (digit <= 9)); - if (value < limit_value || - (value == limit_value && digit > limit_digit)) - return false; - value = (value * 10) - digit; - return true; - }); -} - -template -bool -parse_positive_integral(Int& num, FwdIt first, FwdIt last) -{ - Int limit_value = std::numeric_limits::max() / 10; - Int limit_digit = std::numeric_limits::max() % 10; - - return parse_integral( - num, first, last, [limit_value, limit_digit](Int& value, Int digit) { - assert((digit >= 0) && (digit <= 9)); - if (value > limit_value || - (value == limit_value && digit > limit_digit)) - return false; - value = (value * 10) + digit; - 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); -} - -//------------------------------------------------------------------------------ - // These specializatons get called by the non-member functions to do the work template struct LexicalCast; @@ -148,7 +47,7 @@ struct LexicalCast explicit LexicalCast() = default; template - std::enable_if_t::value, bool> + std::enable_if_t, bool> operator()(std::string& out, Arithmetic in) { out = std::to_string(in); @@ -156,7 +55,7 @@ struct LexicalCast } template - std::enable_if_t::value, bool> + std::enable_if_t, bool> operator()(std::string& out, Enumeration in) { out = std::to_string( @@ -172,21 +71,24 @@ struct LexicalCast explicit LexicalCast() = default; static_assert( - std::is_integral::value, + std::is_integral_v, "beast::LexicalCast can only be used with integral types"); template - std::enable_if_t::value, bool> + std::enable_if_t< + std::is_integral_v && !std::is_same_v, + bool> operator()(Integral& out, std::string const& in) const { - return parseUnsigned(out, in.begin(), in.end()); - } + auto first = in.data(); + auto last = in.data() + in.size(); - template - std::enable_if_t::value, bool> - operator()(Integral& out, std::string const& in) const - { - return parseSigned(out, in.begin(), in.end()); + if (first != last && *first == '+') + ++first; + + auto ret = std::from_chars(first, last, out); + + return ret.ec == std::errc() && ret.ptr == last; } bool @@ -242,10 +144,6 @@ struct LexicalCast } }; -#if BOOST_COMP_MSVC -#pragma warning(pop) -#endif - } // namespace detail //------------------------------------------------------------------------------ @@ -278,9 +176,7 @@ template Out lexicalCastThrow(In in) { - Out out; - - if (lexicalCastChecked(out, in)) + if (Out out; lexicalCastChecked(out, in)) return out; throw BadLexicalCast(); @@ -295,9 +191,7 @@ template Out lexicalCast(In in, Out defaultValue = Out()) { - Out out; - - if (lexicalCastChecked(out, in)) + if (Out out; lexicalCastChecked(out, in)) return out; return defaultValue;