From c17b24257e11d34f89a7b8c8fd3cedcdbbddb372 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Sun, 24 Aug 2014 15:20:56 +0200
Subject: [PATCH] Implement set container represenation

---
 alib2data/src/Api.cpp                         | 13 +++++
 alib2data/src/Api.hpp                         | 10 +++-
 alib2data/src/container/Container.h           | 25 +++++++++
 alib2data/src/container/ContainerBase.h       | 28 ++++++++++
 alib2data/src/container/ContainerFeatures.h   | 19 +++++++
 .../src/container/ContainerFromXMLParser.cpp  | 27 +++++++++
 .../src/container/ContainerFromXMLParser.hpp  | 13 ++++-
 .../src/container/ContainerToXMLComposer.cpp  | 25 +++++++++
 .../src/container/ContainerToXMLComposer.hpp  | 23 +++++++-
 alib2data/src/container/ObjectsSet.cpp        | 55 +++++++++++++++++++
 alib2data/src/container/ObjectsSet.h          | 47 ++++++++++++++++
 alib2data/src/object/Object.h                 |  3 +-
 alib2data/src/object/ObjectBase.h             | 12 +++-
 alib2data/src/object/ObjectFromXMLParser.cpp  |  3 +
 .../test-src/container/ContainerTest.cpp      | 48 ++++++++++++++++
 alib2data/test-src/container/ContainerTest.h  | 19 +++++++
 16 files changed, 362 insertions(+), 8 deletions(-)
 create mode 100644 alib2data/src/container/Container.h
 create mode 100644 alib2data/src/container/ContainerBase.h
 create mode 100644 alib2data/src/container/ContainerFeatures.h
 create mode 100644 alib2data/src/container/ContainerToXMLComposer.cpp
 create mode 100644 alib2data/src/container/ObjectsSet.cpp
 create mode 100644 alib2data/src/container/ObjectsSet.h
 create mode 100644 alib2data/test-src/container/ContainerTest.cpp
 create mode 100644 alib2data/test-src/container/ContainerTest.h

diff --git a/alib2data/src/Api.cpp b/alib2data/src/Api.cpp
index 32660945af..e07c77f7bb 100644
--- a/alib2data/src/Api.cpp
+++ b/alib2data/src/Api.cpp
@@ -27,9 +27,18 @@ const automaton::AutomatonToXMLComposer ToXMLComposers::automatonComposer;
 const grammar::GrammarToXMLComposer ToXMLComposers::grammarComposer;
 const alib::ObjectToXMLComposer ToXMLComposers::objectComposer;
 const exception::ExceptionToXMLComposer ToXMLComposers::exceptionComposer;
+const container::ContainerToXMLComposer ToXMLComposers::containerComposer;
 
 const ToXMLComposers ToXMLComposers::toXMLComposers;
 
+container::ObjectsSet api<container::ObjectsSet>::parse(std::list<sax::Token>& input) {
+	return FromXMLParsers::containerParser.parseObjectsSet(input);
+}
+
+std::list<sax::Token> api<container::ObjectsSet>::compose(const container::ObjectsSet& data) {
+	return ToXMLComposers::containerComposer.compose(data);
+}
+
 alib::Object api<alib::Object>::parse(std::list<sax::Token>& input) {
 	return FromXMLParsers::objectParser.parseObject(input);
 }
@@ -379,6 +388,10 @@ std::list<sax::Token> api<string::Epsilon>::compose(const string::Epsilon& data)
 	return ToXMLComposers::stringComposer.compose(data);
 }
 
+void ToXMLComposers::Visit(void* data, const container::ObjectsSet& container) const {
+	*((std::list<sax::Token>*) data) = std::move(ToXMLComposers::containerComposer.compose(container));
+}
+
 void ToXMLComposers::Visit(void* data, const exception::AlibException& symbol) const {
 	*((std::list<sax::Token>*) data) = std::move(ToXMLComposers::exceptionComposer.compose(symbol));
 }
