diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e066a5..8489dd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,8 @@ endif() # Reference the FindDBus module until an upstream one is available list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() diff --git a/include/simppl/detail/holders.h b/include/simppl/detail/holders.h index a838440..1b43bba 100644 --- a/include/simppl/detail/holders.h +++ b/include/simppl/detail/holders.h @@ -2,6 +2,8 @@ #define SIMPPL_DETAIL_HOLDERS_H +#include + #include "callinterface.h" @@ -128,10 +130,10 @@ struct PropertyCallbackHolder DBusMessageIter iter; dbus_message_iter_init(msg.get(), &iter); - simppl::Variant v; + std::variant v; decode(iter, v); - that->f_(cs, *v.template get()); + that->f_(cs, std::get(v)); } else that->f_(cs, DataT()); diff --git a/include/simppl/property.h b/include/simppl/property.h index 5e84c76..e8bd894 100644 --- a/include/simppl/property.h +++ b/include/simppl/property.h @@ -8,7 +8,7 @@ namespace simppl { - + namespace dbus { @@ -67,9 +67,9 @@ struct PropertyCodec { detail::VariantSerializer(iter).operator()(t); } - - - static + + + static void decode(DBusMessageIter& iter, T& t) { DBusMessageIter _iter; @@ -78,7 +78,7 @@ struct PropertyCodec Codec::decode(_iter, t); dbus_message_iter_next(&iter); - } + } }; diff --git a/include/simppl/serverside.h b/include/simppl/serverside.h index 26a3366..ac10205 100644 --- a/include/simppl/serverside.h +++ b/include/simppl/serverside.h @@ -270,9 +270,7 @@ struct BaseProperty : ServerPropertyBase const DataT& value() const { - const DataT* t = t_.template get(); - assert(t); - return *t; + return std::get(t_); } static @@ -283,7 +281,7 @@ struct BaseProperty : ServerPropertyBase // missing initialization? assert(!that->t_.empty()); - detail::PropertyCodec::encode(*iter, that->t_.template get() ? (*that->t_.template get())() : *that->t_.template get()); + detail::PropertyCodec::encode(*iter, std::get_if(&that->t_) ? (std::get(that->t_))() : std::get(that->t_)); } /** @@ -314,7 +312,7 @@ struct BaseProperty : ServerPropertyBase protected: - Variant t_; + std::variant t_; }; @@ -377,7 +375,7 @@ namespace detail static void eval(BaseProperty& p, const DataT& d) { - if (!p.t_.template get() || PropertyComparator::compare(p.value(), d)) + if (!std::get_if(&p.t_) || PropertyComparator::compare(p.value(), d)) { p.t_ = d; p.notify(d); diff --git a/include/simppl/stubbase.h b/include/simppl/stubbase.h index 85b50ff..600f55e 100644 --- a/include/simppl/stubbase.h +++ b/include/simppl/stubbase.h @@ -10,7 +10,6 @@ #include "simppl/callstate.h" #include "simppl/pendingcall.h" -#include "simppl/variant.h" #include "simppl/detail/constants.h" #include "simppl/detail/holders.h" diff --git a/include/simppl/variant.h b/include/simppl/variant.h index b8d2af3..77e86e3 100644 --- a/include/simppl/variant.h +++ b/include/simppl/variant.h @@ -5,6 +5,7 @@ #include "simppl/typelist.h" #include "simppl/serialization.h" +#include #include #include #include @@ -13,369 +14,6 @@ namespace simppl { -struct AlignFunc -{ - template - struct apply_ - { - enum { value = std::alignment_of::value }; - }; -}; - - -struct SizeFunc -{ - template - struct apply_ - { - enum { value = sizeof(T) }; - }; -}; - - -// FIXME the algorithm should look a little bit like max_element and return an index of the -// maximum element as given by the Functor -template -struct Max; - -template -struct Max, FuncT> -{ - typedef typename FuncT::template apply_ first_type__; - enum { value1__ = first_type__::value }; - enum { value2__ = Max::value }; - - enum { value = (int)value1__ > (int)value2__ ? (int)value1__ : (int)value2__ }; -}; - - -template -struct Max, FuncT> -{ - typedef typename FuncT::template apply_ type__; - enum { value = type__::value }; -}; - - -// ---------------------------------------------------------------------------------------------- - - -template -struct Variant -{ - // FIXME make sure not to be able to add the same type multiple times - - typedef typename make_typelist::type typelist_type; - - enum { size = Max::value }; - enum { alignment = Max::value }; - - static_assert(sizeof...(T) <= 7, "currently only 7 variant entries supported"); - - /*private*/ enum { unset = -1 }; - - inline - Variant() - : idx_(unset) - { - // NOOP - } - - inline - ~Variant() - { - try_destroy(); - } - - template - inline - Variant(const _T& t) // FIXME use calltraits here - : idx_(Find<_T, typelist_type>::value) - { - static_assert(Size::value >= 0, "variant with size 0 invalid"); - static_assert(Find<_T, typelist_type>::value >= 0, "given_type_is_not_element_of_variant_maybe_use_explicit_cast"); - ::new(&data_) _T(t); - } - - - // TODO implement inplace factories and assignment operator - - Variant(const Variant& rhs); - Variant& operator=(const Variant& rhs); - - // NO INLINE, TOO LONG - template - Variant& operator=(const _T& t) // FIXME use calltraits here - { - static_assert(Find<_T, typelist_type>::value >= 0, "given_type_is_not_element_of_variant_maybe_use_explicit_cast"); - - if (idx_ == Find<_T, typelist_type>::value) - { - *get<_T>() = t; - } - else - { - try_destroy(); - idx_ = Find<_T, typelist_type>::value; - ::new(&data_) _T(t); - } - - return *this; - } - - template - inline - _T* const get() - { - static_assert(Find<_T, typelist_type>::value >= 0, "given_type_is_not_element_of_variant_maybe_use_explicit_cast"); - - if (Find<_T, typelist_type>::value != idx_) - return 0; - - return (_T*)(&data_); - } - - template - inline - const _T* const get() const - { - static_assert(Find<_T, typelist_type>::value >= 0, "given_type_is_not_element_of_variant_maybe_use_explicit_cast"); - - if (Find<_T, typelist_type>::value != idx_) - return 0; - - return (_T*)(&data_); - } - -// private - - template - static inline - void variant_destroy(void* t) - { - typedef typename RelaxedTypeAt::type _T; - ((_T*)t)->~_T(); - } - - - bool empty() const - { - return idx_ == unset; - } - - - // NON INLINE - too long!!! - // FIXME write with recursive function instead - void try_destroy() - { - // Beware that the direction of types in the typelist is in reverse order!!! - typedef void(*func_type)(void*); - static func_type funcs[] = { - &variant_destroy<0>, - &variant_destroy<1>, - &variant_destroy<2>, - &variant_destroy<3>, - &variant_destroy<4>, - &variant_destroy<5>, - &variant_destroy<6>, - &variant_destroy<7> - // append if necessary - }; - if (idx_ >= 0 && idx_ < Size::value) - funcs[(int)idx_](&data_); - } - - // with an ordinary union only simple data types could be stored in here - typename std::aligned_storage::type data_; - int8_t idx_; -}; - - -template -struct StaticVisitor -{ - typedef ReturnT return_type; -}; - - -template -struct Callfunc -{ - template - static inline - typename VisitorT::return_type eval(VisitorT& visitor, VariantT& variant) - { - return visitor(*variant.template get()); - } -}; - -template<> -struct Callfunc -{ - template - static inline - typename VisitorT::return_type eval(VisitorT&, VariantT&) - { - throw; - } -}; - - -template -typename VisitorT::return_type static_visit(VisitorT& visitor, VariantT& variant) -{ - // FIXME recursive iterate - switch(variant.idx_) - { - // FIXME case -1: - case 0: - return Callfunc::type>::eval(visitor, variant); - - case 1: - return Callfunc::type>::eval(visitor, variant); - - case 2: - return Callfunc::type>::eval(visitor, variant); - - case 3: - return Callfunc::type>::eval(visitor, variant); - - case 4: - return Callfunc::type>::eval(visitor, variant); - - case 5: - return Callfunc::type>::eval(visitor, variant); - - case 6: - return Callfunc::type>::eval(visitor, variant); - - case 7: - return Callfunc::type>::eval(visitor, variant); - - default: - //std::cerr << "Hey, ugly!" << std::endl; - throw; - } -} - - -// FIXME make visitor a first class object -template -typename VisitorT::return_type static_visit(VisitorT& visitor, const VariantT& variant) -{ - // FIXME subsitute switch with static function table - // FIXME recursive iterate - switch(variant.idx_) - { - case 0: - return Callfunc::type>::eval(visitor, variant); - - case 1: - return Callfunc::type>::eval(visitor, variant); - - case 2: - return Callfunc::type>::eval(visitor, variant); - - case 3: - return Callfunc::type>::eval(visitor, variant); - - case 4: - return Callfunc::type>::eval(visitor, variant); - - case 5: - return Callfunc::type>::eval(visitor, variant); - - case 6: - return Callfunc::type>::eval(visitor, variant); - - case 7: - return Callfunc::type>::eval(visitor, variant); - - default: - //std::cerr << "Hey, ugly!" << std::endl; - throw; - } -} - - -namespace detail -{ - template - struct ConstructionVisitor : StaticVisitor<> - { - ConstructionVisitor(VariantT& v) - : v_(v) - { - // NOOP - } - - template - void operator()(const T& t) - { - ::new(&v_.data_) T(t); - } - - VariantT& v_; - }; - - - template - struct AssignmentVisitor : StaticVisitor<> - { - AssignmentVisitor(VariantT& v) - : v_(v) - { - // NOOP - } - - template - void operator()(const T& t) - { - *v_.template get() = t; - } - - VariantT& v_; - }; -} - - -template -Variant::Variant(const Variant& rhs) - : idx_(rhs.idx_) -{ - if (idx_ != unset) - { - detail::ConstructionVisitor> v(*this); - static_visit(v, rhs); - } -} - - -template -Variant& Variant::operator=(const Variant& rhs) -{ - if (this != &rhs) - { - if (idx_ != rhs.idx_) - { - // need to call copy constructor - try_destroy(); - - idx_ = rhs.idx_; - detail::ConstructionVisitor> v(*this); - static_visit(v, rhs); - } - else - { - detail::AssignmentVisitor> v(*this); - static_visit(v, rhs); - } - } - - return *this; -} - - namespace dbus { @@ -383,7 +21,7 @@ namespace detail { -struct VariantSerializer : StaticVisitor<> +struct VariantSerializer { inline VariantSerializer(DBusMessageIter& iter) @@ -415,7 +53,7 @@ struct VariantDeserializer if (!strcmp(buf.str().c_str(), sig)) { v = T1(); - Codec::decode(iter, *v.template get()); + Codec::decode(iter, std::get(v)); return true; } @@ -438,7 +76,7 @@ struct VariantDeserializer if (!strcmp(buf.str().c_str(), sig)) { v = T(); - Codec::decode(iter, *v.template get()); + Codec::decode(iter, std::get(v)); return true; } @@ -450,25 +88,25 @@ struct VariantDeserializer template -bool try_deserialize(DBusMessageIter& iter, Variant& v, const char* sig); +bool try_deserialize(DBusMessageIter& iter, std::variant& v, const char* sig); } // namespace detail template -struct Codec> +struct Codec> { static - void encode(DBusMessageIter& iter, const Variant& v) + void encode(DBusMessageIter& iter, const std::variant& v) { detail::VariantSerializer vs(iter); - static_visit(vs, const_cast&>(v)); // TODO need const visitor + std::visit(vs, const_cast&>(v)); // TODO need const visitor } static - void decode(DBusMessageIter& orig, Variant& v) + void decode(DBusMessageIter& orig, std::variant& v) { DBusMessageIter iter; simppl_dbus_message_iter_recurse(&orig, &iter, DBUS_TYPE_VARIANT); @@ -491,7 +129,7 @@ struct Codec> template -bool detail::try_deserialize(DBusMessageIter& iter, Variant& v, const char* sig) +bool detail::try_deserialize(DBusMessageIter& iter, std::variant& v, const char* sig) { return VariantDeserializer::eval(iter, v, sig); } diff --git a/src/holders.cpp b/src/holders.cpp index b0356e8..93a29fd 100644 --- a/src/holders.cpp +++ b/src/holders.cpp @@ -1,5 +1,4 @@ #include "simppl/pendingcall.h" -#include "simppl/variant.h" #include "simppl/stub.h" #include "simppl/detail/holders.h" diff --git a/tests/introserver.cpp b/tests/introserver.cpp index ede510d..7d5aebe 100644 --- a/tests/introserver.cpp +++ b/tests/introserver.cpp @@ -72,7 +72,7 @@ struct ComboEntry struct Menu { - typedef simppl::Variant entry_type; + typedef std::variant entry_type; typedef std::map> menu_entries_type; diff --git a/tests/variant.cpp b/tests/variant.cpp index 9c112ad..fc8f2ec 100644 --- a/tests/variant.cpp +++ b/tests/variant.cpp @@ -28,7 +28,7 @@ namespace test INTERFACE(VServer) { - Method>>> getData; + Method>>> getData; VServer() : INIT(getData) @@ -70,7 +70,7 @@ namespace { : simppl::dbus::Stub(d, "role") { connected >> [this](simppl::dbus::ConnectionState s){ - getData.async() >> [this](const simppl::dbus::CallState& state, const std::map>& mapping){ + getData.async() >> [this](const simppl::dbus::CallState& state, const std::map>& mapping){ EXPECT_EQ(3u, mapping.size()); auto hello = mapping.find("Hello"); @@ -81,9 +81,9 @@ namespace { EXPECT_NE(mapping.end(), world); EXPECT_NE(mapping.end(), toll); - EXPECT_EQ(42, *hello->second.get()); - EXPECT_EQ(4711, *world->second.get()); - EXPECT_EQ(std::string("Show"), *toll->second.get()); + EXPECT_EQ(42, std::get(hello->second)); + EXPECT_EQ(4711, std::get(world->second)); + EXPECT_EQ(std::string("Show"), std::get(toll->second)); disp().stop(); }; @@ -97,7 +97,7 @@ namespace { : simppl::dbus::Skeleton(d, "role") { getData >> [this](){ - std::map> mapping; + std::map> mapping; mapping["Hello"] = 42; mapping["World"] = 4711; mapping["Tolle"] = std::string("Show"); @@ -109,62 +109,6 @@ namespace { } -TEST(Variant, basic) -{ - constructs = 0; - destructs = 0; - - simppl::Variant v; - - v = 42; - EXPECT_EQ(42, *v.get()); - - v = std::string("Hallo Welt"); - EXPECT_EQ(std::string("Hallo Welt"), *v.get()); - - v = TestHelper(); - - v = 43; - EXPECT_EQ(43, *v.get()); - - EXPECT_EQ(2, constructs); - EXPECT_EQ(2, destructs); -} - - -TEST(Variant, map) -{ - simppl::Variant > v; - - std::map m { - { 1, "Hallo" }, - { 2, "Welt" } - }; - - v = m; - EXPECT_EQ(2u, (v.get>()->size())); - - int i=0; - for(auto& e : *v.get>()) - { - if (i == 0) - { - EXPECT_EQ(1, e.first); - EXPECT_EQ(std::string("Hallo"), e.second); - } - else if (i == 1) - { - EXPECT_EQ(2, e.first); - EXPECT_EQ(std::string("Welt"), e.second); - } - - ++i; - } - - EXPECT_EQ(2, i); -} - - TEST(Variant, method) { simppl::dbus::Dispatcher d("bus:session");