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);
170 pimpl_->scheduleAfter(millis, [fn = std::forward<decltype(fn)>(fn)](auto stopToken) -> std::any {
171 if constexpr (std::is_void_v<RetType>) {
172 fn(std::move(stopToken));
173 return {};
174 } else {
175 return std::make_any<RetType>(fn(std::move(stopToken)));
176 }
177 })
178 );
179 }
180
191 [[nodiscard]] auto
193 {
194 using RetType = std::decay_t<decltype(fn(std::declval<AnyStopToken>(), true))>;
195 static_assert(not std::is_same_v<RetType, std::any>);
196
197 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
198 return AnyOperation<RetType>(pimpl_->scheduleAfter(
199 millis, [fn = std::forward<decltype(fn)>(fn)](auto stopToken, auto cancelled) -> std::any {
200 if constexpr (std::is_void_v<RetType>) {
201 fn(std::move(stopToken), cancelled);
202 return {};
203 } else {
204 return std::make_any<RetType>(fn(std::move(stopToken), cancelled));
205 }
206 }
207 ));
208 }
209
217 [[nodiscard]] auto
219 {
220 using RetType = std::decay_t<decltype(fn())>;
221 static_assert(not std::is_same_v<RetType, std::any>);
222
223 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
224 return AnyOperation<RetType>( //
225 pimpl_->executeRepeatedly(millis, [fn = std::forward<decltype(fn)>(fn)] -> std::any {
226 fn();
227 return {};
228 })
229 );
230 }
231
240 [[nodiscard]] auto
242 {
243 return pimpl_->makeStrand();
244 }
245
249 void
250 stop() const
251 {
252 pimpl_->stop();
253 }
254
258 void
259 join() const
260 {
261 pimpl_->join();
262 }
263
264private:
265 struct Concept {
266 virtual ~Concept() = default;
267
269 execute(
270 std::function<std::any(AnyStopToken)>,
271 std::optional<std::chrono::milliseconds> timeout = std::nullopt
272 ) = 0;
273 virtual impl::ErasedOperation execute(std::function<std::any()>) = 0;
275 scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken)>) = 0;
277 scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken, bool)>) = 0;
278 virtual impl::ErasedOperation executeRepeatedly(std::chrono::milliseconds, std::function<std::any()>) = 0;
279 virtual AnyStrand
280 makeStrand() = 0;
281 virtual void
282 stop() const = 0;
283 virtual void
284 join() const = 0;
285 };
286
287 template <typename CtxType>
288 struct Model : Concept {
289 CtxType ctx;
290
291 template <typename Type>
292 Model(Type&& ctx) : ctx(std::forward<Type>(ctx))
293 {
294 }
295
296 impl::ErasedOperation
297 execute(std::function<std::any(AnyStopToken)> fn, std::optional<std::chrono::milliseconds> timeout) override
298 {
299 return ctx.execute(std::move(fn), timeout);
300 }
301
302 impl::ErasedOperation
303 execute(std::function<std::any()> fn) override
304 {
305 return ctx.execute(std::move(fn));
306 }
307
308 impl::ErasedOperation
309 scheduleAfter(std::chrono::milliseconds delay, std::function<std::any(AnyStopToken)> fn) override
310 {
311 return ctx.scheduleAfter(delay, std::move(fn));
312 }
313
314 impl::ErasedOperation
315 scheduleAfter(std::chrono::milliseconds delay, std::function<std::any(AnyStopToken, bool)> fn) override
316 {
317 return ctx.scheduleAfter(delay, std::move(fn));
318 }
319
320 impl::ErasedOperation
321 executeRepeatedly(std::chrono::milliseconds interval, std::function<std::any()> fn) override
322 {
323 return ctx.executeRepeatedly(interval, std::move(fn));
324 }
325
326 AnyStrand
327 makeStrand() override
328 {
329 return ctx.makeStrand();
330 }
331
332 void
333 stop() const override
334 {
335 ctx.stop();
336 }
337
338 void
339 join() const override
340 {
341 ctx.join();
342 }
343 };
344
345private:
346 std::shared_ptr<Concept> pimpl_;
347};
348
349} // 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:241
void stop() const
Stop the execution context.
Definition AnyExecutionContext.hpp:250
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:192
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:259
auto executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto &&fn)
Schedule a repeating operation on the execution context.
Definition AnyExecutionContext.hpp:218
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