diff --git a/alib2data/src/Api.hpp b/alib2data/src/Api.hpp
index 62d7caf187..093ef63e93 100644
--- a/alib2data/src/Api.hpp
+++ b/alib2data/src/Api.hpp
@@ -42,6 +42,12 @@ struct api<std::set<T>> {
 	static std::list<sax::Token> compose(const std::set<T>& data);
 };
 
+template<>
+struct api<container::ObjectsSet> {
+	static container::ObjectsSet parse(std::list<sax::Token>& input);
+	static std::list<sax::Token> compose(const container::ObjectsSet& data);
+};
+
 
 template<>
 struct api<alib::Object> {
@@ -378,6 +384,8 @@ class ToXMLComposers : public ObjectBase::const_visitor_type {
 	void Visit(void*, const string::CyclicString& string) const;
 	void Visit(void*, const string::Epsilon& string) const;
 
+	void Visit(void*, const container::ObjectsSet& set) const;
+
 public:
 	static const label::LabelToXMLComposer labelComposer;
 	static const alphabet::SymbolToXMLComposer symbolComposer;
@@ -399,7 +407,7 @@ std::set<T> api<std::set<T>>::parse(std::list<sax::Token>& input) {
 
 template<typename T>
 std::list<sax::Token> api<std::set<T>>::compose(const std::set<T>& input) {
-	return ToXMLComposers::containerComposer.composeSet<T>(input);
+	return ToXMLComposers::containerComposer.compose<T>(input);
 }
 
 } /* namespace alib */
diff --git a/alib2data/src/container/Container.h b/alib2data/src/container/Container.h
new file mode 100644
index 0000000000..3577d661e0
--- /dev/null
+++ b/alib2data/src/container/Container.h
@@ -0,0 +1,25 @@
+/*
+ * Container.h
+ *
+ *  Created on: Apr 10, 2013
+ *      Author: Martin Zak
+ */
+
+#ifndef CONTAINER_H_
+#define CONTAINER_H_
+
+#include "../std/visitor.hpp"
+#include "ContainerBase.h"
+#include "../common/wrapper.hpp"
+
+namespace container {
+
+/**
+ * Wrapper around automata.
+ */
+typedef alib::wrapper<ContainerBase> Container;
+
+} /* namespace container */
+
+#endif /* CONTAINER_H_ */
+
diff --git a/alib2data/src/container/ContainerBase.h b/alib2data/src/container/ContainerBase.h
new file mode 100644
index 0000000000..8d0057fccd
--- /dev/null
+++ b/alib2data/src/container/ContainerBase.h
@@ -0,0 +1,28 @@
+/*
+ * ContainerBase.h
+ *
+ *  Created on: Mar 26, 2013
+ *      Author: Jan Travnicek
+ */
+
+#ifndef CONTAINER_BASE_H_
+#define CONTAINER_BASE_H_
+
+#include "../common/base.hpp"
+#include "../object/ObjectBase.h"
+
+namespace container {
+
+/**
+ * Represents symbol in an container.
+ */
+class ContainerBase : public alib::ObjectBase {
+public:
+	virtual ContainerBase* clone() const = 0;
+	virtual ContainerBase* plunder() && = 0;
+
+};
+
+} /* namespace container */
+
+#endif /* CONTAINER_BASE_H_ */
diff --git a/alib2data/src/container/ContainerFeatures.h b/alib2data/src/container/ContainerFeatures.h
new file mode 100644
index 0000000000..05e5cf6dc0
--- /dev/null
+++ b/alib2data/src/container/ContainerFeatures.h
@@ -0,0 +1,19 @@
+/*
+ * ContainerFeatures.h
+ *
+ *  Created on: Jun 19, 2014
+ *      Author: Jan Travnicek
+ */
+
+#ifndef CONTAINER_FEATURES_H_
+#define CONTAINER_FEATURES_H_
+
+namespace container {
+
+enum class FEATURES {
+	SET
+};
+
+} /* namespace container */
+
+#endif /* CONTAINER_FEATURES_H_ */
diff --git a/alib2data/src/container/ContainerFromXMLParser.cpp b/alib2data/src/container/ContainerFromXMLParser.cpp
index 231a96c0fb..2164e1363d 100644
--- a/alib2data/src/container/ContainerFromXMLParser.cpp
+++ b/alib2data/src/container/ContainerFromXMLParser.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "ContainerFromXMLParser.hpp"
+#include "../sax/ParserException.h"
 
 namespace container {
 
@@ -17,5 +18,31 @@ bool ContainerFromXMLParser::first(std::list<sax::Token>& input) const {
 	}
 }
 
+Container ContainerFromXMLParser::parseContainer(std::list<sax::Token>& input) const {
+	return parseContainer(input, std::set<FEATURES>({FEATURES::SET}));
+}
+
+Container ContainerFromXMLParser::parseContainer(std::list<sax::Token>& input, const std::set<FEATURES>& features) const {
+	if(isToken(input, sax::Token::TokenType::START_ELEMENT, "set")) {
+		if(!features.count(FEATURES::SET)) throw exception::AlibException();
+		return Container(parseObjectsSet(input));
+	} else {
+		throw sax::ParserException(sax::Token("set", sax::Token::TokenType::START_ELEMENT), input.front());
+	}
+}
+
+ObjectsSet ContainerFromXMLParser::parseObjectsSet(std::list<sax::Token>& input) const {
+	popToken(input, sax::Token::TokenType::START_ELEMENT, "set");
+
+	ObjectsSet set;
+
+	while(isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
+		set.insert(alib::api<alib::Object>::parse(input));
+	}
+
+	popToken(input, sax::Token::TokenType::END_ELEMENT, "set");
+	return set;
+}
+
 } /* namespace automaton */
 
diff --git a/alib2data/src/container/ContainerFromXMLParser.hpp b/alib2data/src/container/ContainerFromXMLParser.hpp
index 44f56c797b..5bd06047e1 100644
--- a/alib2data/src/container/ContainerFromXMLParser.hpp
+++ b/alib2data/src/container/ContainerFromXMLParser.hpp
@@ -9,8 +9,12 @@
 #define CONTAINER_FROM_XML_PARSER_H_
 
 #include "../sax/FromXMLParserHelper.h"
+#include "ContainerFeatures.h"
 
 #include <set>
+#include "ObjectsSet.h"
+
+#include "Container.h"
 
 namespace alib {
 
@@ -31,15 +35,20 @@ namespace container {
  * Parser used to get general FSM or EpsilonNFA, NFA, DFA from XML parsed into list of Tokens.
  */
 class ContainerFromXMLParser : public sax::FromXMLParserHelper {
-public:
-	bool first(std::list<sax::Token>& input) const;
+	Container parseContainer(std::list<sax::Token>& input) const;
+	Container parseContainer(std::list<sax::Token>& input, const std::set<FEATURES>& features) const;
 
 	template<typename T>
 	std::set<T> parseSet(std::list<sax::Token>& input) const;
 
+	ObjectsSet parseObjectsSet(std::list<sax::Token>& input) const;
+
 	friend class alib::ObjectFromXMLParser;
 
 	template<typename T> friend class alib::api;
+
+public:
+	bool first(std::list<sax::Token>& input) const;
 };
 
 } /* namespace container */
diff --git a/alib2data/src/container/ContainerToXMLComposer.cpp b/alib2data/src/container/ContainerToXMLComposer.cpp
new file mode 100644
index 0000000000..1aea2bd67b
--- /dev/null
+++ b/alib2data/src/container/ContainerToXMLComposer.cpp
@@ -0,0 +1,25 @@
+/*
+ * ContainerToXMLComposer.cpp
+ *
+ *  Created on: Oct 12, 2013
+ *      Author: Jan Travnicek
+ */
+
+#include "ContainerToXMLComposer.hpp"
+
+namespace container {
+
+std::list<sax::Token> ContainerToXMLComposer::compose(const ObjectsSet& container) const {
+	std::list<sax::Token> out;
+	out.push_back(sax::Token("set", sax::Token::TokenType::START_ELEMENT));
+
+	for(const alib::Object& item : container) {
+		out.splice(out.end(), alib::api<alib::Object>::compose(item));
+	}
+
+	out.push_back(sax::Token("set", sax::Token::TokenType::END_ELEMENT));
+	return out;
+}
+
+} /* namespace container */
+
diff --git a/alib2data/src/container/ContainerToXMLComposer.hpp b/alib2data/src/container/ContainerToXMLComposer.hpp
index 0403151185..2deca9412d 100644
--- a/alib2data/src/container/ContainerToXMLComposer.hpp
+++ b/alib2data/src/container/ContainerToXMLComposer.hpp
@@ -12,6 +12,9 @@
 #include <set>
 #include "../sax/Token.h"
 
+#include "Container.h"
+#include "ObjectsSet.h"
+
 namespace alib {
 
 template<typename T>
@@ -26,8 +29,24 @@ namespace container {
  */
 class ContainerToXMLComposer {
 public:
+	/**
+	 * Prints XML representation of UnknownAutomaton to the output stream.
+	 * @param automaton automaton to print
+	 * @return list of xml tokens representing the automaton
+	 */
+	std::list<sax::Token> compose(const ContainerBase& symbol) const;
+
+	/**
+	 * Prints XML representation of String to the output stream.
+	 * @param string String to print
+	 * @param out output stream to which print the String
+	 */
+	std::list<sax::Token> compose(const Container& symbol) const;
+
 	template<typename T>
-	std::list<sax::Token> composeSet(const std::set<T>& container) const;
+	std::list<sax::Token> compose(const std::set<T>& container) const;
+
+	std::list<sax::Token> compose(const ObjectsSet& container) const;
 
 	template<typename T> friend class alib::api;
 };
@@ -39,7 +58,7 @@ public:
 namespace container {
 
 template<typename T>
-std::list<sax::Token> ContainerToXMLComposer::composeSet(const std::set<T>& container) const {
+std::list<sax::Token> ContainerToXMLComposer::compose(const std::set<T>& container) const {
 	std::list<sax::Token> out;
 	out.push_back(sax::Token("set", sax::Token::TokenType::START_ELEMENT));
 
diff --git a/alib2data/src/container/ObjectsSet.cpp b/alib2data/src/container/ObjectsSet.cpp
new file mode 100644
index 0000000000..c127b8a5ad
--- /dev/null
+++ b/alib2data/src/container/ObjectsSet.cpp
@@ -0,0 +1,55 @@
+/*
+ * Set.cpp
+ *
+ * Created on: Apr 1, 2013
+ * Author: Jan Travnicek
+ */
+
+#include "ObjectsSet.h"
+#include "../std/set.hpp"
+
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+
+namespace container {
+
+ContainerBase* ObjectsSet::clone() const {
+	return new ObjectsSet(*this);
+}
+
+ContainerBase* ObjectsSet::plunder() && {
+	return new ObjectsSet(std::move(*this));
+}
+
+bool ObjectsSet::operator==(const ObjectBase& other) const {
+	return other == *this;
+}
+
+bool ObjectsSet::operator<(const ObjectBase& other) const {
+	return other > *this;
+}
+
+bool ObjectsSet::operator>(const ObjectBase& other) const {
+	return other < *this;
+}
+
+bool ObjectsSet::operator==(const ObjectsSet& other) const {
+	return static_cast<const std::set<alib::Object>>(*this) == static_cast<const std::set<alib::Object>>(other);
+}
+
+bool ObjectsSet::operator<(const ObjectsSet& other) const {
+	return static_cast<const std::set<alib::Object>>(*this) < static_cast<const std::set<alib::Object>>(other);
+}
+
+void ObjectsSet::operator>>(std::ostream& os) const {
+	os << *this;
+}
+
+ObjectsSet::operator std::string() const {
+	std::stringstream ss;
+	ss << *this;
+	return std::move(ss).str();
+}
+
+} /* namespace container */
diff --git a/alib2data/src/container/ObjectsSet.h b/alib2data/src/container/ObjectsSet.h
new file mode 100644
index 0000000000..a5a98d46f9
--- /dev/null
+++ b/alib2data/src/container/ObjectsSet.h
@@ -0,0 +1,47 @@
+/*
+ * Set.h
+ *
+ * Created on: Apr 1, 2013
+ * Author: Jan Travnicek
+ */
+
+#ifndef SET_H_
+#define SET_H_
+
+#include <set>
+#include <string>
+
+#include "../object/Object.h"
+#include "ContainerBase.h"
+
+namespace container {
+
+/**
+ * Basic container from which are derived all other containers.
+ * Contains reason why the container occured.
+ */
+class ObjectsSet : public std::set<alib::Object>, public std::element<ObjectsSet, ContainerBase> {
+public:
+	virtual ContainerBase* clone() const;
+	
+	virtual ContainerBase* plunder() &&;
+
+	virtual bool operator>(const ObjectBase& other) const;
+	virtual bool operator==(const ObjectBase& other) const;
+	virtual bool operator<(const ObjectBase& other) const;
+
+	virtual bool operator==(const ObjectsSet& other) const;
+	virtual bool operator<(const ObjectsSet& other) const;
+
+	virtual void operator>>(std::ostream& os) const;
+
+	virtual operator std::string() const;
+
+	virtual int selfTypeId() const {
+		return typeId(*this);
+	}
+};
+
+} /* namespace container */
+
+#endif /* SET_H_ */
diff --git a/alib2data/src/object/Object.h b/alib2data/src/object/Object.h
index a41fa5c3f9..842528ea99 100644
--- a/alib2data/src/object/Object.h
+++ b/alib2data/src/object/Object.h
@@ -8,11 +8,12 @@
 #ifndef OBJECT_H_
 #define OBJECT_H_
 
-#include "ObjectBase.h"
 #include "../common/wrapper.hpp"
 
 namespace alib {
 
+class ObjectBase;
+
 /**
  * Wrapper around object.
  */
diff --git a/alib2data/src/object/ObjectBase.h b/alib2data/src/object/ObjectBase.h
index 62015e9d53..c888b34f8c 100644
--- a/alib2data/src/object/ObjectBase.h
+++ b/alib2data/src/object/ObjectBase.h
@@ -82,6 +82,12 @@ class EndSymbol;
 
 }
 
+namespace container {
+
+class ObjectsSet;
+
+}
+
 namespace alib {
 
 class ObjectBase :
@@ -93,7 +99,8 @@ class ObjectBase :
 			label::StringLabel, label::IntegerLabel, label::CharacterLabel,
 			regexp::UnboundedRegExp, regexp::FormalRegExp,
 			string::Epsilon, string::LinearString, string::CyclicString,
-			alphabet::LabeledSymbol, alphabet::BlankSymbol, alphabet::BottomOfTheStackSymbol, alphabet::EndSymbol
+			alphabet::LabeledSymbol, alphabet::BlankSymbol, alphabet::BottomOfTheStackSymbol, alphabet::EndSymbol,
+			container::ObjectsSet
 	>,
 	public std::elementBase<
 			exception::AlibException,
@@ -102,7 +109,8 @@ class ObjectBase :
 			label::StringLabel, label::IntegerLabel, label::CharacterLabel,
 			regexp::UnboundedRegExp, regexp::FormalRegExp,
 			string::Epsilon, string::LinearString, string::CyclicString,
-			alphabet::LabeledSymbol, alphabet::BlankSymbol, alphabet::BottomOfTheStackSymbol, alphabet::EndSymbol
+			alphabet::LabeledSymbol, alphabet::BlankSymbol, alphabet::BottomOfTheStackSymbol, alphabet::EndSymbol,
+			container::ObjectsSet
 	> {
 };
 
diff --git a/alib2data/src/object/ObjectFromXMLParser.cpp b/alib2data/src/object/ObjectFromXMLParser.cpp
index 662f31b3ff..33f387034e 100644
--- a/alib2data/src/object/ObjectFromXMLParser.cpp
+++ b/alib2data/src/object/ObjectFromXMLParser.cpp
@@ -38,6 +38,9 @@ Object ObjectFromXMLParser::parseObject(std::list<sax::Token>& input) const {
 	} else if(alib::FromXMLParsers::grammarParser.first(input)) {
 		grammar::Grammar grammar = alib::FromXMLParsers::grammarParser.parseGrammar(input);
 		tmp = std::move(grammar.getData()).plunder();
+	} else if(alib::FromXMLParsers::containerParser.first(input)) {
+		container::Container container = alib::FromXMLParsers::containerParser.parseContainer(input);
+		tmp = std::move(container.getData()).plunder();
 	} else {
 		throw exception::AlibException("Unknown element in xml");
 	}
diff --git a/alib2data/test-src/container/ContainerTest.cpp b/alib2data/test-src/container/ContainerTest.cpp
new file mode 100644
index 0000000000..5d257af03d
--- /dev/null
+++ b/alib2data/test-src/container/ContainerTest.cpp
@@ -0,0 +1,48 @@
+#include <list>
+#include "ContainerTest.h"
+
+#include "sax/SaxParseInterface.h"
+#include "sax/SaxComposeInterface.h"
+
+#include "object/Object.h"
+#include "container/ObjectsSet.h"
+#include "alphabet/LabeledSymbol.h"
+
+#include "factory/DataFactory.hpp"
+
+#include "label/StringLabel.h"
+#include "label/Label.h"
+
+#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y))
+#define CPPUNIT_EXCLUSIVE_OR(x, y) CPPUNIT_ASSERT((!(x) && (y)) || ((x) && !(y)))
+
+CPPUNIT_TEST_SUITE_REGISTRATION( ContainerTest );
+
+void ContainerTest::setUp() {
+}
+
+void ContainerTest::tearDown() {
+}
+
+void ContainerTest::testXMLParser() {
+
+  alib::Object tmp(alphabet::LabeledSymbol(label::Label(label::StringLabel("1"))));
+
+  container::ObjectsSet set;
+  set.insert(tmp);
+
+  alib::Object object(set);
+
+  {
+	std::string tmp = alib::DataFactory::toString(object);
+	alib::Object object2 = alib::DataFactory::fromString<alib::Object>(tmp);
+  
+	CPPUNIT_ASSERT( object == object2 );
+
+	std::set<alphabet::LabeledSymbol> concrete = alib::DataFactory::fromString<std::set<alphabet::LabeledSymbol>>(tmp);
+	std::string tmp2 = alib::DataFactory::toString(concrete);
+
+	CPPUNIT_ASSERT( tmp == tmp2 );
+  }
+}
+
diff --git a/alib2data/test-src/container/ContainerTest.h b/alib2data/test-src/container/ContainerTest.h
new file mode 100644
index 0000000000..b13ecd5be4
--- /dev/null
+++ b/alib2data/test-src/container/ContainerTest.h
@@ -0,0 +1,19 @@
+#ifndef CONTAINER_TEST_H_
+#define CONTAINER_TEST_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class ContainerTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE( ContainerTest );
+  CPPUNIT_TEST( testXMLParser );
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+  void setUp();
+  void tearDown();
+
+  void testXMLParser();
+};
+
+#endif  // CONTAINER_TEST_H_
-- 
GitLab