Replace macro in convert.h with partial template specialization.
Dealing with floating points is also closer to YAML 1.2 core schema.
This commit is contained in:
parent
1d26aa7e9f
commit
027f684264
@ -8,9 +8,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <regex>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -24,12 +26,23 @@
|
|||||||
namespace YAML {
|
namespace YAML {
|
||||||
class Binary;
|
class Binary;
|
||||||
struct _Null;
|
struct _Null;
|
||||||
template <typename T>
|
template <typename T, typename Enable>
|
||||||
struct convert;
|
struct convert;
|
||||||
|
|
||||||
} // namespace YAML
|
} // namespace YAML
|
||||||
|
|
||||||
namespace YAML {
|
namespace YAML {
|
||||||
namespace conversion {
|
namespace conversion {
|
||||||
|
static const std::regex re_true("true|True|TRUE");
|
||||||
|
static const std::regex re_false("false|False|FALSE");
|
||||||
|
static const std::regex re_decimal("[-+]?[0-9]+");
|
||||||
|
static const std::regex re_octal("0o[0-7]+");
|
||||||
|
static const std::regex re_hex("0x[0-9a-fA-F]+");
|
||||||
|
static const std::regex re_float(
|
||||||
|
"[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?");
|
||||||
|
static const std::regex re_inf("[-+]?(\\.inf|\\.Inf|\\.INF)");
|
||||||
|
static const std::regex re_nan("\\.nan|\\.NaN|\\.NAN");
|
||||||
|
|
||||||
inline bool IsInfinity(const std::string& input) {
|
inline bool IsInfinity(const std::string& input) {
|
||||||
return input == ".inf" || input == ".Inf" || input == ".INF" ||
|
return input == ".inf" || input == ".Inf" || input == ".INF" ||
|
||||||
input == "+.inf" || input == "+.Inf" || input == "+.INF";
|
input == "+.inf" || input == "+.Inf" || input == "+.INF";
|
||||||
@ -76,7 +89,7 @@ struct convert<const char*> {
|
|||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
struct convert<const char[N]> {
|
struct convert<const char[N]> {
|
||||||
static Node encode(const char(&rhs)[N]) { return Node(rhs); }
|
static Node encode(const char (&rhs)[N]) { return Node(rhs); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -88,70 +101,137 @@ struct convert<_Null> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \
|
// signed integral
|
||||||
template <> \
|
template <typename type>
|
||||||
struct convert<type> { \
|
struct convert<type,
|
||||||
static Node encode(const type& rhs) { \
|
typename std::enable_if<std::is_integral<type>::value &&
|
||||||
std::stringstream stream; \
|
std::is_signed<type>::value>::type> {
|
||||||
stream.precision(std::numeric_limits<type>::digits10 + 1); \
|
static Node encode(const type& rhs) { return Node(std::to_string(rhs)); }
|
||||||
stream << rhs; \
|
|
||||||
return Node(stream.str()); \
|
static bool decode(const Node& node, type& rhs) {
|
||||||
} \
|
if (node.Type() != NodeType::Scalar)
|
||||||
\
|
return false;
|
||||||
static bool decode(const Node& node, type& rhs) { \
|
const std::string& input = node.Scalar();
|
||||||
if (node.Type() != NodeType::Scalar) \
|
long long num;
|
||||||
return false; \
|
if (std::regex_match(input, conversion::re_decimal)) {
|
||||||
const std::string& input = node.Scalar(); \
|
try {
|
||||||
std::stringstream stream(input); \
|
num = std::stoll(input);
|
||||||
stream.unsetf(std::ios::dec); \
|
} catch (const std::out_of_range&) {
|
||||||
if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) \
|
return false;
|
||||||
return true; \
|
}
|
||||||
if (std::numeric_limits<type>::has_infinity) { \
|
} else if (std::regex_match(input, conversion::re_octal)) {
|
||||||
if (conversion::IsInfinity(input)) { \
|
try {
|
||||||
rhs = std::numeric_limits<type>::infinity(); \
|
num = std::stoll(input.substr(2), nullptr, 8);
|
||||||
return true; \
|
} catch (const std::out_of_range&) {
|
||||||
} else if (conversion::IsNegativeInfinity(input)) { \
|
return false;
|
||||||
rhs = negative_op std::numeric_limits<type>::infinity(); \
|
}
|
||||||
return true; \
|
} else if (std::regex_match(input, conversion::re_hex)) {
|
||||||
} \
|
try {
|
||||||
} \
|
num = std::stoll(input.substr(2), nullptr, 16);
|
||||||
\
|
} catch (const std::out_of_range&) {
|
||||||
if (std::numeric_limits<type>::has_quiet_NaN && \
|
return false;
|
||||||
conversion::IsNaN(input)) { \
|
}
|
||||||
rhs = std::numeric_limits<type>::quiet_NaN(); \
|
} else {
|
||||||
return true; \
|
return false;
|
||||||
} \
|
}
|
||||||
\
|
if (num > std::numeric_limits<type>::max() ||
|
||||||
return false; \
|
num < std::numeric_limits<type>::min()) {
|
||||||
} \
|
return false;
|
||||||
|
}
|
||||||
|
rhs = num;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// unsigned integral
|
||||||
|
template <typename type>
|
||||||
|
struct convert<type,
|
||||||
|
typename std::enable_if<std::is_integral<type>::value &&
|
||||||
|
std::is_unsigned<type>::value>::type> {
|
||||||
|
static Node encode(const type& rhs) { return Node(std::to_string(rhs)); }
|
||||||
|
|
||||||
|
static bool decode(const Node& node, type& rhs) {
|
||||||
|
if (node.Type() != NodeType::Scalar)
|
||||||
|
return false;
|
||||||
|
const std::string& input = node.Scalar();
|
||||||
|
unsigned long long num;
|
||||||
|
if (std::regex_match(input, conversion::re_decimal)) {
|
||||||
|
try {
|
||||||
|
num = std::stoull(input);
|
||||||
|
} catch (const std::out_of_range&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (std::regex_match(input, conversion::re_octal)) {
|
||||||
|
try {
|
||||||
|
num = std::stoull(input.substr(2), nullptr, 8);
|
||||||
|
} catch (const std::out_of_range&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (std::regex_match(input, conversion::re_hex)) {
|
||||||
|
try {
|
||||||
|
num = std::stoull(input.substr(2), nullptr, 16);
|
||||||
|
} catch (const std::out_of_range&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (num > std::numeric_limits<type>::max() ||
|
||||||
|
num < std::numeric_limits<type>::min()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rhs = num;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// floating point
|
||||||
|
template <typename type>
|
||||||
|
struct convert<
|
||||||
|
type, typename std::enable_if<std::is_floating_point<type>::value>::type> {
|
||||||
|
static Node encode(const type& rhs) {
|
||||||
|
if (std::isnan(rhs)) {
|
||||||
|
return Node(".nan");
|
||||||
|
}
|
||||||
|
if (std::isinf(rhs)) {
|
||||||
|
if (std::signbit(rhs)) {
|
||||||
|
return Node("-.inf");
|
||||||
|
}
|
||||||
|
return Node(".inf");
|
||||||
|
}
|
||||||
|
auto str = std::to_string(rhs);
|
||||||
|
if (std::regex_match(str, conversion::re_decimal)) {
|
||||||
|
return Node(str + "."); // Disambiguate float from int
|
||||||
|
}
|
||||||
|
return Node(std::to_string(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \
|
static bool decode(const Node& node, type& rhs) {
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE(type, -)
|
if (node.Type() != NodeType::Scalar)
|
||||||
|
return false;
|
||||||
#define YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(type) \
|
const std::string& input = node.Scalar();
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE(type, +)
|
long double num;
|
||||||
|
if (std::regex_match(input, conversion::re_float)) {
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(int);
|
try {
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(short);
|
num = std::stold(input);
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long);
|
} catch (const std::out_of_range&) {
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long long);
|
return false;
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned);
|
}
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned short);
|
} else if (std::regex_match(input, conversion::re_inf)) {
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long);
|
if (input[0] == '-') {
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long long);
|
num = -std::numeric_limits<long double>::infinity();
|
||||||
|
} else {
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(char);
|
num = std::numeric_limits<long double>::infinity();
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(signed char);
|
}
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned char);
|
} else if (std::regex_match(input, conversion::re_nan)) {
|
||||||
|
num = std::numeric_limits<long double>::quiet_NaN();
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(float);
|
} else {
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(double);
|
return false;
|
||||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long double);
|
}
|
||||||
|
rhs = num;
|
||||||
#undef YAML_DEFINE_CONVERT_STREAMABLE_SIGNED
|
return true;
|
||||||
#undef YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED
|
}
|
||||||
#undef YAML_DEFINE_CONVERT_STREAMABLE
|
};
|
||||||
|
|
||||||
// bool
|
// bool
|
||||||
template <>
|
template <>
|
||||||
|
|||||||
@ -138,7 +138,7 @@ YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs);
|
|||||||
|
|
||||||
YAML_CPP_API Node Clone(const Node& node);
|
YAML_CPP_API Node Clone(const Node& node);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, typename Enable = void>
|
||||||
struct convert;
|
struct convert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user