mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 12:41:17 +00:00
Refactored the operator >> and Node::Read default functions, as well as the conversion functions, to more easily read new types as keys (this uncovered an error, in example 2.11 of the spec)
This commit is contained in:
@@ -10,36 +10,34 @@
|
|||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
template <typename T>
|
inline bool Convert(const std::string& input, std::string& output) {
|
||||||
struct Converter {
|
|
||||||
static bool Convert(const std::string& input, T& output);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool Convert(const std::string& input, T& output) {
|
|
||||||
return Converter<T>::Convert(input, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is the one to specialize
|
|
||||||
template <typename T>
|
|
||||||
inline bool Converter<T>::Convert(const std::string& input, T& output) {
|
|
||||||
std::stringstream stream(input);
|
|
||||||
stream >> output;
|
|
||||||
return !stream.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
// specializations
|
|
||||||
template <>
|
|
||||||
inline bool Converter<std::string>::Convert(const std::string& input, std::string& output) {
|
|
||||||
output = input;
|
output = input;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
|
||||||
bool Converter<bool>::Convert(const std::string& input, bool& output);
|
|
||||||
|
|
||||||
template <>
|
bool Convert(const std::string& input, bool& output);
|
||||||
bool Converter<_Null>::Convert(const std::string& input, _Null& output);
|
bool Convert(const std::string& input, _Null& output);
|
||||||
|
|
||||||
|
#define YAML_MAKE_STREAM_CONVERT(type) \
|
||||||
|
inline bool Convert(const std::string& input, type& output) { \
|
||||||
|
std::stringstream stream(input); \
|
||||||
|
stream >> output; \
|
||||||
|
return !stream.fail(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
YAML_MAKE_STREAM_CONVERT(char)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(unsigned char)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(int)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(unsigned int)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(short)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(unsigned short)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(long)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(unsigned long)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(float)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(double)
|
||||||
|
YAML_MAKE_STREAM_CONVERT(long double)
|
||||||
|
|
||||||
|
#undef YAML_MAKE_STREAM_CONVERT
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
#endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||||
|
@@ -133,5 +133,6 @@ namespace YAML
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "nodeimpl.h"
|
#include "nodeimpl.h"
|
||||||
|
#include "nodereadimpl.h"
|
||||||
|
|
||||||
#endif // NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
#endif // NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||||
|
@@ -9,15 +9,6 @@
|
|||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
// implementation of templated things
|
// implementation of templated things
|
||||||
template <typename T>
|
|
||||||
inline bool Node::Read(T& value) const {
|
|
||||||
std::string scalar;
|
|
||||||
if(!GetScalar(scalar))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return Convert(scalar, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline const T Node::Read() const {
|
inline const T Node::Read() const {
|
||||||
T value;
|
T value;
|
||||||
@@ -32,7 +23,7 @@ namespace YAML
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void operator >> (const Node& node, T& value) {
|
inline void operator >> (const Node& node, T& value) {
|
||||||
if(!node.Read(value))
|
if(!ConvertScalar(node, value))
|
||||||
throw InvalidScalar(node.m_mark);
|
throw InvalidScalar(node.m_mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
65
include/nodereadimpl.h
Normal file
65
include/nodereadimpl.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
// implementation for Node::Read
|
||||||
|
// (the goal is to call ConvertScalar if we can, and fall back to operator >> if not)
|
||||||
|
// thanks to litb from stackoverflow.com
|
||||||
|
// http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390
|
||||||
|
|
||||||
|
template<bool>
|
||||||
|
struct read_impl;
|
||||||
|
|
||||||
|
// ConvertScalar available
|
||||||
|
template<>
|
||||||
|
struct read_impl<true> {
|
||||||
|
template<typename T>
|
||||||
|
static bool read(const Node& node, T& value) {
|
||||||
|
return ConvertScalar(node, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ConvertScalar not available
|
||||||
|
template<>
|
||||||
|
struct read_impl<false> {
|
||||||
|
template<typename T>
|
||||||
|
static bool read(const Node& node, T& value) {
|
||||||
|
try {
|
||||||
|
node >> value;
|
||||||
|
} catch(const Exception&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace fallback {
|
||||||
|
// sizeof > 1
|
||||||
|
struct flag { char c[2]; };
|
||||||
|
flag Convert(...);
|
||||||
|
|
||||||
|
char (& operator,(flag, flag) )[1];
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void operator,(flag, T const&);
|
||||||
|
|
||||||
|
char (& operator,(char(&)[1], flag) )[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool Node::Read(T& value) const {
|
||||||
|
using namespace fallback;
|
||||||
|
|
||||||
|
return read_impl<sizeof (fallback::flag(), Convert(std::string(), value), fallback::flag()) != 1>::read(*this, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the main conversion function
|
||||||
|
template <typename T>
|
||||||
|
inline bool ConvertScalar(const Node& node, T& value) {
|
||||||
|
std::string scalar;
|
||||||
|
if(!node.GetScalar(scalar))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Convert(scalar, value);
|
||||||
|
}
|
||||||
|
}
|
@@ -49,8 +49,7 @@ namespace
|
|||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
template <>
|
bool Convert(const std::string& input, bool& b)
|
||||||
bool Converter<bool>::Convert(const std::string& input, bool& b)
|
|
||||||
{
|
{
|
||||||
// we can't use iostream bool extraction operators as they don't
|
// we can't use iostream bool extraction operators as they don't
|
||||||
// recognize all possible values in the table below (taken from
|
// recognize all possible values in the table below (taken from
|
||||||
@@ -82,8 +81,7 @@ namespace YAML
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
bool Convert(const std::string& input, _Null& /*output*/)
|
||||||
bool Converter<_Null>::Convert(const std::string& input, _Null& /*output*/)
|
|
||||||
{
|
{
|
||||||
return input.empty() || input == "~" || input == "null" || input == "Null" || input == "NULL";
|
return input.empty() || input == "~" || input == "null" || input == "Null" || input == "NULL";
|
||||||
}
|
}
|
||||||
|
@@ -290,7 +290,49 @@ namespace Test {
|
|||||||
YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa");
|
YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa");
|
||||||
YAML_ASSERT(doc["rbi"][1] == "Ken Griffey");
|
YAML_ASSERT(doc["rbi"][1] == "Ken Griffey");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Pair {
|
||||||
|
Pair() {}
|
||||||
|
Pair(const std::string& f, const std::string& s): first(f), second(s) {}
|
||||||
|
std::string first, second;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator == (const Pair& p, const Pair& q) {
|
||||||
|
return p.first == q.first && p.second == q.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator >> (const YAML::Node& node, Pair& p) {
|
||||||
|
node[0] >> p.first;
|
||||||
|
node[1] >> p.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST MappingBetweenSequences()
|
||||||
|
{
|
||||||
|
std::string input =
|
||||||
|
"? - Detroit Tigers\n"
|
||||||
|
" - Chicago cubs\n"
|
||||||
|
":\n"
|
||||||
|
" - 2001-07-23\n"
|
||||||
|
"\n"
|
||||||
|
"? [ New York Yankees,\n"
|
||||||
|
" Atlanta Braves ]\n"
|
||||||
|
": [ 2001-07-02, 2001-08-12,\n"
|
||||||
|
" 2001-08-14 ]";
|
||||||
|
std::stringstream stream(input);
|
||||||
|
YAML::Parser parser(stream);
|
||||||
|
YAML::Node doc;
|
||||||
|
parser.GetNextDocument(doc);
|
||||||
|
|
||||||
|
YAML_ASSERT(doc.size() == 2);
|
||||||
|
YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago Cubs")].size() == 1);
|
||||||
|
YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago Cubs")][0] == "2001-07-23");
|
||||||
|
YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")].size() == 3);
|
||||||
|
YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][0] == "2001-07-02");
|
||||||
|
YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][1] == "2001-08-12");
|
||||||
|
YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][2] == "2001-08-14");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunSpecTests()
|
bool RunSpecTests()
|
||||||
@@ -306,6 +348,7 @@ namespace Test {
|
|||||||
RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed);
|
RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed);
|
||||||
RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed);
|
RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed);
|
||||||
RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed);
|
RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed);
|
||||||
|
RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed);
|
||||||
return passed;
|
return passed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user