Updated new API conversion to handle nan/inf and to throw when the conversion didn't use the entire string (e.g., parsing 1.2 as an integer)

This commit is contained in:
Jesse Beder
2012-01-12 23:49:05 -06:00
parent d1e4c2640c
commit 643ea61a98
2 changed files with 53 additions and 3 deletions

View File

@@ -9,6 +9,7 @@
#include "yaml-cpp/node/node.h" #include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/iterator.h" #include "yaml-cpp/node/iterator.h"
#include "yaml-cpp/null.h" #include "yaml-cpp/null.h"
#include <limits>
#include <list> #include <list>
#include <map> #include <map>
#include <sstream> #include <sstream>
@@ -16,6 +17,20 @@
namespace YAML namespace YAML
{ {
namespace conversion {
inline bool IsInfinity(const std::string& input) {
return input == ".inf" || input == ".Inf" || input == ".INF" || input == "+.inf" || input == "+.Inf" || input == "+.INF";
}
inline bool IsNegativeInfinity(const std::string& input) {
return input == "-.inf" || input == "-.Inf" || input == "-.INF";
}
inline bool IsNaN(const std::string& input) {
return input == ".nan" || input == ".NaN" || input == ".NAN";
}
}
// std::string // std::string
template<> template<>
struct convert<std::string> { struct convert<std::string> {
@@ -54,9 +69,27 @@ namespace YAML
static bool decode(const Node& node, type& rhs) {\ static bool decode(const Node& node, type& rhs) {\
if(node.Type() != NodeType::Scalar)\ if(node.Type() != NodeType::Scalar)\
return false;\ return false;\
std::stringstream stream(node.Scalar());\ const std::string& input = node.Scalar();\
stream >> rhs;\ std::stringstream stream(input);\
return !!stream;\ stream.unsetf(std::ios::dec);\
if((stream >> rhs) && (stream >> std::ws).eof())\
return true;\
if(std::numeric_limits<type>::has_infinity) {\
if(conversion::IsInfinity(input)) {\
rhs = std::numeric_limits<type>::infinity();\
return true;\
} else if(conversion::IsNegativeInfinity(input)) {\
rhs = -std::numeric_limits<type>::infinity();\
return true;\
}\
}\
\
if(std::numeric_limits<type>::has_quiet_NaN && conversion::IsNaN(input)) {\
rhs = std::numeric_limits<type>::quiet_NaN();\
return true;\
}\
\
return false;\
}\ }\
} }

View File

@@ -15,6 +15,8 @@ namespace {
#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false) #define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false)
#define YAML_ASSERT_THROWS(cond, exc) do { try { (cond); return " Expression did not throw: " #cond; } catch(const exc&) {} catch(...) { return " Expression threw something other than " #exc ": " #cond; } } while(false)
namespace Test namespace Test
{ {
namespace Node namespace Node
@@ -298,6 +300,20 @@ namespace Test
YAML_ASSERT(node["y"].as<int>(5) == 5); YAML_ASSERT(node["y"].as<int>(5) == 5);
return true; return true;
} }
TEST NumericConversion()
{
YAML::Node node = YAML::Load("[1.5, 1, .nan, .inf, -.inf]");
YAML_ASSERT(node[0].as<float>() == 1.5f);
YAML_ASSERT(node[0].as<double>() == 1.5);
YAML_ASSERT_THROWS(node[0].as<int>(), std::runtime_error);
YAML_ASSERT(node[1].as<int>() == 1);
YAML_ASSERT(node[1].as<float>() == 1.0f);
YAML_ASSERT(node[2].as<float>() != node[2].as<float>());
YAML_ASSERT(node[3].as<float>() == std::numeric_limits<float>::infinity());
YAML_ASSERT(node[4].as<float>() == -std::numeric_limits<float>::infinity());
return true;
}
} }
void RunNodeTest(TEST (*test)(), const std::string& name, int& passed, int& total) { void RunNodeTest(TEST (*test)(), const std::string& name, int& passed, int& total) {
@@ -345,6 +361,7 @@ namespace Test
RunNodeTest(&Node::AutoBoolConversion, "auto bool conversion", passed, total); RunNodeTest(&Node::AutoBoolConversion, "auto bool conversion", passed, total);
RunNodeTest(&Node::Reassign, "reassign", passed, total); RunNodeTest(&Node::Reassign, "reassign", passed, total);
RunNodeTest(&Node::FallbackValues, "fallback values", passed, total); RunNodeTest(&Node::FallbackValues, "fallback values", passed, total);
RunNodeTest(&Node::NumericConversion, "numeric conversion", passed, total);
std::cout << "Node tests: " << passed << "/" << total << " passed\n"; std::cout << "Node tests: " << passed << "/" << total << " passed\n";
return passed == total; return passed == total;