]> git.sesse.net Git - casparcg/blob - common/future.h
2.1.0: -common: Restructured files. Moved most files into root for easier inclusion...
[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, typename F>\r
26 struct callback_object: public boost::detail::future_object<R>\r
27 {       \r
28         F f;\r
29         bool done;\r
30 \r
31         template<typename F2>\r
32         callback_object(F2&& f)\r
33                 : f(std::forward<F2>(f))\r
34                 , done(false)\r
35         {\r
36         }\r
37                 \r
38         void operator()()\r
39         {               \r
40                 boost::lock_guard<boost::mutex> lock2(mutex);\r
41 \r
42                 if(done)\r
43                         return;\r
44 \r
45         try\r
46         {\r
47                    this->mark_finished_with_result_internal(f());\r
48         }\r
49         catch(...)\r
50         {\r
51                         this->mark_exceptional_finish_internal(boost::current_exception());\r
52         }\r
53 \r
54                 done = true;\r
55         }\r
56 };\r
57 \r
58 template<typename F>\r
59 struct callback_object<void, F> : public boost::detail::future_object<void>\r
60 {       \r
61         F f;\r
62         bool done;\r
63 \r
64         template<typename F2>\r
65         callback_object(F2&& f)\r
66                 : f(std::forward<F2>(f))\r
67                 , done(false)\r
68         {\r
69         }\r
70 \r
71         void operator()()\r
72         {\r
73                 boost::lock_guard<boost::mutex> lock2(mutex);\r
74                 \r
75                 if(done)\r
76                         return;\r
77 \r
78         try\r
79         {\r
80                         f();\r
81                         this->mark_finished_with_result_internal();\r
82                 }\r
83         catch(...)\r
84         {\r
85                         this->mark_exceptional_finish_internal(boost::current_exception());\r
86         }\r
87 \r
88                 done = true;\r
89         }\r
90 };\r
91 \r
92 }\r
93         \r
94 template<typename F>\r
95 auto async(launch policy, F&& f) -> boost::unique_future<decltype(f())>\r
96 {               \r
97         typedef decltype(f()) result_type;\r
98         \r
99         if((policy & launch::async) != 0)\r
100         {\r
101                 typedef boost::packaged_task<result_type> task_t;\r
102 \r
103                 auto task       = task_t(std::forward<F>(f));   \r
104                 auto future = task.get_future();\r
105                 \r
106                 boost::thread(std::move(task)).detach();\r
107         \r
108                 return std::move(future);\r
109         }\r
110         else if((policy & launch::deferred) != 0)\r
111         {               \r
112                 // HACK: THIS IS A MAYOR HACK!\r
113 \r
114                 typedef boost::detail::future_object<result_type> future_object_t;\r
115                                         \r
116                 auto callback_object     = boost::make_shared<detail::callback_object<result_type, F>>(std::forward<F>(f));\r
117                 auto callback_object_raw = callback_object.get();\r
118                 auto future_object               = boost::static_pointer_cast<future_object_t>(std::move(callback_object));\r
119 \r
120                 int dummy = 0;\r
121                 future_object->set_wait_callback(std::function<void(int)>([callback_object_raw](int) mutable\r
122                 {                                                               \r
123                         (*callback_object_raw)();\r
124                 }), &dummy);\r
125                 \r
126                 boost::unique_future<result_type> future;\r
127 \r
128                 static_assert(sizeof(future) == sizeof(future_object), "");\r
129 \r
130                 reinterpret_cast<boost::shared_ptr<future_object_t>&>(future) = std::move(future_object); // Get around the "private" encapsulation.\r
131                 return std::move(future);\r
132         }\r
133         else\r
134                 throw std::invalid_argument("policy");\r
135 }\r
136         \r
137 template<typename F>\r
138 auto async(F&& f) -> boost::unique_future<decltype(f())>\r
139 {       \r
140         return async(launch::async, std::forward<F>(f));\r
141 }\r
142 \r
143 template<typename T>\r
144 auto make_shared(boost::unique_future<T>&& f) -> boost::shared_future<T>\r
145 {       \r
146         return boost::shared_future<T>(std::move(f));\r
147 }\r
148 \r
149 template<typename T>\r
150 auto flatten(boost::unique_future<T>&& f) -> boost::unique_future<decltype(f.get().get())>\r
151 {\r
152         auto shared_f = make_shared(std::move(f));\r
153         return async(launch::deferred, [=]() mutable\r
154         {\r
155                 return shared_f.get().get();\r
156         });\r
157 }\r
158 \r
159 }