diff --git a/CMakeLists.txt b/CMakeLists.txt index 50df2fa..287677d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/conversion.h b/include/conversion.h new file mode 100644 index 0000000..12f688c --- /dev/null +++ b/include/conversion.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace YAML +{ + template + struct Converter { + static bool Convert(const std::string& input, T& output); + }; + + template + bool Convert(const std::string& input, T& output) { + return Converter::Convert(input, output); + } + + // this is the one to specialize + template + inline bool Converter::Convert(const std::string& input, T& output) { + std::stringstream stream(input); + stream >> output; + return !stream.fail(); + } + + // specializations + template <> + inline bool Converter::Convert(const std::string& input, std::string& output) { + output = input; + return true; + } + + template <> + bool Converter::Convert(const std::string& input, bool& output); +} diff --git a/include/node.h b/include/node.h index 0dcac18..1b1530f 100644 --- a/include/node.h +++ b/include/node.h @@ -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 - friend bool Read(const Node& node, T& value); + bool Read(T& value) const; template 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 - 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 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(); } diff --git a/src/alias.cpp b/src/alias.cpp index e8a4560..ae349cf 100644 --- a/src/alias.cpp +++ b/src/alias.cpp @@ -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) diff --git a/src/alias.h b/src/alias.h index 2f15d67..ad80b79 100644 --- a/src/alias.h +++ b/src/alias.h @@ -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 *); diff --git a/src/content.h b/src/content.h index f689cd6..6399682 100644 --- a/src/content.h +++ b/src/content.h @@ -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; } diff --git a/src/conversion.cpp b/src/conversion.cpp new file mode 100644 index 0000000..b990314 --- /dev/null +++ b/src/conversion.cpp @@ -0,0 +1,86 @@ +#include "conversion.h" +#include + + +//////////////////////////////////////////////////////////////// +// 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 + bool IsEntirely(const std::string& str, T func) + { + for(unsigned i=0;i + bool Converter::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;iRead(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) diff --git a/src/scalar.cpp b/src/scalar.cpp index 03dfa4b..34e8280 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -4,8 +4,6 @@ #include "token.h" #include "exceptions.h" #include "node.h" -#include -#include 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 - bool IsEntirely(const std::string& str, T func) - { - for(unsigned i=0;iCompare(this); diff --git a/src/scalar.h b/src/scalar.h index b6a606d..e27d17e 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -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); diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml index 00e30f5..c914749 100644 --- a/yaml-reader/tests/test.yaml +++ b/yaml-reader/tests/test.yaml @@ -1,2 +1,4 @@ ---- -... \ No newline at end of file +- true +- false +- y +- n \ No newline at end of file diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 5c662ae..53d6f37 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -175,6 +175,10 @@ RelativePath=".\src\content.cpp" > + + @@ -290,13 +294,17 @@ Name="Representation" > + +