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