diff --git a/alib2std/src/extensions/container/variant.hpp b/alib2std/src/extensions/container/variant.hpp index 166824e23e9321316c57aef16215faefb633baf4..6783fdc094fe88b03cecb88d64a3f7e67fcdac2b 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 b77f8dd4ef51b0d03bbcdc39410c2a7a2a015095..01b6123957b3766dda593f4d29db348d542f53c2 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 ); }