]> git.sesse.net Git - casparcg/blob - common/future.h
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[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                 future_object->set_wait_callback(std::mem_fn(&detail::callback_object<result_type, F>::operator()), callback_object_raw);\r
121                 \r
122                 boost::unique_future<result_type> future;\r
123 \r
124                 static_assert(sizeof(future) == sizeof(future_object), "");\r
125 \r
126                 reinterpret_cast<boost::shared_ptr<future_object_t>&>(future) = std::move(future_object); // Get around the "private" encapsulation.\r
127                 return std::move(future);\r
128         }\r
129         else\r
130                 throw std::invalid_argument("policy");\r
131 }\r
132         \r
133 template<typename F>\r
134 auto async(F&& f) -> boost::unique_future<decltype(f())>\r
135 {       \r
136         return async(launch::async | launch::deferred, std::forward<F>(f));\r
137 }\r
138 \r
139 template<typename T>\r
140 auto make_shared(boost::unique_future<T>&& f) -> boost::shared_future<T>\r
141 {       \r
142         return boost::shared_future<T>(std::move(f));\r
143 }\r
144 \r
145 template<typename T>\r
146 auto flatten(boost::unique_future<T>&& f) -> boost::unique_future<decltype(f.get().get())>\r
147 {\r
148         auto shared_f = make_shared(std::move(f));\r
149         return async(launch::deferred, [=]() mutable\r
150         {\r
151                 return shared_f.get().get();\r
152         });\r
153 }\r
154 \r
155 }