]> git.sesse.net Git - casparcg/blob - common/future.h
2.1.0: -env: Create folders recursively.
[casparcg] / common / future.h
1 #pragma once\r
2 \r
3 #include "enum_class.h"\r
4 \r
5 #include <boost/thread/future.hpp>\r
6 #include <boost/thread/thread.hpp>\r
7 #include <boost/shared_ptr.hpp>\r
8 \r
9 #include <functional>\r
10 \r
11 namespace caspar {\r
12         \r
13 struct launch_policy_def\r
14 {\r
15         enum type\r
16         {\r
17                 async = 1,\r
18                 deferred = 2\r
19         };\r
20 };\r
21 typedef caspar::enum_class<launch_policy_def> launch;\r
22 \r
23 namespace detail {\r
24         \r
25 template<typename R>\r
26 struct future_object_helper\r
27 {       \r
28         template<typename T, typename F>\r
29         static void nonlocking_invoke(T& future_object, F& f)\r
30         {                               \r
31         try\r
32         {\r
33                         future_object.mark_finished_with_result_internal(f());\r
34         }\r
35         catch(...)\r
36         {\r
37                         future_object.mark_exceptional_finish_internal(boost::current_exception());\r
38         }\r
39         }\r
40 \r
41         template<typename T, typename F>\r
42         static void locking_invoke(T& future_object, F& f)\r
43         {                               \r
44         try\r
45         {\r
46                         future_object.mark_finished_with_result(f());\r
47         }\r
48         catch(...)\r
49         {\r
50                         future_object.mark_exceptional_finish();\r
51         }\r
52         }\r
53 };\r
54 \r
55 template<>\r
56 struct future_object_helper<void>\r
57 {       \r
58         template<typename T, typename F>\r
59         static void nonlocking_invoke(T& future_object, F& f)\r
60         {                               \r
61         try\r
62         {\r
63                         f();\r
64                         future_object.mark_finished_with_result_internal();\r
65         }\r
66         catch(...)\r
67         {\r
68                         future_object.mark_exceptional_finish_internal(boost::current_exception());\r
69         }\r
70         }\r
71 \r
72         template<typename T, typename F>\r
73         static void locking_invoke(T& future_object, F& f)\r
74         {                               \r
75         try\r
76         {\r
77                         f();\r
78                         future_object.mark_finished_with_result();\r
79         }\r
80         catch(...)\r
81         {\r
82                         future_object.mark_exceptional_finish();\r
83         }\r
84         }\r
85 };\r
86 \r
87 template<typename R, typename F>\r
88 struct deferred_future_object : public boost::detail::future_object<R>\r
89 {       \r
90         F f;\r
91         bool done;\r
92 \r
93         template<typename F2>\r
94         deferred_future_object(F2&& f)\r
95                 : f(std::forward<F2>(f))\r
96                 , done(false)\r
97         {\r
98                 set_wait_callback(std::mem_fn(&detail::deferred_future_object<R, F>::operator()), this);\r
99         }\r
100 \r
101         ~deferred_future_object()\r
102         {\r
103         }\r
104                 \r
105         void operator()()\r
106         {               \r
107                 boost::lock_guard<boost::mutex> lock2(mutex);\r
108 \r
109                 if(done)\r
110                         return;\r
111 \r
112                 future_object_helper<R>::nonlocking_invoke(*this, f);\r
113 \r
114                 done = true;\r
115         }\r
116 };\r
117 \r
118 template<typename R, typename F>\r
119 struct async_future_object : public boost::detail::future_object<R>\r
120 {       \r
121         F f;\r
122         boost::thread thread;\r
123 \r
124         template<typename F2>\r
125         async_future_object(F2&& f)\r
126                 : f(std::forward<F2>(f))\r
127                 , thread([this]{run();})\r
128         {\r
129         }\r
130 \r
131         ~async_future_object()\r
132         {\r
133                 thread.join();\r
134         }\r
135 \r
136         void run()\r
137         {\r
138                 future_object_helper<R>::locking_invoke(*this, f);\r
139         }\r
140 };\r
141 \r
142 }\r
143         \r
144 template<typename F>\r
145 auto async(launch policy, F&& f) -> boost::unique_future<decltype(f())>\r
146 {               \r
147         typedef decltype(f())                                                           result_type;    \r
148         typedef boost::detail::future_object<result_type>       future_object_type;\r
149 \r
150         boost::shared_ptr<future_object_type> future_object;\r
151 \r
152         // HACK: This solution is a hack to avoid modifying boost code.\r
153 \r
154         if((policy & launch::async) != 0)\r
155                 future_object.reset(new detail::async_future_object<result_type, F>(std::forward<F>(f)), [](future_object_type* p){delete reinterpret_cast<detail::async_future_object<result_type, F>*>(p);});\r
156         else if((policy & launch::deferred) != 0)\r
157                 future_object.reset(new detail::deferred_future_object<result_type, F>(std::forward<F>(f)), [](future_object_type* p){delete reinterpret_cast<detail::deferred_future_object<result_type, F>*>(p);});\r
158         else\r
159                 throw std::invalid_argument("policy");\r
160         \r
161         boost::unique_future<result_type> future;\r
162 \r
163         static_assert(sizeof(future) == sizeof(future_object), "");\r
164 \r
165         reinterpret_cast<boost::shared_ptr<future_object_type>&>(future) = std::move(future_object); // Get around the "private" encapsulation.\r
166         return std::move(future);\r
167 }\r
168         \r
169 template<typename F>\r
170 auto async(F&& f) -> boost::unique_future<decltype(f())>\r
171 {       \r
172         return async(launch::async | launch::deferred, std::forward<F>(f));\r
173 }\r
174 \r
175 template<typename T>\r
176 auto make_shared(boost::unique_future<T>&& f) -> boost::shared_future<T>\r
177 {       \r
178         return boost::shared_future<T>(std::move(f));\r
179 }\r
180 \r
181 template<typename T>\r
182 auto flatten(boost::unique_future<T>&& f) -> boost::unique_future<decltype(f.get().get())>\r
183 {\r
184         auto shared_f = make_shared(std::move(f));\r
185         return async(launch::deferred, [=]() mutable\r
186         {\r
187                 return shared_f.get().get();\r
188         });\r
189 }\r
190 \r
191 }