Added a (recursive) ordering, so we have a canonical output that we can compare.

This commit is contained in:
beder
2008-07-06 00:06:36 +00:00
parent 3cad5a2ed0
commit 1acc0e4982
15 changed files with 217 additions and 51 deletions

View File

@@ -5,12 +5,16 @@
#include <map> #include <map>
#include "parserstate.h" #include "parserstate.h"
#include "exceptions.h" #include "exceptions.h"
#include "ltnode.h"
namespace YAML namespace YAML
{ {
class Scanner; class Scanner;
class Parser; class Parser;
class Node; class Node;
class Scalar;
class Sequence;
class Map;
class Content class Content
{ {
@@ -22,9 +26,9 @@ namespace YAML
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0;
virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const { return false; } virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const { return false; }
virtual bool GetBegin(std::map <Node *, Node *>::const_iterator& it) const { return false; } virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; }
virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const { return false; } virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const { return false; }
virtual bool GetEnd(std::map <Node *, Node *>::const_iterator& it) const { return false; } virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; }
virtual Node *GetNode(unsigned i) const { return 0; } virtual Node *GetNode(unsigned i) const { return 0; }
virtual unsigned GetSize() 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(double& d) { throw InvalidScalar(); }
virtual void Read(char& c) { 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: protected:
}; };
} }

View File

@@ -11,7 +11,7 @@ namespace YAML
{ {
} }
Node::Iterator::Iterator(std::map <Node *, Node *>::const_iterator it): mapIter(it), type(IT_MAP) Node::Iterator::Iterator(std::map <Node *, Node *, ltnode>::const_iterator it): mapIter(it), type(IT_MAP)
{ {
} }

10
ltnode.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
namespace YAML
{
class Node;
struct ltnode {
bool operator()(const Node *pNode1, const Node *pNode2) const;
};
}

91
map.cpp
View File

@@ -24,13 +24,13 @@ namespace YAML
m_data.clear(); m_data.clear();
} }
bool Map::GetBegin(std::map <Node *, Node *>::const_iterator& it) const bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const
{ {
it = m_data.begin(); it = m_data.begin();
return true; return true;
} }
bool Map::GetEnd(std::map <Node *, Node *>::const_iterator& it) const bool Map::GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const
{ {
it = m_data.end(); it = m_data.end();
return true; return true;
@@ -68,15 +68,22 @@ namespace YAML
Node *pKey = new Node; Node *pKey = new Node;
Node *pValue = new Node; Node *pValue = new Node;
m_data[pKey] = pValue;
// grab key try {
pKey->Parse(pScanner, state); // grab key
pKey->Parse(pScanner, state);
// now grab value (optional) // now grab value (optional)
if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) {
pScanner->PopNextToken(); pScanner->PopNextToken();
pValue->Parse(pScanner, state); 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 *pKey = new Node;
Node *pValue = new Node; Node *pValue = new Node;
m_data[pKey] = pValue;
// grab key try {
pKey->Parse(pScanner, state); // grab key
pKey->Parse(pScanner, state);
// now grab value (optional) // now grab value (optional)
if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) {
pScanner->PopNextToken(); pScanner->PopNextToken();
pValue->Parse(pScanner, state); 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()) if(m_data.empty())
out << std::endl; 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;
}
} }

12
map.h
View File

@@ -14,17 +14,23 @@ namespace YAML
virtual ~Map(); virtual ~Map();
void Clear(); void Clear();
virtual bool GetBegin(std::map <Node *, Node *>::const_iterator& it) const; virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual bool GetEnd(std::map <Node *, Node *>::const_iterator& it) const; virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); 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: private:
void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseBlock(Scanner *pScanner, const ParserState& state);
void ParseFlow(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, const ParserState& state);
protected: protected:
typedef std::map <Node *, Node *> node_map; typedef std::map <Node *, Node *, ltnode> node_map;
node_map m_data; node_map m_data;
}; };
} }

View File

