Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
AnyExecutionContext.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2024, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "util/async/AnyOperation.hpp"
23#include "util/async/AnyStopToken.hpp"
24#include "util/async/AnyStrand.hpp"
25#include "util/async/Concepts.hpp"
26#include "util/async/impl/ErasedOperation.hpp"
27
28#include <any>
29#include <chrono>
30#include <functional>
31#include <memory>
32#include <optional>
33#include <type_traits>
34#include <utility>
35
36namespace util::async {
37
42public:
51 template <NotSameAs<AnyExecutionContext> CtxType>
52 /* implicit */
53 AnyExecutionContext(CtxType& ctx) : pimpl_{std::make_shared<Model<CtxType&>>(ctx)}
54 {
55 }
56
65 template <RValueNotSameAs<AnyExecutionContext> CtxType>
66 /* implicit */
67 AnyExecutionContext(CtxType&& ctx) : pimpl_{std::make_shared<Model<CtxType>>(std::forward<CtxType>(ctx))}
68 {
69 }
70
74 operator=(AnyExecutionContext const&) = default;
76 operator=(AnyExecutionContext&&) = default;
77 ~AnyExecutionContext() = default;
78
85 [[nodiscard]] auto
87 {
88 using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
89 static_assert(not std::is_same_v<RetType, std::any>);
90
91 return AnyOperation<RetType>(pimpl_->execute([fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
92 if constexpr (std::is_void_v<RetType>) {
93 std::invoke(std::forward<decltype(fn)>(fn));
94 return {};
95 } else {
96 return std::make_any<RetType>(std::invoke(std::forward<decltype(fn)>(fn)));
97 }
98 }));
99 }
100
109 [[nodiscard]] auto
111 {
112 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
113 static_assert(not std::is_same_v<RetType, std::any>);
114
116 pimpl_->execute([fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
117 if constexpr (std::is_void_v<RetType>) {
118 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
119 return {};
120 } else {
121 return std::make_any<RetType>(std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken)));
122 }
123 })
124 );
125 }
126
136 [[nodiscard]] auto
138 {
139 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
140 static_assert(not std::is_same_v<RetType, std::any>);
141
142 return AnyOperation<RetType>(pimpl_->execute(
143 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
144 if constexpr (std::is_void_v<RetType>) {
145 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
146 return {};
147 } else {
148 return std::make_any<RetType>(std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken)));
149 }
150 },
151 std::chrono::duration_cast<std::chrono::milliseconds>(timeout)
152 ));
153 }
154
164 [[nodiscard]] auto
166 {
167 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
168 static_assert(not std::is_same_v<RetType, std::any>);
169
170 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
172 pimpl_->scheduleAfter(millis, [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
173 if constexpr (std::is_void_v<RetType>) {
174 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
175 return {};
176 } else {
177 return std::make_any<RetType>(std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken)));
178 }
179 })
180 );
181 }
182
193 [[nodiscard]] auto
195 {
196 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken, bool>>;
197 static_assert(not std::is_same_v<RetType, std::any>);
198
199 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
200 return AnyOperation<RetType>(pimpl_->scheduleAfter(
201 millis, [fn = std::forward<decltype(fn)>(fn)](auto stopToken, auto cancelled) mutable -> std::any {
202 if constexpr (std::is_void_v<RetType>) {
203 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken), cancelled);
204 return {};
205 } else {
206 return std::make_any<RetType>(
207 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken), cancelled)
208 );
209 }
210 }
211 ));
212 }
213
221 [[nodiscard]] auto
223 {
224 using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
225 static_assert(not std::is_same_v<RetType, std::any>);
226
227 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
228 return AnyOperation<RetType>( //
229 pimpl_->executeRepeatedly(millis, [fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
230 std::invoke(std::forward<decltype(fn)>(fn));
231 return {};
232 })
233 );
234 }
235
242 void
244 {
245 pimpl_->submit(std::forward<decltype(fn)>(fn));
246 }
247
256 [[nodiscard]] auto
258 {
259 return pimpl_->makeStrand();
260 }
261
265 void
266 stop() const
267 {
268 pimpl_->stop();
269 }
270
274 void
275 join() const
276 {
277 pimpl_->join();
278 }
279
280private:
281 struct Concept {
282 virtual ~Concept() = default;
283
285 execute(
286 std::function<std::any(AnyStopToken)>,
287 std::optional<std::chrono::milliseconds> timeout = std::nullopt
288 ) = 0;
289 virtual impl::ErasedOperation execute(std::function<std::any()>) = 0;
291 scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken)>) = 0;
293 scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken, bool)>) = 0;
294 virtual impl::ErasedOperation executeRepeatedly(std::chrono::milliseconds, std::function<std::any()>) = 0;
295 virtual void submit(std::function<void()>) = 0;
296 virtual AnyStrand
297 makeStrand() = 0;
298 virtual void
299 stop() const = 0;
300 virtual void
301 join() const = 0;
302 };
303
304 template <typename CtxType>
305 struct Model : Concept {
306 CtxType ctx;
307
308 template <typename Type>
309 Model(Type&& ctx) : ctx(std::forward<Type>(ctx))
310 {
311 }
312
313 impl::ErasedOperation
314 execute(std::function<std::any(AnyStopToken)> fn, std::optional<std::chrono::milliseconds> timeout) 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(std::chrono::milliseconds delay, std::function<std::any(AnyStopToken)> fn) override
327 {
328 return ctx.scheduleAfter(delay, std::move(fn));
329 }
330
331 impl::ErasedOperation
332 scheduleAfter(std::chrono::milliseconds delay, std::function<std::any(AnyStopToken, bool)> fn) override
333 {
334 return ctx.scheduleAfter(delay, std::move(fn));
335 }
336
337 impl::ErasedOperation
338 executeRepeatedly(std::chrono::milliseconds interval, std::function<std::any()> fn) override
339 {
340 return ctx.executeRepeatedly(interval, std::move(fn));
341 }
342
343 void
344 submit(std::function<void()> fn) override
345 {
346 return ctx.submit(std::move(fn));
347 }
348
349 AnyStrand
350 makeStrand() override
351 {
352 return ctx.makeStrand();
353 }
354
355 void
356 stop() const override
357 {
358 ctx.stop();
359 }
360
361 void
362 join() const override
363 {
364 ctx.join();
365 }
366 };
367
368private:
369 std::shared_ptr<Concept> pimpl_;
370};
371
372} // namespace util::async
A type-erased execution context.
Definition AnyExecutionContext.hpp:41
auto execute(SomeHandlerWith< AnyStopToken > auto &&fn)
Execute a function on the execution context.
Definition AnyExecutionContext.hpp:110
auto execute(SomeHandlerWith< AnyStopToken > auto &&fn, SomeStdDuration auto timeout)
Execute a function with a timeout.
Definition AnyExecutionContext.hpp:137
auto scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith< AnyStopToken > auto &&fn)
Schedule a function for execution.
Definition AnyExecutionContext.hpp:165
auto makeStrand()
Make a strand for this execution context.
Definition AnyExecutionContext.hpp:257
void stop() const
Stop the execution context.
Definition AnyExecutionContext.hpp:266
auto execute(SomeHandlerWithoutStopToken auto &&fn)
Execute a function on the execution context.
Definition AnyExecutionContext.hpp:86
auto scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith< AnyStopToken, bool > auto &&fn)
Schedule a function for execution.
Definition AnyExecutionContext.hpp:194
AnyExecutionContext(CtxType &ctx)
Construct a new type-erased Execution Context object.
Definition AnyExecutionContext.hpp:53
void submit(SomeHandlerWithoutStopToken auto &&fn)
Schedule an operation on the execution context without expectations of a result.
Definition AnyExecutionContext.hpp:243
AnyExecutionContext(CtxType &&ctx)
Construct a new type-erased Execution Context object.
Definition AnyExecutionContext.hpp:67
void join() const
Join the execution context.
Definition AnyExecutionContext.hpp:275
auto executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto &&fn)
Schedule a repeating operation on the execution context.
Definition AnyExecutionContext.hpp:222
A type-erased operation that can be executed via AnyExecutionContext.
Definition AnyOperation.hpp:44
A type-erased stop token.
Definition AnyStopToken.hpp:37
A type-erased execution context.
Definition AnyStrand.hpp:40
Definition ErasedOperation.hpp:34
Specifies the interface for a handler that can be invoked with the specified args.
Definition Concepts.hpp:162
Specifies the interface for a handler that can be stopped.
Definition Concepts.hpp:154
Specifies that the type must be some std::duration.
Definition Concepts.hpp:170
This namespace implements an async framework built on top of execution contexts.
Definition AnyExecutionContext.hpp:36