From d56b54b34fb6c49cb42b6af8ce763a3c65a659ba Mon Sep 17 00:00:00 2001 From: Jesse Beder Date: Wed, 2 Jul 2008 01:22:39 +0000 Subject: [PATCH] Added an iterator class that can iterate through both sequence and map nodes. --- content.h | 18 ++++++++ document.cpp | 9 ++++ document.h | 1 + exceptions.h | 6 +++ iterator.cpp | 73 ++++++++++++++++++++++++++++++++ main.cpp | 31 +++++++++++--- map.cpp | 12 ++++++ map.h | 2 + node.cpp | 95 +++++++++++++++++++++++++++++++++++++++++ node.h | 65 ++++++++++++++++++++++++++-- scalar.cpp | 55 ++++++++++++++++++++++++ scalar.h | 9 ++++ sequence.cpp | 12 ++++++ sequence.h | 3 ++ test.yaml | 103 +++------------------------------------------ yaml-reader.vcproj | 4 ++ 16 files changed, 393 insertions(+), 105 deletions(-) create mode 100644 iterator.cpp diff --git a/content.h b/content.h index ce23447733..525a10a8d7 100644 --- a/content.h +++ b/content.h @@ -1,12 +1,16 @@ #pragma once #include +#include +#include #include "parserstate.h" +#include "exceptions.h" namespace YAML { class Scanner; class Parser; + class Node; class Content { @@ -17,6 +21,20 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Write(std::ostream& out, int indent) = 0; + virtual bool GetBegin(std::vector ::const_iterator& it) { return false; } + virtual bool GetBegin(std::map ::const_iterator& it) { return false; } + virtual bool GetEnd(std::vector ::const_iterator& it) { return false; } + virtual bool GetEnd(std::map ::const_iterator& it) { return false; } + + // extraction + virtual void Read(std::string& s) { throw InvalidScalar(); } + virtual void Read(int& i) { throw InvalidScalar(); } + virtual void Read(unsigned& u) { throw InvalidScalar(); } + virtual void Read(long& l) { throw InvalidScalar(); } + virtual void Read(float& f) { throw InvalidScalar(); } + virtual void Read(double& d) { throw InvalidScalar(); } + virtual void Read(char& c) { throw InvalidScalar(); } + protected: }; } diff --git a/document.cpp b/document.cpp index c5d1996511..8d4d55f341 100644 --- a/document.cpp +++ b/document.cpp @@ -41,8 +41,17 @@ namespace YAML pScanner->EatNextToken(); } + const Node& Document::GetRoot() const + { + if(!m_pRoot) + throw; + + return *m_pRoot; + } + std::ostream& operator << (std::ostream& out, const Document& doc) { + out << "---\n"; if(!doc.m_pRoot) { out << "{empty node}\n"; return out; diff --git a/document.h b/document.h index 257f57035b..3517cf07b0 100644 --- a/document.h +++ b/document.h @@ -16,6 +16,7 @@ namespace YAML void Clear(); void Parse(Scanner *pScanner, const ParserState& state); + const Node& GetRoot() const; friend std::ostream& operator << (std::ostream& out, const Document& doc); diff --git a/exceptions.h b/exceptions.h index 9c5df62687..2998d08353 100644 --- a/exceptions.h +++ b/exceptions.h @@ -6,7 +6,9 @@ namespace YAML { class Exception: public std::exception {}; class ScannerException: public Exception {}; + class RepresentationException: public Exception {}; + // scanner exceptions class UnknownToken: public ScannerException {}; class IllegalBlockEntry: public ScannerException {}; class IllegalMapKey: public ScannerException {}; @@ -37,4 +39,8 @@ namespace YAML InvalidUnicode(unsigned value_): value(value_) {} unsigned value; }; + + // representation exceptions + class InvalidScalar: public RepresentationException {}; + class BadDereference: public RepresentationException {}; } diff --git a/iterator.cpp b/iterator.cpp new file mode 100644 index 0000000000..074e5eed95 --- /dev/null +++ b/iterator.cpp @@ -0,0 +1,73 @@ +#include "node.h" +#include "exceptions.h" + +namespace YAML +{ + Node::Iterator::Iterator(): type(IT_NONE) + { + } + + Node::Iterator::Iterator(std::vector ::const_iterator it): seqIter(it), type(IT_SEQ) + { + } + + Node::Iterator::Iterator(std::map ::const_iterator it): mapIter(it), type(IT_MAP) + { + } + + Node::Iterator::~Iterator() + { + } + + Node::Iterator& Node::Iterator::operator ++ () + { + if(type == IT_SEQ) + ++seqIter; + else if(type == IT_MAP) + ++mapIter; + + return *this; + } + + const Node& Node::Iterator::operator * () + { + if(type == IT_SEQ) + return **seqIter; + + throw BadDereference(); + } + + const Node& Node::Iterator::first() + { + if(type == IT_MAP) + return *mapIter->first; + + throw BadDereference(); + } + + const Node& Node::Iterator::second() + { + if(type == IT_MAP) + return *mapIter->second; + + throw BadDereference(); + } + + bool operator == (const Node::Iterator& it, const Node::Iterator& jt) + { + if(it.type != jt.type) + return false; + + if(it.type == Node::Iterator::IT_SEQ) + return it.seqIter == jt.seqIter; + else if(it.type == Node::Iterator::IT_MAP) + return it.mapIter == jt.mapIter; + + return true; + } + + bool operator != (const Node::Iterator& it, const Node::Iterator& jt) + { + return !(it == jt); + } +} diff --git a/main.cpp b/main.cpp index 22d0b1b41b..12de0fbd10 100644 --- a/main.cpp +++ b/main.cpp @@ -1,18 +1,39 @@ #include "parser.h" +#include "node.h" +#include "exceptions.h" #include #include int main() { std::ifstream fin("test.yaml"); - YAML::Parser parser(fin); - YAML::Document doc; - while(parser) { - std::cout << "---\n"; + try { + YAML::Parser parser(fin); + if(!parser) + return 0; + + YAML::Document doc; parser.GetNextDocument(doc); - std::cout << doc; + + const YAML::Node& root = doc.GetRoot(); + for(YAML::Node::Iterator it=root.begin();it!=root.end();++it) { + std::string name; + (*it)["name"] >> name; + std::cout << "Name: " << name << std::endl; + + int age; + (*it)["age"] >> age; + std::cout << "Age: " << age << std::endl; + + std::string school; + (*it)["school"] >> school; + std::cout << "School: " << school << std::endl; + } + } catch(YAML::Exception& e) { + std::cout << "Error parsing the yaml!\n"; } + getchar(); return 0; diff --git a/map.cpp b/map.cpp index e759f37839..6cc511c5a7 100644 --- a/map.cpp +++ b/map.cpp @@ -23,6 +23,18 @@ namespace YAML m_data.clear(); } + bool Map::GetBegin(std::map ::const_iterator& it) + { + it = m_data.begin(); + return true; + } + + bool Map::GetEnd(std::map ::const_iterator& it) + { + it = m_data.end(); + return true; + } + void Map::Parse(Scanner *pScanner, const ParserState& state) { Clear(); diff --git a/map.h b/map.h index 9f2929875c..bceb7058ff 100644 --- a/map.h +++ b/map.h @@ -14,6 +14,8 @@ namespace YAML virtual ~Map(); void Clear(); + virtual bool GetBegin(std::map ::const_iterator& it); + virtual bool GetEnd(std::map ::const_iterator& it); virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); diff --git a/node.cpp b/node.cpp index 47e2080d9c..4f9e7d9224 100644 --- a/node.cpp +++ b/node.cpp @@ -136,4 +136,99 @@ namespace YAML m_pContent->Write(out, indent); } } + + // begin + // Returns an iterator to the beginning of this (sequence or map). + Node::Iterator Node::begin() const + { + if(!m_pContent) + return Iterator(); + + std::vector ::const_iterator seqIter; + if(m_pContent->GetBegin(seqIter)) + return Iterator(seqIter); + + std::map ::const_iterator mapIter; + if(m_pContent->GetBegin(mapIter)) + return Iterator(mapIter); + + return Iterator(); + } + + // end + // . Returns an iterator to the end of this (sequence or map). + Node::Iterator Node::end() const + { + if(!m_pContent) + return Iterator(); + + std::vector ::const_iterator seqIter; + if(m_pContent->GetEnd(seqIter)) + return Iterator(seqIter); + + std::map ::const_iterator mapIter; + if(m_pContent->GetEnd(mapIter)) + return Iterator(mapIter); + + return Iterator(); + } + + /////////////////////////////////////////////////////// + // Extraction + + void operator >> (const Node& node, std::string& s) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(s); + } + + void operator >> (const Node& node, int& i) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(i); + } + + void operator >> (const Node& node, unsigned& u) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(u); + } + + void operator >> (const Node& node, long& l) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(l); + } + + void operator >> (const Node& node, float& f) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(f); + } + + void operator >> (const Node& node, double& d) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(d); + } + + void operator >> (const Node& node, char& c) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(c); + } } diff --git a/node.h b/node.h index f8cfe5c0f3..bbfcfe9f67 100644 --- a/node.h +++ b/node.h @@ -2,19 +2,42 @@ #include #include +#include +#include #include "parserstate.h" +#include "exceptions.h" namespace YAML { - const std::string StrTag = "!!str"; - const std::string SeqTag = "!!seq"; - const std::string MapTag = "!!map"; - class Content; class Scanner; class Node { + public: + class Iterator + { + public: + Iterator(); + Iterator(std::vector ::const_iterator it); + Iterator(std::map ::const_iterator it); + ~Iterator(); + + friend bool operator == (const Iterator& it, const Iterator& jt); + friend bool operator != (const Iterator& it, const Iterator& jt); + Iterator& operator ++ (); + const Node& operator * (); + const Node& first(); + const Node& second(); + + private: + enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; + ITER_TYPE type; + + std::vector ::const_iterator seqIter; + std::map ::const_iterator mapIter; + }; + public: Node(); ~Node(); @@ -23,6 +46,40 @@ namespace YAML void Parse(Scanner *pScanner, const ParserState& state); void Write(std::ostream& out, int indent); + Iterator begin() const; + Iterator end() const; + + template + const Node& operator [] (const T& key) const { + if(!m_pContent) + throw BadDereference(); + + for(Iterator it=begin();it!=end();++it) { + T t; + try { + it.first() >> t; + if(key == t) + return it.second(); + } catch(InvalidScalar&) { + } + } + + throw BadDereference(); + } + + const Node& operator [] (const char *key) const { + return operator [] (std::string(key)); + } + + // extraction + friend void operator >> (const Node& node, std::string& s); + friend void operator >> (const Node& node, int& i); + friend void operator >> (const Node& node, unsigned& u); + friend void operator >> (const Node& node, long& l); + friend void operator >> (const Node& node, float& f); + friend void operator >> (const Node& node, double& d); + friend void operator >> (const Node& node, char& c); + private: void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state); diff --git a/scalar.cpp b/scalar.cpp index 5176e527c7..c33ae321c7 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -1,6 +1,8 @@ #include "scalar.h" #include "scanner.h" #include "token.h" +#include "exceptions.h" +#include namespace YAML { @@ -28,4 +30,57 @@ namespace YAML out << " "; out << m_data << std::endl; } + + void Scalar::Read(std::string& s) + { + s = m_data; + } + + void Scalar::Read(int& i) + { + std::stringstream data(m_data); + data >> i; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(unsigned& u) + { + std::stringstream data(m_data); + data >> u; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(long& l) + { + std::stringstream data(m_data); + data >> l; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(float& f) + { + std::stringstream data(m_data); + data >> f; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(double& d) + { + std::stringstream data(m_data); + data >> d; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(char& c) + { + std::stringstream data(m_data); + data >> c; + if(!data) + throw InvalidScalar(); + } } diff --git a/scalar.h b/scalar.h index 90f2583da1..42c733cece 100644 --- a/scalar.h +++ b/scalar.h @@ -14,6 +14,15 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); + // extraction + virtual void Read(std::string& s); + virtual void Read(int& i); + virtual void Read(unsigned& u); + virtual void Read(long& l); + virtual void Read(float& f); + virtual void Read(double& d); + virtual void Read(char& c); + protected: std::string m_data; }; diff --git a/sequence.cpp b/sequence.cpp index 8d0ca1354b..16acfa4fcd 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -22,6 +22,18 @@ namespace YAML m_data.clear(); } + bool Sequence::GetBegin(std::vector ::const_iterator& it) + { + it = m_data.begin(); + return true; + } + + bool Sequence::GetEnd(std::vector ::const_iterator& it) + { + it = m_data.end(); + return true; + } + void Sequence::Parse(Scanner *pScanner, const ParserState& state) { Clear(); diff --git a/sequence.h b/sequence.h index 85fcf8a829..389711299e 100644 --- a/sequence.h +++ b/sequence.h @@ -14,6 +14,9 @@ namespace YAML virtual ~Sequence(); void Clear(); + virtual bool GetBegin(std::vector ::const_iterator& it); + virtual bool GetEnd(std::vector ::const_iterator& it); + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); diff --git a/test.yaml b/test.yaml index 8a9714cfc8..340878ef1e 100644 --- a/test.yaml +++ b/test.yaml @@ -1,97 +1,8 @@ --- -model: - file: data/models/compound.model - textures: data/materials/compound -rooms: - - name: "Room #1" - pos: [0, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+--------------------- - -+--------------------- - -+--------------------- - -+--------------------- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- - - name: Doorway - pos: [1000, 400, 0] - size: [50, 200, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [5, 9] - map: | - ----- - -+++- - ----- - ----- - ----- - ----- - ----- - -+++- - ----- - - name: "Room #2" - pos: [1050, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- -exits: - - room1: "Room #1" - room2: "Room #2" - dir: e - pos: [400, 600] +- name: Jesse + age: 23 + school: University of Illinois +- name: Naftali + age: 21 + school: Rhode Island School of Design +... \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 62387b0fac..4e74139bb6 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -220,6 +220,10 @@ RelativePath=".\document.cpp" > + +