Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
AnyExecutionContext.hpp
1#pragma once
2
3#include "util/async/AnyOperation.hpp"
4#include "util/async/AnyStopToken.hpp"
5#include "util/async/AnyStrand.hpp"
6#include "util/async/Concepts.hpp"
7#include "util/async/impl/ErasedOperation.hpp"
8
9#include <any>
10#include <chrono>
11#include <functional>
12#include <memory>
13#include <optional>
14#include <type_traits>
15#include <utility>
16
17namespace util::async {
18
23public:
32 template <NotSameAs<AnyExecutionContext> CtxType>
33 /* implicit */
34 AnyExecutionContext(CtxType& ctx) : pimpl_{std::make_shared<Model<CtxType&>>(ctx)}
35 {
36 }
37
46 template <RValueNotSameAs<AnyExecutionContext> CtxType>
47 /* implicit */
48 AnyExecutionContext(CtxType&& ctx)
49 : pimpl_{std::make_shared<Model<CtxType>>(std::forward<CtxType>(ctx))}
50 {
51 }
52
56 operator=(AnyExecutionContext const&) = default;
58 operator=(AnyExecutionContext&&) = default;
59 ~AnyExecutionContext() = default;
60
67 [[nodiscard]] auto
69 {
70 using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
71 static_assert(not std::is_same_v<RetType, std::any>);
72
74 pimpl_->execute([fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
75 if constexpr (std::is_void_v<RetType>) {
76 std::invoke(std::forward<decltype(fn)>(fn));
77 return {};
78 } else {
79 return std::make_any<RetType>(std::invoke(std::forward<decltype(fn)>(fn)));
80 }
81 })
82 );
83 }
84
93 [[nodiscard]] auto
95 {
96 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
97 static_assert(not std::is_same_v<RetType, std::any>);
98
99 return AnyOperation<RetType>(pimpl_->execute(
100 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
101 if constexpr (std::is_void_v<RetType>) {
102 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
103 return {};
104 } else {
105 return std::make_any<RetType>(
106 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
107 );
108 }
109 }
110 ));
111 }
112
122 [[nodiscard]] auto
124 {
125 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
126 static_assert(not std::is_same_v<RetType, std::any>);
127
128 return AnyOperation<RetType>(pimpl_->execute(
129 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
130 if constexpr (std::is_void_v<RetType>) {
131 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
132 return {};
133 } else {
134 return std::make_any<RetType>(
135 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
136 );
137 }
138 },
139 std::chrono::duration_cast<std::chrono::milliseconds>(timeout)
140 ));
141 }
142
152 [[nodiscard]] auto
154 {
155 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
156 static_assert(not std::is_same_v<RetType, std::any>);
157
158 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
159 return AnyOperation<RetType>(pimpl_->scheduleAfter(
160 millis, [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
161 if constexpr (std::is_void_v<RetType>) {
162 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
163 return {};
164 } else {
165 return std::make_any<RetType>(
166 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
167 );
168 }
169 }
170 ));
171 }
172
183 [[nodiscard]] auto
185 {
186 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken, bool>>;
187 static_assert(not std::is_same_v<RetType, std::any>);
188
189 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
190 return AnyOperation<RetType>(pimpl_->scheduleAfter(
191 millis,
192 [fn = std::forward<decltype(fn)>(fn)](auto stopToken, auto cancelled) mutable
193 -> std::any {
194 if constexpr (std::is_void_v<RetType>) {
195 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken), cancelled);
196 return {};
197 } else {
198 return std::make_any<RetType>(
199 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken), cancelled)
200 );
201 }
202 }
203 ));
204 }
205
213 [[nodiscard]] auto
215 {
216 using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
217 static_assert(not std::is_same_v<RetType, std::any>);
218
219 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
220 return AnyOperation<RetType>( //
221 pimpl_->executeRepeatedly(
222 millis, [fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
223 std::invoke(std::forward<decltype(fn)>(fn));
224 return {};
225 }
226 )
227 );
228 }
229
236 void
238 {
239 pimpl_->submit(std::forward<decltype(fn)>(fn));
240 }
241
250 [[nodiscard]] auto
252 {
253 return pimpl_->makeStrand();
254 }
255
259 void
260 stop() const
261 {
262 pimpl_->stop();
263 }
264
268 void
269 join() const
270 {
271 pimpl_->join();
272 }
273
274private:
275 struct Concept {
276 virtual ~Concept() = default;
277
279 execute(
280 std::function<std::any(AnyStopToken)>,
281 std::optional<std::chrono::milliseconds> timeout = std::nullopt
282 ) = 0;
283 virtual impl::ErasedOperation execute(std::function<std::any()>) = 0;
285 scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken)>) = 0;
286 virtual impl::ErasedOperation scheduleAfter(
287 std::chrono::milliseconds,
288 std::function<std::any(AnyStopToken, bool)>
289 ) = 0;
291 executeRepeatedly(std::chrono::milliseconds, std::function<std::any()>) = 0;
292 virtual void submit(std::function<void()>) = 0;
293 virtual AnyStrand
294 makeStrand() = 0;
295 virtual void
296 stop() const = 0;
297 virtual void
298 join() const = 0;
299 };
300
301 template <typename CtxType>
302 struct Model : Concept {
303 CtxType ctx;
304
305 template <typename Type>
306 Model(Type&& ctx) : ctx(std::forward<Type>(ctx))
307 {
308 }
309
310 impl::ErasedOperation
311 execute(
312 std::function<std::any(AnyStopToken)> fn,
313 std::optional<std::chrono::milliseconds> timeout
314 ) override
315 {
316 return ctx.execute(std::move(fn), timeout);
317 }
318
319 impl::ErasedOperation
320 execute(std::function<std::any()> fn) override
321 {
322 return ctx.execute(std::move(fn));
323 }
324
325 impl::ErasedOperation
326 scheduleAfter(
327 std::chrono::milliseconds delay,
328 std::function<std::any(AnyStopToken)> fn
329 ) override
330 {
331 return ctx.scheduleAfter(delay, std::move(fn));
332 }
333
334 impl::ErasedOperation
335 scheduleAfter(
336 std::chrono::milliseconds delay,
337 std::function<std::any(AnyStopToken, bool)> fn
338 ) override
339 {
340 return ctx.scheduleAfter(delay, std::move(fn));
341 }
342
343 impl::ErasedOperation
344 executeRepeatedly(std::chrono::milliseconds interval, std::function<std::any()> fn) override
345 {
346 return ctx.executeRepeatedly(interval, std::move(fn));
347 }
348
349 void
350 submit(std::function<void()> fn) override
351 {
352 return ctx.submit(std::move(fn));
353 }
354
355 AnyStrand
356 makeStrand() override
357 {
358 return ctx.makeStrand();
359 }
360
361 void
362 stop() const override
363 {
364 ctx.stop();
365 }
366
367 void
368 join() const override
369 {
370 ctx.join();
371 }
372 };
373
374private:
375 std::shared_ptr<Concept> pimpl_;
376};
377
378} // namespace util::async
A type-erased execution context.
Definition AnyExecutionContext.hpp:22
auto execute(SomeHandlerWith< AnyStopToken > auto &&fn)
Execute a function on the execution context.
Definition AnyExecutionContext.hpp:94
auto execute(SomeHandlerWith< AnyStopToken > auto &&fn, SomeStdDuration auto timeout)
Execute a function with a timeout.
Definition AnyExecutionContext.hpp:123
auto scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith< AnyStopToken > auto &&fn)
Schedule a function for execution.
Definition AnyExecutionContext.hpp:153
auto makeStrand()
Make a strand for this execution context.
Definition AnyExecutionContext.hpp:251
void stop() const
Stop the execution context.
Definition AnyExecutionContext.hpp:260
auto execute(SomeHandlerWithoutStopToken auto &&fn)
Execute a function on the execution context.
Definition AnyExecutionContext.hpp:68
auto scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith< AnyStopToken, bool > auto &&fn)
Schedule a function for execution.
Definition AnyExecutionContext.hpp:184
AnyExecutionContext(CtxType &ctx)
Construct a new type-erased Execution Context object.
Definition AnyExecutionContext.hpp:34
void submit(SomeHandlerWithoutStopToken auto &&fn)
Schedule an operation on the execution context without expectations of a result.
Definition AnyExecutionContext.hpp:237
AnyExecutionContext(CtxType &&ctx)
Construct a new type-erased Execution Context object.
Definition AnyExecutionContext.hpp:48
void join() const
Join the execution context.
Definition AnyExecutionContext.hpp:269
auto executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto &&fn)
Schedule a repeating operation on the execution context.
Definition AnyExecutionContext.hpp:214
A type-erased operation that can be executed via AnyExecutionContext.
Definition AnyOperation.hpp:25
A type-erased stop token.
Definition AnyStopToken.hpp:18
A type-erased execution context.
Definition AnyStrand.hpp:21
Definition ErasedOperation.hpp:15
Specifies the interface for a handler that can be invoked with the specified args.
Definition Concepts.hpp:165
Specifies the interface for a handler that can be stopped.
Definition Concepts.hpp:157
Specifies that the type must be some std::duration.
Definition Concepts.hpp:173
This namespace implements an async framework built on top of execution contexts.
Definition AnyExecutionContext.hpp:17