mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 20:51:16 +00:00
Added a (recursive) ordering, so we have a canonical output that we can compare.
This commit is contained in:
14
content.h
14
content.h
@@ -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:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -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
10
ltnode.h
Normal 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
91
map.cpp
@@ -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
12
map.h
@@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
30
node.cpp
30
node.cpp
@@ -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
9
node.h
@@ -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);
|
||||||
|
15
scalar.cpp
15
scalar.cpp
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
6
scalar.h
6
scalar.h
@@ -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;
|
||||||
};
|
};
|
||||||
|
22
sequence.cpp
22
sequence.cpp
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
20
test.yaml
20
test.yaml
@@ -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
|
|
@@ -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
24
tests/scalars.yaml
Normal 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.
|
@@ -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"
|
||||||
>
|
>
|
||||||
|
Reference in New Issue
Block a user