File indexing completed on 2024-05-19 16:40:00
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Ivan Cukic <ivan.cukic(at)kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 // 0008 // W A R N I N G 0009 // ------------- 0010 // 0011 // This file is not part of the AsynQt API. It exists purely as an 0012 // implementation detail. This header file may change from version to 0013 // version without notice, or even be removed. 0014 // 0015 // We mean it. 0016 // 0017 0018 #include <type_traits> 0019 0020 #include "../cxxutils_p.h" 0021 #include "../utils_p.h" 0022 0023 namespace AsynQt 0024 { 0025 namespace detail 0026 { 0027 template<typename _In, typename _Transformation> 0028 struct TransformFutureInterfaceHelper { 0029 typedef typename std::result_of<_Transformation &(_In &&)>::type result_type; 0030 }; 0031 0032 template<typename... _In, typename _Transformation> 0033 struct TransformFutureInterfaceHelper<std::tuple<_In...>, _Transformation> { 0034 typedef typename std::result_of<_Transformation &(_In &&...)>::type result_type; 0035 }; 0036 0037 template<typename _Transformation> 0038 struct TransformFutureInterfaceHelper<void, _Transformation> { 0039 typedef typename std::result_of<_Transformation &()>::type result_type; 0040 }; 0041 0042 template<typename _In, typename _Transformation> 0043 class TransformFutureInterface : public QObject, public QFutureInterface<typename TransformFutureInterfaceHelper<_In, _Transformation>::result_type> 0044 { 0045 public: 0046 typedef typename TransformFutureInterfaceHelper<_In, _Transformation>::result_type result_type; 0047 typedef typename std::is_void<_In>::type in_type_is_void; 0048 typedef typename std::is_void<result_type> result_type_is_void; 0049 0050 TransformFutureInterface(QFuture<_In> future, _Transformation transformation) 0051 : m_future(future) 0052 , m_transformation(transformation) 0053 { 0054 } 0055 0056 ~TransformFutureInterface() override 0057 { 0058 } 0059 0060 // If _In is void, we are never going to get a result, 0061 // so, we need to pretend like we got one when the 0062 // future is successfully finished 0063 inline void setFutureResultOnFinished(std::true_type, // _In is void 0064 std::true_type // result_type is void 0065 ) 0066 { 0067 // no value, no result to create, but we still 0068 // want to call the transformation function 0069 if (!m_future.isCanceled()) { 0070 m_transformation(); 0071 } 0072 } 0073 0074 inline void setFutureResultOnFinished(std::true_type, // _In is void 0075 std::false_type // result_type is not void 0076 ) 0077 { 0078 if (!m_future.isCanceled()) { 0079 this->reportResult(m_transformation()); 0080 } 0081 } 0082 0083 // Ignore id _In is not void 0084 template<typename T> 0085 inline void setFutureResultOnFinished(std::false_type, T) 0086 { 0087 } 0088 0089 // We need to test whether we can unpack a tuple to call 0090 // the transformation 0091 template<typename _InType> 0092 result_type applyTransformation(_InType &&result) 0093 { 0094 return m_transformation(std::forward<_InType>(result)); 0095 } 0096 0097 template<typename _Tuple, int... _Indices> 0098 result_type applyTransformationImpl(_Tuple &&result, index_sequence<_Indices...>) 0099 { 0100 return m_transformation(std::get<_Indices>(result)...); 0101 } 0102 0103 template<typename... _InTypes> 0104 result_type applyTransformation(std::tuple<_InTypes...> &&result) 0105 { 0106 return applyTransformationImpl(std::forward<std::tuple<_InTypes...>>(result), make_index_sequence<sizeof...(_InTypes)>()); 0107 } 0108 0109 // If _In is not void, then all is as it should be 0110 inline void setFutureResultAt(int index, 0111 std::false_type, // _In is not void 0112 std::true_type // result_type is void 0113 ) 0114 { 0115 // nothing to do with the value, but we still 0116 // want to call the transformation function 0117 applyTransformation(m_future.resultAt(index)); 0118 } 0119 0120 inline void setFutureResultAt(int index, 0121 std::false_type, // _In is not void 0122 std::false_type // result_type is not void 0123 ) 0124 { 0125 this->reportResult(applyTransformation(m_future.resultAt(index))); 0126 } 0127 0128 template<typename T> 0129 inline void setFutureResultAt(int, std::true_type, T) 0130 { 0131 } 0132 0133 QFuture<result_type> start() 0134 { 0135 m_futureWatcher.reset(new QFutureWatcher<_In>()); 0136 0137 onFinished(m_futureWatcher, [this]() { 0138 setFutureResultOnFinished(in_type_is_void(), result_type_is_void()); 0139 this->reportFinished(); 0140 }); 0141 0142 onCanceled(m_futureWatcher, [this]() { 0143 this->reportCanceled(); 0144 }); 0145 0146 onResultReadyAt(m_futureWatcher, [this](int index) { 0147 setFutureResultAt(index, in_type_is_void(), result_type_is_void()); 0148 }); 0149 0150 m_futureWatcher->setFuture(m_future); 0151 0152 this->reportStarted(); 0153 0154 return this->future(); 0155 } 0156 0157 private: 0158 QFuture<_In> m_future; 0159 _Transformation m_transformation; 0160 std::unique_ptr<QFutureWatcher<_In>> m_futureWatcher; 0161 }; 0162 0163 template<typename _In, typename _Transformation> 0164 QFuture<typename detail::TransformFutureInterface<_In, _Transformation>::result_type> transform_impl(const QFuture<_In> &future, 0165 _Transformation &&transformation) 0166 { 0167 return (new TransformFutureInterface<_In, _Transformation>(future, std::forward<_Transformation>(transformation)))->start(); 0168 } 0169 0170 namespace operators 0171 { 0172 template<typename _Transformation> 0173 class TransformationModifier 0174 { 0175 public: 0176 TransformationModifier(_Transformation transformation) 0177 : m_transformation(transformation) 0178 { 0179 } 0180 0181 _Transformation m_transformation; 0182 }; 0183 0184 template<typename _In, typename _Transformation> 0185 auto operator|(const QFuture<_In> &future, TransformationModifier<_Transformation> &&modifier) -> decltype(transform_impl(future, modifier.m_transformation)) 0186 { 0187 return transform_impl(future, modifier.m_transformation); 0188 } 0189 0190 } // namespace operators 0191 0192 } // namespace detail 0193 } // namespace AsynQt