From 89518f294dc3dacdb40795a3512170e3850ace97 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Fri, 7 Sep 2018 21:01:09 +0200 Subject: [PATCH] add callback acceptor to variant --- alib2std/src/extensions/container/variant.hpp | 242 ++++++++++++------ .../extensions/container/VariantTest.cpp | 7 + .../extensions/container/VariantTest.h | 5 + 3 files changed, 177 insertions(+), 77 deletions(-) diff --git a/alib2std/src/extensions/container/variant.hpp b/alib2std/src/extensions/container/variant.hpp index 6783fdc094..970cec350a 100644 --- a/alib2std/src/extensions/container/variant.hpp +++ b/alib2std/src/extensions/container/variant.hpp @@ -61,6 +61,25 @@ struct variant_helper; */ template<typename F, typename... Ts> struct variant_helper<F, Ts...> { + /** + * \brief + * Implementation of call passing for type F (if the type F is currently stored inside the variant). + * + * \tparam Result the callback result + * \tparam Callable type of callback to execute + * + * \param id the representation of type stored inside the variant + * \param data storage occupied by value stored in the variant + * \param callable the callback to execute + */ + template < class Result, class Callable > + inline static Result call ( ext::type_index id, const void * data, Callable callable ) { + if (id == ext::type_index ( typeid ( F ) ) ) + return callable ( * reinterpret_cast < const F * > ( data ) ); + else + return variant_helper < Ts ... >::template call < Result > ( id, data, callable ); + } + /** * \brief * Implementation of destructor for type F (if the type F is currently stored inside the variant) @@ -69,7 +88,7 @@ struct variant_helper<F, Ts...> { * \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 ) ) ) ) + if (id == ext::type_index ( typeid ( F ) ) ) reinterpret_cast<F*>(data)->~F(); else variant_helper<Ts...>::destroy(id, data); @@ -105,34 +124,6 @@ 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); - else - 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) ); - else - 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) @@ -161,6 +152,25 @@ struct variant_helper<F, Ts...> { */ template<typename... Ts> struct variant_helper<void, Ts...> { + /** + * \brief + * Implementation of call passing for type F (if the type F is currently stored inside the variant). + * + * \tparam Result the callback result + * \tparam Callable type of callback to execute + * + * \param id the representation of type stored inside the variant + * \param data storage occupied by value stored in the variant + * \param callable the callback to execute + */ + template < class Result, class Callable > + inline static Result call ( ext::type_index id, const void * data, Callable callable ) { + if (id == ext::type_index ( typeid ( void ) ) ) + return callable ( ); + else + return variant_helper < Ts ... >::template call < Result > ( id, data, callable ); + } + /** * \brief * Implementation of destructor for void type (if the void type is currently stored inside the variant) @@ -199,34 +209,6 @@ struct variant_helper<void, Ts...> { 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"; - else - 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"; - else - 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) @@ -254,45 +236,38 @@ 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. + * Implementation of call passing for type F (if the type F is currently stored inside the variant). * * Does nothing. */ - inline static void copy(ext::type_index, const void *, void *) { } + template < class Result, class Callable > + inline static Result call ( ext::type_index, const void *, Callable ) { + throw std::logic_error ( "Out of types of variant." ); + } /** * \brief - * Move constructor helper when the pack of types of the variant was depleted. + * Destructor helper when the pack of types of the variant was depleted. * * Does nothing. */ - inline static void move(ext::type_index, void *, void *) { } + inline static void destroy(ext::type_index, void *) { } /** * \brief - * Print to stream helper when the pack of types of the variant was depleted. + * Copy constructor helper when the pack of types of the variant was depleted. * * Does nothing. */ - inline static void print(std::ostream&, ext::type_index, const void *) { } + inline static void copy(ext::type_index, const void *, void *) { } /** * \brief - * To string helper when the pack of types of the variant was depleted. + * Move constructor 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 ""; } + inline static void move(ext::type_index, void *, void *) { } /** * \brief @@ -457,6 +432,71 @@ class variant : public variant_base < max ( SizeOf < Ts >::size ... ), max ( Ali */ using helper_t = variant_helper<Ts...>; + /** + * Internal variant to string callback implementation. + */ + class VariantToString { + public: + /** + * The callback for types different from void + * + * \tparam T the accepted tye + * + * \param value the accepted value + * + * \return string representation of the value + */ + template < class T > + std::string operator ( ) ( const T & value ) const { + return ext::to_string ( value ); + } + + /** + * The callback for void type + * + * \return string "void" + */ + std::string operator ( ) ( ) const { + return "void"; + } + }; + + /** + * Internal variant to ostream callback implementation. + */ + class VariantToStream { + /** + * The stream to print to. + */ + std::ostream & m_out; + public: + /** + * Constructor of the variant to stream callback. + * + * \param out the output stream to use in function call operators. + */ + VariantToStream ( std::ostream & out ) : m_out ( out ) { + } + + /** + * The callback for types different from void + * + * \tparam T the accepted tye + * + * \param value the accepted value + */ + template < class T > + void operator ( ) ( const T & value ) { + m_out << value; + } + + /** + * The callback for void type, printing "void" to the stream + */ + void operator ( ) ( ) { + m_out << "void"; + } + }; public: /** * \brief @@ -720,6 +760,22 @@ public: helper_t::destroy(this->type_id, &this->data); } + /** + * \brief + * Callback executor on current variant value. + * + * \tparam Result the uniform result type + * \tparam Callable type of callable able to accept any variant type. + * + * \param callable object of callable type able to accept any variant type via function call operator. The possible void type is represented by call with no parameters + * + * \return the result of the callable on the current variable type + */ + template < class Result, class Callable > + Result call ( Callable callable ) const { + return helper_t::template call < Result > ( this->type_id, & this->data, callable ); + } + /** * \brief * Operator to print the variant to the output stream. @@ -730,7 +786,7 @@ public: * \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); + obj.call < void > ( VariantToStream ( out ) ); return out; } @@ -741,7 +797,7 @@ public: * \return string representation of the variant */ explicit operator std::string() const { - return helper_t::string(this->type_id, &this->data); + return this->call < std::string > ( VariantToString ( ) ); } /** @@ -969,6 +1025,22 @@ public: return std::move ( m_value ); } + /** + * \brief + * Callback executor on current variant value. + * + * \tparam Result the uniform result type + * \tparam Callable type of callable able to accept any variant type. + * + * \param callable object of callable type able to accept any variant type via function call operator. The possible void type is represented by call with no parameters + * + * \return the result of the callable on the current variable type + */ + template < class Result, class Callable > + Result call ( Callable callable ) const { + return callable ( m_value ); + } + /** * \brief * Operator to print the variant to the output stream. @@ -1126,6 +1198,22 @@ public: typename std::enable_if < std::is_same < T, void >::value, void >::type set ( ) { } + /** + * \brief + * Callback executor on current variant value. + * + * \tparam Result the uniform result type + * \tparam Callable type of callable able to accept any variant type. + * + * \param callable object of callable type able to accept any variant type via function call operator. The possible void type is represented by call with no parameters + * + * \return the result of the callable on the current variable type + */ + template < class Result, class Callable > + Result call ( Callable callable ) const { + return callable ( ); + } + /** * \brief * Operator to print the variant to the output stream. diff --git a/alib2std/test-src/extensions/container/VariantTest.cpp b/alib2std/test-src/extensions/container/VariantTest.cpp index 01b6123957..8fea1b358f 100644 --- a/alib2std/test-src/extensions/container/VariantTest.cpp +++ b/alib2std/test-src/extensions/container/VariantTest.cpp @@ -3,6 +3,7 @@ #include <alib/set> #include <alib/algorithm> #include <alib/map> +#include <sstream> CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( VariantTest, "bits" ); CPPUNIT_TEST_SUITE_REGISTRATION( VariantTest ); @@ -57,6 +58,12 @@ void VariantTest::testVariant() { CPPUNIT_ASSERT( (e < d) == false ); CPPUNIT_ASSERT( (e == d) == true ); + + CPPUNIT_ASSERT ( ( ( std::string ) e ) == "43" ); + + std::stringstream ss; + ss << e; + CPPUNIT_ASSERT ( ss.str ( ) == "43" ); } void VariantTest::testVariantSet() { diff --git a/alib2std/test-src/extensions/container/VariantTest.h b/alib2std/test-src/extensions/container/VariantTest.h index da2eb7ea55..d8205974e6 100644 --- a/alib2std/test-src/extensions/container/VariantTest.h +++ b/alib2std/test-src/extensions/container/VariantTest.h @@ -3,6 +3,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <alib/compare> +#include <alib/string> class VariantTest : public CppUnit::TestFixture { @@ -60,6 +61,10 @@ struct test { out << *(other.holder); return out; } + + operator std::string ( ) const { + return ext::to_string ( * holder ); + } }; struct test2 { -- GitLab