mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 10:35:50 +00:00
Per XLS-0095, we are taking steps to rename ripple(d) to xrpl(d). This change specifically removes all copyright notices referencing Ripple, XRPLF, and certain affiliated contributors upon mutual agreement, so the notice in the LICENSE.md file applies throughout. Copyright notices referencing external contributions remain as-is. Duplicate verbiage is also removed.
220 lines
5.3 KiB
C++
220 lines
5.3 KiB
C++
#ifndef BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED
|
|
#define BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED
|
|
|
|
#include <xrpl/beast/utility/instrumentation.h>
|
|
|
|
#include <boost/core/detail/string_view.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <cerrno>
|
|
#include <charconv>
|
|
#include <cstdlib>
|
|
#include <iterator>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <typeinfo>
|
|
|
|
namespace beast {
|
|
|
|
namespace detail {
|
|
|
|
// These specializatons get called by the non-member functions to do the work
|
|
template <class Out, class In>
|
|
struct LexicalCast;
|
|
|
|
// conversion to std::string
|
|
template <class In>
|
|
struct LexicalCast<std::string, In>
|
|
{
|
|
explicit LexicalCast() = default;
|
|
|
|
template <class Arithmetic = In>
|
|
std::enable_if_t<std::is_arithmetic_v<Arithmetic>, bool>
|
|
operator()(std::string& out, Arithmetic in)
|
|
{
|
|
out = std::to_string(in);
|
|
return true;
|
|
}
|
|
|
|
template <class Enumeration = In>
|
|
std::enable_if_t<std::is_enum_v<Enumeration>, bool>
|
|
operator()(std::string& out, Enumeration in)
|
|
{
|
|
out = std::to_string(
|
|
static_cast<std::underlying_type_t<Enumeration>>(in));
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// Parse a std::string_view into a number
|
|
template <typename Out>
|
|
struct LexicalCast<Out, std::string_view>
|
|
{
|
|
explicit LexicalCast() = default;
|
|
|
|
static_assert(
|
|
std::is_integral_v<Out>,
|
|
"beast::LexicalCast can only be used with integral types");
|
|
|
|
template <class Integral = Out>
|
|
std::enable_if_t<
|
|
std::is_integral_v<Integral> && !std::is_same_v<Integral, bool>,
|
|
bool>
|
|
operator()(Integral& out, std::string_view in) const
|
|
{
|
|
auto first = in.data();
|
|
auto last = in.data() + in.size();
|
|
|
|
if (first != last && *first == '+')
|
|
++first;
|
|
|
|
auto ret = std::from_chars(first, last, out);
|
|
|
|
return ret.ec == std::errc() && ret.ptr == last;
|
|
}
|
|
|
|
bool
|
|
operator()(bool& out, std::string_view in) const
|
|
{
|
|
std::string result;
|
|
|
|
// Convert the input to lowercase
|
|
std::transform(
|
|
in.begin(), in.end(), std::back_inserter(result), [](auto c) {
|
|
return std::tolower(static_cast<unsigned char>(c));
|
|
});
|
|
|
|
if (result == "1" || result == "true")
|
|
{
|
|
out = true;
|
|
return true;
|
|
}
|
|
|
|
if (result == "0" || result == "false")
|
|
{
|
|
out = false;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Parse boost library's string_view to number or boolean value
|
|
// Note: As of Jan 2024, Boost contains three different types of string_view
|
|
// (boost::core::basic_string_view<char>, boost::string_ref and
|
|
// boost::string_view). The below template specialization is included because
|
|
// it is used in the handshake.cpp file
|
|
template <class Out>
|
|
struct LexicalCast<Out, boost::core::basic_string_view<char>>
|
|
{
|
|
explicit LexicalCast() = default;
|
|
|
|
bool
|
|
operator()(Out& out, boost::core::basic_string_view<char> in) const
|
|
{
|
|
return LexicalCast<Out, std::string_view>()(out, in);
|
|
}
|
|
};
|
|
|
|
// Parse std::string to number or boolean value
|
|
template <class Out>
|
|
struct LexicalCast<Out, std::string>
|
|
{
|
|
explicit LexicalCast() = default;
|
|
|
|
bool
|
|
operator()(Out& out, std::string in) const
|
|
{
|
|
return LexicalCast<Out, std::string_view>()(out, in);
|
|
}
|
|
};
|
|
|
|
// Conversion from null terminated char const*
|
|
template <class Out>
|
|
struct LexicalCast<Out, char const*>
|
|
{
|
|
explicit LexicalCast() = default;
|
|
|
|
bool
|
|
operator()(Out& out, char const* in) const
|
|
{
|
|
XRPL_ASSERT(
|
|
in, "beast::detail::LexicalCast(char const*) : non-null input");
|
|
return LexicalCast<Out, std::string_view>()(out, in);
|
|
}
|
|
};
|
|
|
|
// Conversion from null terminated char*
|
|
// The string is not modified.
|
|
template <class Out>
|
|
struct LexicalCast<Out, char*>
|
|
{
|
|
explicit LexicalCast() = default;
|
|
|
|
bool
|
|
operator()(Out& out, char* in) const
|
|
{
|
|
XRPL_ASSERT(in, "beast::detail::LexicalCast(char*) : non-null input");
|
|
return LexicalCast<Out, std::string_view>()(out, in);
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
/** Thrown when a conversion is not possible with LexicalCast.
|
|
Only used in the throw variants of lexicalCast.
|
|
*/
|
|
struct BadLexicalCast : public std::bad_cast
|
|
{
|
|
explicit BadLexicalCast() = default;
|
|
};
|
|
|
|
/** Intelligently convert from one type to another.
|
|
@return `false` if there was a parsing or range error
|
|
*/
|
|
template <class Out, class In>
|
|
bool
|
|
lexicalCastChecked(Out& out, In in)
|
|
{
|
|
return detail::LexicalCast<Out, In>()(out, in);
|
|
}
|
|
|
|
/** Convert from one type to another, throw on error
|
|
|
|
An exception of type BadLexicalCast is thrown if the conversion fails.
|
|
|
|
@return The new type.
|
|
*/
|
|
template <class Out, class In>
|
|
Out
|
|
lexicalCastThrow(In in)
|
|
{
|
|
if (Out out; lexicalCastChecked(out, in))
|
|
return out;
|
|
|
|
throw BadLexicalCast();
|
|
}
|
|
|
|
/** Convert from one type to another.
|
|
|
|
@param defaultValue The value returned if parsing fails
|
|
@return The new type.
|
|
*/
|
|
template <class Out, class In>
|
|
Out
|
|
lexicalCast(In in, Out defaultValue = Out())
|
|
{
|
|
if (Out out; lexicalCastChecked(out, in))
|
|
return out;
|
|
|
|
return defaultValue;
|
|
}
|
|
|
|
} // namespace beast
|
|
|
|
#endif
|