From b1d017792a085c9650b75be922eb2a5f2eb538f9 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Wed, 16 Jul 2014 08:41:45 +0200
Subject: [PATCH] change std::variant to have specific constructors

---
 .../src/automaton/AutomatonFromXMLParser.cpp  | 26 +++--
 alib2data/src/automaton/FSM/EpsilonNFA.cpp    | 15 +--
 .../FSM/FiniteAutomatonFromStringParser.cpp   |  5 +-
 alib2data/src/automaton/PDA/NPDA.cpp          | 12 +--
 alib2data/src/automaton/PDA/SinglePopNPDA.cpp | 12 +--
 alib2data/src/std/variant.hpp                 | 96 ++++++++++---------
 alib2data/test-src/std/StdTest.cpp            | 18 ++--
 alib2data/test-src/std/StdTest.h              |  8 +-
 8 files changed, 94 insertions(+), 98 deletions(-)

diff --git a/alib2data/src/automaton/AutomatonFromXMLParser.cpp b/alib2data/src/automaton/AutomatonFromXMLParser.cpp
index 26a3da3e79..1733f7e722 100644
--- a/alib2data/src/automaton/AutomatonFromXMLParser.cpp
+++ b/alib2data/src/automaton/AutomatonFromXMLParser.cpp
@@ -526,35 +526,33 @@ alphabet::Symbol AutomatonFromXMLParser::parseTransitionOutputSymbol(std::list<s
 std::variant<string::Epsilon, alphabet::Symbol> AutomatonFromXMLParser::parseTransitionInputEpsilonSymbol(std::list<sax::Token>& input) const {
 	popToken(input, sax::Token::TokenType::START_ELEMENT, "input");
 	
-	std::variant<string::Epsilon, alphabet::Symbol> result;
 	if(isToken(input, sax::Token::TokenType::START_ELEMENT, "epsilon")) {
-		result.set<string::Epsilon>(string::Epsilon());
+		std::variant<string::Epsilon, alphabet::Symbol> result(string::Epsilon::EPSILON);
 		input.pop_front();
 		popToken(input, sax::Token::TokenType::END_ELEMENT, "epsilon");
+		popToken(input, sax::Token::TokenType::END_ELEMENT, "input");
+		return result;
 	} else {
-		result.set<alphabet::Symbol>(alib::FromXMLParsers::symbolParser.parse(input));
+		std::variant<string::Epsilon, alphabet::Symbol> result(alib::FromXMLParsers::symbolParser.parse(input));
+		popToken(input, sax::Token::TokenType::END_ELEMENT, "input");
+		return result;
 	}
-	
-	popToken(input, sax::Token::TokenType::END_ELEMENT, "input");
-	
-	return result;
 }
 
 std::variant<string::Epsilon, alphabet::Symbol> AutomatonFromXMLParser::parseTransitionOutputEpsilonSymbol(std::list<sax::Token>& input) const {
 	popToken(input, sax::Token::TokenType::START_ELEMENT, "output");
 	
-	std::variant<string::Epsilon, alphabet::Symbol> result;
 	if(isToken(input, sax::Token::TokenType::START_ELEMENT, "epsilon")) {
-		result.set<string::Epsilon>(string::Epsilon());
+		std::variant<string::Epsilon, alphabet::Symbol> result(string::Epsilon::EPSILON);
 		input.pop_front();
 		popToken(input, sax::Token::TokenType::END_ELEMENT, "epsilon");
+		popToken(input, sax::Token::TokenType::END_ELEMENT, "output");
+		return result;
 	} else {
-		result.set<alphabet::Symbol>(alib::FromXMLParsers::symbolParser.parse(input));
+		std::variant<string::Epsilon, alphabet::Symbol> result(alib::FromXMLParsers::symbolParser.parse(input));
+		popToken(input, sax::Token::TokenType::END_ELEMENT, "output");
+		return result;
 	}
-	
-	popToken(input, sax::Token::TokenType::END_ELEMENT, "output");
-	
-	return result;
 }
 
 string::String AutomatonFromXMLParser::parseTransitionInputString(std::list<sax::Token>& input) const {
diff --git a/alib2data/src/automaton/FSM/EpsilonNFA.cpp b/alib2data/src/automaton/FSM/EpsilonNFA.cpp
index d1afbb8211..79a1268dac 100644
--- a/alib2data/src/automaton/FSM/EpsilonNFA.cpp
+++ b/alib2data/src/automaton/FSM/EpsilonNFA.cpp
@@ -38,8 +38,7 @@ bool EpsilonNFA::removeState(const State& state) {
 }
 
 bool EpsilonNFA::removeInputSymbol(const alphabet::Symbol& symbol) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<alphabet::Symbol>(symbol);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(symbol);
 	for (std::map<std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> >, std::set<State> >::const_iterator transition = transitions.begin(); transition != transitions.end();
 			transition++) {
 		if (transition->first.second.is<alphabet::Symbol>() && transition->first.second.get<alphabet::Symbol>() == symbol)
@@ -66,28 +65,24 @@ bool EpsilonNFA::addTransition(const State& from, const std::variant<string::Eps
 }
 
 bool EpsilonNFA::addTransition(const State& from, const alphabet::Symbol& input, const State& to) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<alphabet::Symbol>(input);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(input);
 	return addTransition(from, inputVariant, to);
 }
 
 bool EpsilonNFA::addTransition(const State& from, const State& to) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<string::Epsilon>(string::Epsilon());
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(string::Epsilon::EPSILON);
 	return addTransition(from, inputVariant, to);
 }
 
 bool EpsilonNFA::removeTransition(const State& from, const alphabet::Symbol& input, const State& to) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<alphabet::Symbol>(input);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(input);
 	std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> > key = std::make_pair(from, inputVariant);
 	
 	return transitions[key].erase(to);
 }
 
 bool EpsilonNFA::removeTransition(const State& from, const State& to) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<string::Epsilon>(string::Epsilon());
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(string::Epsilon::EPSILON);
 	std::pair<State, std::variant<string::Epsilon, alphabet::Symbol> > key = std::make_pair(from, inputVariant);
 	
 	return transitions[key].erase(to);
