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

0001 /*
0002  *   SPDX-FileCopyrightText: 2017 Ivan Čukić <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 "../cxxutils_p.h"
0019 #include "../utils_p.h"
0020 
0021 namespace AsynQt
0022 {
0023 namespace detail
0024 {
0025 template<typename... _Results>
0026 class CollectFutureInterface : public QObject, public QFutureInterface<std::tuple<_Results...>>
0027 {
0028 public:
0029     CollectFutureInterface(QFuture<_Results>... futures)
0030         : m_waitingCount(m_count)
0031         , m_futures(std::make_tuple(futures...))
0032     {
0033     }
0034 
0035     template<int index>
0036     bool connectFuture()
0037     {
0038         auto future = std::get<index>(m_futures);
0039         auto &watcher = std::get<index>(m_watchers);
0040 
0041         onFinished(watcher, [this] {
0042             m_waitingCount--;
0043 
0044             // We are saving the result
0045             std::get<index>(m_results) = std::get<index>(m_futures).result();
0046 
0047             // If all futures are done, report the result
0048             if (m_waitingCount == 0) {
0049                 this->reportResult(m_results);
0050                 this->reportFinished();
0051             }
0052         });
0053 
0054         onCanceled(watcher, [this] {
0055             // If any of the futures fail, we can not return
0056             // the result :(
0057             this->reportCanceled();
0058         });
0059 
0060         watcher.setFuture(future);
0061 
0062         return true;
0063     }
0064 
0065     template<int... Indices>
0066     void connectFutures(index_sequence<Indices...>)
0067     {
0068         auto ignore = {connectFuture<Indices>()...};
0069         Q_UNUSED(ignore);
0070     }
0071 
0072     QFuture<std::tuple<_Results...>> start()
0073     {
0074         // we need to call connectFuture for index = 0 to sizeof..._Results
0075         connectFutures(make_index_sequence<m_count>());
0076 
0077         this->reportStarted();
0078 
0079         return this->future();
0080     }
0081 
0082 private:
0083     static const constexpr std::size_t m_count = sizeof...(_Results);
0084     int m_waitingCount;
0085     std::tuple<QFuture<_Results>...> m_futures;
0086     std::tuple<QFutureWatcher<_Results>...> m_watchers;
0087     std::tuple<_Results...> m_results;
0088 };
0089 
0090 template<typename... _Results>
0091 QFuture<std::tuple<_Results...>> collect_impl(QFuture<_Results>... futures)
0092 {
0093     return (new CollectFutureInterface<_Results...>(futures...))->start();
0094 }
0095 
0096 } // namespace detail
0097 } // namespace AsynQt