ifw-daq  3.0.0-pre2
IFW Data Acquisition modules
initiate.hpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_common_libdaq
4  * @copyright 2022 ESO - European Southern Observatory
5  *
6  * @brief Contains declarations for the helper functions to initiate operations
7  */
8 #ifndef OCM_DAQ_OP_INITIATE_HPP_
9 #define OCM_DAQ_OP_INITIATE_HPP_
10 #include "../config.hpp"
11 
12 #include <functional>
13 #include <memory>
14 #include <type_traits>
15 #include <utility>
16 
17 #include <boost/thread/future.hpp>
18 
19 namespace daq::op {
20 
21 /**
22  * Constructs and initiates `Op` and return the future result.
23  *
24  * InitiateOperation performs the following:
25  *
26  * 1. Constructs the operation by forwarding the parameters Params.
27  * 2. Invokes `Op::Initiate() -> boost::future<R>`
28  * 3. Returns result of `Op::Initiate()`.
29  * 4. Keeps Operation alive until result of `Op::Initiate()` is set, such that
30  * the operation itself does not have to manage this.
31  *
32  *
33  * Type Requirements:
34  *
35  * `Op`:
36  * `Op::Op(Params...)`
37  * `Op::Initiate() -> boost::future<R>`
38  */
39 template<class Op, class R=decltype(std::declval<Op&>().Initiate()), class... Params>
40 R InitiateOperation(Params&&... params);
41 
42 /**
43  * Like InitiateOperation but in addition to returning the future
44  * it also returns an unspecified object @a Abort that can be invoked to abort the operation.
45  *
46  * If @a Abort return true it will have invoked `Op::Abort()`.
47  * If @a Abort return false the operation has already been completed and future value has been set.
48  *
49  * Type Requirements:
50  *
51  * `Op`:
52  * `Op::Op(Params...)`
53  * `Op::Initiate() -> boost::future<R>`
54  * `Op::Abort() -> void`
55  * note: It's not required that the future returned from Initiate() has a value set
56  * when returning from Abort.
57  */
58 template<class Op, class R=decltype(std::declval<Op&>().Initiate()), class... Params>
59 std::pair<R, std::function<bool()>> InitiateAbortableOperation(Params&&... params);
60 
61 
62 //
63 // Implementation
64 //
65 template <class Op, class R, class... Params>
66 R InitiateOperation(Params&&... params) {
67  std::unique_ptr<Op> op = std::make_unique<Op>(std::forward<Params>(params)...);
68  auto* ptr = op.get();
69 
70  // Add continuation that keeps operation alive
71  return ptr->Initiate().then(boost::launch::inherit, [op = std::move(op)](auto f) { return f.get(); });
72 }
73 
74 template <class Op, class R, class... Params>
75 std::pair<R, std::function<bool()>> InitiateAbortableOperation(Params&&... params) {
76  // AbortOperation needs a handle to Op so it can abort it. So in this case
77  // we create a shared pointer instead of unique as in InitiateOperation.
78  std::shared_ptr<Op> op = std::make_shared<Op>(std::forward<Params>(params)...);
79  auto* ptr = op.get();
80  auto weak = std::weak_ptr<Op>(op);
81  return {// Add continuation that keeps operation alive
82  ptr->Initiate().then(boost::launch::inherit,
83  [op = std::move(op)](auto f) { return f.get(); }),
84  [weak = std::move(weak)]() mutable -> bool {
85  if (auto op = weak.lock(); op) {
86  // m_operation is still valid
87  op->Abort();
88  weak.reset();
89  return true;
90  }
91  return false;
92  }};
93 }
94 
95 }
96 
97 #endif // #ifndef OCM_DAQ_OP_INITIATE_HPP_
R InitiateOperation(Params &&... params)
Constructs and initiates Op and return the future result.
Definition: initiate.hpp:66
std::pair< R, std::function< bool()> > InitiateAbortableOperation(Params &&... params)
Like InitiateOperation but in addition to returning the future it also returns an unspecified object ...
Definition: initiate.hpp:75