From 60fa4d7f6397f737a36774032b6c399630c5c7aa Mon Sep 17 00:00:00 2001 From: beder Date: Thu, 12 Jan 2012 23:49:05 -0600 Subject: [PATCH] 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) --- include/yaml-cpp/node/convert.h | 39 ++++++++++++++++++++++++++++++--- test/new-api/nodetests.cpp | 17 ++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/include/yaml-cpp/node/convert.h b/include/yaml-cpp/node/convert.h index 7acda3e..420a935 100644 --- a/include/yaml-cpp/node/convert.h +++ b/include/yaml-cpp/node/convert.h @@ -9,6 +9,7 @@ #include "yaml-cpp/node/node.h" #include "yaml-cpp/node/iterator.h" #include "yaml-cpp/null.h" +#include #include #include #include @@ -16,6 +17,20 @@ 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 template<> struct convert { @@ -54,9 +69,27 @@ namespace YAML static bool decode(const Node& node, type& rhs) {\ if(node.Type() != NodeType::Scalar)\ return false;\ - std::stringstream stream(node.Scalar());\ - stream >> rhs;\ - return !!stream;\ + const std::string& input = node.Scalar();\ + std::stringstream stream(input);\ + stream.unsetf(std::ios::dec);\ + if((stream >> rhs) && (stream >> std::ws).eof())\ + return true;\ + if(std::numeric_limits::has_infinity) {\ + if(conversion::IsInfinity(input)) {\ + rhs = std::numeric_limits::infinity();\ + return true;\ + } else if(conversion::IsNegativeInfinity(input)) {\ + rhs = -std::numeric_limits::infinity();\ + return true;\ + }\ + }\ + \ + if(std::numeric_limits::has_quiet_NaN && conversion::IsNaN(input)) {\ + rhs = std::numeric_limits::quiet_NaN();\ + return true;\ + }\ + \ + return false;\ }\ } diff --git a/test/new-api/nodetests.cpp b/test/new-api/nodetests.cpp index 74f92ae..1bd9c12 100644 --- a/test/new-api/nodetests.cpp +++ b/test/new-api/nodetests.cpp @@ -15,6 +15,8 @@ namespace { #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 Node @@ -298,6 +300,20 @@ namespace Test YAML_ASSERT(node["y"].as(5) == 5); return true; } + + TEST NumericConversion() + { + YAML::Node node = YAML::Load("[1.5, 1, .nan, .inf, -.inf]"); + YAML_ASSERT(node[0].as() == 1.5f); + YAML_ASSERT(node[0].as() == 1.5); + YAML_ASSERT_THROWS(node[0].as(), std::runtime_error); + YAML_ASSERT(node[1].as() == 1); + YAML_ASSERT(node[1].as() == 1.0f); + YAML_ASSERT(node[2].as() != node[2].as()); + YAML_ASSERT(node[3].as() == std::numeric_limits::infinity()); + YAML_ASSERT(node[4].as() == -std::numeric_limits::infinity()); + return true; + } } 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::Reassign, "reassign", passed, total); RunNodeTest(&Node::FallbackValues, "fallback values", passed, total); + RunNodeTest(&Node::NumericConversion, "numeric conversion", passed, total); std::cout << "Node tests: " << passed << "/" << total << " passed\n"; return passed == total;