mirror of
https://github.com/anope/anope.git
synced 2026-07-07 19:43:14 +02:00
Replace convertTo/stringify with non-throwing alternatives.
Having these throw is terrible for ergonomics and there are loads of places where the exception was either silently ignored or not handled at all. Having a function which returns an optional and another that returns a default works a lot better imo.
This commit is contained in:
+3
-66
@@ -39,6 +39,7 @@ namespace Anope
|
||||
typedef std::string::reverse_iterator reverse_iterator;
|
||||
typedef std::string::const_reverse_iterator const_reverse_iterator;
|
||||
typedef std::string::size_type size_type;
|
||||
typedef std::string::value_type value_type;
|
||||
static const size_type npos = static_cast<size_type>(-1);
|
||||
|
||||
/**
|
||||
@@ -729,72 +730,6 @@ public:
|
||||
virtual ~ModuleException() noexcept = default;
|
||||
};
|
||||
|
||||
class CoreExport ConvertException final
|
||||
: public CoreException
|
||||
{
|
||||
public:
|
||||
ConvertException(const Anope::string &reason = "") : CoreException(reason) { }
|
||||
|
||||
virtual ~ConvertException() noexcept = default;
|
||||
};
|
||||
|
||||
/** Convert something to a string
|
||||
*/
|
||||
inline Anope::string stringify(const Anope::string &x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename T> inline Anope::string stringify(const T &x)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
if (!(stream << x))
|
||||
throw ConvertException("Stringify fail");
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
template<typename T> inline void convert(const Anope::string &s, T &x, Anope::string &leftover, bool failIfLeftoverChars = true)
|
||||
{
|
||||
leftover.clear();
|
||||
std::istringstream i(s.str());
|
||||
char c;
|
||||
if (!(i >> x))
|
||||
throw ConvertException("Convert fail");
|
||||
if (failIfLeftoverChars)
|
||||
{
|
||||
if (i.get(c))
|
||||
throw ConvertException("Convert fail");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string left;
|
||||
getline(i, left);
|
||||
leftover = left;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> inline void convert(const Anope::string &s, T &x, bool failIfLeftoverChars = true)
|
||||
{
|
||||
Anope::string Unused;
|
||||
convert(s, x, Unused, failIfLeftoverChars);
|
||||
}
|
||||
|
||||
template<typename T> inline T convertTo(const Anope::string &s, Anope::string &leftover, bool failIfLeftoverChars = true)
|
||||
{
|
||||
T x;
|
||||
convert(s, x, leftover, failIfLeftoverChars);
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename T> inline T convertTo(const Anope::string &s, bool failIfLeftoverChars = true)
|
||||
{
|
||||
T x;
|
||||
convert(s, x, failIfLeftoverChars);
|
||||
return x;
|
||||
}
|
||||
|
||||
/** Casts to be used instead of dynamic_cast, this uses dynamic_cast
|
||||
* for debug builds and static_cast on release builds
|
||||
* to speed up the program because dynamic_cast relies on RTTI.
|
||||
@@ -814,3 +749,5 @@ template<typename T, typename O> inline T anope_dynamic_static_cast(O ptr)
|
||||
return static_cast<T>(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "convert.h"
|
||||
|
||||
+1
-8
@@ -46,14 +46,7 @@ namespace Configuration
|
||||
|
||||
template<typename T> T Get(const Anope::string &tag, const Anope::string &def = "") const
|
||||
{
|
||||
const Anope::string &value = this->Get<const Anope::string>(tag, def);
|
||||
if (!value.empty())
|
||||
try
|
||||
{
|
||||
return convertTo<T>(value);
|
||||
}
|
||||
catch (const ConvertException &) { }
|
||||
return T();
|
||||
return Anope::TryConvert<T>(this->Get<const Anope::string>(tag, def)).value_or(T());
|
||||
}
|
||||
|
||||
bool Set(const Anope::string &tag, const Anope::string &value);
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
*
|
||||
* (C) 2003-2024 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*
|
||||
* Based on the original code of Epona by Lara.
|
||||
* Based on the original code of Services by Andy Church.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace Anope
|
||||
{
|
||||
/** Attempts to convert a string to any type.
|
||||
* @param in The value to convert.
|
||||
* @param leftover If non-nullptr then the location to store leftover data.
|
||||
*/
|
||||
template<typename T>
|
||||
inline std::optional<T> TryConvert(const Anope::string &in, Anope::string *leftover = nullptr)
|
||||
{
|
||||
std::istringstream tmp(in.str());
|
||||
T out;
|
||||
if (!(tmp >> out))
|
||||
return std::nullopt;
|
||||
|
||||
if (leftover)
|
||||
{
|
||||
std::string extra;
|
||||
std::getline(tmp, extra);
|
||||
*leftover = extra;
|
||||
}
|
||||
else
|
||||
{
|
||||
char extra;
|
||||
if (tmp >> extra)
|
||||
return std::nullopt;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Converts a string to any type.
|
||||
* @param in The value to convert.
|
||||
* @param def The default to use if the conversion failed.
|
||||
* @param leftover If non-nullptr then the location to store leftover data.
|
||||
*/
|
||||
template<typename T>
|
||||
inline T Convert(const Anope::string &in, T def, Anope::string *leftover = nullptr)
|
||||
{
|
||||
return TryConvert<T>(in, leftover).value_or(def);
|
||||
}
|
||||
|
||||
/** Attempts to convert any type to a string.
|
||||
* @param in The value to convert.
|
||||
*/
|
||||
template <class T>
|
||||
inline std::optional<Anope::string> TryString(const T &in)
|
||||
{
|
||||
std::ostringstream tmp;
|
||||
if (!(tmp << in))
|
||||
return std::nullopt;
|
||||
return tmp.str();
|
||||
}
|
||||
|
||||
/** No-op function that returns the string that was passed to it.
|
||||
* @param in The string to return.
|
||||
*/
|
||||
inline const string &ToString(const string &in)
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
||||
/** Converts a std::string to a string.
|
||||
* @param in The value to convert.
|
||||
*/
|
||||
inline string ToString(const std::string &in)
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
||||
/** Converts a char array to a string.
|
||||
* @param in The value to convert.
|
||||
*/
|
||||
inline string ToString(const char *in)
|
||||
{
|
||||
return string(in);
|
||||
}
|
||||
|
||||
/** Converts a char to a string.
|
||||
* @param in The value to convert.
|
||||
*/
|
||||
inline string ToString(char in)
|
||||
{
|
||||
return string(1, static_cast<string::value_type>(in));
|
||||
}
|
||||
|
||||
/** Converts an unsigned char to a string.
|
||||
* @param in The value to convert.
|
||||
*/
|
||||
inline string ToString(unsigned char in)
|
||||
{
|
||||
return string(1, static_cast<string::value_type>(in));
|
||||
}
|
||||
|
||||
/** Converts a bool to a string.
|
||||
* @param in The value to convert.
|
||||
*/
|
||||
inline string ToString(bool in)
|
||||
{
|
||||
return (in ? "1" : "0");
|
||||
}
|
||||
|
||||
/** Converts a type that std::to_string is implemented for to a string.
|
||||
* @param in The value to convert.
|
||||
*/
|
||||
template<typename Stringable>
|
||||
inline std::enable_if_t<std::is_arithmetic_v<Stringable>, string> ToString(const Stringable &in)
|
||||
{
|
||||
return std::to_string(in);
|
||||
}
|
||||
|
||||
/** Converts any type to a string.
|
||||
* @param in The value to convert.
|
||||
*/
|
||||
template <class T>
|
||||
inline std::enable_if_t<!std::is_arithmetic_v<T>, string> ToString(const T &in)
|
||||
{
|
||||
return TryString(in).value_or(Anope::string());
|
||||
}
|
||||
}
|
||||
@@ -128,13 +128,12 @@ namespace SQL
|
||||
|
||||
template<typename T> void SetValue(const Anope::string &key, const T &value, bool escape = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
Anope::string string_value = stringify(value);
|
||||
this->parameters[key].data = string_value;
|
||||
this->parameters[key].escape = escape;
|
||||
}
|
||||
catch (const ConvertException &ex) { }
|
||||
auto str = Anope::TryString(value);
|
||||
if (!str.has_value())
|
||||
return;
|
||||
|
||||
this->parameters[key].data = str.value();
|
||||
this->parameters[key].escape = escape;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+3
-3
@@ -164,14 +164,14 @@ public:
|
||||
template <typename... Args>
|
||||
void SendMode(const MessageSource &source, Channel *chan, const Anope::string &modes, Args &&...args)
|
||||
{
|
||||
SendModeInternal(source, chan, modes, { stringify(args)... });
|
||||
SendModeInternal(source, chan, modes, { Anope::ToString(args)... });
|
||||
}
|
||||
|
||||
virtual void SendModeInternal(const MessageSource &source, User *u, const Anope::string &modes, const std::vector<Anope::string> &values);
|
||||
template <typename... Args>
|
||||
void SendMode(const MessageSource &source, User *u, const Anope::string &modes, Args &&...args)
|
||||
{
|
||||
SendModeInternal(source, u, modes, { stringify(args)... });
|
||||
SendModeInternal(source, u, modes, { Anope::ToString(args)... });
|
||||
}
|
||||
|
||||
/** Introduces a client to the rest of the network
|
||||
@@ -258,7 +258,7 @@ public:
|
||||
template <typename... Args>
|
||||
void SendNumeric(int numeric, const Anope::string &dest, Args &&...args)
|
||||
{
|
||||
SendNumericInternal(numeric, dest, { stringify(args)... });
|
||||
SendNumericInternal(numeric, dest, { Anope::ToString(args)... });
|
||||
}
|
||||
|
||||
virtual void SendLogin(User *u, NickAlias *na) = 0;
|
||||
|
||||
+4
-4
@@ -23,25 +23,25 @@ namespace Uplink
|
||||
template<typename... Args>
|
||||
void Send(const Anope::map<Anope::string> &tags, const MessageSource &source, const Anope::string &command, Args &&...args)
|
||||
{
|
||||
SendInternal(tags, source, command, { stringify(args)... });
|
||||
SendInternal(tags, source, command, { Anope::ToString(args)... });
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Send(const Anope::map<Anope::string> &tags, const Anope::string &command, Args &&...args)
|
||||
{
|
||||
SendInternal(tags, Me, command, { stringify(args)... });
|
||||
SendInternal(tags, Me, command, { Anope::ToString(args)... });
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Send(const MessageSource &source, const Anope::string &command, Args &&...args)
|
||||
{
|
||||
SendInternal({}, source, command, { stringify(args)... });
|
||||
SendInternal({}, source, command, { Anope::ToString(args)... });
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Send(const Anope::string &command, Args &&...args)
|
||||
{
|
||||
SendInternal({}, Me, command, { stringify(args)... });
|
||||
SendInternal({}, Me, command, { Anope::ToString(args)... });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user