Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Remove unused type definitions.
[simgrid.git] / include / xbt / future.hpp
1 /* Copyright (c) 2015-2019. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #ifndef XBT_FUTURE_HPP
8 #define XBT_FUTURE_HPP
9
10 #include <cstddef>
11
12 #include <boost/variant.hpp>
13 #include <exception>
14 #include <functional>
15 #include <stdexcept>
16 #include <type_traits>
17 #include <utility>
18 #include <xbt/ex.h>
19
20 namespace simgrid {
21 namespace xbt {
22
23 /** A value or an exception (or nothing)
24  *
25  *  This is similar to `optional<expected<T>>`` but it with a Future/Promise
26  *  like API.
27  *
28  *  Also the name is not so great.
29  **/
30 template<class T>
31 class Result {
32 public:
33   bool is_valid() const
34   {
35     return value_.which() > 0;
36   }
37   void set_exception(std::exception_ptr e)
38   {
39     value_ = std::move(e);
40   }
41   void set_value(T&& value)
42   {
43     value_ = std::move(value);
44   }
45   void set_value(T const& value)
46   {
47     value_ = value;
48   }
49
50   /** Extract the value from the future
51    *
52    *  After this, the value is invalid.
53    **/
54   T get()
55   {
56     switch (value_.which()) {
57       case 1: {
58         T value = std::move(boost::get<T>(value_));
59         value_  = boost::blank();
60         return value;
61       }
62       case 2: {
63         std::exception_ptr exception = std::move(boost::get<std::exception_ptr>(value_));
64         value_                       = boost::blank();
65         std::rethrow_exception(std::move(exception));
66         break;
67       }
68       default:
69         throw std::logic_error("Invalid result");
70     }
71   }
72 private:
73   boost::variant<boost::blank, T, std::exception_ptr> value_;
74 };
75
76 template<>
77 class Result<void> : public Result<std::nullptr_t>
78 {
79 public:
80   void set_value()
81   {
82     Result<std::nullptr_t>::set_value(nullptr);
83   }
84   void get()
85   {
86     Result<std::nullptr_t>::get();
87   }
88 };
89
90 template<class T>
91 class Result<T&> : public Result<std::reference_wrapper<T>>
92 {
93 public:
94   void set_value(T& value)
95   {
96     Result<std::reference_wrapper<T>>::set_value(std::ref(value));
97   }
98   T& get()
99   {
100     return Result<std::reference_wrapper<T>>::get();
101   }
102 };
103
104 /** Execute some code and set a promise or result accordingly
105  *
106  *  Roughly this does:
107  *
108  *  <pre>
109  *  promise.set_value(code());
110  *  </pre>
111  *
112  *  but it takes care of exceptions and works with `void`.
113  *
114  *  We might need this when working with generic code because
115  *  the trivial implementation does not work with `void` (before C++1z).
116  *
117  *  @param    code  What we want to do
118  *  @param  promise Where to want to store the result
119  */
120 template <class R, class F> auto fulfill_promise(R& promise, F&& code) -> decltype(promise.set_value(code()))
121 {
122   try {
123     promise.set_value(std::forward<F>(code)());
124   } catch (...) {
125     promise.set_exception(std::current_exception());
126   }
127 }
128 template <class R, class F>
129 XBT_ATTRIB_DEPRECATED_v323("Please use xbt::fulfill_promise()") auto fulfillPromise(R& promise, F&& code)
130     -> decltype(promise.set_value(code()))
131 {
132   try {
133     promise.set_value(std::forward<F>(code)());
134   }
135   catch(...) {
136     promise.set_exception(std::current_exception());
137   }
138 }
139
140 template <class P, class F> auto fulfill_promise(P& promise, F&& code) -> decltype(promise.set_value())
141 {
142   try {
143     std::forward<F>(code)();
144     promise.set_value();
145   } catch (...) {
146     promise.set_exception(std::current_exception());
147   }
148 }
149 template <class P, class F>
150 XBT_ATTRIB_DEPRECATED_v323("Please use xbt::fulfill_promise()") auto fulfillPromise(P& promise, F&& code)
151     -> decltype(promise.set_value())
152 {
153   try {
154     std::forward<F>(code)();
155     promise.set_value();
156   }
157   catch(...) {
158     promise.set_exception(std::current_exception());
159   }
160 }
161
162 /** Set a promise/result from a future/result
163  *
164  *  Roughly this does:
165  *
166  *  <pre>promise.set_value(future);</pre>
167  *
168  *  but it takes care of exceptions and works with `void`.
169  *
170  *  We might need this when working with generic code because
171  *  the trivial implementation does not work with `void` (before C++1z).
172  *
173  *  @param promise output (a valid future or a result)
174  *  @param future  input (a ready/waitable future or a valid result)
175  */
176 template <class P, class F> inline void set_promise(P& promise, F&& future)
177 {
178   fulfill_promise(promise, [&future] { return std::forward<F>(future).get(); });
179 }
180
181 }
182 }
183
184 #endif