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

This commit is contained in:
Jesse Beder 2008-07-06 00:06:36 +00:00
parent 2a0ddc8cb2
commit 115cf601e9
15 changed files with 217 additions and 51 deletions

View file

@ -5,12 +5,16 @@
#include <map>
#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 <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::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 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:
};
}

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();
}
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();
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();
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;
}
}

12
map.h
View file

@ -14,17 +14,23 @@ namespace YAML
virtual ~Map();
void Clear();
virtual bool GetBegin(std::map <Node *, Node *>::const_iterator& it) const;
virtual bool GetEnd(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 *, ltnode>::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 *, Node *> node_map;
typedef std::map <Node *, Node *, ltnode> node_map;
node_map m_data;
};
}

View file

@ -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 <Node *, Node *>::const_iterator mapIter;
std::map <Node *, Node *, ltnode>::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 <Node *, Node *>::const_iterator mapIter;
std::map <Node *, Node *, ltnode>::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;
}
}

9
node.h
View file

@ -6,6 +6,7 @@
#include <map>
#include "parserstate.h"
#include "exceptions.h"
#include "ltnode.h"
namespace YAML
{
@ -20,7 +21,7 @@ namespace YAML
public:
Iterator();
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();
friend bool operator == (const Iterator& it, const Iterator& jt);
@ -37,7 +38,7 @@ namespace YAML
ITER_TYPE type;
std::vector <Node *>::const_iterator seqIter;
std::map <Node *, Node *>::const_iterator mapIter;
std::map <Node *, Node *, ltnode>::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);

View file

@ -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;
}
}

View file

@ -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;
};

View file

@ -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;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 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);

View file

@ -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
abeginning: value
zend: value
middle: value

View file

@ -15,6 +15,7 @@ namespace YAML
std::vector <std::string> 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<files.size();i++) {
@ -63,7 +64,7 @@ namespace YAML
if(firstTry == secondTry)
return true;
std::ofstream fout("out.yaml");
std::ofstream fout("tests/out.yaml");
fout << "---\n";
fout << firstTry << std::endl;
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"
>
</File>
<File
RelativePath=".\ltnode.h"
>
</File>
<File
RelativePath=".\map.h"
>