Adobe Source Libraries 1.49.0
A collection of C++ libraries.
Loading...
Searching...
No Matches
future.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6/**************************************************************************************************/
7
8#ifndef ADOBE_FUTURE_HPP
9#define ADOBE_FUTURE_HPP
10
11#include <future>
12#include <list>
13#include <memory>
14#include <type_traits>
15#include <utility>
16
17#include <adobe/cassert.hpp>
18#include <adobe/type_traits.hpp>
19
20/**************************************************************************************************/
21
22namespace adobe {
23
24/**************************************************************************************************/
25
26namespace detail {
27
28struct any_packaged_task_ {
29
30 any_packaged_task_() = default;
31
32 template <typename T>
33 any_packaged_task_(T&& task) : object_(new model_<T>(std::forward<T>(task))) {}
34
35 any_packaged_task_(any_packaged_task_&& x) noexcept = default;
36 any_packaged_task_& operator=(any_packaged_task_&& x) noexcept = default;
37
38 void operator()() const {
39 ADOBE_ASSERT(object_);
40 object_->call();
41 }
42
43 struct concept_t {
44 virtual ~concept_t() {}
45 virtual void call() = 0;
46 };
47
48 template <typename T>
49 struct model_ : concept_t {
50 model_(T&& task) : task_(std::move(task)) {}
51 void call() override { task_(); }
52
53 T task_;
54 };
55
56 std::unique_ptr<concept_t> object_;
57};
58
59void async_(any_packaged_task_&&);
60void async_(const std::chrono::steady_clock::time_point&, any_packaged_task_&&);
61
62} // namespace detail
63
64/**************************************************************************************************/
65
66template <class F, class... Args>
67auto async(F&& f, Args&&... args) -> std::future<typename adobe::invoke_result_t<F, Args...>> {
68 using namespace std;
69
70 using result_t = adobe::invoke_result_t<F, Args...>;
71 using packaged_t = packaged_task<result_t()>;
72
73 auto p = packaged_t(forward<F>(f), forward<Args>(args)...);
74 auto result = p.get_future();
75
76 detail::async_(move(p));
77
78 return result;
79}
80
81/**************************************************************************************************/
82
83template <class Duration, class F, class... Args>
84auto async(const std::chrono::time_point<std::chrono::steady_clock, Duration>& when, F&& f,
85 Args&&... args) -> std::future<adobe::invoke_result_t<F, Args...>> {
86 using namespace std;
87 using namespace chrono;
88
89 using result_t = typename adobe::invoke_result_t<F, Args...>;
90 using packaged_t = packaged_task<result_t()>;
91
92 auto p = packaged_t(forward<F>(f), forward<Args>(args)...);
93 auto result = p.get_future();
94
95 detail::async_(when, move(p));
96 return result;
97}
98
99/**************************************************************************************************/
100
101// REVISIT (sparent) : This probably is not the correct place for a concurrent queue
102
103template <typename T>
105 using queue_t = std::list<T>;
106 using lock_t = std::lock_guard<std::mutex>;
107
108 queue_t q_;
109 std::mutex mutex_;
110
111public:
112 using value_type = T;
113
114 void push(T x) {
115 queue_t tmp;
116 tmp.push_back(move(x));
117 {
118 lock_t lock(mutex_);
119 q_.splice(q_.end(), tmp);
120 }
121 }
122
123 /*
124 REVISIT (sparent) : This should return an optional<T>, using reference and bool as
125 temporary solution.
126 */
127
128 bool pop(T& out) {
129 queue_t tmp;
130 {
131 lock_t lock(mutex_);
132 if (!q_.empty())
133 tmp.splice(tmp.end(), q_, q_.begin());
134 }
135 if (tmp.empty())
136 return false;
137 out = move(tmp.back());
138 return true;
139 }
140};
141
142/**************************************************************************************************/
143
145 struct task_queue_;
146
147 template <typename P>
148 struct move_binder_ {
149 move_binder_(std::shared_ptr<task_queue_> q, P&& p) : q_(std::move(q)), p_(std::move(p)) {}
150
151 void operator()() {
152 p_();
153 continue_(q_);
154 }
155
156 std::shared_ptr<task_queue_> q_;
157 P p_;
158 };
159
160 static auto make_task_queue_() -> std::shared_ptr<task_queue_>;
161 void async_(detail::any_packaged_task_&&);
162
163 static void continue_(const std::shared_ptr<task_queue_>&);
164 static void suspend_(const std::shared_ptr<task_queue_>&);
165 static void resume_(const std::shared_ptr<task_queue_>&);
166
167 std::shared_ptr<task_queue_> object_ = make_task_queue_();
168
169public:
170 template <class F, class... Args>
171 auto async(F&& f, Args&&... args) -> std::future<adobe::invoke_result_t<F, Args...>> {
172 using namespace std;
173
174 using result_t = typename adobe::invoke_result_t<F, Args...>;
175 using packaged_t = packaged_task<result_t()>;
176
177 auto p = packaged_t(forward<F>(f), forward<Args>(args)...);
178 auto result = p.get_future();
179
180 async_(move_binder_<packaged_t>(object_, move(p)));
181
182 return result;
183 }
184
185 void suspend() { suspend_(object_); }
186 void resume() { resume_(object_); }
187};
188
189/**************************************************************************************************/
190
191} // namespace adobe
192
193/**************************************************************************************************/
194
195#endif
196
197/**************************************************************************************************/
#define ADOBE_ASSERT(p)
Definition cassert.hpp:32
auto async(F &&f, Args &&... args) -> std::future< adobe::invoke_result_t< F, Args... > >
Definition future.hpp:171
std::result_of_t< F(Args...)> invoke_result_t
auto async(F &&f, Args &&... args) -> std::future< typename adobe::invoke_result_t< F, Args... > >
Definition future.hpp:67
STL namespace.