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:
Jesse Beder
2009-05-23 23:51:01 +00:00
parent b952bc594f
commit e76521c0e9
12 changed files with 158 additions and 270 deletions

View File

@@ -4,6 +4,7 @@ project (YAML_CPP)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
set(PUB_HDR
include/conversion.h
include/crt.h
include/emitter.h
include/emittermanip.h
@@ -41,6 +42,7 @@ set(PVT_HDR
set(SRC
src/alias.cpp
src/content.cpp
src/conversion.cpp
src/emitter.cpp
src/emitterstate.cpp
src/emitterutils.cpp

35
include/conversion.h Normal file
View 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);
}

View File

@@ -7,6 +7,7 @@
#include "parserstate.h"
#include "exceptions.h"
#include "iterator.h"
#include "conversion.h"
namespace YAML
{
@@ -37,18 +38,11 @@ namespace YAML
unsigned size() const;
// extraction of scalars
bool Read(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;
bool GetScalar(std::string& s) const;
// so you can specialize for other values
// we can specialize this for other values
template <typename T>
friend bool Read(const Node& node, T& value);
bool Read(T& value) const;
template <typename T>
friend void operator >> (const Node& node, T& value);
@@ -100,15 +94,18 @@ namespace YAML
// templated things we need to keep inline in the header
template <typename T>
inline bool Read(const Node& node, T& value)
{
return node.Read(value);
inline bool Node::Read(T& value) const {
std::string scalar;
if(!GetScalar(scalar))
return false;
return Convert(scalar, value);
}
template <typename T>
inline void operator >> (const Node& node, T& value)
{
if(!Read(node, value))
if(!node.Read(value))
throw InvalidScalar(node.m_line, node.m_column);
}
@@ -120,7 +117,7 @@ namespace YAML
for(Iterator it=begin();it!=end();++it) {
T t;
if(YAML::Read(it.first(), t)) {
if(it.first().Read(t)) {
if(key == t)
return it.second();
}

View File

@@ -63,44 +63,9 @@ namespace YAML
return m_pRef->IsSequence();
}
bool Alias::Read(std::string& v) const
bool Alias::GetScalar(std::string& scalar) const
{
return m_pRef->Read(v);
}
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);
return m_pRef->GetScalar(scalar);
}
int Alias::Compare(Content *pContent)

View File

@@ -22,14 +22,7 @@ namespace YAML
virtual bool IsMap() const;
virtual bool IsSequence() const;
virtual bool Read(std::string&) 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 bool GetScalar(std::string& s) const;
virtual int Compare(Content *);
virtual int Compare(Scalar *);

View File

@@ -36,14 +36,7 @@ namespace YAML
virtual bool IsSequence() const { return false; }
// extraction
virtual bool Read(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; }
virtual bool GetScalar(std::string&) const { return false; }
// ordering
virtual int Compare(Content *) { return 0; }

86
src/conversion.cpp Normal file
View 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;
}
}

View File

@@ -282,75 +282,11 @@ namespace YAML
return GetValue(i);
}
///////////////////////////////////////////////////////
// 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
bool Node::GetScalar(std::string& s) const
{
if(!m_pContent)
return false;
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);
return m_pContent->GetScalar(s);
}
std::ostream& operator << (std::ostream& out, const Node& node)

View File

@@ -4,8 +4,6 @@
#include "token.h"
#include "exceptions.h"
#include "node.h"
#include <sstream>
#include <algorithm>
namespace YAML
{
@@ -39,129 +37,6 @@ namespace YAML
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)
{
return -pContent->Compare(this);

View File

@@ -17,14 +17,10 @@ namespace YAML
virtual bool IsScalar() const { return true; }
// extraction
virtual bool Read(std::string& s) const;
virtual bool Read(int& i) const;
virtual bool Read(unsigned& u) const;
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;
virtual bool GetScalar(std::string& scalar) const {
scalar = m_data;
return true;
}
// ordering
virtual int Compare(Content *pContent);

View File

@@ -1,2 +1,4 @@
---
...
- true
- false
- y
- n

View File

@@ -175,6 +175,10 @@
RelativePath=".\src\content.cpp"
>
</File>
<File
RelativePath=".\src\conversion.cpp"
>
</File>
<File
RelativePath=".\src\iterator.cpp"
>
@@ -290,13 +294,17 @@
Name="Representation"
>
<File
RelativePath=".\include\alias.h"
RelativePath=".\src\alias.h"
>
</File>
<File
RelativePath=".\src\content.h"
>
</File>
<File
RelativePath=".\include\conversion.h"
>
</File>
<File
RelativePath=".\include\iterator.h"
>