DASH  0.3.0
Future.h
1 #ifndef DASH__FUTURE_H__INCLUDED
2 #define DASH__FUTURE_H__INCLUDED
3 
4 #include <cstddef>
5 #include <functional>
6 #include <sstream>
7 #include <iostream>
8 #include <utility>
9 #include <dash/Exception.h>
10 #include <dash/internal/Logging.h>
11 
12 
13 namespace dash {
14 
19 template<typename ResultT>
20 class Future
21 {
22 public:
23  typedef Future<ResultT> self_t;
24 
28  typedef std::function<ResultT (void)> get_func_t;
29 
33  typedef std::function<bool (ResultT*)> test_func_t;
34 
38  typedef std::function<void (void)> destroy_func_t;
39 
40 private:
42  get_func_t _get_func;
44  test_func_t _test_func;
46  destroy_func_t _destroy_func;
48  ResultT _value{};
50  bool _ready{false};
51 
52 public:
53  // For ostream output
54  template<typename ResultT_>
55  friend std::ostream & operator<<(
56  std::ostream & os,
57  const Future<ResultT_> & future);
58 
59 public:
60 
66  Future() noexcept(std::is_nothrow_constructible<ResultT>::value) = default;
67 
71  Future(ResultT result) noexcept(std::is_nothrow_move_constructible<ResultT>::value)
72  : _value(std::move(result)),
73  _ready(true)
74  { }
75 
81  Future(get_func_t get_func) noexcept
82  : _get_func(std::move(get_func))
83  {
84  }
85 
94  Future(get_func_t get_func, test_func_t test_func) noexcept
95  : _get_func(std::move(get_func))
96  , _test_func(std::move(test_func))
97  {
98  }
99 
111  get_func_t get_func, test_func_t test_func, destroy_func_t destroy_func) noexcept
112  : _get_func(std::move(get_func))
113  , _test_func(std::move(test_func))
114  , _destroy_func(std::move(destroy_func))
115  {
116  }
117 
121  Future(const self_t& other) = delete;
122 
126  Future(self_t&& other) noexcept(
127  std::is_nothrow_move_assignable<Future>::value)
128  {
129  *this = std::move(other);
130  }
131 
137  if (_destroy_func) {
138  _destroy_func();
139  }
140  }
141 
145  self_t & operator=(const self_t& other) = delete;
146 
150  self_t& operator=(self_t&& other) noexcept(
151  std::is_nothrow_move_assignable<ResultT>::value)
152  {
153  _get_func = std::move(other._get_func);
154  _test_func = std::move(other._test_func);
155  _destroy_func = std::move(other._destroy_func);
156  _value = std::move(other._value);
157  _ready = other._ready;
158  return *this;
159  }
160 
165  void wait()
166  {
167  DASH_LOG_TRACE_VAR("Future.wait()", _ready);
168  if (_ready) {
169  return;
170  }
171  if (!_get_func) {
172  DASH_LOG_ERROR("Future.wait()", "No function");
173  DASH_THROW(
175  "Future not initialized with function");
176  }
177  _value = _get_func();
178  _ready = true;
179  DASH_LOG_TRACE_VAR("Future.wait >", _ready);
180  }
181 
189  bool test()
190  {
191  if (!_ready) {
192  if (_test_func) {
193  _ready = _test_func(&_value);
194  } else if (_get_func) {
195  _value = _get_func();
196  _ready = true;
197  } else {
198  DASH_THROW(
200  "Future not initialized with function");
201  }
202  }
203  return _ready;
204  }
205 
209  ResultT get()
210  {
211  DASH_LOG_TRACE_VAR("Future.get()", _ready);
212  wait();
213  DASH_LOG_TRACE_VAR("Future.get >", _value);
214  return _value;
215  }
216 
217 
222  bool valid() noexcept
223  {
224  return (_ready || _get_func != nullptr);
225  }
226 
227 }; // class Future
228 
229 
234 template<>
235 class Future<void>
236 {
237 public:
238  typedef Future<void> self_t;
239 
243  typedef std::function<void (void)> get_func_t;
244 
248  typedef std::function<bool (void)> test_func_t;
249 
253  typedef std::function<void (void)> destroy_func_t;
254 
255 private:
257  get_func_t _get_func;
259  test_func_t _test_func;
261  destroy_func_t _destroy_func;
263  bool _ready{false};
264 
265 public:
266  // For ostream output
267  template<typename ResultT_>
268  friend std::ostream & operator<<(
269  std::ostream & os,
270  const Future<ResultT_> & future);
271 
272 public:
278  Future()
279 // This commit fixes the issue:
280 // https://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20161121/177858.html
281 #if defined(__clang__) && (__clang_major__ < 6)
282  {}
283 #else
284  noexcept = default;
285 #endif
286 
292  Future(get_func_t get_func) noexcept
293  : _get_func(std::move(get_func))
294  {
295  }
296 
304  Future(get_func_t get_func, test_func_t test_func) noexcept
305  : _get_func(std::move(get_func))
306  , _test_func(std::move(test_func))
307  {
308  }
309 
320  get_func_t get_func,
321  test_func_t test_func,
322  destroy_func_t destroy_func) noexcept
323  : _get_func(std::move(get_func)),
324  _test_func(std::move(test_func)),
325  _destroy_func(std::move(destroy_func))
326  { }
327 
331  Future(const self_t& other) = delete;
332 
336  Future(self_t&& other) noexcept
337  {
338  *this = std::move(other);
339  }
340 
346  if (_destroy_func) {
347  _destroy_func();
348  }
349  }
350 
354  self_t& operator=(const self_t& other) = delete;
355 
359  self_t& operator=(self_t&& other) noexcept
360  {
361  _get_func = std::move(other._get_func);
362  _test_func = std::move(other._test_func);
363  _destroy_func = std::move(other._destroy_func);
364  _ready = other._ready;
365  return *this;
366  }
367 
372  void wait()
373  {
374  DASH_LOG_TRACE_VAR("Future.wait()", _ready);
375  if (_ready) {
376  return;
377  }
378  if (!_get_func) {
379  DASH_LOG_ERROR("Future.wait()", "No function");
380  DASH_THROW(
382  "Future not initialized with function");
383  }
384  _get_func();
385  _ready = true;
386  DASH_LOG_TRACE_VAR("Future.wait >", _ready);
387  }
388 
396  bool test()
397  {
398  if (!_ready) {
399  if (_test_func) {
400  _ready = _test_func();
401  } else if (_get_func) {
402  _get_func();
403  _ready = true;
404  } else {
405  DASH_THROW(
407  "Future not initialized with function");
408  }
409  }
410  return _ready;
411  }
412 
416  void get()
417  {
418  DASH_LOG_TRACE_VAR("Future.get()", _ready);
419  wait();
420  DASH_LOG_TRACE("Future.get >");
421  }
422 
427  bool valid() noexcept
428  {
429  return (_get_func != nullptr);
430  }
431 
432 }; // class Future
433 
434 template<typename ResultT>
435 std::ostream & operator<<(
436  std::ostream & os,
437  const Future<ResultT> & future)
438 {
439  std::ostringstream ss;
440  ss << "dash::Future<" << typeid(ResultT).name() << ">(";
441  if (future._ready) {
442  ss << future._value;
443  } else {
444  ss << "not ready";
445  }
446  ss << ")";
447  return operator<<(os, ss.str());
448 }
449 
450 } // namespace dash
451 
452 #endif // DASH__FUTURE_H__INCLUDED
void wait()
Wait for the value to become available.
Definition: Future.h:372
Future(get_func_t get_func, test_func_t test_func) noexcept
Create a future using a function that returns the value and a function to test whether the result val...
Definition: Future.h:304
std::function< void(void)> destroy_func_t
Callback function called upon destruction.
Definition: Future.h:253
This class is a simple memory pool which holds allocates elements of size ValueType.
Definition: AllOf.h:8
Future(self_t &&other) noexcept(std::is_nothrow_move_assignable< Future >::value)
Move constructor.
Definition: Future.h:126
Implementation of a future used to wait for an operation to complete and access the value returned by...
Definition: Future.h:20
Future(get_func_t get_func) noexcept
Create a future using a function that returns the value.
Definition: Future.h:81
~Future()
Destructor.
Definition: Future.h:345
Future(self_t &&other) noexcept
Move constructor.
Definition: Future.h:336
~Future()
Destructor.
Definition: Future.h:136
std::function< bool(ResultT *)> test_func_t
Callback function to test for the availability of the result value.
Definition: Future.h:33
std::function< void(void)> destroy_func_t
Callback function called upon destruction.
Definition: Future.h:38
void wait()
Wait for the value to become available.
Definition: Future.h:165
self_t & operator=(self_t &&other) noexcept(std::is_nothrow_move_assignable< ResultT >::value)
Move assignment.
Definition: Future.h:150
Future(get_func_t get_func, test_func_t test_func) noexcept
Create a future using a function that returns the value and a function to test whether the value retu...
Definition: Future.h:94
Future(get_func_t get_func, test_func_t test_func, destroy_func_t destroy_func) noexcept
Create a future using a function to wait for completion and a function to test for completion...
Definition: Future.h:319
Overload of dash::Future for operations returning void.
Definition: Future.h:235
self_t & operator=(self_t &&other) noexcept
Move assignment.
Definition: Future.h:359
Future(get_func_t get_func) noexcept
Create a future using a function that returns the value.
Definition: Future.h:292
Future(ResultT result) noexcept(std::is_nothrow_move_constructible< ResultT >::value)
Create a future from an already available value.
Definition: Future.h:71
Future(get_func_t get_func, test_func_t test_func, destroy_func_t destroy_func) noexcept
Create a future using a function that returns the value and a function to test whether the value retu...
Definition: Future.h:110
Future() noexcept(std::is_nothrow_constructible< ResultT >::value)=default
Default constructor, creates a future that invalid.
std::function< void(void)> get_func_t
Callback function to wait for completion.
Definition: Future.h:243
bool test()
Test whether the operation has completed.
Definition: Future.h:396
bool valid() noexcept
Check whether the future is valid, i.e., a function to wait for completion has been provided...
Definition: Future.h:427
bool valid() noexcept
Check whether the future is valid, i.e., whether either a value or a function to access the valid has...
Definition: Future.h:222
see https://en.cppreference.com/w/cpp/feature_test for recommended feature tests
Definition: cstddef.h:8
bool test()
Test whether the value is available.
Definition: Future.h:189
self_t & operator=(const self_t &other)=delete
Copy assignment is not permited.
std::function< bool(void)> test_func_t
Callback function to test for completion.
Definition: Future.h:248
std::function< ResultT(void)> get_func_t
Callback function returning the result value.
Definition: Future.h:28