1 /*******************************************************************************
2  * thrill/api/action_node.hpp
3  *
4  * Part of Project Thrill - http://project-thrill.org
5  *
6  * Copyright (C) 2015 Sebastian Lamm <seba.lamm@gmail.com>
7  * Copyright (C) 2016 Timo Bingmann <tb@panthema.net>
8  *
9  * All rights reserved. Published under the BSD-2 license in the LICENSE file.
10  ******************************************************************************/
11 
12 #pragma once
13 #ifndef THRILL_API_ACTION_NODE_HEADER
14 #define THRILL_API_ACTION_NODE_HEADER
15 
16 #include <thrill/api/dia_base.hpp>
17 
18 #include <string>
19 #include <vector>
20 
21 namespace thrill {
22 namespace api {
23 
24 //! \ingroup api_layer
25 //! \{
26 
27 class ActionNode : public DIABase
28 {
29 public:
ActionNode(Context & ctx,const char * label,const std::initializer_list<size_t> & parent_ids,const std::initializer_list<DIABasePtr> & parents)30     ActionNode(Context& ctx, const char* label,
31                const std::initializer_list<size_t>& parent_ids,
32                const std::initializer_list<DIABasePtr>& parents)
33         : DIABase(ctx, label, parent_ids, parents) { }
34 
35     //! ActionNodes do not have children.
RemoveChild(DIABase *)36     void RemoveChild(DIABase* /* node */) final { }
37 
38     //! ActionNodes do not have children.
RemoveAllChildren()39     void RemoveAllChildren() final { }
40 
41     //! ActionNodes do not have children.
children() const42     std::vector<DIABase*> children() const final
43     { return std::vector<DIABase*>(); }
44 
45     //! ActionNodes do not push data, they only Execute.
PushData(bool)46     void PushData(bool /* consume */) final { abort(); }
47 
48     //! ActionNodes do not push data, they only Execute.
RunPushData()49     void RunPushData() final { abort(); }
50 
IncConsumeCounter(size_t)51     void IncConsumeCounter(size_t /* counter */) final {
52         die("Setting .Keep() on Actions does not make sense.");
53     }
54 
DecConsumeCounter(size_t)55     void DecConsumeCounter(size_t /* counter */) final {
56         die("Setting .Keep() on Actions does not make sense.");
57     }
58 
SetConsumeCounter(size_t)59     void SetConsumeCounter(size_t /* counter */) final {
60         die("Setting .Keep() on Actions does not make sense.");
61     }
62 };
63 
64 template <typename ResultType>
65 class ActionResultNode : public ActionNode
66 {
67 public:
ActionResultNode(Context & ctx,const char * label,const std::initializer_list<size_t> & parent_ids,const std::initializer_list<DIABasePtr> & parents)68     ActionResultNode(Context& ctx, const char* label,
69                      const std::initializer_list<size_t>& parent_ids,
70                      const std::initializer_list<DIABasePtr>& parents)
71         : ActionNode(ctx, label, parent_ids, parents) { }
72 
73     //! virtual method to return result via an ActionFuture
74     virtual const ResultType& result() const = 0;
75 };
76 
77 /*!
78  * The return type class for all ActionFutures. This is not a multi-threading
79  * Future, instead it is only a variable placeholder containing a pointer to the
80  * action node to retrieve the value once it is calculated.
81  */
82 template <typename ValueType = void>
83 class Future
84 {
85 public:
86     using ActionResultNodePtr =
87         tlx::CountingPtr<ActionResultNode<ValueType> >;
88 
Future(const ActionResultNodePtr & node)89     explicit Future(const ActionResultNodePtr& node)
90         : node_(node) { }
91 
92     //! Evaluate the DIA data-flow graph for this ActionFuture.
wait()93     void wait() {
94         if (node_->state() == DIAState::NEW)
95             node_->RunScope();
96     }
97 
98     //! true if already executed/valid
valid() const99     bool valid() const {
100         return (node_->state() == DIAState::EXECUTED);
101     }
102 
103     //! Return the value of the ActionFuture
get()104     const ValueType& get() {
105         if (node_->state() == DIAState::NEW)
106             node_->RunScope();
107 
108         return node_->result();
109     }
110 
111     //! Return the value of the ActionFuture
operator ()()112     const ValueType& operator () () {
113         return get();
114     }
115 
116 private:
117     //! shared pointer to the action node, which may not be executed yet.
118     ActionResultNodePtr node_;
119 };
120 
121 /*!
122  * Specialized template class for ActionFuture which return void. This class
123  * does not have a get() method.
124  */
125 template <>
126 class Future<void>
127 {
128 public:
129     using ActionNodePtr = tlx::CountingPtr<ActionNode>;
130 
Future(const ActionNodePtr & node)131     explicit Future(const ActionNodePtr& node)
132         : node_(node) { }
133 
134     //! Evaluate the DIA data-flow graph for this ActionFuture.
wait()135     void wait() {
136         if (node_->state() == DIAState::NEW)
137             node_->RunScope();
138     }
139 
140     //! true if already executed/valid
valid() const141     bool valid() const {
142         return (node_->state() == DIAState::EXECUTED);
143     }
144 
145     //! Return the value of the ActionFuture
operator ()()146     void operator () () {
147         return wait();
148     }
149 
150 private:
151     //! shared pointer to the action node, which may not be executed yet.
152     ActionNodePtr node_;
153 };
154 
155 //! \}
156 
157 } // namespace api
158 
159 //! imported from api namespace
160 template <typename ValueType = void>
161 using Future = api::Future<ValueType>;
162 
163 } // namespace thrill
164 
165 #endif // !THRILL_API_ACTION_NODE_HEADER
166 
167 /******************************************************************************/
168