From d5602a1b8df44e0b96098afc7e5feb0e5ebfe097 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Thu, 6 Sep 2018 10:45:54 +0200
Subject: [PATCH] simplify variant for single type

---
 alib2std/src/extensions/container/variant.hpp | 483 ++++++++++++++++--
 .../extensions/container/VariantTest.cpp      |   8 +-
 2 files changed, 456 insertions(+), 35 deletions(-)

diff --git a/alib2std/src/extensions/container/variant.hpp b/alib2std/src/extensions/container/variant.hpp
index 166824e23e..6783fdc094 100644
--- a/alib2std/src/extensions/container/variant.hpp
+++ b/alib2std/src/extensions/container/variant.hpp
@@ -477,7 +477,7 @@ public:
 	 *
 	 * \param old the source instance
 	 */
-	variant(const variant<Ts...>& old) : variant_base < max ( SizeOf < Ts >::size ... ), max ( AlignOf < Ts >::align ... ), Ts...> ( old.type_id ) {
+	variant ( const variant < Ts ... > & old ) : variant_base < max ( SizeOf < Ts >::size ... ), max ( AlignOf < Ts >::align ... ), Ts...> ( old.type_id ) {
 		helper_t::copy(old.type_id, &old.data, &this->data);
 	}
 
@@ -487,7 +487,7 @@ public:
 	 *
 	 * \param old the source instance
 	 */
-	variant(variant<Ts...>&& old) noexcept : variant_base < max ( SizeOf < Ts >::size ... ), max ( AlignOf < Ts >::align ... ), Ts...> ( old.type_id ) {
+	variant ( variant < Ts ... > && old ) noexcept : variant_base < max ( SizeOf < Ts >::size ... ), max ( AlignOf < Ts >::align ... ), Ts...> ( old.type_id ) {
 		helper_t::move(old.type_id, &old.data, &this->data);
 	}
 
@@ -499,8 +499,8 @@ public:
 	 *
 	 * \return the modified target instance
 	 */
-	variant<Ts...>& operator =( const variant<Ts...> & other ) {
-		return this->operator =( variant <Ts...> ( other ) );
+	variant < Ts ... > & operator = ( const variant < Ts ... > & other ) {
+		return this->operator =( variant < Ts ... > ( other ) );
 	}
 
 	/**
@@ -511,7 +511,7 @@ public:
 	 *
 	 * \return the modified target instance
 	 */
-	variant<Ts...>& operator= (variant<Ts...> && old) noexcept {
+	variant < Ts ... > & operator = ( variant < Ts ... > && old ) noexcept {
 		helper_t::destroy(this->type_id, &this->data);
 		helper_t::move(old.type_id, &old.data, &this->data);
 		this->type_id = old.type_id;
@@ -527,7 +527,7 @@ public:
 	 *
 	 * \return true if compared values are the same, false othervise
 	 */
-	bool operator== (const variant<Ts...>& other) const {
+	bool operator == ( const variant < Ts ... > & other ) const {
 		return compare ( other ) == 0;
 	}
 
@@ -539,7 +539,7 @@ public:
 	 *
 	 * \return true if compared values are not the same, false othervise
 	 */
-	bool operator!= (const variant<Ts...>& other) const {
+	bool operator != ( const variant < Ts ... > & other ) const {
 		return !(*this == other);
 	}
 
@@ -551,7 +551,7 @@ public:
 	 *
 	 * \return true if this is smaller than the other instance, false othervise
 	 */
-	bool operator< (const variant<Ts...>& other) const {
+	bool operator < ( const variant < Ts ... > & other ) const {
 		return compare ( other ) < 0;
 	}
 
@@ -563,7 +563,7 @@ public:
 	 *
 	 * \return true if this is greater than the other instance, false othervise
 	 */
-	bool operator> (const variant<Ts...>& other) const {
+	bool operator > ( const variant < Ts ... > & other ) const {
 		return other < *this;
 	}
 
@@ -575,7 +575,7 @@ public:
 	 *
 	 * \return true if this is smaller than or the same as the other instance, false othervise
 	 */
-	bool operator<= (const variant<Ts...>& other) const {
+	bool operator <= ( const variant < Ts ... > & other ) const {
 		return !(*this > other);
 	}
 
@@ -587,7 +587,7 @@ public:
 	 *
 	 * \return true if this is greater than or the same as the other instance, false othervise
 	 */
-	bool operator>= (const variant<Ts...>& other) const {
+	bool operator >= ( const variant < Ts ... > & other ) const {
 		return !(*this < other);
 	}
 
@@ -599,7 +599,7 @@ public:
 	 *
 	 * \return negative value if this is smaller than the other instance, positive if this is greater than the other instance, zero othervise
 	 */
-	int compare(const variant<Ts...>& other) const {
+	int compare ( const variant < Ts ... > & other ) const {
 		if (this->type_id < other.type_id) return -1;
 		if (this->type_id > other.type_id) return 1;
 
@@ -670,10 +670,10 @@ public:
 	 * \throws bad_cast exception if the variant stores different type than specified
 	 */
 	template < typename T >
-	typename std::enable_if < ext::is_in<T, Ts...>::value && ! std::is_same < void, T >::value, T >::type & get ( ) {
+	typename std::enable_if < ext::is_in<T, Ts...>::value && ! std::is_same < void, T >::value, T >::type & get ( ) & {
 		// It is a dynamic_cast-like behaviour
-		if (this->type_id == ext::type_index ( typeid ( T ) ))
-			return *reinterpret_cast<T*>(&this->data);
+		if ( this->type_id == ext::type_index ( typeid ( T ) ) )
+			return * reinterpret_cast < T * > ( & this->data );
 		else
 			throw std::bad_cast();
 	}
@@ -689,19 +689,34 @@ public:
 	 * \throws bad_cast exception if the variant stores different type than specified
 	 */
 	template<typename T >
-	const typename std::enable_if < ext::is_in<T, Ts...>::value && ! std::is_same < void, T >::value, T >::type& get ( ) const {
+	const typename std::enable_if < ext::is_in<T, Ts...>::value && ! std::is_same < void, T >::value, T >::type && get ( ) const & {
 		// It is a dynamic_cast-like behaviour
-		if (this->type_id == ext::type_index ( typeid ( T ) ))
-			return *reinterpret_cast<const T*>(&this->data);
+		if ( this->type_id == ext::type_index ( typeid ( T ) ) )
+			return std::move ( * reinterpret_cast < const T * > ( & this->data ) );
 		else
 			throw std::bad_cast();
 	}
 
+	/**
+	 * \brief
+	 * Allows to retrieve a value from the variant.
+	 *
+	 * \tparam T the type of the value to retrieve
+	 *
+	 * \return value retrieved from the variant
+	 *
+	 * \throws bad_cast exception if the variant stores different type than specified
+	 */
+	template < typename T >
+	typename std::enable_if < ext::is_in<T, Ts...>::value && ! std::is_same < void, T >::value, T >::type && get ( ) && {
+		return std::move ( this->get < T > ( ) );
+	}
+
 	/**
 	 * \brief
 	 * Destructor of the variant.
 	 */
-	~variant() noexcept {
+	~variant ( ) noexcept {
 		helper_t::destroy(this->type_id, &this->data);
 	}
 
@@ -714,7 +729,7 @@ public:
 	 *
 	 * \return the output stream from the \p out
 	 */
-	friend std::ostream& operator <<(std::ostream& out, const variant<Ts...>& obj) {
+	friend std::ostream & operator << ( std::ostream & out, const variant < Ts ... > & obj ) {
 		helper_t::print(out, obj.type_id, &obj.data);
 		return out;
 	}
@@ -739,7 +754,7 @@ public:
 	 */
 	template < typename T >
 	static typename std::enable_if < ! std::is_same < void, T >::value, variant < Ts ... > >::type from ( ) {
-		return variant < Ts ... >( T { } );
+		return variant < Ts ... > ( T { } );
 	}
 
 	/**
@@ -756,6 +771,398 @@ public:
 	}
 };
 
+/**
+ * \brief
+ * Implementation of the variant class allowing to store any type of those listed in the template parameters. Void type is allowed, multiply specified same type is irrelevant.
+ *
+ * \tparam Ts ... pack of allowed types.
+ */
+template < typename T >
+class variant < T > {
+	T m_value;
+
+public:
+	/**
+	 * \brief
+	 * Alows construction of the variant based on const referenced value of type F.
+	 *
+	 * \param value the value to base the variant content on
+	 */
+	variant ( const T & value ) : m_value ( value ) {
+	}
+
+	/**
+	 * \brief
+	 * Alows construction of the variant based on rvalue referenced value of type F.
+	 *
+	 * \param value the value to base the variant content on
+	 */
+	variant ( T && value ) : m_value ( std::move ( value ) ) {
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of equality operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if compared values are the same, false othervise
+	 */
+	bool operator == ( const variant < T > & other ) const {
+		return compare ( other ) == 0;
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of non-equality operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if compared values are not the same, false othervise
+	 */
+	bool operator != ( const variant < T > & other ) const {
+		return !(*this == other);
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of less than operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if this is smaller than the other instance, false othervise
+	 */
+	bool operator < ( const variant < T > & other ) const {
+		return compare ( other ) < 0;
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of more than operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if this is greater than the other instance, false othervise
+	 */
+	bool operator > ( const variant < T > & other ) const {
+		return other < *this;
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of less than or equal operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if this is smaller than or the same as the other instance, false othervise
+	 */
+	bool operator <= ( const variant < T > & other ) const {
+		return !(*this > other);
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of greater than or equal operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if this is greater than or the same as the other instance, false othervise
+	 */
+	bool operator >= ( const variant < T > & other ) const {
+		return !(*this < other);
+	}
+
+	/**
+	 * \brief
+	 * Implementation of the three way comparison for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return negative value if this is smaller than the other instance, positive if this is greater than the other instance, zero othervise
+	 */
+	int compare ( const variant < T > & other ) const {
+		static ext::compare < typename std::decay < T >::type > comp;
+		return comp ( m_value, other.m_value );
+	}
+
+	/**
+	 * \brief
+	 * Function to test whether the variant currently contains type T.
+	 *
+	 * \tparam T the type to test
+	 *
+	 * \return true it the variant contains instance of type T
+	 */
+	template < typename F, typename std::enable_if < std::is_same < F, T >::value >::type * = nullptr >
+	bool is ( ) const {
+		return true;
+	}
+
+	/**
+	 * \brief
+	 * Allows to assign a value to the variant.
+	 *
+	 * \tparam T the type of the value to assign
+	 *
+	 * \param value the new value to assign to the variant
+	 */
+	template < typename F, typename std::enable_if < std::is_same < F, T >::value >::type * = nullptr >
+	void set ( F && value ) {
+		m_value = std::move ( value );
+	}
+
+	/**
+	 * \brief
+	 * Allows to assign a value to the variant.
+	 *
+	 * \tparam T the type of the value to assign
+	 *
+	 * \param value the new value to assign to the variant
+	 */
+	template < typename F, typename std::enable_if < std::is_same < F, T >::value >::type * = nullptr >
+	void set ( const F & value ) {
+		m_value = value;
+	}
+
+	/**
+	 * \brief
+	 * Allows to retrieve a value from the variant.
+	 *
+	 * \tparam T the type of the value to retrieve
+	 *
+	 * \return value retrieved from the variant
+	 *
+	 * \throws bad_cast exception if the variant stores different type than specified
+	 */
+	template < typename F, typename std::enable_if < std::is_same < F, T >::value >::type * = nullptr >
+	F & get ( ) & {
+		return m_value;
+	}
+
+	/**
+	 * \brief
+	 * Allows to retrieve a value from the variant.
+	 *
+	 * \tparam T the type of the value to retrieve
+	 *
+	 * \return value retrieved from the variant
+	 *
+	 * \throws bad_cast exception if the variant stores different type than specified
+	 */
+	template < typename F, typename std::enable_if < std::is_same < F, T >::value >::type * = nullptr >
+	const F && get ( ) const & {
+		return std::move ( m_value );
+	}
+
+	/**
+	 * \brief
+	 * Allows to retrieve a value from the variant.
+	 *
+	 * \tparam T the type of the value to retrieve
+	 *
+	 * \return value retrieved from the variant
+	 *
+	 * \throws bad_cast exception if the variant stores different type than specified
+	 */
+	template < typename F, typename std::enable_if < std::is_same < F, T >::value >::type * = nullptr >
+	F && get ( ) && {
+		return std::move ( m_value );
+	}
+
+	/**
+	 * \brief
+	 * Operator to print the variant to the output stream.
+	 *
+	 * \param out the output stream
+	 * \param obj the variant to print
+	 *
+	 * \return the output stream from the \p out
+	 */
+	friend std::ostream & operator << ( std::ostream & out, const variant < T > & obj ) {
+		return out << obj.m_value;
+	}
+
+	/**
+	 * \brief
+	 * To string cast operator.
+	 *
+	 * \return string representation of the variant
+	 */
+	explicit operator std::string ( ) const {
+		return ( std::string ) m_value;
+	}
+
+	/**
+	 * \brief
+	 * Allows to create the variant from defaultly constructed value of specified type.
+	 *
+	 * \tparam T the type to default construct ańd assign to newly constructed variant
+	 *
+	 * \return new variant with content of defaultly constructed value of type T
+	 */
+	static variant < T > from ( ) {
+		return variant < T > ( T { } );
+	}
+};
+
+/**
+ * \brief
+ * Implementation of the variant class allowing to store any type of those listed in the template parameters. Void type is allowed, multiply specified same type is irrelevant.
+ *
+ * \tparam Ts ... pack of allowed types.
+ */
+template < >
+class variant < void > {
+public:
+	/**
+	 * \brief
+	 * Default constructor allowed if the void type is in the pack of variant's possible type.
+	 */
+	variant ( ) {
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of equality operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if compared values are the same, false othervise
+	 */
+	bool operator == ( const variant < void > & other ) const {
+		return compare ( other ) == 0;
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of non-equality operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if compared values are not the same, false othervise
+	 */
+	bool operator != ( const variant < void > & other ) const {
+		return !(*this == other);
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of less than operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if this is smaller than the other instance, false othervise
+	 */
+	bool operator < ( const variant < void > & other ) const {
+		return compare ( other ) < 0;
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of more than operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if this is greater than the other instance, false othervise
+	 */
+	bool operator > ( const variant < void > & other ) const {
+		return other < *this;
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of less than or equal operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if this is smaller than or the same as the other instance, false othervise
+	 */
+	bool operator <= ( const variant < void > & other ) const {
+		return !(*this > other);
+	}
+
+	/**
+	 * \brief
+	 * Specialisation of greater than or equal operator for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return true if this is greater than or the same as the other instance, false othervise
+	 */
+	bool operator >= ( const variant < void > & other ) const {
+		return !(*this < other);
+	}
+
+	/**
+	 * \brief
+	 * Implementation of the three way comparison for varant.
+	 *
+	 * \param other the value compared to compared this
+	 *
+	 * \return negative value if this is smaller than the other instance, positive if this is greater than the other instance, zero othervise
+	 */
+	int compare ( const variant < void > & ) const {
+		return true;
+	}
+
+	/**
+	 * \brief
+	 * Function to test whether the variant currently contains type T.
+	 *
+	 * \tparam T the type to test
+	 *
+	 * \return true it the variant contains instance of type T
+	 */
+	template < typename T, typename std::enable_if < std::is_same < T, void >::value >::type * = nullptr >
+	bool is ( ) const {
+		return true;
+	}
+
+	/**
+	 * \brief
+	 * Allows to assign a void to the variant.
+	 */
+	template < typename T = void >
+	typename std::enable_if < std::is_same < T, void >::value, void >::type set ( ) {
+	}
+
+	/**
+	 * \brief
+	 * Operator to print the variant to the output stream.
+	 *
+	 * \param out the output stream
+	 * \param obj the variant to print
+	 *
+	 * \return the output stream from the \p out
+	 */
+	friend std::ostream & operator << ( std::ostream & out, const variant < void > & ) {
+		return out << "void";
+	}
+
+	/**
+	 * \brief
+	 * To string cast operator.
+	 *
+	 * \return string representation of the variant
+	 */
+	explicit operator std::string ( ) const {
+		return "void";
+	}
+
+	/**
+	 * \brief
+	 * Allows to create the variant from void type.
+	 *
+	 * \tparam T the void type
+	 *
+	 * \return new variant with content of defaultly constructed value of type T
+	 */
+	template < typename F >
+	static typename std::enable_if < std::is_same < void, F >::value, variant < F > >::type from ( ) {
+		return variant < F > ( );
+	}
+};
+
 /**
  * \brief
  * Specialisation of the compare structure implementing the three-way comparison.
@@ -763,7 +1170,7 @@ public:
  * \tparam Ts ... types in the variant
  */
 template<typename ... Ts>
-struct compare<ext::variant<Ts...>> {
+struct compare < ext::variant < Ts ... > > {
 
 	/**
 	 * \brief
@@ -774,7 +1181,7 @@ struct compare<ext::variant<Ts...>> {
 	 *
 	 * \return negative value of left < right, positive value if left > right, zero if left == right
 	 */
-	int operator()(const ext::variant<Ts...>& first, const ext::variant<Ts...>& second) const {
+	int operator()(const ext::variant < Ts ... > & first, const ext::variant < Ts ... > & second) const {
 		return first.compare(second);
 	}
 };
@@ -802,7 +1209,7 @@ std::string to_string ( const ext::variant < Ts ... > & value ) {
  * \tparam Ts ... pack of types to construct the variant from 
  */
 template < class Res, class ... Ts >
-struct variant_builder_int {
+struct variant_builder_impl {
 };
 
 /**
@@ -812,12 +1219,27 @@ struct variant_builder_int {
  * \tparam T type to construct the variant from
  */
 template < class T >
-struct variant_builder_int < ext::variant < >, T > {
+struct variant_builder_impl < ext::variant < >, T > {
+	/**
+	 * \brief
+	 * The type T as simplification of the variant to the type T.
+	 */
+	typedef ext::variant < T > type;
+};
+
+/**
+ * \brief
+ * Specialisation of the helper class to build the variant type as the type T as case when the variant is requested to be constructed from single type.
+ *
+ * \tparam T type to construct the variant from
+ */
+template < >
+struct variant_builder_impl < ext::variant < >, void > {
 	/**
 	 * \brief
 	 * The type T as simplification of the variant to the type T.
 	 */
-	typedef T type;
+	typedef ext::variant < void > type;
 };
 
 /**
@@ -828,7 +1250,7 @@ struct variant_builder_int < ext::variant < >, T > {
  * \tparam T last type to construct the variant from
  */
 template < class ... ResTs, class T >
-struct variant_builder_int < ext::variant < ResTs ... >, T > {
+struct variant_builder_impl < ext::variant < ResTs ... >, T > {
 	/**
 	 * \brief
 	 * The resulting variant type.
@@ -845,11 +1267,11 @@ struct variant_builder_int < ext::variant < ResTs ... >, T > {
  * \tparam Ts ... remaining types to add to variant template parameters
  */
 template < class ... ResTs, class T, class ... Ts >
-struct variant_builder_int < ext::variant < ResTs ... >, T, Ts ... > {
+struct variant_builder_impl < ext::variant < ResTs ... >, T, Ts ... > {
 	/**
 	 * The type T is tested whether it is included in the Ts ... pack. If it is included it is skipped, if not it is added to types of resulting variant.
 	 */
-	typedef typename variant_builder_int < typename std::conditional < is_in < T, Ts ... >::value, ext::variant < ResTs ... >, ext::variant < ResTs ..., T > >::type, Ts ... >::type type;
+	typedef typename variant_builder_impl < typename std::conditional < is_in < T, Ts ... >::value, ext::variant < ResTs ... >, ext::variant < ResTs ..., T > >::type, Ts ... >::type type;
 };
 
 /**
@@ -859,8 +1281,7 @@ struct variant_builder_int < ext::variant < ResTs ... >, T, Ts ... > {
  * \tparam Ts ... pack of types to build the variant for
  */
 template < class ... Ts >
-struct variant_builder : public variant_builder_int < ext::variant < >, Ts ... > {
-};
+using variant_builder = typename variant_builder_impl < ext::variant < >, Ts ... >::type;
 
 } /* namespace ext */
 
diff --git a/alib2std/test-src/extensions/container/VariantTest.cpp b/alib2std/test-src/extensions/container/VariantTest.cpp
index b77f8dd4ef..01b6123957 100644
--- a/alib2std/test-src/extensions/container/VariantTest.cpp
+++ b/alib2std/test-src/extensions/container/VariantTest.cpp
@@ -197,15 +197,15 @@ void VariantTest::testSetVariant ( ) {
 
 void VariantTest::testVariantBuilder ( ) {
 	bool same;
-	same = std::is_same < ext::variant_builder < int >::type, int >::value;
+	same = std::is_same < ext::variant_builder < void >, ext::variant < void > >::value;
 	CPPUNIT_ASSERT ( same );
 
-	same = std::is_same < ext::variant_builder < int, int, int >::type, int >::value;
+	same = std::is_same < ext::variant_builder < int, int, int >, ext::variant < int > >::value;
 	CPPUNIT_ASSERT ( same );
 
-	same = std::is_same < ext::variant_builder < double, int, char >::type, ext::variant < double, int, char > >::value;
+	same = std::is_same < ext::variant_builder < double, int, char >, ext::variant < double, int, char > >::value;
 	CPPUNIT_ASSERT ( same );
 
-	same = std::is_same < ext::variant_builder < double, int, char, char, int, double >::type, ext::variant < char, int, double > >::value;
+	same = std::is_same < ext::variant_builder < double, int, char, char, int, double >, ext::variant < char, int, double > >::value;
 	CPPUNIT_ASSERT ( same );
 }
-- 
GitLab