From: Olivier Goffart Date: Mon, 18 Apr 2011 12:07:32 +0000 (+0200) Subject: Support of lambdas in QtConcurrent::run X-Git-Tag: qt-v5.0.0-alpha1~4250 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d3e5fc0220e57d5a9bba35780915c53790ff249f;p=profile%2Fivi%2Fqtbase.git Support of lambdas in QtConcurrent::run Reviewed-by: Joao (cherry picked from commit 917f2ff617209bcc283eb3590b422bcf239c0537) Change-Id: I837f18f043b18410c1d93b9f1156acf729dad510 Reviewed-on: http://codereview.qt.nokia.com/142 Reviewed-by: Olivier Goffart --- diff --git a/src/corelib/concurrent/qtconcurrentcompilertest.h b/src/corelib/concurrent/qtconcurrentcompilertest.h index 884badb..c139c7a 100644 --- a/src/corelib/concurrent/qtconcurrentcompilertest.h +++ b/src/corelib/concurrent/qtconcurrentcompilertest.h @@ -57,6 +57,20 @@ QT_MODULE(Core) # define QT_TYPENAME typename #endif +namespace QtPrivate { + +template +class HasResultType { + typedef char Yes; + typedef void *No; + template static Yes test(int, const typename U::result_type * = 0); + template static No test(double); +public: + enum { Value = (sizeof(test(0)) == sizeof(Yes)) }; +}; + +} + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/corelib/concurrent/qtconcurrentfunctionwrappers.h b/src/corelib/concurrent/qtconcurrentfunctionwrappers.h index a79ad1c..4bf2736 100644 --- a/src/corelib/concurrent/qtconcurrentfunctionwrappers.h +++ b/src/corelib/concurrent/qtconcurrentfunctionwrappers.h @@ -195,17 +195,10 @@ QtConcurrent::ConstMemberFunctionWrapper createFunctionWrapper(T (C::*func return QtConcurrent::ConstMemberFunctionWrapper(func); } - -template -void *lazyResultType_helper(int, typename T::result_type * = 0); -template -char lazyResultType_helper(double); - -template (0)) != sizeof(void*)> +template ::Value> struct LazyResultType { typedef typename Functor::result_type Type; }; template -struct LazyResultType { typedef void Type; }; - +struct LazyResultType { typedef void Type; }; template struct ReduceResultType; diff --git a/src/corelib/concurrent/qtconcurrentrun.h b/src/corelib/concurrent/qtconcurrentrun.h index 8611fba..ef51b2a 100644 --- a/src/corelib/concurrent/qtconcurrentrun.h +++ b/src/corelib/concurrent/qtconcurrentrun.h @@ -71,63 +71,114 @@ namespace QtConcurrent { template QFuture run(T (*functionPointer)()) { - return (new QT_TYPENAME SelectStoredFunctorCall0::type(functionPointer))->start(); + return (new StoredFunctorCall0(functionPointer))->start(); } template QFuture run(T (*functionPointer)(Param1), const Arg1 &arg1) { - return (new QT_TYPENAME SelectStoredFunctorCall1::type(functionPointer, arg1))->start(); + return (new StoredFunctorCall1(functionPointer, arg1))->start(); } template QFuture run(T (*functionPointer)(Param1, Param2), const Arg1 &arg1, const Arg2 &arg2) { - return (new QT_TYPENAME SelectStoredFunctorCall2::type(functionPointer, arg1, arg2))->start(); + return (new StoredFunctorCall2(functionPointer, arg1, arg2))->start(); } template QFuture run(T (*functionPointer)(Param1, Param2, Param3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { - return (new QT_TYPENAME SelectStoredFunctorCall3::type(functionPointer, arg1, arg2, arg3))->start(); + return (new StoredFunctorCall3(functionPointer, arg1, arg2, arg3))->start(); } template QFuture run(T (*functionPointer)(Param1, Param2, Param3, Param4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { - return (new QT_TYPENAME SelectStoredFunctorCall4::type(functionPointer, arg1, arg2, arg3, arg4))->start(); + return (new StoredFunctorCall4(functionPointer, arg1, arg2, arg3, arg4))->start(); } template QFuture run(T (*functionPointer)(Param1, Param2, Param3, Param4, Param5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { - return (new QT_TYPENAME SelectStoredFunctorCall5::type(functionPointer, arg1, arg2, arg3, arg4, arg5))->start(); + return (new StoredFunctorCall5(functionPointer, arg1, arg2, arg3, arg4, arg5))->start(); } +#ifdef Q_COMPILER_DECLTYPE + +template +auto run(Functor functor) -> typename QtPrivate::QEnableIf::Value, QFuture >::Type +{ + typedef decltype(functor()) result_type; + return (new StoredFunctorCall0(functor))->start(); +} + +template +auto run(Functor functor, const Arg1 &arg1) + -> typename QtPrivate::QEnableIf::Value, QFuture >::Type +{ + typedef decltype(functor(arg1)) result_type; + return (new StoredFunctorCall1(functor, arg1))->start(); +} + +template +auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2) + -> typename QtPrivate::QEnableIf::Value, QFuture >::Type +{ + typedef decltype(functor(arg1, arg2)) result_type; + return (new StoredFunctorCall2(functor, arg1, arg2))->start(); +} + +template +auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) + -> typename QtPrivate::QEnableIf::Value, QFuture >::Type +{ + typedef decltype(functor(arg1, arg2, arg3)) result_type; + return (new StoredFunctorCall3(functor, arg1, arg2, arg3))->start(); +} + +template +auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) + -> typename QtPrivate::QEnableIf::Value, QFuture >::Type +{ + typedef decltype(functor(arg1, arg2, arg3, arg4)) result_type; + return (new StoredFunctorCall4(functor, arg1, arg2, arg3, arg4))->start(); +} + +template +auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) + -> typename QtPrivate::QEnableIf::Value, QFuture >::Type +{ + typedef decltype(functor(arg1, arg2, arg3, arg4, arg5)) result_type; + return (new StoredFunctorCall5(functor, arg1, arg2, arg3, arg4, arg5))->start(); +} + +#endif + template QFuture run(FunctionObject functionObject) { - return (new QT_TYPENAME SelectStoredFunctorCall0::type(functionObject))->start(); + return (new StoredFunctorCall0(functionObject))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1) { - return (new QT_TYPENAME SelectStoredFunctorCall1::type(functionObject, arg1))->start(); + return (new StoredFunctorCall1(functionObject, arg1))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2) { - return (new QT_TYPENAME SelectStoredFunctorCall2::type(functionObject, arg1, arg2))->start(); + return (new StoredFunctorCall2(functionObject, arg1, arg2))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { - return (new QT_TYPENAME SelectStoredFunctorCall3::type(functionObject, arg1, arg2, arg3))->start(); + return (new StoredFunctorCall3(functionObject, arg1, arg2, arg3))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { - return (new QT_TYPENAME SelectStoredFunctorCall4::type(functionObject, arg1, arg2, arg3, arg4))->start(); + return (new StoredFunctorCall4(functionObject, arg1, arg2, arg3, arg4))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { - return (new QT_TYPENAME SelectStoredFunctorCall5::type(functionObject, arg1, arg2, arg3, arg4, arg5))->start(); + return (new StoredFunctorCall5(functionObject, arg1, arg2, arg3, arg4, arg5))->start(); } template diff --git a/src/corelib/concurrent/qtconcurrentstoredfunctioncall.h b/src/corelib/concurrent/qtconcurrentstoredfunctioncall.h index c61f9b8..9beb0b9 100644 --- a/src/corelib/concurrent/qtconcurrentstoredfunctioncall.h +++ b/src/corelib/concurrent/qtconcurrentstoredfunctioncall.h @@ -66,10 +66,10 @@ struct StoredFunctorCall0: public RunFunctionTask }; -template -struct VoidStoredFunctorCall0: public RunFunctionTask +template +struct StoredFunctorCall0: public RunFunctionTask { - inline VoidStoredFunctorCall0(FunctionPointer _function) + inline StoredFunctorCall0(FunctionPointer _function) : function(_function) {} void runFunctor() { function(); } FunctionPointer function; @@ -77,13 +77,6 @@ struct VoidStoredFunctorCall0: public RunFunctionTask }; template -struct SelectStoredFunctorCall0 -{ - typedef typename SelectSpecialization::template - Type, - VoidStoredFunctorCall0 >::type type; -}; -template struct StoredFunctorPointerCall0: public RunFunctionTask { inline StoredFunctorPointerCall0(FunctionPointer * _function) @@ -276,10 +269,10 @@ struct StoredFunctorCall1: public RunFunctionTask Arg1 arg1; }; -template -struct VoidStoredFunctorCall1: public RunFunctionTask +template +struct StoredFunctorCall1: public RunFunctionTask { - inline VoidStoredFunctorCall1(FunctionPointer _function, const Arg1 &_arg1) + inline StoredFunctorCall1(FunctionPointer _function, const Arg1 &_arg1) : function(_function), arg1(_arg1) {} void runFunctor() { function(arg1); } FunctionPointer function; @@ -287,13 +280,6 @@ struct VoidStoredFunctorCall1: public RunFunctionTask }; template -struct SelectStoredFunctorCall1 -{ - typedef typename SelectSpecialization::template - Type, - VoidStoredFunctorCall1 >::type type; -}; -template struct StoredFunctorPointerCall1: public RunFunctionTask { inline StoredFunctorPointerCall1(FunctionPointer * _function, const Arg1 &_arg1) @@ -486,10 +472,10 @@ struct StoredFunctorCall2: public RunFunctionTask Arg1 arg1; Arg2 arg2; }; -template -struct VoidStoredFunctorCall2: public RunFunctionTask +template +struct StoredFunctorCall2: public RunFunctionTask { - inline VoidStoredFunctorCall2(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2) + inline StoredFunctorCall2(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2) : function(_function), arg1(_arg1), arg2(_arg2) {} void runFunctor() { function(arg1, arg2); } FunctionPointer function; @@ -497,13 +483,6 @@ struct VoidStoredFunctorCall2: public RunFunctionTask }; template -struct SelectStoredFunctorCall2 -{ - typedef typename SelectSpecialization::template - Type, - VoidStoredFunctorCall2 >::type type; -}; -template struct StoredFunctorPointerCall2: public RunFunctionTask { inline StoredFunctorPointerCall2(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2) @@ -696,10 +675,10 @@ struct StoredFunctorCall3: public RunFunctionTask Arg1 arg1; Arg2 arg2; Arg3 arg3; }; -template -struct VoidStoredFunctorCall3: public RunFunctionTask +template +struct StoredFunctorCall3: public RunFunctionTask { - inline VoidStoredFunctorCall3(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) + inline StoredFunctorCall3(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3) {} void runFunctor() { function(arg1, arg2, arg3); } FunctionPointer function; @@ -707,13 +686,6 @@ struct VoidStoredFunctorCall3: public RunFunctionTask }; template -struct SelectStoredFunctorCall3 -{ - typedef typename SelectSpecialization::template - Type, - VoidStoredFunctorCall3 >::type type; -}; -template struct StoredFunctorPointerCall3: public RunFunctionTask { inline StoredFunctorPointerCall3(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3) @@ -906,10 +878,10 @@ struct StoredFunctorCall4: public RunFunctionTask Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; }; -template -struct VoidStoredFunctorCall4: public RunFunctionTask +template +struct StoredFunctorCall4: public RunFunctionTask { - inline VoidStoredFunctorCall4(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) + inline StoredFunctorCall4(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4) {} void runFunctor() { function(arg1, arg2, arg3, arg4); } FunctionPointer function; @@ -917,13 +889,6 @@ struct VoidStoredFunctorCall4: public RunFunctionTask }; template -struct SelectStoredFunctorCall4 -{ - typedef typename SelectSpecialization::template - Type, - VoidStoredFunctorCall4 >::type type; -}; -template struct StoredFunctorPointerCall4: public RunFunctionTask { inline StoredFunctorPointerCall4(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4) @@ -1116,10 +1081,10 @@ struct StoredFunctorCall5: public RunFunctionTask Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; }; -template -struct VoidStoredFunctorCall5: public RunFunctionTask +template +struct StoredFunctorCall5: public RunFunctionTask { - inline VoidStoredFunctorCall5(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) + inline StoredFunctorCall5(FunctionPointer _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) : function(_function), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5) {} void runFunctor() { function(arg1, arg2, arg3, arg4, arg5); } FunctionPointer function; @@ -1127,13 +1092,6 @@ struct VoidStoredFunctorCall5: public RunFunctionTask }; template -struct SelectStoredFunctorCall5 -{ - typedef typename SelectSpecialization::template - Type, - VoidStoredFunctorCall5 >::type type; -}; -template struct StoredFunctorPointerCall5: public RunFunctionTask { inline StoredFunctorPointerCall5(FunctionPointer * _function, const Arg1 &_arg1, const Arg2 &_arg2, const Arg3 &_arg3, const Arg4 &_arg4, const Arg5 &_arg5) @@ -1316,6 +1274,33 @@ struct SelectStoredConstMemberFunctionPointerCall5 Type, VoidStoredConstMemberFunctionPointerCall5 >::type type; }; + +template +class StoredFunctorCall : public RunFunctionTask +{ +public: + StoredFunctorCall(const Functor &f) : functor(f) { } + void runFunctor() + { + this->result = functor(); + } +private: + Functor functor; +}; +template +class StoredFunctorCall : public RunFunctionTask +{ +public: + StoredFunctorCall(const Functor &f) : functor(f) { } + void runFunctor() + { + functor(); + } +private: + Functor functor; +}; + + } //namespace QtConcurrent #endif // qdoc diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 445b65b..3282390 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -428,6 +428,7 @@ namespace QT_NAMESPACE {} # define Q_COMPILER_INITIALIZER_LISTS # define Q_COMPILER_AUTO_TYPE # define Q_COMPILER_LAMBDA +# define Q_COMPILER_DECLTYPE //# define Q_COMPILER_VARIADIC_TEMPLATES //# define Q_COMPILER_CLASS_ENUM //# define Q_COMPILER_DEFAULT_DELETE_MEMBERS @@ -524,6 +525,7 @@ namespace QT_NAMESPACE {} # if (__GNUC__ * 100 + __GNUC_MINOR__) >= 403 /* C++0x features supported in GCC 4.3: */ # define Q_COMPILER_RVALUE_REFS +# define Q_COMPILER_DECLTYPE # endif # if (__GNUC__ * 100 + __GNUC_MINOR__) >= 404 /* C++0x features supported in GCC 4.4: */ @@ -791,6 +793,7 @@ namespace QT_NAMESPACE {} # if __INTEL_COMPILER >= 1100 # define Q_COMPILER_RVALUE_REFS # define Q_COMPILER_EXTERN_TEMPLATES +# define Q_COMPILER_DECLTYPE # elif __INTEL_COMPILER >= 1200 # define Q_COMPILER_VARIADIC_TEMPLATES # define Q_COMPILER_AUTO_TYPE diff --git a/tests/auto/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/qtconcurrentrun/tst_qtconcurrentrun.cpp index e4e9479..cacb09a 100644 --- a/tests/auto/qtconcurrentrun/tst_qtconcurrentrun.cpp +++ b/tests/auto/qtconcurrentrun/tst_qtconcurrentrun.cpp @@ -67,6 +67,8 @@ private slots: #if 0 void createFunctor(); #endif + void functor(); + void lambda(); }; #if 0 @@ -444,6 +446,71 @@ void tst_QtConcurrentRun::createFunctor() } #endif +struct Functor { + int operator()() { return 42; } + double operator()(double a, double b) { return a/b; } + int operator()(int a, int b) { return a/b; } + void operator()(int) { } + void operator()(int, int, int) { } + void operator()(int, int, int, int) { } + void operator()(int, int, int, int, int) { } + void operator()(int, int, int, int, int, int) { } +}; + +void tst_QtConcurrentRun::functor() +{ + //this test functor without result_type, decltype need to be supported by the compiler +#ifndef Q_COMPILER_DECLTYPE + QSKIP("Compiler do not suport decltype", SkipAll); +#else + Functor f; + { + QFuture fut = QtConcurrent::run(f); + QCOMPARE(fut.result(), 42); + } + { + QFuture fut = QtConcurrent::run(f, 8.5, 1.8); + QCOMPARE(fut.result(), (8.5/1.8)); + } + { + QFuture fut = QtConcurrent::run(f, 19, 3); + QCOMPARE(fut.result(), int(19/3)); + } + { + QtConcurrent::run(f, 1).waitForFinished(); + QtConcurrent::run(f, 1,2).waitForFinished(); + QtConcurrent::run(f, 1,2,3).waitForFinished(); + QtConcurrent::run(f, 1,2,3,4).waitForFinished(); + QtConcurrent::run(f, 1,2,3,4,5).waitForFinished(); + } +#endif +} + + +void tst_QtConcurrentRun::lambda() +{ +#ifndef Q_COMPILER_LAMBDA + QSKIP("Compiler do not suport lambda", SkipAll); +#else + + QCOMPARE(QtConcurrent::run([](){ return 45; }).result(), 45); + QCOMPARE(QtConcurrent::run([](int a){ return a+15; }, 12).result(), 12+15); + QCOMPARE(QtConcurrent::run([](int a, double b){ return a + b; }, 12, 15).result(), double(12+15)); + QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); + +#ifdef Q_COMPILER_INITIALIZER_LISTS + { + QString str { "Hello World Foo" }; + QFuture f1 = QtConcurrent::run([&](){ return str.split(' '); }); + auto r = f1.result(); + QCOMPARE(r, QStringList({"Hello", "World", "Foo"})); + } +#endif + +#endif +} + + #include "tst_qtconcurrentrun.moc" #else