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<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)]() -> std::any {
92 if constexpr (std::is_void_v<RetType>) {
93 fn();
94 return {};
95 } else {
96 return std::make_any<RetType>(fn());
97 }
98 }));
99 }
100
109 [[nodiscard]] auto
111 {
112 using RetType = std::decay_t<decltype(fn(std::declval<AnyStopToken>()))>;
113 static_assert(not std::is_same_v<RetType, std::any>);
114
115 return AnyOperation<RetType>(pimpl_->execute([fn = std::forward<decltype(fn)>(fn)](auto stopToken) -> std::any {
116 if constexpr (std::is_void_v<RetType>) {
117 fn(std::move(stopToken));
118 return {};
119 } else {
120 return std::make_any<RetType>(fn(std::move(stopToken)));
121 }
122 }));
123 }
124
134 [[nodiscard]] auto
136 {
137 using RetType = std::decay_t<decltype(fn(std::declval<AnyStopToken>()))>;
138 static_assert(not std::is_same_v<RetType, std::any>);
139
140 return AnyOperation<RetType>(pimpl_->execute(
141 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) -> std::any {
142 if constexpr (std::is_void_v<RetType>) {
143 fn(std::move(stopToken));
144 return {};
145 } else {
146 return std::make_any<RetType>(fn(std::move(stopToken)));
147 }
148 },
149 std::chrono::duration_cast<std::chrono::milliseconds>(timeout)
150 ));
151 }
152
162 [[nodiscard]] auto
164 {
165 using RetType = std::decay_t<decltype(fn(std::declval<AnyStopToken>()))>;
166 static_assert(not std::is_same_v<RetType, std::any>);
167
168 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
169 return AnyOperation<RetType>(pimpl_->scheduleAfter(
170 millis,
171 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) -> std::any {
172 if constexpr (std::is_void_v<RetType>) {
173 fn(std::move(stopToken));
174 return {};
175 } else {
176 return std::make_any<RetType>(fn(std::move(stopToken)));
177 }
178 }
179 ));
180 }
181
192 [[nodiscard]] auto
194 {
195 using RetType = std::decay_t<decltype(fn(std::declval<AnyStopToken>(), true))>;
196 static_assert(not std::is_same_v<RetType, std::any>);
197
198 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
199 return AnyOperation<RetType>(pimpl_->scheduleAfter(
200 millis,
201 [fn = std::forward<decltype(fn)>(fn)](auto stopToken, auto cancelled) -> std::any {
202 if constexpr (std::is_void_v<RetType>) {
203 fn(std::move(stopToken), cancelled);
204 return {};
205 } else {
206 return std::make_any<RetType>(fn(std::move(stopToken), cancelled));
207 }
208 }
209 ));
210 }
211
219 [[nodiscard]] auto
221 {
222 using RetType = std::decay_t<decltype(fn())>;
223 static_assert(not std::is_same_v<RetType, std::any>);
224
225 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
226 return AnyOperation<RetType>( //
227 pimpl_->executeRepeatedly(
228 millis,
229 [fn = std::forward<decltype(fn)>(fn)] -> std::any {
230 fn();
231 return {};
232 }
233 )
234 );
235 }
236
245 [[nodiscard]] auto
247 {
248 return pimpl_->makeStrand();
249 }
250
254 void
255 stop() const
256 {
257 pimpl_->stop();
258 }
259
263 void
264 join() const
265 {
266 pimpl_->join();
267 }
268
269private:
270 struct Concept {
271 virtual ~Concept() = default;
272
274 execute(
275 std::function<std::any(AnyStopToken)>,
276 std::optional<std::chrono::milliseconds> timeout = std::nullopt
277 ) = 0;
278 virtual impl::ErasedOperation execute(std::function<std::any()>) = 0;
280 scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken)>) = 0;
282 scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken, bool)>) = 0;
283 virtual impl::ErasedOperation executeRepeatedly(std::chrono::milliseconds, std::function<std::any()>) = 0;
284 virtual AnyStrand
285 makeStrand() = 0;
286 virtual void
287 stop() const = 0;
288 virtual void
289 join() const = 0;
290 };
291
292 template <typename CtxType>
293 struct Model : Concept {
294 CtxType ctx;
295
296 template <typename Type>
297 Model(Type&& ctx) : ctx(std::forward<Type>(ctx))
298 {
299 }
300
301 impl::ErasedOperation
302 execute(std::function<std::any(AnyStopToken)> fn, std::optional<std::chrono::milliseconds> timeout) override
303 {
304 return ctx.execute(std::move(fn), timeout);
305 }
306
307 impl::ErasedOperation
308 execute(std::function<std::any()> fn) override
309 {
310 return ctx.execute(std::move(fn));
311 }
312
313 impl::ErasedOperation
314 scheduleAfter(std::chrono::milliseconds delay, std::function<std::any(AnyStopToken)> fn) override
315 {
316 return ctx.scheduleAfter(delay, std::move(fn));
317 }
318
319 impl::ErasedOperation
320 scheduleAfter(std::chrono::milliseconds delay, std::function<std::any(AnyStopToken, bool)> fn) override
321 {
322 return ctx.scheduleAfter(delay, std::move(fn));
323 }
324
325 impl::ErasedOperation
326 executeRepeatedly(std::chrono::milliseconds interval, std::function<std::any()> fn) override
327 {
328 return ctx.executeRepeatedly(interval, std::move(fn));
329 }
330
331 AnyStrand
332 makeStrand() override
333 {
334 return ctx.makeStrand();
335 }
336
337 void
338 stop() const override
339 {
340 ctx.stop();
341 }
342
343 void
344 join() const override
345 {
346 ctx.join();
347 }
348 };
349
350private:
351 std::shared_ptr<Concept> pimpl_;
352};
353
354} // 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:135
auto scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith< AnyStopToken > auto &&fn)
Schedule a function for execution.
Definition AnyExecutionContext.hpp:163
auto makeStrand()
Make a strand for this execution context.
Definition AnyExecutionContext.hpp:246
void stop() const
Stop the execution context.
Definition AnyExecutionContext.hpp:255
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:193
AnyExecutionContext(CtxType &ctx)
Construct a new type-erased Execution Context object.
Definition AnyExecutionContext.hpp:53
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:264
auto executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto &&fn)
Schedule a repeating operation on the execution context.
Definition AnyExecutionContext.hpp:220
A type-erased operation that can be executed via AnyExecutionContext.
Definition AnyOperation.hpp:45
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:154
Specifies the interface for a handler that can be stopped.
Definition Concepts.hpp:146
Specifies that the type must be some std::duration.
Definition Concepts.hpp:162
This namespace implements an async framework built on top of execution contexts.
Definition AnyExecutionContext.hpp:36