@@ -9,6 +9,12 @@
namespace YAML 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) Node::Node(): m_pContent(0), m_alias(false)
{ {
} }
@@ -150,7 +156,7 @@ namespace YAML
if(m_pContent->GetBegin(seqIter)) if(m_pContent->GetBegin(seqIter))
return Iterator(seqIter); return Iterator(seqIter);
std::map <Node *, Node *>::const_iterator mapIter; std::map <Node *, Node *, ltnode>::const_iterator mapIter;
if(m_pContent->GetBegin(mapIter)) if(m_pContent->GetBegin(mapIter))
return Iterator(mapIter); return Iterator(mapIter);
@@ -168,7 +174,7 @@ namespace YAML
if(m_pContent->GetEnd(seqIter)) if(m_pContent->GetEnd(seqIter))
return Iterator(seqIter); return Iterator(seqIter);
std::map <Node *, Node *>::const_iterator mapIter; std::map <Node *, Node *, ltnode>::const_iterator mapIter;
if(m_pContent->GetEnd(mapIter)) if(m_pContent->GetEnd(mapIter))
return Iterator(mapIter); return Iterator(mapIter);
@@ -274,4 +280,24 @@ namespace YAML
node.Write(out, 0, false, false); node.Write(out, 0, false, false);
return out; 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;
}
} }

9
node.h
View File

@@ -6,6 +6,7 @@
#include <map> #include <map>
#include "parserstate.h" #include "parserstate.h"
#include "exceptions.h" #include "exceptions.h"
#include "ltnode.h"
namespace YAML namespace YAML
{ {
@@ -20,7 +21,7 @@ namespace YAML
public: public:
Iterator(); Iterator();
Iterator(std::vector <Node *>::const_iterator it); Iterator(std::vector <Node *>::const_iterator it);
Iterator(std::map <Node *, Node *>::const_iterator it); Iterator(std::map <Node *, Node *, ltnode>::const_iterator it);
~Iterator(); ~Iterator();
friend bool operator == (const Iterator& it, const Iterator& jt); friend bool operator == (const Iterator& it, const Iterator& jt);
@@ -37,7 +38,7 @@ namespace YAML
ITER_TYPE type; ITER_TYPE type;
std::vector <Node *>::const_iterator seqIter; std::vector <Node *>::const_iterator seqIter;
std::map <Node *, Node *>::const_iterator mapIter; std::map <Node *, Node *, ltnode>::const_iterator mapIter;
}; };
public: public:
@@ -95,6 +96,10 @@ namespace YAML
// insertion // insertion
friend std::ostream& operator << (std::ostream& out, const Node& node); 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: private:
void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseHeader(Scanner *pScanner, const ParserState& state);
void ParseTag(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state);

View File

@@ -88,4 +88,19 @@ namespace YAML
if(!data) if(!data)
throw InvalidScalar(); 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;
}
} }

View File

@@ -23,6 +23,12 @@ namespace YAML
virtual void Read(double& d); virtual void Read(double& d);
virtual void Read(char& c); 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: protected:
std::string m_data; std::string m_data;
}; };

View File

@@ -151,4 +151,26 @@ namespace YAML
if(m_data.empty()) if(m_data.empty())
out << std::endl; 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;i<n;i++) {
int cmp = m_data[i]->Compare(*pSeq->m_data[i]);
if(cmp != 0)
return cmp;
}
return 0;
}
} }

View File

@@ -22,6 +22,12 @@ namespace YAML
virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); 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: private:
void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseBlock(Scanner *pScanner, const ParserState& state);
void ParseImplicit(Scanner *pScanner, const ParserState& state); void ParseImplicit(Scanner *pScanner, const ParserState& state);

View File

@@ -1,17 +1,3 @@
literal: | abeginning: value
Here's a literal scalar. zend: value
That's a newline. middle: value
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

View File

@@ -15,6 +15,7 @@ namespace YAML
std::vector <std::string> files; std::vector <std::string> files;
files.push_back("tests/simple.yaml"); files.push_back("tests/simple.yaml");
files.push_back("tests/mixed.yaml"); files.push_back("tests/mixed.yaml");
files.push_back("tests/scalars.yaml");
bool passed = true; bool passed = true;
for(unsigned i=0;i<files.size();i++) { for(unsigned i=0;i<files.size();i++) {
@@ -63,7 +64,7 @@ namespace YAML
if(firstTry == secondTry) if(firstTry == secondTry)
return true; return true;
std::ofstream fout("out.yaml"); std::ofstream fout("tests/out.yaml");
fout << "---\n"; fout << "---\n";
fout << firstTry << std::endl; fout << firstTry << std::endl;
fout << "---\n"; fout << "---\n";

24
tests/scalars.yaml Normal file
View File

@@ -0,0 +1,24 @@
- normal scalar, but
over several lines
- |
literal scalar - so we can draw ASCII:
- -
| - |
------
- >
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.

View File

@@ -302,6 +302,10 @@
RelativePath=".\content.h" RelativePath=".\content.h"
> >
</File> </File>
<File
RelativePath=".\ltnode.h"
>
</File>
<File <File
RelativePath=".\map.h" RelativePath=".\map.h"
> >