diff --git a/alib2data/src/automaton/FSM/FiniteAutomatonFromStringParser.cpp b/alib2data/src/automaton/FSM/FiniteAutomatonFromStringParser.cpp
index 70d029ac27..d3b7ea50f1 100644
--- a/alib2data/src/automaton/FSM/FiniteAutomatonFromStringParser.cpp
+++ b/alib2data/src/automaton/FSM/FiniteAutomatonFromStringParser.cpp
@@ -78,11 +78,10 @@ EpsilonNFA FiniteAutomatonFromStringParser::parseEpsilonNFA() {
 			alphabet::Symbol symbol = m_SymbolParser.parse();
 			res.addInputSymbol(symbol);
 
-			std::variant<string::Epsilon, alphabet::Symbol> symbolVariant;
-			symbolVariant.set<alphabet::Symbol>(symbol);
+			std::variant<string::Epsilon, alphabet::Symbol> symbolVariant(symbol);
 			symbols.push_back(symbolVariant);
 		} else if(token.type == FiniteAutomatonFromStringLexer::TokenType::EPSILON) {
-			symbols.push_back(std::variant<string::Epsilon, alphabet::Symbol>());
+			symbols.push_back(std::variant<string::Epsilon, alphabet::Symbol>(string::Epsilon::EPSILON));
 		}
 
 		next() || m_SymbolParser.first() || m_SymbolParser.m_LabelParser.first();
diff --git a/alib2data/src/automaton/PDA/NPDA.cpp b/alib2data/src/automaton/PDA/NPDA.cpp
index 2c8f99eaa1..5c498c2b3b 100644
--- a/alib2data/src/automaton/PDA/NPDA.cpp
+++ b/alib2data/src/automaton/PDA/NPDA.cpp
@@ -102,14 +102,12 @@ bool NPDA::addTransition(const State& from, const std::variant<string::Epsilon,
 }
 
 bool NPDA::addTransition(const State& from, const alphabet::Symbol& input, const std::vector<alphabet::Symbol>& pop, const State& to, const std::vector<alphabet::Symbol>& push) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<alphabet::Symbol>(input);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(input);
 	return addTransition(from, inputVariant, pop, to, push);
 }
 
 bool NPDA::addTransition(const State& from, const std::vector<alphabet::Symbol>& pop, const State& to, const std::vector<alphabet::Symbol>& push) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<string::Epsilon>(string::Epsilon::EPSILON);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(string::Epsilon::EPSILON);
 	return addTransition(from, inputVariant, pop, to, push);
 }
 
