KASync

async.h
1 /*
2  * Copyright 2014 - 2015 Daniel Vrátil <[email protected]>
3  * Copyright 2016 Daniel Vrátil <[email protected]>
4  * Copyright 2016 Christian Mollekopf <[email protected]tems.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef KASYNC_H
21 #define KASYNC_H
22 
23 #include "kasync_export.h"
24 
25 #include <functional>
26 #include <type_traits>
27 #include <cassert>
28 
29 #include "future.h"
30 #include "debug.h"
31 
32 #include "continuations_p.h"
33 #include "executor_p.h"
34 
35 class QObject;
36 
68 namespace KAsync {
69 
70 template<typename PrevOut, typename Out, typename ... In>
71 class Executor;
72 
73 class JobBase;
74 
75 template<typename Out, typename ... In>
76 class Job;
77 
78 //@cond PRIVATE
79 namespace Private {
80 
81 template<typename Out, typename ... In>
82 Job<Out, In ...> startImpl(Private::ContinuationHolder<Out, In ...> &&helper)
83 {
84  static_assert(sizeof...(In) <= 1, "Only one or zero input parameters are allowed.");
85  return Job<Out, In...>(QSharedPointer<Private::Executor<Out, In ...>>::create(
86  std::forward<Private::ContinuationHolder<Out, In...>>(helper), nullptr, Private::ExecutionFlag::GoodCase));
87 }
88 
89 } // namespace Private
90 //@endcond
91 
92 
104 template<typename Out = void, typename ... In, typename F>
106 auto start(F &&func) -> std::enable_if_t<!std::is_base_of<JobBase, decltype(func(std::declval<In>() ...))>::value,
107  Job<decltype(func(std::declval<In>() ...)), In...>>
108 {
109  static_assert(sizeof...(In) <= 1, "Only one or zero input parameters are allowed.");
110  return Private::startImpl<Out, In...>(Private::ContinuationHolder<Out, In ...>(SyncContinuation<Out, In ...>(std::forward<F>(func))));
111 }
112 
114 template<typename Out = void, typename ... In, typename F>
115 auto start(F &&func) -> std::enable_if_t<std::is_base_of<JobBase, decltype(func(std::declval<In>() ...))>::value,
116  Job<typename decltype(func(std::declval<In>() ...))::OutType, In...>>
117 {
118  static_assert(sizeof...(In) <= 1, "Only one or zero input parameters are allowed.");
119  return Private::startImpl<Out, In...>(Private::ContinuationHolder<Out, In ...>(JobContinuation<Out, In...>(std::forward<F>(func))));
120 }
121 
123 template<typename Out = void, typename ... In>
124 auto start(AsyncContinuation<Out, In ...> &&func) -> Job<Out, In ...>
125 {
126  static_assert(sizeof...(In) <= 1, "Only one or zero input parameters are allowed.");
127  return Private::startImpl<Out, In...>(Private::ContinuationHolder<Out, In ...>(std::forward<AsyncContinuation<Out, In ...>>(func)));
128 }
129 
130 enum ControlFlowFlag {
131  Break,
132  Continue
133 };
134 
142 KASYNC_EXPORT Job<void> doWhile(const Job<ControlFlowFlag> &body);
143 
153 KASYNC_EXPORT Job<void> doWhile(const JobContinuation<ControlFlowFlag> &body);
154 
155 
156 
162 KASYNC_EXPORT Job<void> wait(int delay);
163 
172 template<typename Out = void>
173 Job<Out> null();
174 
180 template<typename Out>
181 Job<Out> value(Out);
182 
191 template<typename List, typename ValueType = typename List::value_type>
193 
203 template<typename List, typename ValueType = typename List::value_type>
204  Job<void, List> forEach(JobContinuation<void, ValueType> &&);
205 
206 
215 template<typename List, typename ValueType = typename List::value_type>
217 
227 template<typename List, typename ValueType = typename List::value_type>
228 Job<void, List> serialForEach(JobContinuation<void, ValueType> &&);
229 
233 template<template<typename> class Container>
234 Job<void> waitForCompletion(Container<KAsync::Future<void>> &futures);
235 
244 template<typename Out = void>
245 Job<Out> error(int errorCode = 1, const QString &errorMessage = QString());
246 
255 template<typename Out = void>
256 Job<Out> error(const char *);
257 
266 template<typename Out = void>
267 Job<Out> error(const Error &);
268 
269 //@cond PRIVATE
270 class KASYNC_EXPORT JobBase
271 {
272  template<typename Out, typename ... In>
273  friend class Job;
274 
275 public:
276  explicit JobBase(const Private::ExecutorBasePtr &executor)
277  : mExecutor(executor)
278  {}
279 
280  virtual ~JobBase() = default;
281 
282 protected:
283  Private::ExecutorBasePtr mExecutor;
284 };
285 //@endcond
286 
329 template<typename Out, typename ... In>
330 class Job : public JobBase
331 {
332  //@cond PRIVATE
333  template<typename OutOther, typename ... InOther>
334  friend class Job;
335 
336  template<typename OutOther, typename ... InOther>
337  friend Job<OutOther, InOther ...> Private::startImpl(Private::ContinuationHolder<OutOther, InOther ...> &&);
338 
339  template<typename List, typename ValueType>
340  friend Job<void, List> forEach(KAsync::Job<void, ValueType> job);
341 
342  template<typename List, typename ValueType>
343  friend Job<void, List> serialForEach(KAsync::Job<void, ValueType> job);
344 
345  // Used to disable implicit conversion of Job<void to Job<void> which triggers
346  // comiler warning.
347  struct IncompleteType;
348  //@endcond
349 
350 public:
351  typedef Out OutType;
352 
354  template<typename OutOther, typename ... InOther>
355  Job<OutOther, In ...> then(const Job<OutOther, InOther ...> &job) const;
356 
358  //
359  //OutOther and InOther are only there fore backwards compatibility, but are otherwise ignored.
360  //It should never be neccessary to specify any template arguments, as they are automatically deduced from the provided argument.
361  //
362  //We currently have to write a then overload for:
363  //* One argument in the continuation
364  //* No argument in the continuation
365  //* One argument + error in the continuation
366  //* No argument + error in the continuation
367  //This is due to how we extract the return type with "decltype(func(std::declval<Out>()))".
368  //Ideally we could conflate this into at least fewer overloads, but I didn't manage so far and this at least works as expected.
369 
371  template<typename OutOther = void, typename ... InOther, typename F>
372  auto then(F &&func) const -> std::enable_if_t<std::is_base_of<JobBase, decltype(func(std::declval<Out>()))>::value,
373  Job<typename decltype(func(std::declval<Out>()))::OutType, In...>>
374  {
375  using ResultJob = decltype(func(std::declval<Out>())); //Job<QString, int>
376  return thenImpl<typename ResultJob::OutType, Out>(
377  {JobContinuation<typename ResultJob::OutType, Out>(std::forward<F>(func))}, Private::ExecutionFlag::GoodCase);
378  }
379 
381  template<typename OutOther = void, typename ... InOther, typename F>
382  auto then(F &&func) const -> std::enable_if_t<std::is_base_of<JobBase, decltype(func())>::value,
383  Job<typename decltype(func())::OutType, In...>>
384  {
385  using ResultJob = decltype(func()); //Job<QString, void>
386  return thenImpl<typename ResultJob::OutType>(
387  {JobContinuation<typename ResultJob::OutType>(std::forward<F>(func))}, Private::ExecutionFlag::GoodCase);
388  }
389 
391  template<typename OutOther = void, typename ... InOther, typename F>
392  auto then(F &&func) const -> std::enable_if_t<std::is_base_of<JobBase, decltype(func(KAsync::Error{}, std::declval<Out>()))>::value,
393  Job<typename decltype(func(KAsync::Error{}, std::declval<Out>()))::OutType, In...>>
394  {
395  using ResultJob = decltype(func(KAsync::Error{}, std::declval<Out>())); //Job<QString, int>
396  return thenImpl<typename ResultJob::OutType, Out>(
397  {JobErrorContinuation<typename ResultJob::OutType, Out>(std::forward<F>(func))}, Private::ExecutionFlag::Always);
398  }
399 
401  template<typename OutOther = void, typename ... InOther, typename F>
402  auto then(F &&func) const -> std::enable_if_t<std::is_base_of<JobBase, decltype(func(KAsync::Error{}))>::value,
403  Job<typename decltype(func(KAsync::Error{}))::OutType, In...>>
404  {
405  using ResultJob = decltype(func(KAsync::Error{}));
406  return thenImpl<typename ResultJob::OutType>(
407  {JobErrorContinuation<typename ResultJob::OutType>(std::forward<F>(func))}, Private::ExecutionFlag::Always);
408  }
409 
411  template<typename OutOther = void, typename ... InOther, typename F>
412  auto then(F &&func) const -> std::enable_if_t<!std::is_base_of<JobBase, decltype(func(std::declval<Out>()))>::value,
413  Job<decltype(func(std::declval<Out>())), In...>>
414  {
415  using ResultType = decltype(func(std::declval<Out>())); //QString
416  return thenImpl<ResultType, Out>(
417  {SyncContinuation<ResultType, Out>(std::forward<F>(func))}, Private::ExecutionFlag::GoodCase);
418  }
419 
421  template<typename OutOther = void, typename ... InOther, typename F>
422  auto then(F &&func) const -> std::enable_if_t<!std::is_base_of<JobBase, decltype(func())>::value,
423  Job<decltype(func()), In...>>
424  {
425  using ResultType = decltype(func()); //QString
426  return thenImpl<ResultType>(
427  {SyncContinuation<ResultType>(std::forward<F>(func))}, Private::ExecutionFlag::GoodCase);
428  }
429 
431  template<typename OutOther = void, typename ... InOther, typename F>
432  auto then(F &&func) const -> std::enable_if_t<!std::is_base_of<JobBase, decltype(func(KAsync::Error{}, std::declval<Out>()))>::value,
433  Job<decltype(func(KAsync::Error{}, std::declval<Out>())),In...>>
434  {
435  using ResultType = decltype(func(KAsync::Error{}, std::declval<Out>())); //QString
436  return thenImpl<ResultType, Out>(
437  {SyncErrorContinuation<ResultType, Out>(std::forward<F>(func))}, Private::ExecutionFlag::Always);
438  }
439 
441  template<typename OutOther = void, typename ... InOther, typename F>
442  auto then(F &&func) const -> std::enable_if_t<!std::is_base_of<JobBase, decltype(func(KAsync::Error{}))>::value,
443  Job<decltype(func(KAsync::Error{})), In...>>
444  {
445  using ResultType = decltype(func(KAsync::Error{}));
446  return thenImpl<ResultType>(
447  {SyncErrorContinuation<ResultType>(std::forward<F>(func))}, Private::ExecutionFlag::Always);
448  }
449 
451  template<typename OutOther, typename ... InOther>
452  Job<OutOther, In ...> then(AsyncContinuation<OutOther, InOther ...> &&func) const
453  {
454  return thenImpl<OutOther, InOther ...>({std::forward<AsyncContinuation<OutOther, InOther ...>>(func)},
455  Private::ExecutionFlag::GoodCase);
456  }
457 
459  template<typename OutOther, typename ... InOther>
460  Job<OutOther, In ...> then(AsyncErrorContinuation<OutOther, InOther ...> &&func) const
461  {
462  return thenImpl<OutOther, InOther ...>({std::forward<AsyncErrorContinuation<OutOther, InOther ...>>(func)}, Private::ExecutionFlag::Always);
463  }
464 
466  Job<Out, In ...> onError(SyncErrorContinuation<void> &&errorFunc) const;
467 
472  template<typename OutOther = void, typename ListType = Out, typename ValueType = typename ListType::value_type, std::enable_if_t<!std::is_void<ListType>::value, int> = 0>
473  Job<void, In ...> each(JobContinuation<void, ValueType> &&func) const
474  {
475  eachInvariants<OutOther>();
476  return then<void, In ...>(forEach<Out, ValueType>(std::forward<JobContinuation<void, ValueType>>(func)));
477  }
478 
483  template<typename OutOther = void, typename ListType = Out, typename ValueType = typename ListType::value_type, std::enable_if_t<!std::is_void<ListType>::value, int> = 0>
484  Job<void, In ...> serialEach(JobContinuation<void, ValueType> &&func) const
485  {
486  eachInvariants<OutOther>();
487  return then<void, In ...>(serialForEach<Out, ValueType>(std::forward<JobContinuation<void, ValueType>>(func)));
488  }
489 
499  template<typename ... InOther>
500  operator std::conditional_t<std::is_void<OutType>::value, IncompleteType, Job<void>>();
501 
509  template<typename T>
510  Job<Out, In ...> &addToContext(const T &value)
511  {
512  assert(mExecutor);
513  mExecutor->addToContext(QVariant::fromValue<T>(value));
514  return *this;
515  }
516 
523  Job<Out, In ...> &guard(const QObject *o)
524  {
525  assert(mExecutor);
526  mExecutor->guard(o);
527  return *this;
528  }
529 
544  template<typename FirstIn>
545  KAsync::Future<Out> exec(FirstIn in);
546 
560  KAsync::Future<Out> exec();
561 
562  explicit Job(JobContinuation<Out, In ...> &&func);
563  explicit Job(AsyncContinuation<Out, In ...> &&func);
564 
565 private:
566  //@cond PRIVATE
567  explicit Job(Private::ExecutorBasePtr executor);
568 
569  template<typename OutOther, typename ... InOther>
570  Job<OutOther, In ...> thenImpl(Private::ContinuationHolder<OutOther, InOther ...> helper,
571  Private::ExecutionFlag execFlag = Private::ExecutionFlag::GoodCase) const;
572 
573  template<typename InOther, typename ... InOtherTail>
574  void thenInvariants() const;
575 
576  //Base case for an empty parameter pack
577  template<typename ... InOther>
578  auto thenInvariants() const -> std::enable_if_t<(sizeof...(InOther) == 0)>;
579 
580  template<typename OutOther>
581  void eachInvariants() const;
582  //@endcond
583 };
584 
585 } // namespace KAsync
586 
587 
588 // out-of-line definitions of Job methods
589 #include "job_impl.h"
590 
591 #endif // KASYNC_H
Job< void, In... > each(JobContinuation< void, ValueType > &&func) const
Shorthand for a forEach loop that automatically uses the return type of this job to deduce the type e...
Definition: async.h:473
An Asynchronous job.
Definition: async.h:76
auto then(F &&func) const -> std::enable_if_t< std::is_base_of< JobBase, decltype(func(std::declval< Out >()))>::value, Job< typename decltype(func(std::declval< Out >()))::OutType, In... >>
Shorthands for a job that returns another job from it&#39;s continuation.
Definition: async.h:372
STL namespace.
auto start(F &&func) -> std::enable_if_t< std::is_base_of< JobBase, decltype(func(std::declval< In >()...))>::value, Job< typename decltype(func(std::declval< In >()...))::OutType, In... >>
continuation with job: [] () -> KAsync::Job<...> { ... }
Definition: async.h:115
Job< void, In... > serialEach(JobContinuation< void, ValueType > &&func) const
Shorthand for a serialForEach loop that automatically uses the return type of this job to deduce the ...
Definition: async.h:484
auto then(F &&func) const -> std::enable_if_t< std::is_base_of< JobBase, decltype(func())>::value, Job< typename decltype(func())::OutType, In... >>
Void continuation with job: [] () -> KAsync::Job<...> { ... }.
Definition: async.h:382
KCALUTILS_EXPORT QString errorMessage(const KCalendarCore::Exception &exception)
auto then(F &&func) const -> std::enable_if_t<!std::is_base_of< JobBase, decltype(func(std::declval< Out >()))>::value, Job< decltype(func(std::declval< Out >())), In... >>
Sync continuation: [] (Arg) -> void { ... }.
Definition: async.h:412
Job< Out, In... > & guard(const QObject *o)
Adds a guard.
Definition: async.h:523
Job< Out, In... > & addToContext(const T &value)
Adds an unnamed value to the context.
Definition: async.h:510
Future is a promise that is used by Job to deliver result of an asynchronous execution.
Definition: future.h:196
Definition: async.h:68
auto start(F &&func) -> std::enable_if_t<!std::is_base_of< JobBase, decltype(func(std::declval< In >()...))>::value, Job< decltype(func(std::declval< In >()...)), In... >>
Definition: async.h:106
Job< OutOther, In... > then(AsyncErrorContinuation< OutOther, InOther... > &&func) const
Shorthand for a job that receives the error and a handle.
Definition: async.h:460
Job< OutOther, In... > then(AsyncContinuation< OutOther, InOther... > &&func) const
Shorthand for a job that receives the error and a handle.
Definition: async.h:452
auto then(F &&func) const -> std::enable_if_t<!std::is_base_of< JobBase, decltype(func())>::value, Job< decltype(func()), In... >>
Sync void continuation: [] () -> void { ... }.
Definition: async.h:422
auto then(F &&func) const -> std::enable_if_t<!std::is_base_of< JobBase, decltype(func(KAsync::Error
Sync error continuation: [] (KAsync::Error, Arg) -> void { ... }.
Definition: async.h:432
A specialization of Future<T> for tasks that have no (void) result.
Definition: future.h:386
auto then(F &&func) const -> std::enable_if_t< std::is_base_of< JobBase, decltype(func(KAsync::Error
Error continuation returning job: [] (KAsync::Error, Arg) -> KAsync::Job<...> { ... }.
Definition: async.h:392
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed Jul 1 2020 23:04:36 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.