Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Strand.hpp
1#pragma once
2
3#include "util/async/Concepts.hpp"
4#include "util/async/Operation.hpp"
5#include "util/async/context/impl/Cancellation.hpp"
6#include "util/async/context/impl/Execution.hpp"
7#include "util/async/context/impl/Timer.hpp"
8#include "util/async/context/impl/Utils.hpp"
9#include "util/async/impl/ErrorHandling.hpp"
10
11#include <chrono>
12#include <functional>
13#include <optional>
14#include <type_traits>
15
16namespace util::async::impl {
17
18template <
19 typename ParentContextType,
20 typename StopSourceType,
21 typename DispatcherType,
22 typename TimerContextProvider = impl::SelfContextProvider,
23 typename ErrorHandlerType = impl::DefaultErrorHandler>
24class BasicStrand {
25 std::reference_wrapper<ParentContextType> parentContext_;
26 typename ParentContextType::ContextHolderType::Strand context_;
27 friend AssociatedExecutorExtractor;
28
29public:
30 static constexpr bool kIS_NOEXCEPT = noexcept(ErrorHandlerType::wrap([](auto&) { throw 0; }));
31
32 using ContextHolderType = typename ParentContextType::ContextHolderType::Strand;
33 using ExecutorType = typename ContextHolderType::Executor;
34 using StopToken = typename StopSourceType::Token;
35 using Timer = typename ParentContextType::ContextHolderType::Timer; // timers are associated
36 // with the parent context
37 using RepeatedOperation = RepeatingOperation<BasicStrand>;
38
39 BasicStrand(ParentContextType& parent, auto&& strand)
40 : parentContext_{std::ref(parent)}, context_{std::forward<decltype(strand)>(strand)}
41 {
42 }
43
44 ~BasicStrand() = default;
45 BasicStrand(BasicStrand&&) = default;
46
47 BasicStrand(BasicStrand const&) = delete;
48
49 [[nodiscard]] auto
50 execute(
52 std::optional<std::chrono::milliseconds> timeout = std::nullopt
53 ) noexcept(kIS_NOEXCEPT)
54 {
55 return DispatcherType::dispatch(
56 context_,
57 impl::outcomeForHandler<StopSourceType>(fn),
58 ErrorHandlerType::wrap([this, timeout, fn = std::forward<decltype(fn)>(fn)](
59 auto& outcome, auto& stopSource, auto stopToken
60 ) mutable {
61 [[maybe_unused]] auto timeoutHandler = impl::getTimeoutHandleIfNeeded(
62 TimerContextProvider::getContext(parentContext_.get()), timeout, stopSource
63 );
64
65 using FnRetType = std::decay_t<std::invoke_result_t<decltype(fn), StopToken>>;
66 if constexpr (std::is_void_v<FnRetType>) {
67 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
68 outcome.setValue();
69 } else {
70 outcome.setValue(
71 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
72 );
73 }
74 })
75 );
76 }
77
78 [[nodiscard]] auto
79 execute(SomeHandlerWith<StopToken> auto&& fn, SomeStdDuration auto timeout) noexcept(
80 kIS_NOEXCEPT
81 )
82 {
83 return execute(
84 std::forward<decltype(fn)>(fn),
85 std::make_optional(std::chrono::duration_cast<std::chrono::milliseconds>(timeout))
86 );
87 }
88
89 [[nodiscard]] auto
90 execute(SomeHandlerWithoutStopToken auto&& fn) noexcept(kIS_NOEXCEPT)
91 {
92 return DispatcherType::dispatch(
93 context_,
94 impl::outcomeForHandler<StopSourceType>(fn),
95 ErrorHandlerType::wrap([fn = std::forward<decltype(fn)>(fn)](auto& outcome) mutable {
96 using FnRetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
97 if constexpr (std::is_void_v<FnRetType>) {
98 std::invoke(std::forward<decltype(fn)>(fn));
99 outcome.setValue();
100 } else {
101 outcome.setValue(std::invoke(std::forward<decltype(fn)>(fn)));
102 }
103 })
104 );
105 }
106
107 [[nodiscard]] auto
108 executeRepeatedly(
109 SomeStdDuration auto interval,
111 ) noexcept(kIS_NOEXCEPT)
112 {
113 if constexpr (not std::is_same_v<
114 decltype(TimerContextProvider::getContext(*this)),
115 decltype(*this)>) {
116 return TimerContextProvider::getContext(*this).executeRepeatedly(
117 interval, std::forward<decltype(fn)>(fn)
118 );
119 } else {
120 return RepeatedOperation(
121 impl::extractAssociatedExecutor(*this), interval, std::forward<decltype(fn)>(fn)
122 );
123 }
124 }
125
126 void
127 submit(SomeHandlerWithoutStopToken auto&& fn) noexcept(kIS_NOEXCEPT)
128 {
129 DispatcherType::post(context_, ErrorHandlerType::catchAndAssert(fn));
130 }
131};
132
133} // namespace util::async::impl
The future side of async operations that automatically repeat until aborted.
Definition Operation.hpp:215
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