From dbdd9e3cdcbc75a33b4d1d765d0bec5fe56e3385 Mon Sep 17 00:00:00 2001 From: David Rosca <roscadav@fit.cvut.cz> Date: Thu, 26 Feb 2015 16:23:04 +0100 Subject: [PATCH] Graphs - Initial commit --- alib2data/src/StringApi.cpp | 10 + alib2data/src/StringApi.hpp | 10 + alib2data/src/XmlApi.cpp | 32 ++++ alib2data/src/XmlApi.hpp | 22 +++ alib2data/src/graph/Graph.h | 29 +++ alib2data/src/graph/GraphBase.h | 29 +++ alib2data/src/graph/GraphFeatures.h | 13 ++ alib2data/src/graph/GraphFromStringLexer.cpp | 76 ++++++++ alib2data/src/graph/GraphFromStringLexer.h | 35 ++++ alib2data/src/graph/GraphFromStringParser.cpp | 160 ++++++++++++++++ alib2data/src/graph/GraphFromStringParser.h | 47 +++++ alib2data/src/graph/GraphFromXMLParser.cpp | 141 ++++++++++++++ alib2data/src/graph/GraphFromXMLParser.h | 47 +++++ alib2data/src/graph/GraphRepresentation.cpp | 31 ++++ alib2data/src/graph/GraphRepresentation.h | 19 ++ alib2data/src/graph/GraphToStringComposer.cpp | 112 ++++++++++++ alib2data/src/graph/GraphToStringComposer.h | 38 ++++ alib2data/src/graph/GraphToXMLComposer.cpp | 101 ++++++++++ alib2data/src/graph/GraphToXMLComposer.h | 43 +++++ alib2data/src/graph/common/GraphElement.cpp | 9 + alib2data/src/graph/common/GraphElement.h | 30 +++ alib2data/src/graph/common/Macros.h | 28 +++ alib2data/src/graph/common/Node.cpp | 103 +++++++++++ alib2data/src/graph/common/Node.h | 58 ++++++ .../directed/AdjacencyListDirectedGraph.cpp | 121 ++++++++++++ .../directed/AdjacencyListDirectedGraph.h | 37 ++++ alib2data/src/graph/directed/DirectedEdge.cpp | 170 +++++++++++++++++ alib2data/src/graph/directed/DirectedEdge.h | 67 +++++++ .../src/graph/directed/DirectedGraph.cpp | 154 ++++++++++++++++ alib2data/src/graph/directed/DirectedGraph.h | 72 ++++++++ .../src/graph/directed/IDirectedGraph.cpp | 23 +++ alib2data/src/graph/directed/IDirectedGraph.h | 38 ++++ .../src/graph/undirected/UndirectedEdge.cpp | 173 ++++++++++++++++++ .../src/graph/undirected/UndirectedEdge.h | 67 +++++++ .../src/graph/undirected/UndirectedGraph.h | 14 ++ alib2data/src/object/ObjectBase.h | 9 + alib2data/src/std/compare.hpp | 16 ++ 37 files changed, 2184 insertions(+) create mode 100644 alib2data/src/graph/Graph.h create mode 100644 alib2data/src/graph/GraphBase.h create mode 100644 alib2data/src/graph/GraphFeatures.h create mode 100644 alib2data/src/graph/GraphFromStringLexer.cpp create mode 100644 alib2data/src/graph/GraphFromStringLexer.h create mode 100644 alib2data/src/graph/GraphFromStringParser.cpp create mode 100644 alib2data/src/graph/GraphFromStringParser.h create mode 100644 alib2data/src/graph/GraphFromXMLParser.cpp create mode 100644 alib2data/src/graph/GraphFromXMLParser.h create mode 100644 alib2data/src/graph/GraphRepresentation.cpp create mode 100644 alib2data/src/graph/GraphRepresentation.h create mode 100644 alib2data/src/graph/GraphToStringComposer.cpp create mode 100644 alib2data/src/graph/GraphToStringComposer.h create mode 100644 alib2data/src/graph/GraphToXMLComposer.cpp create mode 100644 alib2data/src/graph/GraphToXMLComposer.h create mode 100644 alib2data/src/graph/common/GraphElement.cpp create mode 100644 alib2data/src/graph/common/GraphElement.h create mode 100644 alib2data/src/graph/common/Macros.h create mode 100644 alib2data/src/graph/common/Node.cpp create mode 100644 alib2data/src/graph/common/Node.h create mode 100644 alib2data/src/graph/directed/AdjacencyListDirectedGraph.cpp create mode 100644 alib2data/src/graph/directed/AdjacencyListDirectedGraph.h create mode 100644 alib2data/src/graph/directed/DirectedEdge.cpp create mode 100644 alib2data/src/graph/directed/DirectedEdge.h create mode 100644 alib2data/src/graph/directed/DirectedGraph.cpp create mode 100644 alib2data/src/graph/directed/DirectedGraph.h create mode 100644 alib2data/src/graph/directed/IDirectedGraph.cpp create mode 100644 alib2data/src/graph/directed/IDirectedGraph.h create mode 100644 alib2data/src/graph/undirected/UndirectedEdge.cpp create mode 100644 alib2data/src/graph/undirected/UndirectedEdge.h create mode 100644 alib2data/src/graph/undirected/UndirectedGraph.h diff --git a/alib2data/src/StringApi.cpp b/alib2data/src/StringApi.cpp index b1ed53c2f6..48e958afd0 100644 --- a/alib2data/src/StringApi.cpp +++ b/alib2data/src/StringApi.cpp @@ -17,6 +17,7 @@ const regexp::RegExpFromStringParser FromStringParsers::regexpParser; const string::StringFromStringParser FromStringParsers::stringParser; const automaton::AutomatonFromStringParser FromStringParsers::automatonParser; const grammar::GrammarFromStringParser FromStringParsers::grammarParser; +const graph::GraphFromStringParser FromStringParsers::graphParser; const primitive::PrimitiveFromStringParser FromStringParsers::primitiveParser; const label::LabelToStringComposer ToStringComposers::labelComposer; @@ -25,6 +26,7 @@ const regexp::RegExpToStringComposer ToStringComposers::regexpComposer; const string::StringToStringComposer ToStringComposers::stringComposer; const automaton::AutomatonToStringComposer ToStringComposers::automatonComposer; const grammar::GrammarToStringComposer ToStringComposers::grammarComposer; +const graph::GraphToStringComposer ToStringComposers::graphComposer; const primitive::PrimitiveToStringComposer ToStringComposers::primitiveComposer; alphabet::Symbol stringApi<alphabet::Symbol>::parse(std::istream& input) { @@ -52,6 +54,14 @@ void stringApi<grammar::Grammar>::compose(std::ostream& output, const grammar::G return ToStringComposers::grammarComposer.compose(output, data); } +graph::Graph stringApi<graph::Graph>::parse(std::istream& input) { + return FromStringParsers::graphParser.parseGraph(input); +} + +void stringApi<graph::Graph>::compose(std::ostream& output, const graph::Graph& data) { + return ToStringComposers::graphComposer.compose(output, data); +} + label::Label stringApi<label::Label>::parse(std::istream& input) { return FromStringParsers::labelParser.parseLabel(input); } diff --git a/alib2data/src/StringApi.hpp b/alib2data/src/StringApi.hpp index cc9044f776..752e3f1224 100644 --- a/alib2data/src/StringApi.hpp +++ b/alib2data/src/StringApi.hpp @@ -14,6 +14,7 @@ #include "string/StringFromStringParser.h" #include "automaton/AutomatonFromStringParser.h" #include "grammar/GrammarFromStringParser.h" +#include "graph/GraphFromStringParser.h" #include "primitive/PrimitiveFromStringParser.h" #include "label/LabelToStringComposer.h" @@ -22,6 +23,7 @@ #include "string/StringToStringComposer.h" #include "automaton/AutomatonToStringComposer.h" #include "grammar/GrammarToStringComposer.h" +#include "graph/GraphToStringComposer.h" #include "primitive/PrimitiveToStringComposer.h" #include "object/ObjectBase.h" @@ -53,6 +55,12 @@ struct stringApi<grammar::Grammar> { static void compose(std::ostream& output, const grammar::Grammar& data); }; +template<> +struct stringApi<graph::Graph> { + static graph::Graph parse(std::istream& input); + static void compose(std::ostream& output, const graph::Graph& data); +}; + template<> struct stringApi<label::Label> { static label::Label parse(std::istream& input); @@ -85,6 +93,7 @@ public: static const string::StringFromStringParser stringParser; static const automaton::AutomatonFromStringParser automatonParser; static const grammar::GrammarFromStringParser grammarParser; + static const graph::GraphFromStringParser graphParser; static const primitive::PrimitiveFromStringParser primitiveParser; }; @@ -97,6 +106,7 @@ public: static const string::StringToStringComposer stringComposer; static const automaton::AutomatonToStringComposer automatonComposer; static const grammar::GrammarToStringComposer grammarComposer; + static const graph::GraphToStringComposer graphComposer; static const primitive::PrimitiveToStringComposer primitiveComposer; }; diff --git a/alib2data/src/XmlApi.cpp b/alib2data/src/XmlApi.cpp index 30ee8856de..824409f9e6 100644 --- a/alib2data/src/XmlApi.cpp +++ b/alib2data/src/XmlApi.cpp @@ -15,6 +15,7 @@ const regexp::RegExpFromXMLParser FromXMLParsers::regexpParser; const string::StringFromXMLParser FromXMLParsers::stringParser; const automaton::AutomatonFromXMLParser FromXMLParsers::automatonParser; const grammar::GrammarFromXMLParser FromXMLParsers::grammarParser; +const graph::GraphFromXMLParser FromXMLParsers::graphParser; const exception::ExceptionFromXMLParser FromXMLParsers::exceptionParser; const alib::ObjectFromXMLParser FromXMLParsers::objectParser; const container::ContainerFromXMLParser FromXMLParsers::containerParser; @@ -26,6 +27,7 @@ const regexp::RegExpToXMLComposer ToXMLComposers::regexpComposer; const string::StringToXMLComposer ToXMLComposers::stringComposer; const automaton::AutomatonToXMLComposer ToXMLComposers::automatonComposer; const grammar::GrammarToXMLComposer ToXMLComposers::grammarComposer; +const graph::GraphToXMLComposer ToXMLComposers::graphComposer; const alib::ObjectToXMLComposer ToXMLComposers::objectComposer; const exception::ExceptionToXMLComposer ToXMLComposers::exceptionComposer; const container::ContainerToXMLComposer ToXMLComposers::containerComposer; @@ -82,6 +84,7 @@ const std::string Names::GRAMMAR_CSG = "CSG"; const std::string Names::GRAMMAR_NON_CONTRACTING_GRAMMAR = "NonContractingGrammar"; const std::string Names::GRAMMAR_CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR = "ContextPpreservingUnrestrictedGrammar"; const std::string Names::GRAMMAR_UNRESTRICTED_GRAMMAR = "UnrestrictedGrammar"; +const std::string Names::GRAPH_DIRECTED_GRAPH = "DirectedGraph"; const std::string Names::LABEL_PRIMITIVE_LABEL = "PrimitiveLabel"; const std::string Names::LABEL_HEXAVIGESIMAL_LABEL = "HexavigesimalLabel"; const std::string Names::LABEL_OBJECT_LABEL = "ObjectLabel"; @@ -751,6 +754,31 @@ void xmlApi<grammar::UnrestrictedGrammar>::compose(std::list<sax::Token>& output } +graph::Graph xmlApi<graph::Graph>::parse(std::list<sax::Token>& input) { + return FromXMLParsers::graphParser.parseGraph(input); +} + +bool xmlApi<graph::Graph>::first(const std::list<sax::Token>& input) { + return FromXMLParsers::graphParser.first(input); +} + +void xmlApi<graph::Graph>::compose(std::list<sax::Token>& output, const graph::Graph& data) { + ToXMLComposers::graphComposer.compose(output, data); +} + +graph::DirectedGraph xmlApi<graph::DirectedGraph>::parse(std::list<sax::Token>& input) { + return FromXMLParsers::graphParser.parseDirectedGraph(input); +} + +bool xmlApi<graph::DirectedGraph>::first(const std::list<sax::Token>& input) { + return sax::FromXMLParserHelper::isToken(input, sax::Token::TokenType::START_ELEMENT, Names::GRAPH_DIRECTED_GRAPH); +} + +void xmlApi<graph::DirectedGraph>::compose(std::list<sax::Token>& output, const graph::DirectedGraph& data) { + ToXMLComposers::graphComposer.compose(output, data); +} + + label::Label xmlApi<label::Label>::parse(std::list<sax::Token>& input) { return FromXMLParsers::labelParser.parseLabel(input); } @@ -1246,6 +1274,10 @@ void ToXMLComposers::Visit(void* data, const grammar::UnrestrictedGrammar& gramm xmlApi<grammar::UnrestrictedGrammar>::compose(*((std::list<sax::Token>*) data), grammar); } +void ToXMLComposers::Visit(void* data, const graph::DirectedGraph& graph) const { + xmlApi<graph::DirectedGraph>::compose(*((std::list<sax::Token>*) data), graph); +} + void ToXMLComposers::Visit(void* data, const label::PrimitiveLabel& label) const { xmlApi<label::PrimitiveLabel>::compose(*((std::list<sax::Token>*) data), label); } diff --git a/alib2data/src/XmlApi.hpp b/alib2data/src/XmlApi.hpp index 65e8d82ab7..5278d7af1b 100644 --- a/alib2data/src/XmlApi.hpp +++ b/alib2data/src/XmlApi.hpp @@ -14,6 +14,7 @@ #include "string/StringFromXMLParser.h" #include "automaton/AutomatonFromXMLParser.h" #include "grammar/GrammarFromXMLParser.h" +#include "graph/GraphFromXMLParser.h" #include "object/ObjectFromXMLParser.h" #include "exception/ExceptionFromXMLParser.h" #include "primitive/PrimitiveFromXMLParser.h" @@ -24,6 +25,7 @@ #include "string/StringToXMLComposer.h" #include "automaton/AutomatonToXMLComposer.h" #include "grammar/GrammarToXMLComposer.h" +#include "graph/GraphToXMLComposer.h" #include "object/ObjectToXMLComposer.h" #include "exception/ExceptionToXMLComposer.h" #include "primitive/PrimitiveToXMLComposer.h" @@ -83,6 +85,7 @@ public: const static std::string GRAMMAR_NON_CONTRACTING_GRAMMAR; const static std::string GRAMMAR_CONTEXT_PRESERVING_UNRESTRICTED_GRAMMAR; const static std::string GRAMMAR_UNRESTRICTED_GRAMMAR; + const static std::string GRAPH_DIRECTED_GRAPH; const static std::string LABEL_PRIMITIVE_LABEL; const static std::string LABEL_HEXAVIGESIMAL_LABEL; const static std::string LABEL_OBJECT_LABEL; @@ -526,6 +529,21 @@ struct xmlApi<grammar::UnrestrictedGrammar> { }; +template<> +struct xmlApi<graph::Graph> { + static graph::Graph parse(std::list<sax::Token>& input); + static bool first(const std::list<sax::Token>& input); + static void compose(std::list<sax::Token>& output, const graph::Graph& data); +}; + +template<> +struct xmlApi<graph::DirectedGraph> { + static graph::DirectedGraph parse(std::list<sax::Token>& input); + static bool first(const std::list<sax::Token>& input); + static void compose(std::list<sax::Token>& output, const graph::DirectedGraph& data); +}; + + template<> struct xmlApi<label::Label> { static label::Label parse(std::list<sax::Token>& input); @@ -731,6 +749,7 @@ public: static const string::StringFromXMLParser stringParser; static const automaton::AutomatonFromXMLParser automatonParser; static const grammar::GrammarFromXMLParser grammarParser; + static const graph::GraphFromXMLParser graphParser; static const exception::ExceptionFromXMLParser exceptionParser; static const ObjectFromXMLParser objectParser; static const container::ContainerFromXMLParser containerParser; @@ -788,6 +807,8 @@ class ToXMLComposers : public VisitableObjectBase::const_visitor_type { void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& grammar) const; void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const; + void Visit(void*, const graph::DirectedGraph& graph) const; + void Visit(void*, const label::PrimitiveLabel& label) const; void Visit(void*, const label::HexavigesimalLabel& label) const; void Visit(void*, const label::ObjectLabel& label) const; @@ -820,6 +841,7 @@ public: static const string::StringToXMLComposer stringComposer; static const automaton::AutomatonToXMLComposer automatonComposer; static const grammar::GrammarToXMLComposer grammarComposer; + static const graph::GraphToXMLComposer graphComposer; static const exception::ExceptionToXMLComposer exceptionComposer; static const ObjectToXMLComposer objectComposer; static const container::ContainerToXMLComposer containerComposer; diff --git a/alib2data/src/graph/Graph.h b/alib2data/src/graph/Graph.h new file mode 100644 index 0000000000..7d47b0c256 --- /dev/null +++ b/alib2data/src/graph/Graph.h @@ -0,0 +1,29 @@ +#ifndef GRAPH_H_ +#define GRAPH_H_ + +#include "../std/visitor.hpp" +#include "../std/compare.hpp" +#include "../common/wrapper.hpp" +#include "GraphBase.h" + +namespace graph { + +// Wrapper around graphs. +typedef alib::wrapper<GraphBase> Graph; + +} // namespace graph + +namespace std { + +template<> +struct compare<graph::Graph> +{ + int operator()(const graph::Graph &first, const graph::Graph &second) const + { + return first.getData().compare(second.getData()); + } +}; + +} // namespace + +#endif // GRAPH_H_ diff --git a/alib2data/src/graph/GraphBase.h b/alib2data/src/graph/GraphBase.h new file mode 100644 index 0000000000..e3539fef1a --- /dev/null +++ b/alib2data/src/graph/GraphBase.h @@ -0,0 +1,29 @@ +#ifndef GRAPH_BASE_H_ +#define GRAPH_BASE_H_ + +#include "common/Macros.h" +#include "../common/base.hpp" +#include "../object/ObjectBase.h" + +namespace graph { + +class GraphBase; + +typedef std::acceptor_base<GraphBase, DirectedGraph, UndirectedGraph> VisitableGraphBase; + +// Abstract base class for all graphs. +class GraphBase : public alib::ObjectBase, public VisitableGraphBase +{ +public: + using VisitableGraphBase::Accept; + using alib::VisitableObjectBase::Accept; + + virtual GraphBase *clone() const = 0; + virtual GraphBase *plunder() && = 0; +}; + +} // namespace graph + +GRAPH_DEFINE_STD_COMPARE(GraphBase) + +#endif // GRAPH_BASE_H_ diff --git a/alib2data/src/graph/GraphFeatures.h b/alib2data/src/graph/GraphFeatures.h new file mode 100644 index 0000000000..dba0c28394 --- /dev/null +++ b/alib2data/src/graph/GraphFeatures.h @@ -0,0 +1,13 @@ +#ifndef GRAPH_FEATURES_H_ +#define GRAPH_FEATURES_H_ + +namespace graph { + +enum class FEATURES { + DIRECTED, + UNDIRECTED +}; + +} // namespace graph + +#endif // GRAPH_FEATURES_H_ diff --git a/alib2data/src/graph/GraphFromStringLexer.cpp b/alib2data/src/graph/GraphFromStringLexer.cpp new file mode 100644 index 0000000000..422de85536 --- /dev/null +++ b/alib2data/src/graph/GraphFromStringLexer.cpp @@ -0,0 +1,76 @@ +#include "GraphFromStringLexer.h" + +#include <cctype> + +namespace graph { + +GraphFromStringLexer::Token GraphFromStringLexer::next(std::istream &in) const +{ + Token token; + token.type = TokenType::ERROR; + char character; + +L0: + character = in.get(); + + if (in.eof()) { + token.type = TokenType::TEOF; + return token; + } else if (isspace(character)) { + token.raw += character; + goto L0; + } else if (character == '(') { + token.type = TokenType::LPAR; + token.value += character; + token.raw += character; + return token; + } else if (character == ')') { + token.type = TokenType::RPAR; + token.value += character; + token.raw += character; + return token; + } else if (character == ':') { + token.type = TokenType::COLON; + token.value += character; + token.raw += character; + return token; + } else if (character == ',') { + token.type = TokenType::COMMA; + token.value += character; + token.raw += character; + return token; + } else { + in.putback(character); + putback(in, std::move(token)); + token.type = TokenType::ERROR; + return token; + } +} + +void GraphFromStringLexer::putback(std::istream &input, GraphFromStringLexer::Token token) const +{ + while (!token.raw.empty()) { + input.putback(token.raw.back()); + token.raw.pop_back(); + } + input.clear(); +} + +std::string GraphFromStringLexer::getString(std::istream &input) const +{ + std::string str; + char character; + + while (input >> character) { + if (character == ':') { + input.putback(character); + return str; + } + str += character; + } + + return std::string(); +} + +} // namespace graph + diff --git a/alib2data/src/graph/GraphFromStringLexer.h b/alib2data/src/graph/GraphFromStringLexer.h new file mode 100644 index 0000000000..5246f9795d --- /dev/null +++ b/alib2data/src/graph/GraphFromStringLexer.h @@ -0,0 +1,35 @@ +#ifndef GRAPH_FROM_STRING_LEXER_H_ +#define GRAPH_FROM_STRING_LEXER_H_ + +#include <string> +#include <sstream> + +namespace graph { + +class GraphFromStringLexer +{ +public: + enum class TokenType { + LPAR, + RPAR, + COLON, + COMMA, + TEOF, + ERROR + }; + + struct Token { + TokenType type; + std::string value; + std::string raw; + }; + + Token next(std::istream &input) const; + void putback(std::istream &input, Token token) const; + + std::string getString(std::istream &input) const; +}; + +} // namespace graph + +#endif // GRAPH_FROM_STRING_LEXER_H_ diff --git a/alib2data/src/graph/GraphFromStringParser.cpp b/alib2data/src/graph/GraphFromStringParser.cpp new file mode 100644 index 0000000000..4b75e0bfa0 --- /dev/null +++ b/alib2data/src/graph/GraphFromStringParser.cpp @@ -0,0 +1,160 @@ +#include "GraphFromStringParser.h" +#include "../exception/AlibException.h" + +#include "../StringApi.hpp" + +namespace graph { + +Graph GraphFromStringParser::parseGraph(std::istream &input) const +{ + GraphFromStringLexer::Token token = lexer.next(input); + if (token.type != GraphFromStringLexer::TokenType::LPAR) { + throw exception::AlibException("Invalid input. Expected LPAR"); + } + + const std::string &str = lexer.getString(input); + if (str == "DirectedGraph") { + parseDelimiter(input); // : + Graph graph{parseDirectedGraph(input)}; + + if (lexer.next(input).type != GraphFromStringLexer::TokenType::RPAR) { + throw exception::AlibException("Invalid input. Expected RPAR"); + } + return graph; + } else if (str == "UndirectedGraph") { + parseDelimiter(input); // : + //Graph graph{parseUndirectedGraph(input)}; + + if (lexer.next(input).type != GraphFromStringLexer::TokenType::RPAR) { + throw exception::AlibException("Invalid input. Expected RPAR"); + } + // return graph; + } + + throw exception::AlibException("Invalid graph type"); +} + +DirectedGraph GraphFromStringParser::parseDirectedGraph(std::istream &input) const +{ + DirectedGraph graph(parseRepresentation(input)); + parseDelimiter(input); // : + parseNodes(input, graph); + parseDelimiter(input); // : + parseDirectedEdges(input, graph); + return graph; +} + +UndirectedGraph GraphFromStringParser::parseUndirectedGraph(std::istream &input) const +{ + //UndirectedGraph graph(parseRepresentation(input)); + //parseDelimiter(input); // : + //parseNodes(input, graph); + //parseDelimiter(input); // : + //parseUndirectedEdges(input, graph); + //return graph; +} + +REPRESENTATION GraphFromStringParser::parseRepresentation(std::istream &input) const +{ + std::string representation = lexer.getString(input); + if (representation.empty()) { + throw exception::AlibException("Invalid representation"); + } + return representationFromString(representation); +} + +Node GraphFromStringParser::parseNode(std::istream &input) const +{ + return Node(alib::stringApi<label::Label>::parse(input)); +} + +DirectedEdge GraphFromStringParser::parseDirectedEdge(std::istream &input) const +{ + Node from = parseNode(input); + label::Label name = alib::stringApi<label::Label>::parse(input); + Node to = parseNode(input); + return DirectedEdge(from, to, name); +} + +UndirectedEdge GraphFromStringParser::parseUndirectedEdge(std::istream &input) const +{ + Node first = parseNode(input); + label::Label name = alib::stringApi<label::Label>::parse(input); + Node second = parseNode(input); + return UndirectedEdge(first, second, name); +} + +template<typename T> +void GraphFromStringParser::parseNodes(std::istream &input, T &graph) const +{ + GraphFromStringLexer::Token token = lexer.next(input); + + // Empty nodes? + if (token.type == GraphFromStringLexer::TokenType::COLON) { + return; + } + lexer.putback(input, token); + + while (true) { + graph.addNode(parseNode(input)); + + token = lexer.next(input); + if (token.type != GraphFromStringLexer::TokenType::COMMA) { + lexer.putback(input, token); + return; + } + } +} + +void GraphFromStringParser::parseDirectedEdges(std::istream &input, DirectedGraph &graph) const +{ + GraphFromStringLexer::Token token = lexer.next(input); + + // Empty edges? + if (token.type == GraphFromStringLexer::TokenType::COLON) { + return; + } + lexer.putback(input, token); + + + while (true) { + graph.addEdge(parseDirectedEdge(input)); + + token = lexer.next(input); + if (token.type != GraphFromStringLexer::TokenType::COMMA) { + lexer.putback(input, token); + return; + } + } +} + +void GraphFromStringParser::parseUndirectedEdges(std::istream &input, UndirectedGraph &graph) const +{ + GraphFromStringLexer::Token token = lexer.next(input); + + // Empty edges? + if (token.type == GraphFromStringLexer::TokenType::COLON) { + return; + } + lexer.putback(input, token); + + while (true) { + //graph.addEdge(parseUndirectedEdge(input)); + + token = lexer.next(input); + if (token.type != GraphFromStringLexer::TokenType::COMMA) { + lexer.putback(input, token); + return; + } + } +} + +void GraphFromStringParser::parseDelimiter(std::istream &input) const +{ + GraphFromStringLexer::Token token = lexer.next(input); + if (token.type != GraphFromStringLexer::TokenType::COLON) { + throw exception::AlibException("Invalid input. Expected COLON"); + } +} + +} // namespace graph diff --git a/alib2data/src/graph/GraphFromStringParser.h b/alib2data/src/graph/GraphFromStringParser.h new file mode 100644 index 0000000000..48e979b143 --- /dev/null +++ b/alib2data/src/graph/GraphFromStringParser.h @@ -0,0 +1,47 @@ +#ifndef GRAPH_FROM_STRING_PARSER_H_ +#define GRAPH_FROM_STRING_PARSER_H_ + +#include "Graph.h" +#include "GraphFeatures.h" +#include "GraphRepresentation.h" +#include "directed/DirectedGraph.h" +#include "undirected/UndirectedGraph.h" + +#include "GraphFromStringLexer.h" +#include "GraphFeatures.h" + +namespace alib { + +template<typename T> +struct stringApi; + +} // namespace alib + +namespace graph { + +class GraphFromStringParser +{ +private: + Graph parseGraph(std::istream &input) const; + DirectedGraph parseDirectedGraph(std::istream &input) const; + UndirectedGraph parseUndirectedGraph(std::istream &input) const; + + REPRESENTATION parseRepresentation(std::istream &input) const; + Node parseNode(std::istream &input) const; + DirectedEdge parseDirectedEdge(std::istream &input) const; + UndirectedEdge parseUndirectedEdge(std::istream &input) const; + + template<typename T> + void parseNodes(std::istream &input, T &graph) const; + void parseDirectedEdges(std::istream &input, DirectedGraph &graph) const; + void parseUndirectedEdges(std::istream &input, UndirectedGraph &graph) const; + void parseDelimiter(std::istream &input) const; + + GraphFromStringLexer lexer; + + template<typename T> friend class alib::stringApi; +}; + +} // namespace graph + +#endif // GRAPH_FROM_STRING_PARSER_H_ diff --git a/alib2data/src/graph/GraphFromXMLParser.cpp b/alib2data/src/graph/GraphFromXMLParser.cpp new file mode 100644 index 0000000000..8858373146 --- /dev/null +++ b/alib2data/src/graph/GraphFromXMLParser.cpp @@ -0,0 +1,141 @@ +#include "GraphFromXMLParser.h" +#include "../sax/ParserException.h" + +#include "../XmlApi.hpp" + +namespace graph { + +bool GraphFromXMLParser::first(const std::list<sax::Token> &input) const +{ + if (alib::xmlApi<DirectedGraph>::first(input)) { + return true; + } + + return false; +} + +Graph GraphFromXMLParser::parseGraph(std::list<sax::Token> &input) const +{ + if (alib::xmlApi<DirectedGraph>::first(input)) { + return Graph(parseDirectedGraph(input)); + } + + throw exception::AlibException(); +} + +DirectedGraph GraphFromXMLParser::parseDirectedGraph(std::list<sax::Token> &input) const +{ + popToken(input, sax::Token::TokenType::START_ELEMENT, alib::Names::GRAPH_DIRECTED_GRAPH); + + DirectedGraph graph(parseRepresentation(input)); + parseNodes(input, graph); + parseDirectedEdges(input, graph); + + popToken(input, sax::Token::TokenType::END_ELEMENT, alib::Names::GRAPH_DIRECTED_GRAPH); + return graph; +} + +UndirectedGraph GraphFromXMLParser::parseUndirectedGraph(std::list<sax::Token> &input) const +{ + //popToken(input, sax::Token::TokenType::START_ELEMENT, alib::Names::GRAPH_UNDIRECTED_GRAPH); + + //UndirectedGraph graph(parseRepresentation(input)); + //parseNodes(input, graph); + //parseUndirectedEdges(input, graph); + + //popToken(input, sax::Token::TokenType::END_ELEMENT, alib::Names::GRAPH_UNDIRECTED_GRAPH); + //return graph; +} + +REPRESENTATION GraphFromXMLParser::parseRepresentation(std::list<sax::Token> &input) const +{ + popToken(input, sax::Token::TokenType::START_ELEMENT, "representation"); + + REPRESENTATION r = representationFromString(popTokenData(input, sax::Token::TokenType::CHARACTER)); + + popToken(input, sax::Token::TokenType::END_ELEMENT, "representation"); + return r; +} + +Node GraphFromXMLParser::parseNode(std::list<sax::Token> &input) const +{ + popToken(input, sax::Token::TokenType::START_ELEMENT, "node"); + + Node n = Node(alib::xmlApi<label::Label>::parse(input)); + + popToken(input, sax::Token::TokenType::END_ELEMENT, "node"); + return n; +} + +DirectedEdge GraphFromXMLParser::parseDirectedEdge(std::list<sax::Token> &input) const +{ + popToken(input, sax::Token::TokenType::START_ELEMENT, "edge"); + + popToken(input, sax::Token::TokenType::START_ELEMENT, "from"); + Node from = parseNode(input); + popToken(input, sax::Token::TokenType::END_ELEMENT, "from"); + + label::Label name = alib::xmlApi<label::Label>::parse(input); + + popToken(input, sax::Token::TokenType::START_ELEMENT, "to"); + Node to = parseNode(input); + popToken(input, sax::Token::TokenType::END_ELEMENT, "to"); + + popToken(input, sax::Token::TokenType::END_ELEMENT, "edge"); + return DirectedEdge(from, to, name); +} + +UndirectedEdge GraphFromXMLParser::parseUndirectedEdge(std::list<sax::Token> &input) const +{ + popToken(input, sax::Token::TokenType::START_ELEMENT, "edge"); + + popToken(input, sax::Token::TokenType::START_ELEMENT, "first"); + Node first = parseNode(input); + popToken(input, sax::Token::TokenType::END_ELEMENT, "first"); + + label::Label name = alib::xmlApi<label::Label>::parse(input); + + popToken(input, sax::Token::TokenType::START_ELEMENT, "second"); + Node second = parseNode(input); + popToken(input, sax::Token::TokenType::END_ELEMENT, "second"); + + popToken(input, sax::Token::TokenType::END_ELEMENT, "edge"); + return UndirectedEdge(first, second, name); +} + +template<typename T> +void GraphFromXMLParser::parseNodes(std::list<sax::Token> &input, T &graph) const +{ + popToken(input, sax::Token::TokenType::START_ELEMENT, "nodes"); + + while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) { + graph.addNode(parseNode(input)); + } + + popToken(input, sax::Token::TokenType::END_ELEMENT, "nodes"); +} + +void GraphFromXMLParser::parseDirectedEdges(std::list<sax::Token> &input, DirectedGraph &graph) const +{ + popToken(input, sax::Token::TokenType::START_ELEMENT, "edges"); + + while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) { + graph.addEdge(parseDirectedEdge(input)); + } + + popToken(input, sax::Token::TokenType::END_ELEMENT, "edges"); +} + +void GraphFromXMLParser::parseUndirectedEdges(std::list<sax::Token> &input, UndirectedGraph &graph) const +{ + //popToken(input, sax::Token::TokenType::START_ELEMENT, "edges"); + + //while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) { + // graph.addEdge(parseUndirectedEdge(input)); + //} + + //popToken(input, sax::Token::TokenType::END_ELEMENT, "edges"); +} + +} // namespace graph + diff --git a/alib2data/src/graph/GraphFromXMLParser.h b/alib2data/src/graph/GraphFromXMLParser.h new file mode 100644 index 0000000000..472dfc921c --- /dev/null +++ b/alib2data/src/graph/GraphFromXMLParser.h @@ -0,0 +1,47 @@ +#ifndef GRAPH_FROM_XML_PARSER_H_ +#define GRAPH_FROM_XML_PARSER_H_ + +#include "../sax/FromXMLParserHelper.h" +#include "Graph.h" +#include "GraphFeatures.h" +#include "directed/DirectedGraph.h" +#include "undirected/UndirectedGraph.h" +#include "../sax/Token.h" +#include "../alphabet/Symbol.h" + +namespace alib { + +template<typename T> +struct xmlApi; + +} // namespace alib + +namespace graph { + +// Parser used to get Graph from XML parsed into list of tokens. +class GraphFromXMLParser : public sax::FromXMLParserHelper +{ +public: + bool first(const std::list<sax::Token> &input) const; + +private: + Graph parseGraph(std::list<sax::Token> &input) const; + DirectedGraph parseDirectedGraph(std::list<sax::Token> &input) const; + UndirectedGraph parseUndirectedGraph(std::list<sax::Token> &input) const; + + REPRESENTATION parseRepresentation(std::list<sax::Token> &input) const; + Node parseNode(std::list<sax::Token> &input) const; + DirectedEdge parseDirectedEdge(std::list<sax::Token> &input) const; + UndirectedEdge parseUndirectedEdge(std::list<sax::Token> &input) const; + + template<typename T> + void parseNodes(std::list<sax::Token> &input, T &graph) const; + void parseDirectedEdges(std::list<sax::Token> &input, DirectedGraph &graph) const; + void parseUndirectedEdges(std::list<sax::Token> &input, UndirectedGraph &graph) const; + + template<typename T> friend class alib::xmlApi; +}; + +} // namespace graph + +#endif // GRAPH_FROM_XML_PARSER_H_ diff --git a/alib2data/src/graph/GraphRepresentation.cpp b/alib2data/src/graph/GraphRepresentation.cpp new file mode 100644 index 0000000000..180569fa4a --- /dev/null +++ b/alib2data/src/graph/GraphRepresentation.cpp @@ -0,0 +1,31 @@ +#include "GraphRepresentation.h" + +namespace graph { + +std::string representationToString(REPRESENTATION r) +{ + switch (r) { + case REPRESENTATION::ADJACENCY_LIST: + return "AdjacencyList"; + case REPRESENTATION::ADJACENCY_MATRIX: + return "AdjacencyMatrix"; + case REPRESENTATION::INCIDENCE_MATRIX: + return "IncidenceMatrix"; + default: + return "AdjacencyList"; + } +} + +REPRESENTATION representationFromString(const std::string &str) +{ + if (str == "AdjacencyList") { + return REPRESENTATION::ADJACENCY_LIST; + } else if (str == "AdjacencyMatrix") { + return REPRESENTATION::ADJACENCY_MATRIX; + } else if (str == "IncidenceMatrix") { + return REPRESENTATION::INCIDENCE_MATRIX; + } + return REPRESENTATION::ADJACENCY_LIST; +} + +} // namespace graph diff --git a/alib2data/src/graph/GraphRepresentation.h b/alib2data/src/graph/GraphRepresentation.h new file mode 100644 index 0000000000..e93115b7ff --- /dev/null +++ b/alib2data/src/graph/GraphRepresentation.h @@ -0,0 +1,19 @@ +#ifndef GRAPH_REPRESENTATION_H_ +#define GRAPH_REPRESENTATION_H_ + +#include <string> + +namespace graph { + +enum class REPRESENTATION { + ADJACENCY_LIST, + ADJACENCY_MATRIX, + INCIDENCE_MATRIX +}; + +std::string representationToString(REPRESENTATION r); +REPRESENTATION representationFromString(const std::string &str); + +} // namespace graph + +#endif // GRAPH_REPRESENTATION_H_ diff --git a/alib2data/src/graph/GraphToStringComposer.cpp b/alib2data/src/graph/GraphToStringComposer.cpp new file mode 100644 index 0000000000..8ec08c07c2 --- /dev/null +++ b/alib2data/src/graph/GraphToStringComposer.cpp @@ -0,0 +1,112 @@ +#include "GraphToStringComposer.h" +#include "../StringApi.hpp" + +#include <algorithm> + +namespace graph { + +void GraphToStringComposer::compose(std::ostream &out, const Graph &graph) const +{ + out << "("; + graph.getData().Accept(static_cast<void*>(&out), *this); + out << ")"; +} + +void GraphToStringComposer::Visit(void *data, const DirectedGraph &graph) const +{ + std::ostream &out = *static_cast<std::ostream*>(data); + + out << "DirectedGraph:"; + composeRepresentation(out, graph.getRepresentation()); + out << ":"; + composeNodes(out, graph.getNodes()); + out << ":"; + composeDirectedEdges(out, graph.getEdges()); +} + +void GraphToStringComposer::Visit(void *data, const UndirectedGraph &graph) const +{ + std::ostream &out = *static_cast<std::ostream*>(data); + + out << "UndirectedGraph:"; + (void) graph; + //composeRepresentation(out, graph.getRepresentation()); + //out << ":"; + //composeNodes(out, graph.getNodes()); + //out << ":"; + //composeUndirectedEdges(out, graph.getEdges()); +} + +void GraphToStringComposer::Visit(void *data, const Node &node) const +{ + std::ostream &out = *static_cast<std::ostream*>(data); + + alib::stringApi<label::Label>::compose(out, node.getName()); +} + +void GraphToStringComposer::Visit(void *data, const DirectedEdge &edge) const +{ + std::ostream &out = *static_cast<std::ostream*>(data); + + edge.getFromNode().Accept(static_cast<void*>(&out), *this); + alib::stringApi<label::Label>::compose(out, edge.getName()); + edge.getToNode().Accept(static_cast<void*>(&out), *this); +} + +void GraphToStringComposer::Visit(void *data, const UndirectedEdge &edge) const +{ + std::ostream &out = *static_cast<std::ostream*>(data); + + edge.getFirstNode().Accept(static_cast<void*>(&out), *this); + alib::stringApi<label::Label>::compose(out, edge.getName()); + edge.getSecondNode().Accept(static_cast<void*>(&out), *this); +} + +void GraphToStringComposer::composeRepresentation(std::ostream &out, REPRESENTATION representation) const +{ + out << representationToString(representation); +} + +void GraphToStringComposer::composeNodes(std::ostream &out, const std::set<Node> &nodes) const +{ + bool first = true; + + for (const Node &node : nodes) { + if (first) { + first = false; + } else { + out << ","; + } + node.Accept(static_cast<void*>(&out), *this); + } +} + +void GraphToStringComposer::composeDirectedEdges(std::ostream &out, const std::set<DirectedEdge> &edges) const +{ + bool first = true; + + for (const DirectedEdge &edge : edges) { + if (first) { + first = false; + } else { + out << ","; + } + edge.Accept(static_cast<void*>(&out), *this); + } +} + +void GraphToStringComposer::composeUndirectedEdges(std::ostream &out, const std::set<UndirectedEdge> &edges) const +{ + bool first = true; + + for (const UndirectedEdge &edge : edges) { + if (first) { + first = false; + } else { + out << ","; + } + edge.Accept(static_cast<void*>(&out), *this); + } +} + +} // namespace graph diff --git a/alib2data/src/graph/GraphToStringComposer.h b/alib2data/src/graph/GraphToStringComposer.h new file mode 100644 index 0000000000..6a7c211b99 --- /dev/null +++ b/alib2data/src/graph/GraphToStringComposer.h @@ -0,0 +1,38 @@ +#ifndef GRAPH_TO_STRING_COMPOSER_H_ +#define GRAPH_TO_STRING_COMPOSER_H_ + +#include <set> +#include <string> + +#include "Graph.h" +#include "GraphRepresentation.h" +#include "common/GraphElement.h" +#include "directed/DirectedGraph.h" +#include "undirected/UndirectedGraph.h" +#include "../std/visitor.hpp" +#include "../sax/Token.h" + +namespace graph { + +class GraphToStringComposer : public VisitableGraphBase::const_visitor_type, GraphElement::const_visitor_type +{ +public: + void compose(std::ostream &out, const Graph &graph) const; + +private: + void Visit(void *data, const DirectedGraph &graph) const; + void Visit(void *data, const UndirectedGraph &graph) const; + + void Visit(void *data, const Node &node) const; + void Visit(void *data, const DirectedEdge &edge) const; + void Visit(void *data, const UndirectedEdge &edge) const; + + void composeRepresentation(std::ostream &out, REPRESENTATION representation) const; + void composeNodes(std::ostream &out, const std::set<Node> &nodes) const; + void composeDirectedEdges(std::ostream &out, const std::set<DirectedEdge> &edges) const; + void composeUndirectedEdges(std::ostream &out, const std::set<UndirectedEdge> &edges) const; +}; + +} // namespace graph + +#endif // GRAPH_TO_STRING_COMPOSER_H_ diff --git a/alib2data/src/graph/GraphToXMLComposer.cpp b/alib2data/src/graph/GraphToXMLComposer.cpp new file mode 100644 index 0000000000..1c909506bb --- /dev/null +++ b/alib2data/src/graph/GraphToXMLComposer.cpp @@ -0,0 +1,101 @@ +#include "GraphToXMLComposer.h" +#include "GraphRepresentation.h" + +#include "../XmlApi.hpp" + +namespace graph { + +void GraphToXMLComposer::Visit(void *data, const Node &node) const +{ + std::list<sax::Token> &out = *static_cast<std::list<sax::Token>*>(data); + + out.push_back(sax::Token("node", sax::Token::TokenType::START_ELEMENT)); + alib::xmlApi<label::Label>::compose(out, node.getName()); + out.push_back(sax::Token("node", sax::Token::TokenType::END_ELEMENT)); +} + +void GraphToXMLComposer::Visit(void *data, const DirectedEdge &edge) const +{ + std::list<sax::Token> &out = *static_cast<std::list<sax::Token>*>(data); + + out.push_back(sax::Token("edge", sax::Token::TokenType::START_ELEMENT)); + + out.push_back(sax::Token("from", sax::Token::TokenType::START_ELEMENT)); + edge.getFromNode().Accept(static_cast<void*>(&out), *this); + out.push_back(sax::Token("from", sax::Token::TokenType::END_ELEMENT)); + + alib::xmlApi<label::Label>::compose(out, edge.getName()); + + out.push_back(sax::Token("to", sax::Token::TokenType::START_ELEMENT)); + edge.getToNode().Accept(static_cast<void*>(&out), *this); + out.push_back(sax::Token("to", sax::Token::TokenType::END_ELEMENT)); + + out.push_back(sax::Token("edge", sax::Token::TokenType::END_ELEMENT)); +} + +void GraphToXMLComposer::Visit(void *data, const UndirectedEdge &edge) const +{ + std::list<sax::Token> &out = *static_cast<std::list<sax::Token>*>(data); + + out.push_back(sax::Token("edge", sax::Token::TokenType::START_ELEMENT)); + + out.push_back(sax::Token("first", sax::Token::TokenType::START_ELEMENT)); + edge.getFirstNode().Accept(static_cast<void*>(&out), *this); + out.push_back(sax::Token("first", sax::Token::TokenType::END_ELEMENT)); + + alib::xmlApi<label::Label>::compose(out, edge.getName()); + + out.push_back(sax::Token("second", sax::Token::TokenType::START_ELEMENT)); + edge.getSecondNode().Accept(static_cast<void*>(&out), *this); + out.push_back(sax::Token("second", sax::Token::TokenType::END_ELEMENT)); + + out.push_back(sax::Token("edge", sax::Token::TokenType::END_ELEMENT)); +} + +void GraphToXMLComposer::compose(std::list<sax::Token> &out, const GraphBase &graph) const +{ + graph.Accept((void*) &out, alib::ToXMLComposers::toXMLComposers); +} + +void GraphToXMLComposer::compose(std::list<sax::Token> &out, const Graph &graph) const +{ + graph.getData().Accept((void*) &out, alib::ToXMLComposers::toXMLComposers); +} + +void GraphToXMLComposer::compose(std::list<sax::Token> &out, const DirectedGraph &graph) const +{ + out.push_back(sax::Token(alib::Names::GRAPH_DIRECTED_GRAPH, sax::Token::TokenType::START_ELEMENT)); + + composeRepresentation(out, representationToString(graph.getRepresentation())); + composeNodes(out, graph.getNodes()); + composeDirectedEdges(out, graph.getEdges()); + + out.push_back(sax::Token(alib::Names::GRAPH_DIRECTED_GRAPH, sax::Token::TokenType::END_ELEMENT)); +} + +void GraphToXMLComposer::composeRepresentation(std::list<sax::Token> &out, const std::string &representation) const +{ + out.push_back(sax::Token("representation", sax::Token::TokenType::START_ELEMENT)); + out.push_back(sax::Token(representation, sax::Token::TokenType::CHARACTER)); + out.push_back(sax::Token("representation", sax::Token::TokenType::END_ELEMENT)); +} + +void GraphToXMLComposer::composeNodes(std::list<sax::Token> &out, const std::set<Node> &nodes) const +{ + out.push_back(sax::Token("nodes", sax::Token::TokenType::START_ELEMENT)); + for (const Node &node : nodes) { + node.Accept(static_cast<void*>(&out), *this); + } + out.push_back(sax::Token("nodes", sax::Token::TokenType::END_ELEMENT)); +} + +void GraphToXMLComposer::composeDirectedEdges(std::list<sax::Token> &out, const std::set<DirectedEdge> &edges) const +{ + out.push_back(sax::Token("edges", sax::Token::TokenType::START_ELEMENT)); + for (const DirectedEdge &edge : edges) { + edge.Accept(static_cast<void*>(&out), *this); + } + out.push_back(sax::Token("edges", sax::Token::TokenType::END_ELEMENT)); +} + +} // namespace graph diff --git a/alib2data/src/graph/GraphToXMLComposer.h b/alib2data/src/graph/GraphToXMLComposer.h new file mode 100644 index 0000000000..a53d9b1e88 --- /dev/null +++ b/alib2data/src/graph/GraphToXMLComposer.h @@ -0,0 +1,43 @@ +#ifndef GRAPH_TO_XML_COMPOSER_H_ +#define GRAPH_TO_XML_COMPOSER_H_ + +#include <set> +#include <list> + +#include "Graph.h" +#include "common/GraphElement.h" +#include "directed/DirectedGraph.h" +#include "undirected/UndirectedGraph.h" +#include "../std/visitor.hpp" +#include "../sax/Token.h" + +namespace alib { + +template<typename T> +struct xmlApi; + +} // namespace alib + +namespace graph { + +// This class contains methods to print XML representation of graph to the output stream. +class GraphToXMLComposer : public GraphElement::const_visitor_type +{ +private: + void Visit(void *data, const Node &node) const; + void Visit(void *data, const DirectedEdge &edge) const; + void Visit(void *data, const UndirectedEdge &edge) const; + + void compose(std::list<sax::Token> &out, const GraphBase &graph) const; + void compose(std::list<sax::Token> &out, const Graph &graph) const; + void compose(std::list<sax::Token> &out, const DirectedGraph &graph) const; + void composeRepresentation(std::list<sax::Token> &out, const std::string &representation) const; + void composeNodes(std::list<sax::Token> &out, const std::set<Node> &nodes) const; + void composeDirectedEdges(std::list<sax::Token> &out, const std::set<DirectedEdge> &edges) const; + + template<typename T> friend class alib::xmlApi; +}; + +} // namespace graph + +#endif // GRAPH_TO_XML_COMPOSER_H_ diff --git a/alib2data/src/graph/common/GraphElement.cpp b/alib2data/src/graph/common/GraphElement.cpp new file mode 100644 index 0000000000..0687b8aab7 --- /dev/null +++ b/alib2data/src/graph/common/GraphElement.cpp @@ -0,0 +1,9 @@ +#include "GraphElement.h" + +namespace graph { + +GraphElement::GraphElement() +{ +} + +} // namespace graph diff --git a/alib2data/src/graph/common/GraphElement.h b/alib2data/src/graph/common/GraphElement.h new file mode 100644 index 0000000000..ac6a1d8ff0 --- /dev/null +++ b/alib2data/src/graph/common/GraphElement.h @@ -0,0 +1,30 @@ +#ifndef GRAPH_ELEMENT_H_ +#define GRAPH_ELEMENT_H_ + +// for std::hash +#include <string> +#include <functional> + +#include "../../std/visitor.hpp" +#include "../../object/Object.h" + +namespace graph { + +class GraphElement; + +class Node; +class DirectedEdge; +class UndirectedEdge; + +// Abstract class representing element in the graph. Can be node or edge. +typedef std::acceptor_base<GraphElement, Node, DirectedEdge, UndirectedEdge> VisitableGraphElement; + +class GraphElement : public alib::base<GraphElement, Node, DirectedEdge, UndirectedEdge>, public VisitableGraphElement +{ +public: + explicit GraphElement(); +}; + +} // namespace graph + +#endif // GRAPH_ELEMENT_H_ diff --git a/alib2data/src/graph/common/Macros.h b/alib2data/src/graph/common/Macros.h new file mode 100644 index 0000000000..5e17259986 --- /dev/null +++ b/alib2data/src/graph/common/Macros.h @@ -0,0 +1,28 @@ +#ifndef GRAPH_MACROS_H_ +#define GRAPH_MACROS_H_ + +#define GRAPH_DEFINE_STD_HASH(T) \ + namespace std { \ + template <> \ + struct hash<graph::T> \ + { \ + std::size_t operator()(const graph::T &t) const \ + { \ + return std::hash<std::string>()(static_cast<std::string>(t)); \ + } \ + }; \ + } \ + +#define GRAPH_DEFINE_STD_COMPARE(T) \ + namespace std { \ + template<> \ + struct compare<graph::T> \ + { \ + int operator()(const graph::T &first, const graph::T &second) const \ + { \ + return first.compare(second); \ + } \ + }; \ + } \ + +#endif // GRAPH_MACROS_H_ diff --git a/alib2data/src/graph/common/Node.cpp b/alib2data/src/graph/common/Node.cpp new file mode 100644 index 0000000000..a2251e7b08 --- /dev/null +++ b/alib2data/src/graph/common/Node.cpp @@ -0,0 +1,103 @@ +#include "Node.h" +#include "../../label/Label.h" + +#include <sstream> + +namespace graph { + +Node::Node(const label::Label &name) + : name(name) +{ +} + +Node::Node(label::Label &&name) + : name(std::move(name)) +{ +} + +Node::Node(int number) + : name(label::labelFrom(number)) +{ +} + +Node::Node(char character) + : name(label::labelFrom(character)) +{ +} + +Node::Node(const std::string &name) + : name(label::labelFrom(name)) +{ +} + +Node::Node(const Node &other) + : name(other.name) +{ +} + +Node::Node(Node &&other) noexcept + : name(std::move(other.name)) +{ +} + +Node &Node::operator=(const Node &other) +{ + if (this == &other) { + return *this; + } + + *this = Node(other); + return *this; +} + +Node &Node::operator=(Node &&other) +{ + std::swap(name, other.name); + return *this; +} + +GraphElement *Node::clone() const +{ + return new Node(*this); +} + +GraphElement *Node::plunder() && +{ + return new Node(std::move(*this)); +} + +const label::Label &Node::getName() const +{ + return name; +} + +int Node::compare(const Node &other) const +{ + return name.getData().compare(other.name.getData()); +} + +void Node::operator>>(std::ostream &out) const +{ + dump(out); +} + +Node::operator std::string() const +{ + std::stringstream ss; + ss << *this; + return ss.str(); +} + +std::ostream &operator<<(std::ostream &out, const Node &node) +{ + node.dump(out); + return out; +} + +void Node::dump(std::ostream &os) const +{ + os << "(Node " << name << ")"; +} + +} // namespace graph + diff --git a/alib2data/src/graph/common/Node.h b/alib2data/src/graph/common/Node.h new file mode 100644 index 0000000000..ec5c004f26 --- /dev/null +++ b/alib2data/src/graph/common/Node.h @@ -0,0 +1,58 @@ +#ifndef NODE_H_ +#define NODE_H_ + +#include "Macros.h" +#include "GraphElement.h" +#include "../../label/Label.h" + +namespace graph { + +class Node : public std::acceptor<Node, GraphElement, GraphElement> +{ +public: + explicit Node(const label::Label &name); + explicit Node(label::Label &&name); + explicit Node(int number); + explicit Node(char character); + explicit Node(const std::string &name); + + Node(const Node &other); + Node(Node &&other) noexcept; + Node &operator=(const Node &other); + Node &operator=(Node &&other); + + GraphElement *clone() const; + GraphElement *plunder() &&; + + const label::Label &getName() const; + + int compare(const GraphElement &other) const override + { + return -other.compare(*this); + } + + int compare(const Node &other) const; + + void operator>>(std::ostream &out) const override; + + operator std::string() const override; + + int selfTypeId() const override + { + return typeId<Node>(); + } + + friend std::ostream &operator<<(std::ostream &out, const Node &node); + +private: + void dump(std::ostream &os) const; + + label::Label name; +}; + +} // namespace graph + +GRAPH_DEFINE_STD_HASH(Node) +GRAPH_DEFINE_STD_COMPARE(Node) + +#endif // NODE_H_ diff --git a/alib2data/src/graph/directed/AdjacencyListDirectedGraph.cpp b/alib2data/src/graph/directed/AdjacencyListDirectedGraph.cpp new file mode 100644 index 0000000000..35528bafd9 --- /dev/null +++ b/alib2data/src/graph/directed/AdjacencyListDirectedGraph.cpp @@ -0,0 +1,121 @@ +#include "AdjacencyListDirectedGraph.h" +#include "../../std/compare.hpp" + +namespace graph { + +std::set<Node> AdjacencyListDirectedGraph::allNodes() const +{ + std::set<Node> out; + + for (auto i : adj) { + out.insert(i.first); + } + + return out; +} + +std::set<DirectedEdge> AdjacencyListDirectedGraph::allEdges() const +{ + return edges; +} + +std::set<DirectedEdge> AdjacencyListDirectedGraph::findEdges(const Node &from, const Node &to) const +{ + std::set<DirectedEdge> out; + + for (const DirectedEdge &e : edges) { + if (e.getFromNode() == from && e.getToNode() == to) { + out.insert(e); + } + } + + return out; +} + +std::set<Node> AdjacencyListDirectedGraph::neighbors(const Node &node) const +{ + auto search = adj.find(node); + if (search == adj.end()) { + return std::set<Node>(); + } + return search->second; +} + +std::set<DirectedEdge> AdjacencyListDirectedGraph::neighborEdges(const Node &node) const +{ + std::set<DirectedEdge> out; + const std::set<Node> &nghbrs = neighbors(node); + + for (const DirectedEdge &e : edges) { + if (e.getFromNode() == node && nghbrs.find(e.getToNode()) != nghbrs.end()) { + out.insert(e); + } + } + + return out; +} + +void AdjacencyListDirectedGraph::addNode(const Node &node) +{ + if (adj.find(node) != adj.end()) { + return; + } + + adj[node]; // insert key +} + +void AdjacencyListDirectedGraph::removeNode(const Node &node) +{ + auto search = adj.find(node); + if (search == adj.end()) { + return; + } + + adj.erase(search); + + auto i = edges.begin(); + while (i != edges.end()) { + if (i->getFromNode() == node || i->getToNode() == node) { + edges.erase(i++); + } else { + i++; + } + } +} + +void AdjacencyListDirectedGraph::addEdge(const DirectedEdge &edge) +{ + if (edges.find(edge) != edges.end()) { + return; + } + + edges.insert(edge); +} + +void AdjacencyListDirectedGraph::removeEdge(const DirectedEdge &edge) +{ + auto search = edges.find(edge); + if (search == edges.end()) { + return; + } + + edges.erase(search); + + // Don't touch adj if there still is an edge, in case of multigraph, + if (!findEdges(edge.getFromNode(), edge.getToNode()).empty()) { + adj[edge.getFromNode()].erase(edge.getToNode()); + } +} + +int AdjacencyListDirectedGraph::compare(IDirectedGraph *other) const +{ + AdjacencyListDirectedGraph *o = dynamic_cast<AdjacencyListDirectedGraph*>(other); + + auto first = std::tie(edges, adj); + auto second = std::tie(o->edges, o->adj); + + std::compare<decltype(first)> comp; + return comp(first, second); +} + +} // namespace graph diff --git a/alib2data/src/graph/directed/AdjacencyListDirectedGraph.h b/alib2data/src/graph/directed/AdjacencyListDirectedGraph.h new file mode 100644 index 0000000000..5d22b85845 --- /dev/null +++ b/alib2data/src/graph/directed/AdjacencyListDirectedGraph.h @@ -0,0 +1,37 @@ +#ifndef ADJACENCY_LIST_DIRECTED_GRAPH_H_ +#define ADJACENCY_LIST_DIRECTED_GRAPH_H_ + +#include <set> +#include <unordered_map> + +#include "IDirectedGraph.h" + +namespace graph { + +class AdjacencyListDirectedGraph : public IDirectedGraph +{ +public: + std::set<Node> allNodes() const override; + std::set<DirectedEdge> allEdges() const override; + + std::set<DirectedEdge> findEdges(const Node &from, const Node &to) const override; + + std::set<Node> neighbors(const Node &node) const override; + std::set<DirectedEdge> neighborEdges(const Node &node) const override; + + void addNode(const Node &node) override; + void removeNode(const Node &node) override; + + void addEdge(const DirectedEdge &edge) override; + void removeEdge(const DirectedEdge &edge) override; + + int compare(IDirectedGraph *other) const override; + +private: + std::set<DirectedEdge> edges; + std::unordered_map<Node, std::set<Node>> adj; +}; + +} // namespace graph + +#endif // ADJACENCY_LIST_DIRECTED_GRAPH_H_ diff --git a/alib2data/src/graph/directed/DirectedEdge.cpp b/alib2data/src/graph/directed/DirectedEdge.cpp new file mode 100644 index 0000000000..dedcefb852 --- /dev/null +++ b/alib2data/src/graph/directed/DirectedEdge.cpp @@ -0,0 +1,170 @@ +#include "DirectedEdge.h" + +#include <sstream> + +namespace graph { + +DirectedEdge::DirectedEdge(const Node &from, const Node &to) + : from(from) + , to(to) + , name(label::labelFrom('d')) +{ +} + +DirectedEdge::DirectedEdge(Node &&from, Node &&to) + : from(std::move(from)) + , to(std::move(to)) + , name(label::labelFrom('d')) +{ +} + +DirectedEdge::DirectedEdge(const Node &from, const Node &to, const label::Label &name) + : from(from) + , to(to) + , name(name) +{ +} + +DirectedEdge::DirectedEdge(Node &&from, Node &&to, label::Label &&name) + : from(std::move(from)) + , to(std::move(to)) + , name(std::move(name)) +{ +} + +DirectedEdge::DirectedEdge(const Node &from, const Node &to, int number) + : from(from) + , to(to) + , name(label::labelFrom(number)) +{ +} + +DirectedEdge::DirectedEdge(Node &&from, Node &&to, int number) + : from(std::move(from)) + , to(std::move(to)) + , name(label::labelFrom(number)) +{ +} + +DirectedEdge::DirectedEdge(const Node &from, const Node &to, char character) + : from(from) + , to(to) + , name(label::labelFrom(character)) +{ +} + +DirectedEdge::DirectedEdge(Node &&from, Node &&to, char character) + : from(std::move(from)) + , to(std::move(to)) + , name(label::labelFrom(character)) +{ +} + +DirectedEdge::DirectedEdge(const Node &from, const Node &to, const std::string &name) + : from(from) + , to(to) + , name(label::labelFrom(name)) +{ +} + +DirectedEdge::DirectedEdge(Node &&from, Node &&to, const std::string &name) + : from(std::move(from)) + , to(std::move(to)) + , name(label::labelFrom(name)) +{ +} + +DirectedEdge::DirectedEdge(const DirectedEdge &other) + : from(other.from) + , to(other.to) + , name(other.name) +{ +} + +DirectedEdge::DirectedEdge(DirectedEdge &&other) noexcept + : from(std::move(other.from)) + , to(std::move(other.to)) + , name(std::move(other.name)) +{ +} + +DirectedEdge &DirectedEdge::operator=(const DirectedEdge &other) +{ + if (this == &other) { + return *this; + } + + *this = DirectedEdge(other); + return *this; +} + +DirectedEdge &DirectedEdge::operator=(DirectedEdge &&other) +{ + std::swap(from, other.from); + std::swap(to, other.to); + std::swap(name, other.name); + return *this; +} + +GraphElement *DirectedEdge::clone() const +{ + return new DirectedEdge(*this); +} + +GraphElement *DirectedEdge::plunder() && +{ + return new DirectedEdge(std::move(*this)); +} + +const Node &DirectedEdge::getFromNode() const +{ + return from; +} + +const Node &DirectedEdge::getToNode() const +{ + return to; +} + +const label::Label &DirectedEdge::getName() const +{ + return name; +} + +int DirectedEdge::compare(const DirectedEdge &other) const +{ + int res = name.getData().compare(other.name.getData()); + if (res == 0) { + res = from.compare(other.from); + if (res == 0) { + res = to.compare(other.to); + } + } + return res; +} + +void DirectedEdge::operator>>(std::ostream &out) const +{ + dump(out); +} + +DirectedEdge::operator std::string() const +{ + std::stringstream ss; + ss << *this; + return ss.str(); +} + +std::ostream &operator<<(std::ostream &out, const DirectedEdge &node) +{ + node.dump(out); + return out; +} + +void DirectedEdge::dump(std::ostream &os) const +{ + os << "(DirectedEdge " << from << " -> " << to << ")"; +} + +} // namespace graph + diff --git a/alib2data/src/graph/directed/DirectedEdge.h b/alib2data/src/graph/directed/DirectedEdge.h new file mode 100644 index 0000000000..53a901f662 --- /dev/null +++ b/alib2data/src/graph/directed/DirectedEdge.h @@ -0,0 +1,67 @@ +#ifndef DIRECTED_EDGE_H_ +#define DIRECTED_EDGE_H_ + +#include "../common/GraphElement.h" +#include "../common/Macros.h" +#include "../common/Node.h" + +namespace graph { + +class DirectedEdge : public std::acceptor<DirectedEdge, GraphElement, GraphElement> +{ +public: + explicit DirectedEdge(const Node &from, const Node &to); + explicit DirectedEdge(Node &&from, Node &&to); + explicit DirectedEdge(const Node &from, const Node &to, const label::Label &name); + explicit DirectedEdge(Node &&from, Node &&to, label::Label &&name); + explicit DirectedEdge(const Node &from, const Node &to, int number); + explicit DirectedEdge(Node &&from, Node &&to, int number); + explicit DirectedEdge(const Node &from, const Node &to, char character); + explicit DirectedEdge(Node &&from, Node &&to, char character); + explicit DirectedEdge(const Node &from, const Node &to, const std::string &name); + explicit DirectedEdge(Node &&from, Node &&to, const std::string &name); + + DirectedEdge(const DirectedEdge &other); + DirectedEdge(DirectedEdge &&other) noexcept; + DirectedEdge &operator=(const DirectedEdge &other); + DirectedEdge &operator=(DirectedEdge &&other); + + GraphElement *clone() const; + GraphElement *plunder() &&; + + const Node &getFromNode() const; + const Node &getToNode() const; + const label::Label &getName() const; + + int compare(const GraphElement &other) const override + { + return -other.compare(*this); + } + + int compare(const DirectedEdge &other) const; + + void operator>>(std::ostream &out) const override; + + operator std::string() const override; + + int selfTypeId() const override + { + return typeId<DirectedEdge>(); + } + + friend std::ostream &operator<<(std::ostream &out, const DirectedEdge &node); + +private: + void dump(std::ostream &os) const; + + Node from; + Node to; + label::Label name; +}; + +} // namespace graph + +GRAPH_DEFINE_STD_HASH(DirectedEdge) +GRAPH_DEFINE_STD_COMPARE(DirectedEdge) + +#endif // DIRECTED_EDGE_H_ diff --git a/alib2data/src/graph/directed/DirectedGraph.cpp b/alib2data/src/graph/directed/DirectedGraph.cpp new file mode 100644 index 0000000000..874495de56 --- /dev/null +++ b/alib2data/src/graph/directed/DirectedGraph.cpp @@ -0,0 +1,154 @@ +#include "DirectedGraph.h" +#include "IDirectedGraph.h" +#include "AdjacencyListDirectedGraph.h" +#include "../../std/set.hpp" + +#include <iostream> +#include <algorithm> +#include <sstream> + +namespace graph { + +DirectedGraph::DirectedGraph(REPRESENTATION representation) + : representation(representation) +{ + init(); +} + +DirectedGraph::~DirectedGraph() noexcept +{ + delete impl; +} + +DirectedGraph::DirectedGraph(const DirectedGraph &other) + : representation(other.representation) +{ + init(); +} + +DirectedGraph::DirectedGraph(DirectedGraph &&other) noexcept + : representation(other.representation) + , impl(other.impl) +{ + other.impl = 0; +} + +DirectedGraph &DirectedGraph::operator=(const DirectedGraph &other) +{ + if (this == &other) { + return *this; + } + + *this = DirectedGraph(other); + return *this; +} + +DirectedGraph &DirectedGraph::operator=(DirectedGraph &&other) noexcept +{ + this->representation = other.representation; + std::swap(this->impl, other.impl); + return *this; +} + +GraphBase *DirectedGraph::clone() const +{ + return new DirectedGraph(*this); +} + +GraphBase *DirectedGraph::plunder() && +{ + return new DirectedGraph(std::move(*this)); +} + +REPRESENTATION DirectedGraph::getRepresentation() const +{ + return representation; +} + +std::set<Node> DirectedGraph::getNodes() const +{ + return impl->allNodes(); +} + +std::set<DirectedEdge> DirectedGraph::getEdges() const +{ + return impl->allEdges(); +} + +bool DirectedGraph::hasEdge(const Node &from, const Node &to) const +{ + return !impl->findEdges(from, to).empty(); +} + +std::set<DirectedEdge> DirectedGraph::findEdges(const Node &from, const Node &to) const +{ + return impl->findEdges(from, to); +} + +std::set<Node> DirectedGraph::neighbors(const Node &node) const +{ + return impl->neighbors(node); +} + +std::set<DirectedEdge> DirectedGraph::neighborEdges(const Node &node) const +{ + return impl->neighborEdges(node); +} + +void DirectedGraph::addNode(const Node &node) +{ + return impl->addNode(node); +} + +void DirectedGraph::removeNode(const Node &node) +{ + return impl->removeNode(node); +} + +void DirectedGraph::addEdge(const DirectedEdge &edge) +{ + return impl->addEdge(edge); +} + +void DirectedGraph::removeEdge(const DirectedEdge &edge) +{ + return impl->removeEdge(edge); +} + +void DirectedGraph::operator>>(std::ostream &out) const +{ + out << "(DirectedGraph " << static_cast<std::string>(*impl) << ")"; +} + +int DirectedGraph::compare(const DirectedGraph &other) const +{ + if (representation != other.representation) { + return static_cast<int>(representation) - static_cast<int>(other.representation); + } + + return impl->compare(other.impl); +} + +DirectedGraph::operator std::string() const +{ + std::stringstream ss; + ss << *this; + return ss.str(); +} + +void DirectedGraph::init() +{ + switch (representation) { + case REPRESENTATION::ADJACENCY_LIST: + impl = new AdjacencyListDirectedGraph(); + break; + + case REPRESENTATION::ADJACENCY_MATRIX: + case REPRESENTATION:::INCIDENCE_MATRIX: + + default: + impl = 0; + } +} + +} // namespace graph diff --git a/alib2data/src/graph/directed/DirectedGraph.h b/alib2data/src/graph/directed/DirectedGraph.h new file mode 100644 index 0000000000..c3693578b4 --- /dev/null +++ b/alib2data/src/graph/directed/DirectedGraph.h @@ -0,0 +1,72 @@ +#ifndef DIRECTED_GRAPH_H_ +#define DIRECTED_GRAPH_H_ + +#include "../GraphBase.h" +#include "../GraphRepresentation.h" +#include "../common/Macros.h" +#include "../common/Node.h" +#include "DirectedEdge.h" + +namespace graph { + +class IDirectedGraph; + +class DirectedGraph : public std::acceptor<DirectedGraph, VisitableGraphBase, std::acceptor<DirectedGraph, alib::VisitableObjectBase, GraphBase>> +{ +public: + explicit DirectedGraph(REPRESENTATION representation); + ~DirectedGraph() noexcept; + + DirectedGraph(const DirectedGraph &other); + DirectedGraph(DirectedGraph &&other) noexcept; + DirectedGraph &operator=(const DirectedGraph &other); + DirectedGraph &operator=(DirectedGraph &&other) noexcept; + + GraphBase *clone() const override; + GraphBase *plunder() && override; + + REPRESENTATION getRepresentation() const; + + std::set<Node> getNodes() const; + std::set<DirectedEdge> getEdges() const; + + bool hasEdge(const Node &from, const Node &to) const; + std::set<DirectedEdge> findEdges(const Node &from, const Node &to) const; + + std::set<Node> neighbors(const Node &node) const; + std::set<DirectedEdge> neighborEdges(const Node &node) const; + + void addNode(const Node &node); + void removeNode(const Node &node); + + void addEdge(const DirectedEdge &edge); + void removeEdge(const DirectedEdge &edge); + + int compare(const ObjectBase &other) const override + { + return -other.compare(*this); + } + + int compare(const DirectedGraph &other) const; + + void operator>>(std::ostream &out) const override; + + operator std::string() const override; + + int selfTypeId() const override + { + return typeId<DirectedGraph>(); + } + +private: + void init(); + + REPRESENTATION representation; + IDirectedGraph *impl; +}; + +} // namespace graph + +GRAPH_DEFINE_STD_COMPARE(DirectedGraph) + +#endif // DIRECTED_GRAPH_H_ diff --git a/alib2data/src/graph/directed/IDirectedGraph.cpp b/alib2data/src/graph/directed/IDirectedGraph.cpp new file mode 100644 index 0000000000..eba90153b8 --- /dev/null +++ b/alib2data/src/graph/directed/IDirectedGraph.cpp @@ -0,0 +1,23 @@ +#include "IDirectedGraph.h" + +#include <sstream> + +namespace graph { + +IDirectedGraph::~IDirectedGraph() noexcept +{ +} + +IDirectedGraph::operator std::string() const +{ + std::stringstream ss; + for (const Node &node : allNodes()) { + ss << node; + } + for (const DirectedEdge &edge : allEdges()) { + ss << edge; + } + return ss.str(); +} + +} // namespace graph diff --git a/alib2data/src/graph/directed/IDirectedGraph.h b/alib2data/src/graph/directed/IDirectedGraph.h new file mode 100644 index 0000000000..5961c0817f --- /dev/null +++ b/alib2data/src/graph/directed/IDirectedGraph.h @@ -0,0 +1,38 @@ +#ifndef I_DIRECTED_GRAPH_H_ +#define I_DIRECTED_GRAPH_H_ + +#include <set> +#include <map> + +#include "../common/Node.h" +#include "DirectedEdge.h" + +namespace graph { + +class IDirectedGraph +{ +public: + virtual ~IDirectedGraph() noexcept; + + virtual std::set<Node> allNodes() const = 0; + virtual std::set<DirectedEdge> allEdges() const = 0; + + virtual std::set<DirectedEdge> findEdges(const Node &from, const Node &to) const = 0; + + virtual std::set<Node> neighbors(const Node &node) const = 0; + virtual std::set<DirectedEdge> neighborEdges(const Node &node) const = 0; + + virtual void addNode(const Node &node) = 0; + virtual void removeNode(const Node &node) = 0; + + virtual void addEdge(const DirectedEdge &edge) = 0; + virtual void removeEdge(const DirectedEdge &edge) = 0; + + virtual int compare(IDirectedGraph *other) const = 0; + + operator std::string() const; +}; + +} // namespace graph + +#endif // I_DIRECTED_GRAPH_H_ diff --git a/alib2data/src/graph/undirected/UndirectedEdge.cpp b/alib2data/src/graph/undirected/UndirectedEdge.cpp new file mode 100644 index 0000000000..c259152f0b --- /dev/null +++ b/alib2data/src/graph/undirected/UndirectedEdge.cpp @@ -0,0 +1,173 @@ +#include "UndirectedEdge.h" + +#include <sstream> + +namespace graph { + +UndirectedEdge::UndirectedEdge(const Node &first, const Node &second) + : first(first) + , second(second) + , name(label::labelFrom('u')) +{ +} + +UndirectedEdge::UndirectedEdge(Node &&first, Node &&second) + : first(std::move(first)) + , second(std::move(second)) + , name(label::labelFrom('u')) +{ +} + +UndirectedEdge::UndirectedEdge(const Node &first, const Node &second, const label::Label &name) + : first(first) + , second(second) + , name(name) +{ +} + +UndirectedEdge::UndirectedEdge(Node &&first, Node &&second, label::Label &&name) + : first(std::move(first)) + , second(std::move(second)) + , name(std::move(name)) +{ +} + +UndirectedEdge::UndirectedEdge(const Node &first, const Node &second, int number) + : first(first) + , second(second) + , name(label::labelFrom(number)) +{ +} + +UndirectedEdge::UndirectedEdge(Node &&first, Node &&second, int number) + : first(std::move(first)) + , second(std::move(second)) + , name(label::labelFrom(number)) +{ +} + +UndirectedEdge::UndirectedEdge(const Node &first, const Node &second, char character) + : first(first) + , second(second) + , name(label::labelFrom(character)) +{ +} + +UndirectedEdge::UndirectedEdge(Node &&first, Node &&second, char character) + : first(std::move(first)) + , second(std::move(second)) + , name(label::labelFrom(character)) +{ +} + +UndirectedEdge::UndirectedEdge(const Node &first, const Node &second, const std::string &name) + : first(first) + , second(second) + , name(label::labelFrom(name)) +{ +} + +UndirectedEdge::UndirectedEdge(Node &&first, Node &&second, const std::string &name) + : first(std::move(first)) + , second(std::move(second)) + , name(label::labelFrom(name)) +{ +} + +UndirectedEdge::UndirectedEdge(const UndirectedEdge &other) + : first(other.first) + , second(other.second) + , name(other.name) +{ +} + +UndirectedEdge::UndirectedEdge(UndirectedEdge &&other) noexcept + : first(std::move(other.first)) + , second(std::move(other.second)) + , name(std::move(other.name)) +{ +} + +UndirectedEdge &UndirectedEdge::operator=(const UndirectedEdge &other) +{ + if (this == &other) { + return *this; + } + + *this = UndirectedEdge(other); + return *this; +} + +UndirectedEdge &UndirectedEdge::operator=(UndirectedEdge &&other) +{ + std::swap(first, other.first); + std::swap(second, other.second); + std::swap(name, other.name); + return *this; +} + +GraphElement *UndirectedEdge::clone() const +{ + return new UndirectedEdge(*this); +} + +GraphElement *UndirectedEdge::plunder() && +{ + return new UndirectedEdge(std::move(*this)); +} + +const Node &UndirectedEdge::getFirstNode() const +{ + return first; +} + +const Node &UndirectedEdge::getSecondNode() const +{ + return second; +} + +const label::Label &UndirectedEdge::getName() const +{ + return name; +} + +int UndirectedEdge::compare(const UndirectedEdge &other) const +{ + int res = name.getData().compare(other.name.getData()); + if (res == 0) { + if (first.compare(other.second) == 0 && second.compare(other.first) == 0) { + return 0; + } + res = first.compare(other.first); + if (res == 0) { + res = second.compare(other.second); + } + } + return res; +} + +void UndirectedEdge::operator>>(std::ostream &out) const +{ + dump(out); +} + +UndirectedEdge::operator std::string() const +{ + std::stringstream ss; + ss << *this; + return ss.str(); +} + +std::ostream &operator<<(std::ostream &out, const UndirectedEdge &node) +{ + node.dump(out); + return out; +} + +void UndirectedEdge::dump(std::ostream &os) const +{ + os << "(UndirectedEdge " << first << " -> " << second << ")"; +} + +} // namespace graph + diff --git a/alib2data/src/graph/undirected/UndirectedEdge.h b/alib2data/src/graph/undirected/UndirectedEdge.h new file mode 100644 index 0000000000..894cac3683 --- /dev/null +++ b/alib2data/src/graph/undirected/UndirectedEdge.h @@ -0,0 +1,67 @@ +#ifndef UNDIRECTED_EDGE_H_ +#define UNDIRECTED_EDGE_H_ + +#include "../common/GraphElement.h" +#include "../common/Macros.h" +#include "../common/Node.h" + +namespace graph { + +class UndirectedEdge : public std::acceptor<UndirectedEdge, GraphElement, GraphElement> +{ +public: + explicit UndirectedEdge(const Node &first, const Node &second); + explicit UndirectedEdge(Node &&first, Node &&second); + explicit UndirectedEdge(const Node &first, const Node &second, const label::Label &name); + explicit UndirectedEdge(Node &&first, Node &&second, label::Label &&name); + explicit UndirectedEdge(const Node &first, const Node &second, int number); + explicit UndirectedEdge(Node &&first, Node &&second, int number); + explicit UndirectedEdge(const Node &first, const Node &second, char character); + explicit UndirectedEdge(Node &&first, Node &&second, char character); + explicit UndirectedEdge(const Node &first, const Node &second, const std::string &name); + explicit UndirectedEdge(Node &&first, Node &&second, const std::string &name); + + UndirectedEdge(const UndirectedEdge &other); + UndirectedEdge(UndirectedEdge &&other) noexcept; + UndirectedEdge &operator=(const UndirectedEdge &other); + UndirectedEdge &operator=(UndirectedEdge &&other); + + GraphElement *clone() const; + GraphElement *plunder() &&; + + const Node &getFirstNode() const; + const Node &getSecondNode() const; + const label::Label &getName() const; + + int compare(const GraphElement &other) const override + { + return -other.compare(*this); + } + + int compare(const UndirectedEdge &other) const; + + void operator>>(std::ostream &out) const override; + + operator std::string() const override; + + int selfTypeId() const override + { + return typeId<UndirectedEdge>(); + } + + friend std::ostream &operator<<(std::ostream &out, const UndirectedEdge &node); + +private: + void dump(std::ostream &os) const; + + Node first; + Node second; + label::Label name; +}; + +} // namespace graph + +GRAPH_DEFINE_STD_HASH(UndirectedEdge) +GRAPH_DEFINE_STD_COMPARE(UndirectedEdge) + +#endif // UNDIRECTED_EDGE_H_ diff --git a/alib2data/src/graph/undirected/UndirectedGraph.h b/alib2data/src/graph/undirected/UndirectedGraph.h new file mode 100644 index 0000000000..1c48850279 --- /dev/null +++ b/alib2data/src/graph/undirected/UndirectedGraph.h @@ -0,0 +1,14 @@ +#ifndef UNDIRECTED_GRAPH_H_ +#define UNDIRECTED_GRAPH_H_ + +#include "UndirectedEdge.h" + +namespace graph { + +class UndirectedGraph +{ +}; + +} // namespace graph + +#endif // UNDIRECTED_GRAPH_H_ diff --git a/alib2data/src/object/ObjectBase.h b/alib2data/src/object/ObjectBase.h index 04a619b2f0..5596022611 100644 --- a/alib2data/src/object/ObjectBase.h +++ b/alib2data/src/object/ObjectBase.h @@ -64,6 +64,13 @@ class UnrestrictedGrammar; } +namespace graph { + +class DirectedGraph; +class UndirectedGraph; + +} + namespace label { class PrimitiveLabel; @@ -135,6 +142,7 @@ typedef std::acceptor_base<ObjectBase, exception::AlibException, automaton::DFA, automaton::NFA, automaton::MultiInitialStateNFA, automaton::EpsilonNFA, automaton::CompactNFA, automaton::ExtendedNFA, automaton::DPDA, automaton::SinglePopDPDA, automaton::InputDrivenDPDA, automaton::VisiblyPushdownDPDA, automaton::RealTimeHeightDeterministicDPDA, automaton::NPDA, automaton::SinglePopNPDA, automaton::InputDrivenNPDA, automaton::VisiblyPushdownNPDA, automaton::RealTimeHeightDeterministicNPDA, automaton::OneTapeDTM, grammar::LeftLG, grammar::LeftRG, grammar::RightLG, grammar::RightRG, grammar::LG, grammar::CFG, grammar::EpsilonFreeCFG, grammar::CNF, grammar::GNF, grammar::CSG, grammar::NonContractingGrammar, grammar::ContextPreservingUnrestrictedGrammar, grammar::UnrestrictedGrammar, + graph::DirectedGraph, label::PrimitiveLabel, label::HexavigesimalLabel, label::ObjectLabel, label::LabelSetLabel, label::LabelPairLabel, label::UniqueLabel, regexp::UnboundedRegExp, regexp::FormalRegExp, string::Epsilon, string::LinearString, string::CyclicString, @@ -150,6 +158,7 @@ class ObjectBase : exception::AlibException, automaton::DFA, automaton::NFA, automaton::MultiInitialStateNFA, automaton::EpsilonNFA, automaton::CompactNFA, automaton::ExtendedNFA, automaton::DPDA, automaton::SinglePopDPDA, automaton::InputDrivenDPDA, automaton::VisiblyPushdownDPDA, automaton::RealTimeHeightDeterministicDPDA, automaton::NPDA, automaton::SinglePopNPDA, automaton::InputDrivenNPDA, automaton::VisiblyPushdownNPDA, automaton::RealTimeHeightDeterministicNPDA, automaton::OneTapeDTM, grammar::LeftLG, grammar::LeftRG, grammar::RightLG, grammar::RightRG, grammar::LG, grammar::CFG, grammar::EpsilonFreeCFG, grammar::CNF, grammar::GNF, grammar::CSG, grammar::NonContractingGrammar, grammar::ContextPreservingUnrestrictedGrammar, grammar::UnrestrictedGrammar, + graph::DirectedGraph, label::PrimitiveLabel, label::HexavigesimalLabel, label::ObjectLabel, label::LabelSetLabel, label::LabelPairLabel, label::UniqueLabel, regexp::UnboundedRegExp, regexp::FormalRegExp, string::Epsilon, string::LinearString, string::CyclicString, diff --git a/alib2data/src/std/compare.hpp b/alib2data/src/std/compare.hpp index 4e1e780cb0..6f1e7e3559 100644 --- a/alib2data/src/std/compare.hpp +++ b/alib2data/src/std/compare.hpp @@ -12,6 +12,7 @@ #include <vector> #include <string> #include <map> +#include <unordered_map> #include <tuple> namespace std { @@ -92,6 +93,21 @@ struct compare<map<T, R>> { } }; +template<class T, class R> +struct compare<unordered_map<T, R>> { + int operator()(const unordered_map<T, R>& first, const unordered_map<T, R>& second) const { + if(first.size() < second.size()) return -1; + if(first.size() > second.size()) return 1; + + compare<std::pair<T, R>> comp; + for(auto iterF = first.begin(), iterS = second.begin(); iterF != first.end(); iterF++, iterS++) { + int res = comp(*iterF, *iterS); + if(res != 0) return res; + } + return 0; + } +}; + template<int I, typename Tuple> struct compareTupleHelper; -- GitLab