File indexing completed on 2024-05-19 05:37:25

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::invoke_result<_Transformation &, _In &&>::type result_type;
0030 };
0031 
0032 template<typename... _In, typename _Transformation>
0033 struct TransformFutureInterfaceHelper<std::tuple<_In...>, _Transformation> {
0034     typedef typename std::invoke_result<_Transformation &, _In &&...>::type result_type;
0035 };
0036 
0037 template<typename _Transformation>
0038 struct TransformFutureInterfaceHelper<void, _Transformation> {
0039     typedef typename std::invoke_result<_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