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)
68 : pimpl_{std::make_shared<Model<CtxType>>(std::forward<CtxType>(ctx))}
69 {
70 }
71
75 operator=(AnyExecutionContext const&) = default;
77 operator=(AnyExecutionContext&&) = default;
78 ~AnyExecutionContext() = default;
79
86 [[nodiscard]] auto
88 {
89 using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
90 static_assert(not std::is_same_v<RetType, std::any>);
91
93 pimpl_->execute([fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
94 if constexpr (std::is_void_v<RetType>) {
95 std::invoke(std::forward<decltype(fn)>(fn));
96 return {};
97 } else {
98 return std::make_any<RetType>(std::invoke(std::forward<decltype(fn)>(fn)));
99 }
100 })
101 );
102 }
103
112 [[nodiscard]] auto
114 {
115 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
116 static_assert(not std::is_same_v<RetType, std::any>);
117
118 return AnyOperation<RetType>(pimpl_->execute(
119 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
120 if constexpr (std::is_void_v<RetType>) {
121 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
122 return {};
123 } else {
124 return std::make_any<RetType>(
125 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
126 );
127 }
128 }
129 ));
130 }
131
141 [[nodiscard]] auto
143 {
144 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
145 static_assert(not std::is_same_v<RetType, std::any>);
146
147 return AnyOperation<RetType>(pimpl_->execute(
148 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
149 if constexpr (std::is_void_v<RetType>) {
150 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
151 return {};
152 } else {
153 return std::make_any<RetType>(
154 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
155 );
156 }
157 },
158 std::chrono::duration_cast<std::chrono::milliseconds>(timeout)
159 ));
160 }
161
171 [[nodiscard]] auto
173 {
174 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
175 static_assert(not std::is_same_v<RetType, std::any>);
176
177 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
178 return AnyOperation<RetType>(pimpl_->scheduleAfter(
179 millis, [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
180 if constexpr (std::is_void_v<RetType>) {
181 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
182 return {};
183 } else {
184 return std::make_any<RetType>(
185 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
186 );
187 }
188 }
189 ));
190 }
191
202 [[nodiscard]] auto
204 {
205 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken, bool>>;
206 static_assert(not std::is_same_v<RetType, std::any>);
207
208 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
209 return AnyOperation<RetType>(pimpl_->scheduleAfter(
210 millis,
211 [fn = std::forward<decltype(fn)>(fn)](auto stopToken, auto cancelled) mutable
212 -> std::any {
213 if constexpr (std::is_void_v<RetType>) {
214 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken), cancelled);
215 return {};
216 } else {
217 return std::make_any<RetType>(
218 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken), cancelled)
219 );
220 }
221 }
222 ));
223 }
224
232 [[nodiscard]] auto
234 {
235 using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
236 static_assert(not std::is_same_v<RetType, std::any>);
237
238 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
239 return AnyOperation<RetType>( //
240 pimpl_->executeRepeatedly(
241 millis, [fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
242 std::invoke(std::forward<decltype(fn)>(fn));
243 return {};
244 }
245 )
246 );
247 }
248
255 void
257 {
258 pimpl_->submit(std::forward<decltype(fn)>(fn));
259 }
260
269 [[nodiscard]] auto
271 {
272 return pimpl_->makeStrand();
273 }
274
278 void
279 stop() const
280 {
281 pimpl_->stop();
282 }
283
287 void
288 join() const
289 {
290 pimpl_->join();
291 }
292
293private:
294 struct Concept {
295 virtual ~Concept() = default;
296
298 execute(
299 std::function<std::any(AnyStopToken)>,
300 std::optional<std::chrono::milliseconds> timeout = std::nullopt
301 ) = 0;
302 virtual impl::ErasedOperation execute(std::function<std::any()>) = 0;
304 scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken)>) = 0;
305 virtual impl::ErasedOperation scheduleAfter(
306 std::chrono::milliseconds,
307 std::function<std::any(AnyStopToken, bool)>
308 ) = 0;
310 executeRepeatedly(std::chrono::milliseconds, std::function<std::any()>) = 0;
311 virtual void submit(std::function<void()>) = 0;
312 virtual AnyStrand
313 makeStrand() = 0;
314 virtual void
315 stop() const = 0;
316 virtual void
317 join() const = 0;
318 };
319
320 template <typename CtxType>
321 struct Model : Concept {
322 CtxType ctx;
323
324 template <typename Type>
325 Model(Type&& ctx) : ctx(std::forward<Type>(ctx))
326 {
327 }
328
329 impl::ErasedOperation
330 execute(
331 std::function<std::any(AnyStopToken)> fn,
332 std::optional<std::chrono::milliseconds> timeout
333 ) override
334 {
335 return ctx.execute(std::move(fn), timeout);
336 }
337
338 impl::ErasedOperation
339 execute(std::function<std::any()> fn) override
340 {
341 return ctx.execute(std::move(fn));
342 }
343
344 impl::ErasedOperation
345 scheduleAfter(
346 std::chrono::milliseconds delay,
347 std::function<std::any(AnyStopToken)> fn
348 ) override
349 {
350 return ctx.scheduleAfter(delay, std::move(fn));
351 }
352
353 impl::ErasedOperation
354 scheduleAfter(
355 std::chrono::milliseconds delay,
356 std::function<std::any(AnyStopToken, bool)> fn
357 ) override
358 {
359 return ctx.scheduleAfter(delay, std::move(fn));
360 }
361
362 impl::ErasedOperation
363 executeRepeatedly(std::chrono::milliseconds interval, std::function<std::any()> fn) override
364 {
365 return ctx.executeRepeatedly(interval, std::move(fn));
366 }
367
368 void
369 submit(std::function<void()> fn) override
370 {
371 return ctx.submit(std::move(fn));
372 }
373
374 AnyStrand
375 makeStrand() override
376 {
377 return ctx.makeStrand();
378 }
379
380 void
381 stop() const override
382 {
383 ctx.stop();
384 }
385
386 void
387 join() const override
388 {
389 ctx.join();
390 }
391 };
392
393private:
394 std::shared_ptr<Concept> pimpl_;
395};
396
397} // 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:113
auto execute(SomeHandlerWith< AnyStopToken > auto &&fn, SomeStdDuration auto timeout)
Execute a function with a timeout.
Definition AnyExecutionContext.hpp:142
auto scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith< AnyStopToken > auto &&fn)
Schedule a function for execution.
Definition AnyExecutionContext.hpp:172
auto makeStrand()
Make a strand for this execution context.
Definition AnyExecutionContext.hpp:270
void stop() const
Stop the execution context.
Definition AnyExecutionContext.hpp:279
auto execute(SomeHandlerWithoutStopToken auto &&fn)
Execute a function on the execution context.
Definition AnyExecutionContext.hpp:87
auto scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith< AnyStopToken, bool > auto &&fn)
Schedule a function for execution.
Definition AnyExecutionContext.hpp:203
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:256
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:288
auto executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto &&fn)
Schedule a repeating operation on the execution context.
Definition AnyExecutionContext.hpp:233
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:184
Specifies the interface for a handler that can be stopped.
Definition Concepts.hpp:176
Specifies that the type must be some std::duration.
Definition Concepts.hpp:192
This namespace implements an async framework built on top of execution contexts.
Definition AnyExecutionContext.hpp:36