@@ -121,14 +119,12 @@ bool NPDA::removeTransition(const State& from, const std::variant<string::Epsilo
 }
 
 bool NPDA::removeTransition(const State& from, const alphabet::Symbol& input, const std::vector<alphabet::Symbol>& pop, const State& to, const std::vector<alphabet::Symbol>& push) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<alphabet::Symbol>(input);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(input);
 	return removeTransition(from, inputVariant, pop, to, push);
 }
 
 bool NPDA::removeTransition(const State& from, const std::vector<alphabet::Symbol>& pop, const State& to, const std::vector<alphabet::Symbol>& push) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<string::Epsilon>(string::Epsilon::EPSILON);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(string::Epsilon::EPSILON);
 	return removeTransition(from, inputVariant, pop, to, push);
 }
 
diff --git a/alib2data/src/automaton/PDA/SinglePopNPDA.cpp b/alib2data/src/automaton/PDA/SinglePopNPDA.cpp
index 5deb686a79..f11d563453 100644
--- a/alib2data/src/automaton/PDA/SinglePopNPDA.cpp
+++ b/alib2data/src/automaton/PDA/SinglePopNPDA.cpp
@@ -98,14 +98,12 @@ bool SinglePopNPDA::addTransition(const State& from, const std::variant<string::
 }
 
 bool SinglePopNPDA::addTransition(const State& from, const alphabet::Symbol& input, const alphabet::Symbol& pop, const State& to, const std::vector<alphabet::Symbol>& push) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<alphabet::Symbol>(input);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(input);
 	return addTransition(from, inputVariant, pop, to, push);
 }
 
 bool SinglePopNPDA::addTransition(const State& from, const alphabet::Symbol& pop, const State& to, const std::vector<alphabet::Symbol>& push) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<string::Epsilon>(string::Epsilon::EPSILON);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(string::Epsilon::EPSILON);
 	return addTransition(from, inputVariant, pop, to, push);
 }
 
@@ -117,14 +115,12 @@ bool SinglePopNPDA::removeTransition(const State& from, const std::variant<strin
 }
 
 bool SinglePopNPDA::removeTransition(const State& from, const alphabet::Symbol& input, const alphabet::Symbol& pop, const State& to, const std::vector<alphabet::Symbol>& push) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<alphabet::Symbol>(input);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(input);
 	return removeTransition(from, inputVariant, pop, to, push);
 }
 
 bool SinglePopNPDA::removeTransition(const State& from, const alphabet::Symbol& pop, const State& to, const std::vector<alphabet::Symbol>& push) {
-	std::variant<string::Epsilon, alphabet::Symbol> inputVariant;
-	inputVariant.set<string::Epsilon>(string::Epsilon::EPSILON);
+	std::variant<string::Epsilon, alphabet::Symbol> inputVariant(string::Epsilon::EPSILON);
 	return removeTransition(from, inputVariant, pop, to, push);
 }
 
diff --git a/alib2data/src/std/variant.hpp b/alib2data/src/std/variant.hpp
index 8892d3419d..cc6d293d8b 100644
--- a/alib2data/src/std/variant.hpp
+++ b/alib2data/src/std/variant.hpp
@@ -45,22 +45,13 @@ struct variant_helper<F, Ts...> {
 			variant_helper<Ts...>::destroy(id, data);
 	}
 
