From e4d808d60a38b87dd685e1fbaf8c0e1de604562d Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Sat, 21 Jul 2018 22:17:14 +0200 Subject: [PATCH] finish documenting variant and alib2std --- alib2std/src/extensions/variant.hpp | 542 ++++++++++++++++++- alib2std/test-src/extensions/VariantTest.cpp | 4 +- 2 files changed, 530 insertions(+), 16 deletions(-) diff --git a/alib2std/src/extensions/variant.hpp b/alib2std/src/extensions/variant.hpp index d0c209b848..ebfe73956f 100644 --- a/alib2std/src/extensions/variant.hpp +++ b/alib2std/src/extensions/variant.hpp @@ -42,11 +42,31 @@ namespace ext { +/** + * \brief + * Class designed to implement core features of varant. + * + * \tparam Ts ... pack of types of variant + */ template<typename... Ts> struct variant_helper; +/** + * \brief + * Class designed to implement core of variant features for individual non-void types. + * + * \tparam F the currently handled type + * \tparam Ts ... pack of remaining types to handle + */ template<typename F, typename... Ts> struct variant_helper<F, Ts...> { + /** + * \brief + * Implementation of destructor for type F (if the type F is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param data storage occupied by value stored in the variant + */ inline static void destroy(ext::type_index id, void * data) { if (id == ext::type_index ( ext::type_index ( typeid ( F ) ) ) ) reinterpret_cast<F*>(data)->~F(); @@ -54,6 +74,14 @@ struct variant_helper<F, Ts...> { variant_helper<Ts...>::destroy(id, data); } + /** + * \brief + * Implementation of copy constructor for type F (if the type F is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param old_v storage occupied by value stored in the source variant + * \param new_v storage of the target variant + */ inline static void copy(ext::type_index old_t, const void * old_v, void * new_v) { if (old_t == ext::type_index ( typeid ( F ) )) new (new_v) F(*reinterpret_cast<const F*>(old_v)); @@ -61,6 +89,14 @@ struct variant_helper<F, Ts...> { variant_helper<Ts...>::copy(old_t, old_v, new_v); } + /** + * \brief + * Implementation of move constructor for type F (if the type F is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param old_v storage occupied by value stored in the source variant + * \param new_v storage of the target variant + */ inline static void move(ext::type_index old_t, void * old_v, void * new_v) { if (old_t == ext::type_index ( typeid ( F ) )) new (new_v) F(std::move(*reinterpret_cast<F*>(old_v))); @@ -68,6 +104,13 @@ struct variant_helper<F, Ts...> { variant_helper<Ts...>::move(old_t, old_v, new_v); } + /** + * \brief + * Implementation of operator << for type F (if the type F is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param data storage occupied by value stored in the variant + */ inline static void print(std::ostream& out, ext::type_index id, const void* data) { if (id == ext::type_index ( typeid ( F ) )) out << *reinterpret_cast<const F*>(data); @@ -75,6 +118,13 @@ struct variant_helper<F, Ts...> { variant_helper<Ts...>::print(out, id, data); } + /** + * \brief + * Implementation of to_string for type F (if the type F is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param data storage occupied by value stored in the variant + */ inline static std::string string(ext::type_index id, const void* data) { if (id == ext::type_index ( typeid ( F ) )) return ext::to_string ( *reinterpret_cast<const F*>(data) ); @@ -82,6 +132,17 @@ struct variant_helper<F, Ts...> { return variant_helper<Ts...>::string(id, data); } + /** + * \brief + * Implementation of three way comparison for type F (if the type F is currently stored inside the variant) + * + * \param this_t the representation of type stored inside the first variant + * \param this_v storage of the first variant + * \param other_t the representation of type stored inside the second variant + * \param other_v storage of the second variant + * + * \return the result of the comparison + */ inline static int compareHelper(ext::type_index this_t, const void * this_v, ext::type_index other_t, const void * other_v) { if (this_t == ext::type_index ( typeid ( F ) ) && other_t == ext::type_index ( typeid ( F ) )) { static ext::compare<typename std::decay < F >::type > comp; @@ -91,23 +152,59 @@ struct variant_helper<F, Ts...> { } }; +/** + * \brief + * Class designed to implement core of variant features for void type. + * + * \tparam Ts ... pack of remaining types to handle + */ template<typename... Ts> struct variant_helper<void, Ts...> { + /** + * \brief + * Implementation of destructor for void type (if the void type is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param data storage occupied by value stored in the variant + */ inline static void destroy(ext::type_index id, void * data) { if (id != ext::type_index ( typeid ( void ) )) variant_helper<Ts...>::destroy(id, data); } + /** + * \brief + * Implementation of copy constructor for void type (if the void type is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param old_v storage occupied by value stored in the source variant + * \param new_v storage of the target variant + */ inline static void copy(ext::type_index old_t, const void * old_v, void * new_v) { if (old_t != ext::type_index ( typeid ( void ) )) variant_helper<Ts...>::copy(old_t, old_v, new_v); } + /** + * \brief + * Implementation of move constructor for void type (if the void type is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param old_v storage occupied by value stored in the source variant + * \param new_v storage of the target variant + */ inline static void move(ext::type_index old_t, void * old_v, void * new_v) { if (old_t != ext::type_index ( typeid ( void ) )) variant_helper<Ts...>::move(old_t, old_v, new_v); } + /** + * \brief + * Implementation of operator << for void type (if the void type is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param data storage occupied by value stored in the variant + */ inline static void print(std::ostream& out, ext::type_index id, const void* data) { if (id == ext::type_index ( typeid ( void ) )) out << "void"; @@ -115,6 +212,13 @@ struct variant_helper<void, Ts...> { variant_helper<Ts...>::print(out, id, data); } + /** + * \brief + * Implementation of to_string for void type (if the void type is currently stored inside the variant) + * + * \param id the representation of type stored inside the variant + * \param data storage occupied by value stored in the variant + */ inline static std::string string(ext::type_index id, const void* data) { if (id == ext::type_index ( typeid ( void ) )) return "void"; @@ -122,6 +226,17 @@ struct variant_helper<void, Ts...> { return variant_helper<Ts...>::string(id, data); } + /** + * \brief + * Implementation of three way comparison for void type (if the void type is currently stored inside the variant) + * + * \param this_t the representation of type stored inside the first variant + * \param this_v storage of the first variant + * \param other_t the representation of type stored inside the second variant + * \param other_v storage of the second variant + * + * \return the result of the comparison + */ inline static int compareHelper(ext::type_index this_t, const void * this_v, ext::type_index other_t, const void * other_v) { if (this_t == ext::type_index ( typeid ( void ) ) && other_t == ext::type_index ( typeid ( void ) )) return 0; @@ -130,84 +245,271 @@ struct variant_helper<void, Ts...> { } }; -template<> struct variant_helper<> { -inline static void destroy(ext::type_index, void *) { } -inline static void copy(ext::type_index, const void *, void *) { } -inline static void move(ext::type_index, void *, void *) { } -inline static void print(std::ostream&, ext::type_index, const void *) {} -inline static std::string string(ext::type_index, const void *) { return ""; } -inline static int compareHelper(ext::type_index, const void *, ext::type_index, const void *) { return 0; } +/** + * \brief + * Class ending the recursive handling of possible types in the variant type. + */ +template < > struct variant_helper < > { + + /** + * \brief + * Destructor helper when the pack of types of the variant was depleted. + * + * Does nothing. + */ + inline static void destroy(ext::type_index, void *) { } + + /** + * \brief + * Copy constructor helper when the pack of types of the variant was depleted. + * + * Does nothing. + */ + inline static void copy(ext::type_index, const void *, void *) { } + + /** + * \brief + * Move constructor helper when the pack of types of the variant was depleted. + * + * Does nothing. + */ + inline static void move(ext::type_index, void *, void *) { } + + /** + * \brief + * Print to stream helper when the pack of types of the variant was depleted. + * + * Does nothing. + */ + inline static void print(std::ostream&, ext::type_index, const void *) { } + + /** + * \brief + * To string helper when the pack of types of the variant was depleted. + * + * Does nothing. + * + * \return empty string + */ + inline static std::string string(ext::type_index, const void *) { return ""; } + + /** + * \brief + * Comparison helper when the pack of types of the variant was depleted. + * + * Does nothing. + * + * \return 0 + */ + inline static int compareHelper(ext::type_index, const void *, ext::type_index, const void *) { return 0; } }; +/** + * \brief + * Class representing functionality of the variant specific for individual types of variant. + * + * \tparam ST the overal maximum size of types to be stored inside the variant + * \tparam AT the overal maximal alignment of types to be stored inside the variant + * + * \tparam Ts ... pack of variant types + */ template<size_t ST, size_t AT, typename... Ts> class variant_base; + +/** + * \brief + * Class ending the recursive construction of variant_base type. The class is responsible for actual allocation of storage of size ST with alignment AT + * + * \tparam ST the overal maximum size of types to be stored inside the variant + * \tparam AT the overal maximal alignment of types to be stored inside the variant + */ template<size_t ST, size_t AT> class variant_base<ST, AT> { + /** + * \brief + * The type of storage capable of containing any of the concrete variant type. + */ using data_t = typename std::aligned_storage < ST, AT>::type; protected: + /** + * \brief + * Representation of current type stored inside the variant. + */ ext::type_index type_id; + + /** + * \brief + * Representation of the value stored inside the variant. + */ data_t data; + /** + * \brief + * Helper constructor setting up the type stored inside the variant + * + * \param id the identification of type stored inside the variant + */ variant_base( ext::type_index id ) : type_id ( id ) { // just to make the -Werror=maybe-uninitialized go away std::memset( & data, 0, ST ); } }; +/** + * \brief + * Class representing functionality of the variant specific for selected non-void type of variant. + * + * \tparam ST the overal maximum size of types to be stored inside the variant + * \tparam AT the overal maximal alignment of types to be stored inside the variant + * + * \tparam F the currently handled type + * \tparam Ts ... pack of variant types + */ template<size_t ST, size_t AT, typename F, typename... Ts> class variant_base<ST, AT, F, Ts...> : public variant_base<ST, AT, Ts...> { + /** + * \brief + * Use constructors of the base class + */ using variant_base<ST, AT, Ts...>::variant_base; protected: + /** + * \brief + * Pass the construction of the variant with predefined type specification lower in the type recursion + * + * \param id the identification of type stored inside the variant + */ variant_base( ext::type_index id ) : variant_base<ST, AT, Ts...>::variant_base ( id ) { } 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_base(const F& value) : variant_base<ST, AT, Ts...>::variant_base ( ext::type_index ( typeid(F) ) ) { new (&this->data) F(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_base(F&& value) : variant_base<ST, AT, Ts...>::variant_base ( ext::type_index ( typeid(F) ) ) { new (&this->data) F(std::move(value)); } + /** + * \brief + * Pass maybe exitent default constructor of the variant. + */ variant_base() : variant_base<ST, AT, Ts ... >::variant_base ( ) { } }; +/** + * \brief + * Class representing functionality of the variant specific for void type of variant (if any). + * + * \tparam ST the overal maximum size of types to be stored inside the variant + * \tparam AT the overal maximal alignment of types to be stored inside the variant + * + * \tparam Ts ... pack of variant types + */ template<size_t ST, size_t AT, typename... Ts> class variant_base<ST, AT, void, Ts...> : public variant_base<ST, AT, Ts...> { + /** + * \brief + * Use constructors of the base class + */ using variant_base<ST, AT, Ts...>::variant_base; protected: + /** + * \brief + * Pass the construction of the variant with predefined type specification lower in the type recursion + * + * \param id the identification of type stored inside the variant + */ variant_base( ext::type_index id ) : variant_base<ST, AT, Ts...>::variant_base ( id ) { } public: + /** + * \brief + * Allow default constructor of the variant. + */ variant_base() : variant_base<ST, AT, Ts...>::variant_base ( ext::type_index ( typeid ( void ) ) ) { } }; +/** + * \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 ... Ts> class variant : public variant_base < max ( SizeOf < Ts >::size ... ), max ( AlignOf < Ts >::align ... ), Ts...> { + /** + * \brief + * Type of the helper used for type specific operations on the variant. + */ using helper_t = variant_helper<Ts...>; public: + /** + * \brief + * Inherit type specific constructors of the variant. + */ using variant_base < max ( SizeOf < Ts >::size ... ), max ( AlignOf < Ts >::align ... ), Ts...>::variant_base; - template < typename T = void, typename std::enable_if < ext::is_in<T, Ts...>::value >::type* = nullptr > + /** + * \brief + * Default constructor allowed if the void type is in the pack of variant's possible type. + */ variant ( ) : variant_base < max ( SizeOf < Ts >::size ... ), max ( AlignOf < Ts >::align ... ), Ts...> ( ) { } - //copy consructor + /** + * \brief + * Copy constructor of the variant. + * + * \param old the source instance + */ 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); } - //move constructor + /** + * \brief + * Move constructor of the variant. + * + * \param old the source instance + */ 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); } - // copy assignment operator + /** + * \brief + * Copy assignment operator of the variant. + * + * \param old the source instance + * + * \return the modified target instance + */ variant<Ts...>& operator =( const variant<Ts...> & other ) { return this->operator =( variant <Ts...> ( other ) ); } - // move assignment operator + /** + * \brief + * Move assignment operator of the variant. + * + * \param old the source instance + * + * \return the modified target instance + */ 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); @@ -216,30 +518,86 @@ public: return *this; } + /** + * \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<Ts...>& 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<Ts...>& 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<Ts...>& 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<Ts...>& 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<Ts...>& 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<Ts...>& 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<Ts...>& other) const { if (this->type_id < other.type_id) return -1; if (this->type_id > other.type_id) return 1; @@ -247,17 +605,37 @@ public: return helper_t::compareHelper(this->type_id, &this->data, other.type_id, &other.data); } + /** + * \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 < ext::is_in<T, Ts...>::value >::type* = nullptr > bool is() const { return (this->type_id == ext::type_index ( typeid ( T ) )); } + /** + * \brief + * Allows to assign a void to the variant. + */ template < typename T = void > typename std::enable_if < ext::is_in < T, Ts ... >::value, void >::type set ( ) { helper_t::destroy(this->type_id, &this->data); this->type_id = ext::type_index ( typeid ( void ) ); } + /** + * \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 T > void set ( typename std::enable_if < ext::is_in<T, Ts...>::value && ! std::is_same < void, T >::value, T >::type && value ) { helper_t::destroy(this->type_id, &this->data); @@ -265,6 +643,14 @@ public: this->type_id = ext::type_index ( typeid ( T ) ); } + /** + * \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 T > void set ( const typename std::enable_if < ext::is_in<T, Ts...>::value && ! std::is_same < void, T >::value, T >::type & value ) { helper_t::destroy(this->type_id, &this->data); @@ -272,8 +658,18 @@ public: this->type_id = ext::type_index ( typeid ( T ) ); } + /** + * \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() { + 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); @@ -281,8 +677,18 @@ public: 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 > - 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); @@ -290,61 +696,167 @@ public: throw std::bad_cast(); } + /** + * \brief + * Destructor of the variant. + */ ~variant() noexcept { helper_t::destroy(this->type_id, &this->data); } + /** + * \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<Ts...>& obj) { helper_t::print(out, obj.type_id, &obj.data); return out; } + /** + * \brief + * To string cast operator. + * + * \return string representation of the variant + */ explicit operator std::string() const { return helper_t::string(this->type_id, &this->data); } + /** + * \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 + */ template < typename T > static typename std::enable_if < ! std::is_same < void, T >::value, variant < Ts ... > >::type from ( ) { return variant < Ts ... >( T { } ); } + /** + * \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 T > static typename std::enable_if < std::is_same < void, T >::value, variant < Ts ... > >::type from ( ) { return variant < Ts ... >( ); } }; +/** + * \brief + * Specialisation of the compare structure implementing the three-way comparison. + * + * \tparam Ts ... types in the variant + */ template<typename ... Ts> struct compare<ext::variant<Ts...>> { + + /** + * \brief + * Implementation of the three-way comparison. + * + * \param first the left operand of the comparison + * \param second the right operand of the comparison + * + * \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 { return first.compare(second); } }; +/** + * \brief + * Overload of to_string function. + * + * \param value the vector to be converted to string + * + * \tparam Ts ... types in the variant + * + * \return string representation + */ template < class ... Ts > std::string to_string ( const ext::variant < Ts ... > & value ) { return ( std::string ) value; } -template < class Res, class T, class ... Ts > +/** + * \brief + * Class to help building of the variant type or, in case variant is requested to be constructed from single type or more types but all the same, that concrete type. + * + * \tparam Res the resulting contstructed variant + * \tparam Ts ... pack of types to construct the variant from + */ +template < class Res, class ... Ts > struct variant_builder_int { }; +/** + * \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 < class T > struct variant_builder_int < ext::variant < >, T > { + /** + * \brief + * The type T as simplification of the variant to the type T. + */ typedef T type; }; +/** + * \brief + * Recursion ending specialisation of the helper class to build the variant type. The last type T is added as last type to the variant parameters. + * + * \tparam ResTs ... pack of types already accepted as types of the variant + * \tparam T last type to construct the variant from + */ template < class ... ResTs, class T > struct variant_builder_int < ext::variant < ResTs ... >, T > { + /** + * \brief + * The resulting variant type. + */ typedef ext::variant < ResTs ..., T > type; }; +/** + * \brief + * Recursive step of class to build the variant type. + * + * \tparam ResTs ... pack of types already accepted as types of the variant + * \tparam T next type to construct the variant from + * \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 ... > { + /** + * 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; }; +/** + * \brief + * Class to construct variant from types pack. The construction drops duplicate types from the Ts ... pack. Variant of single type is converted to that type. + * + * \tparam Ts ... pack of types to build the variant for + */ template < class ... Ts > struct variant_builder : public variant_builder_int < ext::variant < >, Ts ... > { }; diff --git a/alib2std/test-src/extensions/VariantTest.cpp b/alib2std/test-src/extensions/VariantTest.cpp index 8da10e084f..b77f8dd4ef 100644 --- a/alib2std/test-src/extensions/VariantTest.cpp +++ b/alib2std/test-src/extensions/VariantTest.cpp @@ -117,7 +117,9 @@ void VariantTest::testVariantSet2() { CPPUNIT_ASSERT( s.size() == u.size()); /* ext::variant < void, ext::pair < int, int > > var; - var.get < int > ( );*///should not compile -- correct behavior + var.get < int > ( );*/ //should not compile -- correct behavior + +// ext::variant < int, char > var2;// should not compile -- correct behavior } void VariantTest::testVariantVoid() { -- GitLab