From 5bc911e2599a35cff227cc1042f125dffb6d4a9f Mon Sep 17 00:00:00 2001 From: Johannes Schanda Date: Fri, 11 Jan 2013 16:59:39 +0100 Subject: [PATCH] Dev for variant --- Makefile.am | 67 +-------- src/test/DBusVariantTest.cpp | 333 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 335 insertions(+), 65 deletions(-) create mode 100644 src/test/DBusVariantTest.cpp diff --git a/Makefile.am b/Makefile.am index 4fa9c6b..8bfcb20 100644 --- a/Makefile.am +++ b/Makefile.am @@ -85,73 +85,10 @@ TestInterfaceSources = \ src/test/commonapi/tests/TestInterfaceStubDefault.cpp check_PROGRAMS = \ - DBusCommunicationTest \ - DBusMultipleConnectionTest \ - DBusDaemonProxyTest \ - DBusInputStreamTest \ - DBusOutputStreamTest \ - DBusRuntimeTest \ - DBusFactoryTest \ - DBusProxyTest \ - DBusVariantTest \ - DBusBenchmarkingTest + DBusVariantTest -TESTS = ${check_PROGRAMS} -DBusBenchmarkingTest_SOURCES = src/test/DBusBenchmarkingTest.cpp -DBusBenchmarkingTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusBenchmarkingTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusBenchmarkingTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusCommunicationTest_SOURCES = \ - src/test/DBusCommunicationTest.cpp \ - ${TestInterfaceSources} -DBusCommunicationTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusCommunicationTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusCommunicationTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusDaemonProxyTest_SOURCES = src/test/DBusDaemonProxyTest.cpp -DBusDaemonProxyTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusDaemonProxyTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusDaemonProxyTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusInputStreamTest_SOURCES = src/test/DBusInputStreamTest.cpp -DBusInputStreamTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusInputStreamTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusInputStreamTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusOutputStreamTest_SOURCES = src/test/DBusOutputStreamTest.cpp -DBusOutputStreamTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusOutputStreamTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusOutputStreamTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusFactoryTest_SOURCES = \ - src/test/DBusFactoryTest.cpp \ - ${TestInterfaceSources} -DBusFactoryTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusFactoryTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusFactoryTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusRuntimeTest_SOURCES = src/test/DBusRuntimeTest.cpp -DBusRuntimeTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusRuntimeTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusRuntimeTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -#DBusStubAdapterTest_SOURCES = src/test/DBusStubAdapterTest.cpp -#DBusStubAdapterTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -#DBusStubAdapterTest_CXXFLAGS = ${GTEST_CXXFLAGS} -#DBusStubAdapterTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusMultipleConnectionTest_SOURCES = src/test/DBusMultipleConnectionTest.cpp \ - ${TestInterfaceSources} -DBusMultipleConnectionTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusMultipleConnectionTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusMultipleConnectionTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la - -DBusProxyTest_SOURCES = src/test/DBusProxyTest.cpp -DBusProxyTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} -DBusProxyTest_CXXFLAGS = ${GTEST_CXXFLAGS} -DBusProxyTest_LDADD = ${LDADD} ${GTEST_LIBS} libCommonAPI-DBus.la +TESTS = ${check_PROGRAMS} DBusVariantTest_SOURCES = src/test/DBusVariantTest.cpp DBusVariantTest_CPPFLAGS = ${AM_CPPFLAGS} ${GTEST_CPPFLAGS} diff --git a/src/test/DBusVariantTest.cpp b/src/test/DBusVariantTest.cpp new file mode 100644 index 0000000..d3eeeaa --- /dev/null +++ b/src/test/DBusVariantTest.cpp @@ -0,0 +1,333 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include +#include +#include +#include +#include + +template +struct apply_void_visitor; + +template +struct apply_void_visitor { + static const unsigned int index = 0; + + static + void visit(Visitor&, Variant&) { + //won't be called + assert(false); + throw ""; + } +}; + +template +struct apply_void_visitor { + static const unsigned int index = apply_void_visitor::index + 1; + + static + void visit(Visitor& visitor, Variant& var) { + if (var.getValueType() == index) { + bool b; + visitor(var.template get(b)); + } else { + apply_void_visitor::visit(visitor, var); + } + } +}; + +/*template +struct assign_visitor { +public: + assign_visitor(Variant& lhs, const bool clear = true) : + lhs_(lhs), clear_(clear) { + } + + template + void operator()(const T& value) const { + lhs_.template set(value, clear_); + } + + template + void operator()(T& value) const { + lhs_.template set(value, clear_); + } + +private: + Variant& lhs_; + const bool clear_; +};*/ + +template +struct clear_visitor { +public: + clear_visitor(typename std::aligned_storage::type& storage) : + storage_(storage) { + } + + template + void operator()(const _Type&) const { + (reinterpret_cast(&storage_))->~_Type(); + } + + private: + typename std::aligned_storage::type& storage_; +}; + +template +struct select_type; + +template +struct select_type { +}; + +//U == T +template +struct select_type { + typedef T type; +}; + +//U& == T +template +struct select_type { + typedef T& type; +}; + +//U == T& +template +struct select_type { + typedef T type; +}; + +//const U& == T +template +struct select_type { + typedef const T& type; +}; + +//U == const T& +template +struct select_type { + typedef T type; +}; + +//U == X* +//T == const X* +template +struct select_type { + typedef const T* type; +}; + +//U == X& +//T == const X& +template +struct select_type { + typedef const T& type; +}; + +//U != T, let's try to find U among Ts +template +struct select_type { + typedef typename select_type::type type; +}; + +template +struct type_index_getter; + +template<> +struct type_index_getter<> { + static const unsigned int index = 0; + + template + static + unsigned int get() { + return 0; + } +}; + +template +struct type_index_getter { + static const unsigned int index = type_index_getter::index + 1; + + template + static + unsigned int get( + typename std::enable_if::value >::type* = 0) { + return index; + } + + template + static + unsigned int get(typename std::enable_if::value >::type* = 0) { + return type_index_getter::template get(); + } +}; + +template +struct max_size; + +template<> +struct max_size<> { + static const unsigned int value = 0; +}; + +template +struct max_size { + static const unsigned int current_type_size = sizeof(T); + static const unsigned int next_type_size = max_size::value; + static const unsigned int value = + current_type_size > next_type_size ? + current_type_size : next_type_size; +}; + +template +struct VariantTypeSelector: VariantTypeSelector<_SearchType, _RestTypes...> { +}; + +template +struct VariantTypeSelector<_SearchType, _SearchType, _RestTypes...> { + typedef _SearchType type; +}; + +template +class Variant { + private: + typedef std::tuple_size> TypesTupleSize; + + public: + + static const unsigned int maxSize = max_size<_Types...>::value; + + + Variant(): valueType_(TypesTupleSize::value) { + } + + Variant(const Variant& fromVariant): + valueType_(fromVariant.valueType_), + valueStorage_(fromVariant.valueStorage_) { + } + + Variant(Variant&& fromVariant): + valueType_(std::move(fromVariant.valueType_)), + valueStorage_(std::move(fromVariant.valueStorage_)) { + fromVariant.valueType_ = TypesTupleSize::value; + } + + ~Variant() { + if (hasValue()) { + clear_visitor visitor(valueStorage_); + apply_void_visitor, Variant<_Types...>, _Types...>::visit(visitor, *this); + } + } + + Variant& operator=(const Variant& fromVariant) { + // TODO + return *this; + } + + Variant& operator=(Variant&& fromVariant) { + // TODO + return *this; + } + + template + const bool& isType() const { + typedef typename select_type<_Type, _Types...>::type selected_type_t; + unsigned int cType = type_index_getter<_Types...>::template get(); + if(cType == valueType_) { + return true; + } else { + return false; + } + } + + // TODO use std::enable_if + template + Variant(const _Type& value) { + typedef typename select_type<_Type, _Types...>::type selected_type_t; + valueType_ = type_index_getter<_Types...>::template get(); + new (&valueStorage_) _Type(value); + } + + // TODO use std::enable_if + template + Variant(_Type && value) { + typedef typename select_type<_Type, _Types...>::type selected_type_t; + valueType_ = type_index_getter<_Types...>::template get(); + new (&valueStorage_) typename std::remove_reference<_Type>::type(std::move(value)); + } + + template + const typename VariantTypeSelector<_Type, _Types...>::type & get(bool& success) const { + typedef typename select_type<_Type, _Types...>::type selected_type_t; + unsigned int cType = type_index_getter<_Types...>::template get(); + if(cType == valueType_) { + success = true; + return *(reinterpret_cast(&valueStorage_)); + } else { + success = false; + //TODO: Fix return temporary + return _Type(); + } + } + + inline size_t getValueType() { + return valueType_; + } + + template + void set( const U& value, const bool clear) { + typedef typename select_type::type selected_type_t; + + const selected_type_t& type_value = value; + if(hasValue()) { + clear_visitor visitor(valueStorage_); + apply_void_visitor, Variant<_Types...>, _Types...>::visit(visitor, *this); + } + new (&valueStorage_) selected_type_t(std::move(value)); + valueType_ = type_index_getter<_Types...>::template get(); + } + + private: + inline bool hasValue() const { + return valueType_ < TypesTupleSize::value; + } + + size_t valueType_; + typename std::aligned_storage::type valueStorage_; + +}; + + + +int main(int argc, char** argv) { + int fromInt = 5; + double fromDouble = 12.344d; + std::string fromString = "123abc!"; + Variant myVariant(fromInt); + Variant myVariantf(fromDouble); + + Variant* myVariants = new Variant(fromString); + bool success; + + const int& myInt = myVariant.get(success); + std::cout << "myInt = " << myInt << " (" << std::boolalpha << success << ")\n"; + + const int& myFake = myVariant.get(success); + std::cout << "myFake = " << myFake << " (" << std::boolalpha << success << ")\n"; + + std::cout << "myInt is int = " << " (" << std::boolalpha << myVariant.isType() << ")\n"; + std::cout << "myInt is std::string = " << " (" << std::boolalpha << myVariant.isType() << ")\n"; + + const int& myDouble = myVariantf.get(success); + std::cout << "myDouble = " << myDouble << " (" << std::boolalpha << success << ")\n"; + + const std::string& myString = myVariants->get(success); + std::cout << "myString = " << myString << " (" << std::boolalpha << success << ")\n"; + + delete myVariants; + + return 0; +} -- 2.7.4