-	inline static bool move(size_t old_t, void * old_v, void * new_v)
-	{
-		if (old_t == typeid(F).hash_code()) {
-			new (new_v) F(std::move(*reinterpret_cast<F*>(old_v)));
-			return true;
-		} else
-			return variant_helper<Ts...>::move(old_t, old_v, new_v);
-	}
-
 	inline static void copy(size_t old_t, const void * old_v, void * new_v)
 	{
 		if (old_t == typeid(F).hash_code())
 			new (new_v) F(*reinterpret_cast<const F*>(old_v));
 		else
 			return variant_helper<Ts...>::copy(old_t, old_v, new_v);
-	}   
+	}
 	
 	inline static bool compareEq(size_t this_t, const void * this_v, size_t other_t, const void * other_v)
 	{
@@ -93,49 +84,66 @@ struct variant_helper<F, Ts...> {
 
 template<> struct variant_helper<>  {
 inline static void destroy(size_t, void *) { }
-inline static bool move(size_t, void *, void *) { return false; }
 inline static void copy(size_t, const void *, void *) { }
 inline static bool compareEq(size_t, const void *, size_t, const void *) { return true; }
 inline static void print(ostream&, const size_t, const void *) {}
 inline static bool compareLess(size_t, const void *, size_t, const void *) { return false; }
 };
 
-template<typename F, typename... Ts>
-struct variant {
-private:
-	static const size_t data_size = static_max<sizeof(F), sizeof(Ts)...>::value;
-	static const size_t data_align = static_max<alignof(F), alignof(Ts)...>::value;
+template<typename ST, typename AT, typename... Ts>
+class variant_base;
 
-	using data_t = typename std::aligned_storage<data_size, data_align>::type;
+template<typename ST, typename AT>
+class variant_base<ST, AT> {
+	static const size_t data_size = ST::value;
+	static const size_t data_align = AT::value;
 
-	using helper_t = variant_helper<F, Ts...>;
+	using data_t = typename std::aligned_storage<data_size, data_align>::type;
+protected:
 
 	size_t type_id;
 	data_t data;
-public: 
-	//default constructor
-	variant() : type_id(typeid(F).hash_code()) { new (&data) F(); }
+
+	variant_base() { this->type_id = 0; }
+};
+
+template<typename ST, typename AT, typename F, typename... Ts>
+class variant_base<ST, AT, F, Ts...> : public variant_base<ST, AT, Ts...> {
+protected:
+	variant_base() { this->type_id = 0; }
+public:
+	using variant_base<ST, AT, Ts...>::variant_base;
+
+	variant_base(const F& value) { this->type_id = typeid(F).hash_code(); new (&this->data) F(value); }
+	variant_base(F&& value) { this->type_id = typeid(F).hash_code(); new (&this->data) F(std::move(value)); }
+};
+
+template<typename F, typename... Ts>
+class variant : public variant_base<static_max<sizeof(F), sizeof(Ts)...>, static_max<alignof(F), alignof(Ts)...>, F, Ts...> {
+	using helper_t = variant_helper<F, Ts...>;
+
+public:
+	using variant_base<static_max<sizeof(F), sizeof(Ts)...>, static_max<alignof(F), alignof(Ts)...>, F, Ts...>::variant_base;
 
 	//copy consructor
-	variant(const variant<F, Ts...>& old) : type_id(old.type_id)
+	variant(const variant<F, Ts...>& old) : variant_base<static_max<sizeof(F), sizeof(Ts)...>, static_max<alignof(F), alignof(Ts)...>, F, Ts...>()
 	{
-		helper_t::copy(old.type_id, &old.data, &data);
+		this->type_id = old.type_id;
+		helper_t::copy(old.type_id, &old.data, &this->data);
 	}
 
 	//move constructor
-	variant(variant<F, Ts...>&& old) : type_id(old.type_id)
+	variant(variant<F, Ts...>&& old) : variant_base<static_max<sizeof(F), sizeof(Ts)...>, static_max<alignof(F), alignof(Ts)...>, F, Ts...>()
 	{
-		helper_t::move(old.type_id, &old.data, &data);
-		
-		new (&old.data) F();
-		old.type_id = typeid(F).hash_code();
+		std::swap(this->type_id, old.type_id);
+		std::swap(this->data, old.data);
 	}
 
 	//assignment operator
 	variant<F, Ts...>& operator= (variant<F, Ts...> old)
 	{
-		std::swap(type_id, old.type_id);
-		std::swap(data, old.data);
+		std::swap(this->type_id, old.type_id);
+		std::swap(this->data, old.data);
 
 		return *this;
 	}
@@ -143,7 +151,7 @@ public:
 
 	bool operator== (const variant<F, Ts...>& other) const
 	{
-		return helper_t::compareEq(type_id, &data, other.type_id, &other.data);
+		return helper_t::compareEq(this->type_id, &this->data, other.type_id, &other.data);
 	}
 
 	bool operator!= (const variant<F, Ts...>& other) const
@@ -153,7 +161,7 @@ public:
 
 	bool operator< (const variant<F, Ts...>& other) const
 	{
-		return helper_t::compareLess(type_id, &data, other.type_id, &other.data);
+		return helper_t::compareLess(this->type_id, &this->data, other.type_id, &other.data);
 	}
 
 	bool operator> (const variant<F, Ts...>& other) const
@@ -173,16 +181,16 @@ public:
 
 	template<typename T>
 	bool is() const {
-		return (type_id == typeid(T).hash_code());
+		return (this->type_id == typeid(T).hash_code());
 	}
 
 	template<typename T>
 	void set(T&& value)
 	{
 		if(std::is_base_of_any<T, F, Ts...>::value) {
-			helper_t::destroy(type_id, &data);
-			new (&data) T(value);
-			type_id = typeid(T).hash_code();
+			helper_t::destroy(this->type_id, &this->data);
+			new (&this->data) T(value);
+			this->type_id = typeid(T).hash_code();
 		} else
 			throw std::bad_cast();
 	}
@@ -191,9 +199,9 @@ public:
 	void set(const T& value)
 	{
 		if(std::is_base_of_any<T, F, Ts...>::value) {
-			helper_t::destroy(type_id, &data);
-			new (&data) T(value);
-			type_id = typeid(T).hash_code();
+			helper_t::destroy(this->type_id, &this->data);
+			new (&this->data) T(std::move(value));
+			this->type_id = typeid(T).hash_code();
 		} else
 			throw std::bad_cast();
 	}
@@ -202,8 +210,8 @@ public:
 	T& get()
 	{
 		// It is a dynamic_cast-like behaviour
-		if (type_id == typeid(T).hash_code())
-			return *reinterpret_cast<T*>(&data);
+		if (this->type_id == typeid(T).hash_code())
+			return *reinterpret_cast<T*>(&this->data);
 		else
 			throw std::bad_cast();
 	}
@@ -212,14 +220,14 @@ public:
 	const T& get() const
 	{
 		// It is a dynamic_cast-like behaviour
-		if (type_id == typeid(T).hash_code())
-			return *reinterpret_cast<const T*>(&data);
+		if (this->type_id == typeid(T).hash_code())
+			return *reinterpret_cast<const T*>(&this->data);
 		else
 			throw std::bad_cast();
 	}
 
 	~variant() {
-		helper_t::destroy(type_id, &data);
+		helper_t::destroy(this->type_id, &this->data);
 	}
 
 	friend std::ostream& operator <<(std::ostream& out, const variant<F, Ts...>& obj) {
diff --git a/alib2data/test-src/std/StdTest.cpp b/alib2data/test-src/std/StdTest.cpp
index fd61201ee1..4abf600248 100644
--- a/alib2data/test-src/std/StdTest.cpp
+++ b/alib2data/test-src/std/StdTest.cpp
@@ -18,9 +18,7 @@ void StdTest::testIsBaseOf() {
 }
 
 void StdTest::testVariant() {
-	std::variant<int, std::string, StdTest::test> d;
- 
-	d.set<int>(10);
+	std::variant<int, std::string, StdTest::test> d(10);
 	CPPUNIT_ASSERT( d.is<int>() );
 	CPPUNIT_ASSERT( d.get<int>() == 10 );
 	
@@ -47,7 +45,7 @@ void StdTest::testVariant() {
 	
 	CPPUNIT_ASSERT( (e == d) == false );
 	
-	d = std::variant<int, std::string, StdTest::test>();
+	d = std::variant<int, std::string, StdTest::test>(0);
 	d = e;
 
 	CPPUNIT_ASSERT( *(d.get<StdTest::test>().holder) == 43 );
@@ -64,16 +62,13 @@ void StdTest::testVariantSet() {
 	
 	std::string str = "abcde";
 	
-	std::variant<int, std::string, StdTest::test> d;
-	d.set<StdTest::test>(StdTest::test());
+	std::variant<int, std::string, StdTest::test> d(StdTest::test {});
 	*(d.get<StdTest::test>().holder) = 42;
 	std::variant<int, std::string, StdTest::test> e(d);
 	
-	std::variant<int, std::string, StdTest::test> f;
-	f.set<int>(5);
+	std::variant<int, std::string, StdTest::test> f(5);
 	
-	std::variant<int, std::string, StdTest::test> g;
-	g.set<std::string>(str);
+	std::variant<int, std::string, StdTest::test> g(str);
 	
 	std::set<std::variant<int, std::string, StdTest::test>> testSet;
 	testSet.insert(d);
@@ -91,4 +86,7 @@ void StdTest::testVariantSet() {
 		if(iter->is<StdTest::test>())
 			CPPUNIT_ASSERT( iter->get<StdTest::test>() == tmp );
 	}
+	
+	std::variant<StdTest::test2, std::string, StdTest::test> h("aa");
+	CPPUNIT_ASSERT( h.is<std::string>() );
 }
diff --git a/alib2data/test-src/std/StdTest.h b/alib2data/test-src/std/StdTest.h
index ae59094523..14911a15fc 100644
--- a/alib2data/test-src/std/StdTest.h
+++ b/alib2data/test-src/std/StdTest.h
@@ -49,6 +49,12 @@ struct test {
 	}
 };
 
+struct test2 {
+	int i;
+
+	test2(int i) : i(i) {}
+};
+
 public:
   void setUp();
   void tearDown();
@@ -58,4 +64,4 @@ public:
   void testVariantSet();
 };
 
-#endif  // VARIANT_TEST_H_
\ No newline at end of file
+#endif  // VARIANT_TEST_H_
-- 
GitLab