mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 20:51:16 +00:00
Changed the way we read different types of scalars.
It's better organized now, I think - nodes only offer a single main way of getting the fundamental scalar (as a string), and now we can specialize a single template to read specific types.
This commit is contained in:
@@ -4,6 +4,7 @@ project (YAML_CPP)
|
|||||||
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
|
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
|
||||||
|
|
||||||
set(PUB_HDR
|
set(PUB_HDR
|
||||||
|
include/conversion.h
|
||||||
include/crt.h
|
include/crt.h
|
||||||
include/emitter.h
|
include/emitter.h
|
||||||
include/emittermanip.h
|
include/emittermanip.h
|
||||||
@@ -41,6 +42,7 @@ set(PVT_HDR
|
|||||||
set(SRC
|
set(SRC
|
||||||
src/alias.cpp
|
src/alias.cpp
|
||||||
src/content.cpp
|
src/content.cpp
|
||||||
|
src/conversion.cpp
|
||||||
src/emitter.cpp
|
src/emitter.cpp
|
||||||
src/emitterstate.cpp
|
src/emitterstate.cpp
|
||||||
src/emitterutils.cpp
|
src/emitterutils.cpp
|
||||||
|
35
include/conversion.h
Normal file
35
include/conversion.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
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;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool Converter<bool>::Convert(const std::string& input, bool& output);
|
||||||
|
}
|
@@ -7,6 +7,7 @@
|
|||||||
#include "parserstate.h"
|
#include "parserstate.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "iterator.h"
|
#include "iterator.h"
|
||||||
|
#include "conversion.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
@@ -37,18 +38,11 @@ namespace YAML
|
|||||||
unsigned size() const;
|
unsigned size() const;
|
||||||
|
|
||||||
// extraction of scalars
|
// extraction of scalars
|
||||||
bool Read(std::string& s) const;
|
bool GetScalar(std::string& s) const;
|
||||||
bool Read(int& i) const;
|
|
||||||
bool Read(unsigned& u) const;
|
|
||||||
bool Read(long& l) const;
|
|
||||||
bool Read(float& f) const;
|
|
||||||
bool Read(double& d) const;
|
|
||||||
bool Read(char& c) const;
|
|
||||||
bool Read(bool& b) const;
|
|
||||||
|
|
||||||
// so you can specialize for other values
|
// we can specialize this for other values
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool Read(const Node& node, T& value);
|
bool Read(T& value) const;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend void operator >> (const Node& node, T& value);
|
friend void operator >> (const Node& node, T& value);
|
||||||
@@ -100,15 +94,18 @@ namespace YAML
|
|||||||
|
|
||||||
// templated things we need to keep inline in the header
|
// templated things we need to keep inline in the header
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool Read(const Node& node, T& value)
|
inline bool Node::Read(T& value) const {
|
||||||
{
|
std::string scalar;
|
||||||
return node.Read(value);
|
if(!GetScalar(scalar))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Convert(scalar, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void operator >> (const Node& node, T& value)
|
inline void operator >> (const Node& node, T& value)
|
||||||
{
|
{
|
||||||
if(!Read(node, value))
|
if(!node.Read(value))
|
||||||
throw InvalidScalar(node.m_line, node.m_column);
|
throw InvalidScalar(node.m_line, node.m_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +117,7 @@ namespace YAML
|
|||||||
|
|
||||||
for(Iterator it=begin();it!=end();++it) {
|
for(Iterator it=begin();it!=end();++it) {
|
||||||
T t;
|
T t;
|
||||||
if(YAML::Read(it.first(), t)) {
|
if(it.first().Read(t)) {
|
||||||
if(key == t)
|
if(key == t)
|
||||||
return it.second();
|
return it.second();
|
||||||
}
|
}
|
||||||
|
@@ -63,44 +63,9 @@ namespace YAML
|
|||||||
return m_pRef->IsSequence();
|
return m_pRef->IsSequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Alias::Read(std::string& v) const
|
bool Alias::GetScalar(std::string& scalar) const
|
||||||
{
|
{
|
||||||
return m_pRef->Read(v);
|
return m_pRef->GetScalar(scalar);
|
||||||
}
|
|
||||||
|
|
||||||
bool Alias::Read(int& v) const
|
|
||||||
{
|
|
||||||
return m_pRef->Read(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Alias::Read(unsigned& v) const
|
|
||||||
{
|
|
||||||
return m_pRef->Read(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Alias::Read(long& v) const
|
|
||||||
{
|
|
||||||
return m_pRef->Read(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Alias::Read(float& v) const
|
|
||||||
{
|
|
||||||
return m_pRef->Read(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Alias::Read(double& v) const
|
|
||||||
{
|
|
||||||
return m_pRef->Read(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Alias::Read(char& v) const
|
|
||||||
{
|
|
||||||
return m_pRef->Read(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Alias::Read(bool& v) const
|
|
||||||
{
|
|
||||||
return m_pRef->Read(v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Alias::Compare(Content *pContent)
|
int Alias::Compare(Content *pContent)
|
||||||
|
@@ -22,14 +22,7 @@ namespace YAML
|
|||||||
virtual bool IsMap() const;
|
virtual bool IsMap() const;
|
||||||
virtual bool IsSequence() const;
|
virtual bool IsSequence() const;
|
||||||
|
|
||||||
virtual bool Read(std::string&) const;
|
virtual bool GetScalar(std::string& s) const;
|
||||||
virtual bool Read(int&) const;
|
|
||||||
virtual bool Read(unsigned&) const;
|
|
||||||
virtual bool Read(long&) const;
|
|
||||||
virtual bool Read(float&) const;
|
|
||||||
virtual bool Read(double&) const;
|
|
||||||
virtual bool Read(char&) const;
|
|
||||||
virtual bool Read(bool&) const;
|
|
||||||
|
|
||||||
virtual int Compare(Content *);
|
virtual int Compare(Content *);
|
||||||
virtual int Compare(Scalar *);
|
virtual int Compare(Scalar *);
|
||||||
|
@@ -36,14 +36,7 @@ namespace YAML
|
|||||||
virtual bool IsSequence() const { return false; }
|
virtual bool IsSequence() const { return false; }
|
||||||
|
|
||||||
// extraction
|
// extraction
|
||||||
virtual bool Read(std::string&) const { return false; }
|
virtual bool GetScalar(std::string&) const { return false; }
|
||||||
virtual bool Read(int&) const { return false; }
|
|
||||||
virtual bool Read(unsigned&) const { return false; }
|
|
||||||
virtual bool Read(long&) const { return false; }
|
|
||||||
virtual bool Read(float&) const { return false; }
|
|
||||||
virtual bool Read(double&) const { return false; }
|
|
||||||
virtual bool Read(char&) const { return false; }
|
|
||||||
virtual bool Read(bool&) const { return false; }
|
|
||||||
|
|
||||||
// ordering
|
// ordering
|
||||||
virtual int Compare(Content *) { return 0; }
|
virtual int Compare(Content *) { return 0; }
|
||||||
|
86
src/conversion.cpp
Normal file
86
src/conversion.cpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#include "conversion.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Specializations for converting a string to specific types
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// we're not gonna mess with the mess that is all the isupper/etc. functions
|
||||||
|
bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; }
|
||||||
|
bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; }
|
||||||
|
char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; }
|
||||||
|
|
||||||
|
std::string tolower(const std::string& str)
|
||||||
|
{
|
||||||
|
std::string s(str);
|
||||||
|
std::transform(s.begin(), s.end(), s.begin(), ToLower);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool IsEntirely(const std::string& str, T func)
|
||||||
|
{
|
||||||
|
for(unsigned i=0;i<str.size();i++)
|
||||||
|
if(!func(str[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFlexibleCase
|
||||||
|
// . Returns true if 'str' is:
|
||||||
|
// . UPPERCASE
|
||||||
|
// . lowercase
|
||||||
|
// . Capitalized
|
||||||
|
bool IsFlexibleCase(const std::string& str)
|
||||||
|
{
|
||||||
|
if(str.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(IsEntirely(str, IsLower))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool firstcaps = IsUpper(str[0]);
|
||||||
|
std::string rest = str.substr(1);
|
||||||
|
return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
bool Converter<bool>::Convert(const std::string& input, bool& b)
|
||||||
|
{
|
||||||
|
// we can't use iostream bool extraction operators as they don't
|
||||||
|
// recognize all possible values in the table below (taken from
|
||||||
|
// http://yaml.org/type/bool.html)
|
||||||
|
static const struct {
|
||||||
|
std::string truename, falsename;
|
||||||
|
} names[] = {
|
||||||
|
{ "y", "n" },
|
||||||
|
{ "yes", "no" },
|
||||||
|
{ "true", "false" },
|
||||||
|
{ "on", "off" },
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!IsFlexibleCase(input))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for(unsigned i=0;i<sizeof(names)/sizeof(names[0]);i++) {
|
||||||
|
if(names[i].truename == tolower(input)) {
|
||||||
|
b = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(names[i].falsename == tolower(input)) {
|
||||||
|
b = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
68
src/node.cpp
68
src/node.cpp
@@ -282,75 +282,11 @@ namespace YAML
|
|||||||
return GetValue(i);
|
return GetValue(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
bool Node::GetScalar(std::string& s) const
|
||||||
// Extraction
|
|
||||||
// Note: these Read() functions are identical, but
|
|
||||||
// they're not templated because they use a Content virtual
|
|
||||||
// function, so we'd have to #include that in node.h, and
|
|
||||||
// I don't want to.
|
|
||||||
|
|
||||||
bool Node::Read(std::string& s) const
|
|
||||||
{
|
{
|
||||||
if(!m_pContent)
|
if(!m_pContent)
|
||||||
return false;
|
return false;
|
||||||
|
return m_pContent->GetScalar(s);
|
||||||
return m_pContent->Read(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::Read(int& i) const
|
|
||||||
{
|
|
||||||
if(!m_pContent)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return m_pContent->Read(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::Read(unsigned& u) const
|
|
||||||
{
|
|
||||||
if(!m_pContent)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return m_pContent->Read(u);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::Read(long& l) const
|
|
||||||
{
|
|
||||||
if(!m_pContent)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return m_pContent->Read(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::Read(float& f) const
|
|
||||||
{
|
|
||||||
if(!m_pContent)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return m_pContent->Read(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::Read(double& d) const
|
|
||||||
{
|
|
||||||
if(!m_pContent)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return m_pContent->Read(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::Read(char& c) const
|
|
||||||
{
|
|
||||||
if(!m_pContent)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return m_pContent->Read(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::Read(bool& b) const
|
|
||||||
{
|
|
||||||
if(!m_pContent)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return m_pContent->Read(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator << (std::ostream& out, const Node& node)
|
std::ostream& operator << (std::ostream& out, const Node& node)
|
||||||
|
125
src/scalar.cpp
125
src/scalar.cpp
@@ -4,8 +4,6 @@
|
|||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include <sstream>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
@@ -39,129 +37,6 @@ namespace YAML
|
|||||||
out << "\"\n";
|
out << "\"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scalar::Read(std::string& s) const
|
|
||||||
{
|
|
||||||
s = m_data;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scalar::Read(int& i) const
|
|
||||||
{
|
|
||||||
std::stringstream data(m_data);
|
|
||||||
data >> i;
|
|
||||||
return !data.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scalar::Read(unsigned& u) const
|
|
||||||
{
|
|
||||||
std::stringstream data(m_data);
|
|
||||||
data >> u;
|
|
||||||
return !data.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scalar::Read(long& l) const
|
|
||||||
{
|
|
||||||
std::stringstream data(m_data);
|
|
||||||
data >> l;
|
|
||||||
return !data.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scalar::Read(float& f) const
|
|
||||||
{
|
|
||||||
std::stringstream data(m_data);
|
|
||||||
data >> f;
|
|
||||||
return !data.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scalar::Read(double& d) const
|
|
||||||
{
|
|
||||||
std::stringstream data(m_data);
|
|
||||||
data >> d;
|
|
||||||
return !data.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scalar::Read(char& c) const
|
|
||||||
{
|
|
||||||
std::stringstream data(m_data);
|
|
||||||
data >> c;
|
|
||||||
return !data.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// we're not gonna mess with the mess that is all the isupper/etc. functions
|
|
||||||
bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; }
|
|
||||||
bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; }
|
|
||||||
char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; }
|
|
||||||
|
|
||||||
std::string tolower(const std::string& str)
|
|
||||||
{
|
|
||||||
std::string s(str);
|
|
||||||
std::transform(s.begin(), s.end(), s.begin(), ToLower);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool IsEntirely(const std::string& str, T func)
|
|
||||||
{
|
|
||||||
for(unsigned i=0;i<str.size();i++)
|
|
||||||
if(!func(str[i]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsFlexibleCase
|
|
||||||
// . Returns true if 'str' is:
|
|
||||||
// . UPPERCASE
|
|
||||||
// . lowercase
|
|
||||||
// . Capitalized
|
|
||||||
bool IsFlexibleCase(const std::string& str)
|
|
||||||
{
|
|
||||||
if(str.empty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(IsEntirely(str, IsLower))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bool firstcaps = IsUpper(str[0]);
|
|
||||||
std::string rest = str.substr(1);
|
|
||||||
return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scalar::Read(bool& b) const
|
|
||||||
{
|
|
||||||
// we can't use iostream bool extraction operators as they don't
|
|
||||||
// recognize all possible values in the table below (taken from
|
|
||||||
// http://yaml.org/type/bool.html)
|
|
||||||
static const struct {
|
|
||||||
std::string truename, falsename;
|
|
||||||
} names[] = {
|
|
||||||
{ "y", "n" },
|
|
||||||
{ "yes", "no" },
|
|
||||||
{ "true", "false" },
|
|
||||||
{ "on", "off" },
|
|
||||||
};
|
|
||||||
|
|
||||||
if(!IsFlexibleCase(m_data))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for(unsigned i=0;i<sizeof(names)/sizeof(names[0]);i++) {
|
|
||||||
if(names[i].truename == tolower(m_data)) {
|
|
||||||
b = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(names[i].falsename == tolower(m_data)) {
|
|
||||||
b = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Scalar::Compare(Content *pContent)
|
int Scalar::Compare(Content *pContent)
|
||||||
{
|
{
|
||||||
return -pContent->Compare(this);
|
return -pContent->Compare(this);
|
||||||
|
12
src/scalar.h
12
src/scalar.h
@@ -17,14 +17,10 @@ namespace YAML
|
|||||||
virtual bool IsScalar() const { return true; }
|
virtual bool IsScalar() const { return true; }
|
||||||
|
|
||||||
// extraction
|
// extraction
|
||||||
virtual bool Read(std::string& s) const;
|
virtual bool GetScalar(std::string& scalar) const {
|
||||||
virtual bool Read(int& i) const;
|
scalar = m_data;
|
||||||
virtual bool Read(unsigned& u) const;
|
return true;
|
||||||
virtual bool Read(long& l) const;
|
}
|
||||||
virtual bool Read(float& f) const;
|
|
||||||
virtual bool Read(double& d) const;
|
|
||||||
virtual bool Read(char& c) const;
|
|
||||||
virtual bool Read(bool& b) const;
|
|
||||||
|
|
||||||
// ordering
|
// ordering
|
||||||
virtual int Compare(Content *pContent);
|
virtual int Compare(Content *pContent);
|
||||||
|
@@ -1,2 +1,4 @@
|
|||||||
---
|
- true
|
||||||
...
|
- false
|
||||||
|
- y
|
||||||
|
- n
|
@@ -175,6 +175,10 @@
|
|||||||
RelativePath=".\src\content.cpp"
|
RelativePath=".\src\content.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\conversion.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\iterator.cpp"
|
RelativePath=".\src\iterator.cpp"
|
||||||
>
|
>
|
||||||
@@ -290,13 +294,17 @@
|
|||||||
Name="Representation"
|
Name="Representation"
|
||||||
>
|
>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\alias.h"
|
RelativePath=".\src\alias.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\content.h"
|
RelativePath=".\src\content.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\include\conversion.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\include\iterator.h"
|
RelativePath=".\include\iterator.h"
|
||||||
>
|
>
|
||||||
|
Reference in New Issue
Block a user