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