LeechCraft  0.6.70-3565-g2d86529
Modular cross-platform feature rich live environment.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
futures.h
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #pragma once
31 
32 #include <type_traits>
33 #include <functional>
34 #include <memory>
35 #include <QFutureWatcher>
36 #include <QtConcurrentRun>
37 #include "slotclosure.h"
38 
39 namespace LeechCraft
40 {
41 namespace Util
42 {
43  namespace detail
44  {
45  template<typename T>
47 
48  template<typename T>
50  {
51  typedef T type;
52  };
53 
54  template<typename T>
56 
57  template<typename T>
58  struct IsFuture
59  {
60  constexpr static bool Result_ = false;
61  };
62 
63  template<typename T>
64  struct IsFuture<QFuture<T>>
65  {
66  constexpr static bool Result_ = true;
67  };
68 
69  template<typename RetType, typename ResultHandler>
71  {
72  void operator() (const ResultHandler& rh, QFutureWatcher<RetType> *watcher) const
73  {
74  rh (watcher->result ());
75  }
76  };
77 
78  template<typename ResultHandler>
79  struct HandlerInvoker<void, ResultHandler>
80  {
81  void operator() (const ResultHandler& rh, QFutureWatcher<void>*) const
82  {
83  rh ();
84  }
85  };
86  }
87 
111  template<typename Executor, typename ResultHandler, typename... Args>
112  void ExecuteFuture (Executor f, ResultHandler rh, QObject *parent, Args... args)
113  {
114  static_assert (detail::IsFuture<decltype (f (args...))>::Result_,
115  "The passed functor should return a QFuture.");
116 
117  // Don't replace result_of with decltype, this triggers a gcc bug leading to segfault:
118  // http://leechcraft.org:8080/job/leechcraft/=debian_unstable/1998/console
119  using RetType_t = detail::UnwrapFutureType_t<typename std::result_of<Executor (Args...)>::type>;
120  const auto watcher = new QFutureWatcher<RetType_t> { parent };
121 
123  {
124  [watcher, rh] { detail::HandlerInvoker<RetType_t, ResultHandler> {} (rh, watcher); },
125  watcher,
126  SIGNAL (finished ()),
127  watcher
128  };
129 
130  watcher->setFuture (f (args...));
131  }
132 
133  namespace detail
134  {
147  template<typename Executor, typename... Args>
148  class Sequencer : public QObject
149  {
150  public:
153  using FutureType_t = typename std::result_of<Executor (Args...)>::type;
154 
159  private:
160  const std::function<FutureType_t ()> Functor_;
161  QFutureWatcher<RetType_t> BaseWatcher_;
162  QObject *LastWatcher_ = &BaseWatcher_;
163  public:
170  Sequencer (Executor f, Args... args, QObject *parent)
171  : QObject { parent }
172  , Functor_ { [f, args...] { return f (args...); } }
173  , BaseWatcher_ { this }
174  {
175  }
176 
182  void Start ()
183  {
184  BaseWatcher_.setFuture (Functor_ ());
185  }
186 
207  template<typename RetT, typename ArgT>
208  void Then (const std::function<QFuture<RetT> (ArgT)>& action)
209  {
210  const auto last = dynamic_cast<QFutureWatcher<ArgT>*> (LastWatcher_);
211  if (!last)
212  {
213  deleteLater ();
214  throw std::runtime_error { std::string { "invalid type in " } + Q_FUNC_INFO };
215  }
216 
217  const auto watcher = new QFutureWatcher<RetT> { this };
218  LastWatcher_ = watcher;
219 
220  new SlotClosure<DeleteLaterPolicy>
221  {
222  [this, last, watcher, action]
223  {
224  if (last != &BaseWatcher_)
225  last->deleteLater ();
226  watcher->setFuture (action (last->result ()));
227  },
228  last,
229  SIGNAL (finished ()),
230  last
231  };
232  }
233 
254  template<typename ArgT>
255  void Then (const std::function<void (ArgT)>& action)
256  {
257  const auto last = dynamic_cast<QFutureWatcher<ArgT>*> (LastWatcher_);
258  if (!last)
259  {
260  deleteLater ();
261  throw std::runtime_error { std::string { "invalid type in " } + Q_FUNC_INFO };
262  }
263 
264  new SlotClosure<DeleteLaterPolicy>
265  {
266  [last, action, this]
267  {
268  action (last->result ());
269  deleteLater ();
270  },
271  LastWatcher_,
272  SIGNAL (finished ()),
273  LastWatcher_
274  };
275  }
276  };
277 
294  template<typename Ret, typename E0, typename... A0>
296  {
297  std::shared_ptr<void> ExecuteGuard_;
298  Sequencer<E0, A0...> * const Seq_;
299 
300  SequenceProxy (const std::shared_ptr<void>& guard, Sequencer<E0, A0...> *seq)
301  : ExecuteGuard_ { guard }
302  , Seq_ { seq }
303  {
304  }
305  public:
306  using Ret_t = Ret;
307 
314  : ExecuteGuard_ { nullptr, [sequencer] (void*) { sequencer->Start (); } }
315  , Seq_ { sequencer }
316  {
317  }
318 
324  SequenceProxy (const SequenceProxy& proxy) = default;
325 
331  SequenceProxy (SequenceProxy&& proxy) = default;
332 
347  template<typename F>
349  {
350  Seq_->template Then<UnwrapFutureType_t<decltype (f (std::declval<Ret> ()))>, Ret> (f);
351  return { ExecuteGuard_, Seq_ };
352  }
353 
366  template<typename F>
367  auto Then (const F& f) -> typename std::enable_if<std::is_same<void, decltype (f (std::declval<Ret> ()))>::value>::type
368  {
369  Seq_->template Then<Ret> (f);
370  }
371  };
372  }
373 
441  template<typename Executor, typename... Args>
442  detail::SequenceProxy<typename detail::Sequencer<Executor, Args...>::RetType_t, Executor, Args...> Sequence (QObject *parent, Executor f, Args... args)
443  {
444  return { new detail::Sequencer<Executor, Args...> { f, args..., parent } };
445  }
446 }
447 }
A proxy object allowing type-checked sequencing of actions and responsible for starting the initial a...
Definition: futures.h:295
typename UnwrapFutureType< T >::type UnwrapFutureType_t
Definition: futures.h:55
static constexpr bool Result_
Definition: futures.h:60
SequenceProxy(Sequencer< E0, A0...> *sequencer)
Constructs a sequencer proxy managing the given sequencer.
Definition: futures.h:313
Incapsulates the sequencing logic of asynchronous actions.
Definition: futures.h:148
Executes a given functor upon a signal (or a list of signals).
Definition: slotclosure.h:100
auto Then(const F &f) -> typename std::enable_if< std::is_same< void, decltype(f(std::declval< Ret >()))>::value >::type
Adds the funtor f to the chain of actions and closes the chain.
Definition: futures.h:367
detail::SequenceProxy< typename detail::Sequencer< Executor, Args...>::RetType_t, Executor, Args...> Sequence(QObject *parent, Executor f, Args...args)
Creates a sequencer that allows chaining multiple futures.
Definition: futures.h:442
UnwrapFutureType_t< FutureType_t > RetType_t
The type instantinating the QFuture returned by the Executor.
Definition: futures.h:158
Sequencer(Executor f, Args...args, QObject *parent)
Constructs the sequencer.
Definition: futures.h:170
auto Then(const F &f) -> SequenceProxy< UnwrapFutureType_t< decltype(f(std::declval< Ret >()))>, E0, A0...>
Adds the functor f to the chain of actions.
Definition: futures.h:348
void ExecuteFuture(Executor f, ResultHandler rh, QObject *parent, Args...args)
Runs a QFuture-returning function and feeding the future to a handler when it is ready.
Definition: futures.h:112
void operator()(const ResultHandler &rh, QFutureWatcher< RetType > *watcher) const
Definition: futures.h:72
typename std::result_of< E0(Args...)>::type FutureType_t
The result of calling Executor with Args.
Definition: futures.h:153