From 1acc0e49824391ba3ae0ff9073503fda0b2c3161 Mon Sep 17 00:00:00 2001 From: beder Date: Sun, 6 Jul 2008 00:06:36 +0000 Subject: [PATCH] Added a (recursive) ordering, so we have a canonical output that we can compare. --- content.h | 14 ++++++- iterator.cpp | 2 +- ltnode.h | 10 +++++ map.cpp | 91 ++++++++++++++++++++++++++++++++++------------ map.h | 12 ++++-- node.cpp | 30 ++++++++++++++- node.h | 9 ++++- scalar.cpp | 15 ++++++++ scalar.h | 6 +++ sequence.cpp | 22 +++++++++++ sequence.h | 6 +++ test.yaml | 20 ++-------- tests.cpp | 3 +- tests/scalars.yaml | 24 ++++++++++++ yaml-reader.vcproj | 4 ++ 15 files changed, 217 insertions(+), 51 deletions(-) create mode 100644 ltnode.h create mode 100644 tests/scalars.yaml diff --git a/content.h b/content.h index 9f9ac25..3189478 100644 --- a/content.h +++ b/content.h @@ -5,12 +5,16 @@ #include #include "parserstate.h" #include "exceptions.h" +#include "ltnode.h" namespace YAML { class Scanner; class Parser; class Node; + class Scalar; + class Sequence; + class Map; class Content { @@ -22,9 +26,9 @@ namespace YAML virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; virtual bool GetBegin(std::vector ::const_iterator& it) const { return false; } - virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } + virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } virtual bool GetEnd(std::vector ::const_iterator& it) const { return false; } - virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } + virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } virtual Node *GetNode(unsigned i) const { return 0; } virtual unsigned GetSize() const { return 0; } @@ -37,6 +41,12 @@ namespace YAML virtual void Read(double& d) { throw InvalidScalar(); } virtual void Read(char& c) { throw InvalidScalar(); } + // ordering + virtual int Compare(Content *pContent) { return 0; } + virtual int Compare(Scalar *pScalar) { return 0; } + virtual int Compare(Sequence *pSeq) { return 0; } + virtual int Compare(Map *pMap) { return 0; } + protected: }; } diff --git a/iterator.cpp b/iterator.cpp index 67d050d..bd671be 100644 --- a/iterator.cpp +++ b/iterator.cpp @@ -11,7 +11,7 @@ namespace YAML { } - Node::Iterator::Iterator(std::map ::const_iterator it): mapIter(it), type(IT_MAP) + Node::Iterator::Iterator(std::map ::const_iterator it): mapIter(it), type(IT_MAP) { } diff --git a/ltnode.h b/ltnode.h new file mode 100644 index 0000000..af8c1bb --- /dev/null +++ b/ltnode.h @@ -0,0 +1,10 @@ +#pragma once + +namespace YAML +{ + class Node; + + struct ltnode { + bool operator()(const Node *pNode1, const Node *pNode2) const; + }; +} diff --git a/map.cpp b/map.cpp index b448265..e23c2af 100644 --- a/map.cpp +++ b/map.cpp @@ -24,13 +24,13 @@ namespace YAML m_data.clear(); } - bool Map::GetBegin(std::map ::const_iterator& it) const + bool Map::GetBegin(std::map ::const_iterator& it) const { it = m_data.begin(); return true; } - bool Map::GetEnd(std::map ::const_iterator& it) const + bool Map::GetEnd(std::map ::const_iterator& it) const { it = m_data.end(); return true; @@ -68,15 +68,22 @@ namespace YAML Node *pKey = new Node; Node *pValue = new Node; - m_data[pKey] = pValue; - // grab key - pKey->Parse(pScanner, state); + try { + // grab key + pKey->Parse(pScanner, state); - // now grab value (optional) - if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { - pScanner->PopNextToken(); - pValue->Parse(pScanner, state); + // now grab value (optional) + if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { + pScanner->PopNextToken(); + pValue->Parse(pScanner, state); + } + + m_data[pKey] = pValue; + } catch(Exception& e) { + delete pKey; + delete pValue; + throw e; } } } @@ -105,23 +112,31 @@ namespace YAML Node *pKey = new Node; Node *pValue = new Node; - m_data[pKey] = pValue; - // grab key - pKey->Parse(pScanner, state); + try { + // grab key + pKey->Parse(pScanner, state); - // now grab value (optional) - if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { - pScanner->PopNextToken(); - pValue->Parse(pScanner, state); + // now grab value (optional) + if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { + pScanner->PopNextToken(); + pValue->Parse(pScanner, state); + } + + // now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node) + pToken = pScanner->PeekNextToken(); + if(pToken->type == TT_FLOW_ENTRY) + pScanner->EatNextToken(); + else if(pToken->type != TT_FLOW_MAP_END) + throw MapEndNotFound(); + + m_data[pKey] = pValue; + } catch(Exception& e) { + // clean up and rethrow + delete pKey; + delete pValue; + throw e; } - - // now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node) - pToken = pScanner->PeekNextToken(); - if(pToken->type == TT_FLOW_ENTRY) - pScanner->EatNextToken(); - else if(pToken->type != TT_FLOW_MAP_END) - throw MapEndNotFound(); } } @@ -148,4 +163,34 @@ namespace YAML if(m_data.empty()) out << std::endl; } + + int Map::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Map::Compare(Map *pMap) + { + node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin(); + while(1) { + if(it == m_data.end()) { + if(jt == pMap->m_data.end()) + return 0; + else + return -1; + } + if(jt == pMap->m_data.end()) + return 1; + + int cmp = it->first->Compare(*jt->first); + if(cmp != 0) + return cmp; + + cmp = it->second->Compare(*jt->second); + if(cmp != 0) + return cmp; + } + + return 0; + } } diff --git a/map.h b/map.h index d3a327c..3ebd3f4 100644 --- a/map.h +++ b/map.h @@ -14,17 +14,23 @@ namespace YAML virtual ~Map(); void Clear(); - virtual bool GetBegin(std::map ::const_iterator& it) const; - virtual bool GetEnd(std::map ::const_iterator& it) const; + virtual bool GetBegin(std::map ::const_iterator& it) const; + virtual bool GetEnd(std::map ::const_iterator& it) const; virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar) { return 1; } + virtual int Compare(Sequence *pSeq) { return 1; } + virtual int Compare(Map *pMap); + private: void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, const ParserState& state); protected: - typedef std::map node_map; + typedef std::map node_map; node_map m_data; }; } diff --git a/node.cpp b/node.cpp index c998a45..c31fe96 100644 --- a/node.cpp +++ b/node.cpp @@ -9,6 +9,12 @@ namespace YAML { + // the ordering! + bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const + { + return *pNode1 < *pNode2; + } + Node::Node(): m_pContent(0), m_alias(false) { } @@ -150,7 +156,7 @@ namespace YAML if(m_pContent->GetBegin(seqIter)) return Iterator(seqIter); - std::map ::const_iterator mapIter; + std::map ::const_iterator mapIter; if(m_pContent->GetBegin(mapIter)) return Iterator(mapIter); @@ -168,7 +174,7 @@ namespace YAML if(m_pContent->GetEnd(seqIter)) return Iterator(seqIter); - std::map ::const_iterator mapIter; + std::map ::const_iterator mapIter; if(m_pContent->GetEnd(mapIter)) return Iterator(mapIter); @@ -274,4 +280,24 @@ namespace YAML node.Write(out, 0, false, false); return out; } + + int Node::Compare(const Node& rhs) const + { + // Step 1: no content is the smallest + if(!m_pContent) { + if(rhs.m_pContent) + return -1; + else + return 0; + } + if(!rhs.m_pContent) + return 1; + + return m_pContent->Compare(rhs.m_pContent); + } + + bool operator < (const Node& n1, const Node& n2) + { + return n1.Compare(n2) < 0; + } } diff --git a/node.h b/node.h index 988ee1c..9bc88ca 100644 --- a/node.h +++ b/node.h @@ -6,6 +6,7 @@ #include #include "parserstate.h" #include "exceptions.h" +#include "ltnode.h" namespace YAML { @@ -20,7 +21,7 @@ namespace YAML public: Iterator(); Iterator(std::vector ::const_iterator it); - Iterator(std::map ::const_iterator it); + Iterator(std::map ::const_iterator it); ~Iterator(); friend bool operator == (const Iterator& it, const Iterator& jt); @@ -37,7 +38,7 @@ namespace YAML ITER_TYPE type; std::vector ::const_iterator seqIter; - std::map ::const_iterator mapIter; + std::map ::const_iterator mapIter; }; public: @@ -95,6 +96,10 @@ namespace YAML // insertion friend std::ostream& operator << (std::ostream& out, const Node& node); + // ordering + int Compare(const Node& rhs) const; + friend bool operator < (const Node& n1, const Node& n2); + private: void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state); diff --git a/scalar.cpp b/scalar.cpp index 20b2671..6be1bf4 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -88,4 +88,19 @@ namespace YAML if(!data) throw InvalidScalar(); } + + int Scalar::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Scalar::Compare(Scalar *pScalar) + { + if(m_data < pScalar->m_data) + return -1; + else if(m_data > pScalar->m_data) + return 1; + else + return 0; + } } diff --git a/scalar.h b/scalar.h index 95b9062..0da9df6 100644 --- a/scalar.h +++ b/scalar.h @@ -23,6 +23,12 @@ namespace YAML virtual void Read(double& d); virtual void Read(char& c); + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar); + virtual int Compare(Sequence *pSeq) { return -1; } + virtual int Compare(Map *pMap) { return -1; } + protected: std::string m_data; }; diff --git a/sequence.cpp b/sequence.cpp index 5e08835..1ec82de 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -151,4 +151,26 @@ namespace YAML if(m_data.empty()) out << std::endl; } + + int Sequence::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Sequence::Compare(Sequence *pSeq) + { + unsigned n = m_data.size(), m = pSeq->m_data.size(); + if(n < m) + return -1; + else if(n > m) + return 1; + + for(unsigned i=0;iCompare(*pSeq->m_data[i]); + if(cmp != 0) + return cmp; + } + + return 0; + } } diff --git a/sequence.h b/sequence.h index d305073..35b7765 100644 --- a/sequence.h +++ b/sequence.h @@ -22,6 +22,12 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar) { return 1; } + virtual int Compare(Sequence *pSeq); + virtual int Compare(Map *pMap) { return -1; } + private: void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseImplicit(Scanner *pScanner, const ParserState& state); diff --git a/test.yaml b/test.yaml index f7be014..28e1b7d 100644 --- a/test.yaml +++ b/test.yaml @@ -1,17 +1,3 @@ -literal: | - Here's a literal scalar. - That's a newline. - - Let's go... -folded: > - Here's a folded scalar that - wraps over to a newline. - - Let's go... -regular: Here's a regular - scalar that keeps - on wrapping... - - - Let's go! -and last key: so it doesn't go bonkers \ No newline at end of file +abeginning: value +zend: value +middle: value \ No newline at end of file diff --git a/tests.cpp b/tests.cpp index 2d9b476..01df50b 100644 --- a/tests.cpp +++ b/tests.cpp @@ -15,6 +15,7 @@ namespace YAML std::vector files; files.push_back("tests/simple.yaml"); files.push_back("tests/mixed.yaml"); + files.push_back("tests/scalars.yaml"); bool passed = true; for(unsigned i=0;i + and a folded scalar... so we + can just keep writing various + things. And if we want to keep indentation: + + we just indent a little + see, this stays indented +- >- + Here's a folded scalar + that gets chomped. +- |- + And here's a literal scalar + that gets chomped. +- >2 + Here's a folded scalar + that starts with some indentation. \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 0d77cd1..5239b09 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -302,6 +302,10 @@ RelativePath=".\content.h" > + +