Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
AnyStrand.hpp
1#pragma once
2
3#include "util/async/AnyOperation.hpp"
4#include "util/async/AnyStopToken.hpp"
5#include "util/async/Concepts.hpp"
6#include "util/async/impl/Any.hpp"
7#include "util/async/impl/ErasedOperation.hpp"
8
9#include <any>
10#include <chrono>
11#include <functional>
12#include <memory>
13#include <optional>
14#include <type_traits>
15#include <utility>
16
17namespace util::async {
18
22class AnyStrand {
23public:
30 template <NotSameAs<AnyStrand> StrandType>
31 /* implicit */ AnyStrand(StrandType&& strand)
32 : pimpl_{std::make_shared<Model<StrandType>>(std::forward<StrandType>(strand))}
33 {
34 }
35
36 AnyStrand(AnyStrand const&) = default;
37 AnyStrand(AnyStrand&&) = default;
38 ~AnyStrand() = default;
39
46 [[nodiscard]] auto
48 {
49 using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
50 static_assert(not std::is_same_v<RetType, impl::Any>);
51
52 return AnyOperation<RetType>( //
53 pimpl_->execute([fn = std::forward<decltype(fn)>(fn)] mutable -> impl::Any {
54 if constexpr (std::is_void_v<RetType>) {
55 std::invoke(std::forward<decltype(fn)>(fn));
56 return {};
57 } else {
58 return std::make_any<RetType>(std::invoke(std::forward<decltype(fn)>(fn)));
59 }
60 })
61 );
62 }
63
70 [[nodiscard]] auto
72 {
73 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
74 static_assert(not std::is_same_v<RetType, impl::Any>);
75
76 return AnyOperation<RetType>( //
77 pimpl_->execute(
78 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> impl::Any {
79 if constexpr (std::is_void_v<RetType>) {
80 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
81 return {};
82 } else {
83 return std::make_any<RetType>(
84 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
85 );
86 }
87 }
88 )
89 );
90 }
91
99 [[nodiscard]] auto
101 {
102 using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
103 static_assert(not std::is_same_v<RetType, impl::Any>);
104
105 return AnyOperation<RetType>( //
106 pimpl_->execute(
107 [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> impl::Any {
108 if constexpr (std::is_void_v<RetType>) {
109 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
110 return {};
111 } else {
112 return std::make_any<RetType>(
113 std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken))
114 );
115 }
116 },
117 std::chrono::duration_cast<std::chrono::milliseconds>(timeout)
118 )
119 );
120 }
121
129 [[nodiscard]] auto
131 {
132 using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
133 static_assert(not std::is_same_v<RetType, impl::Any>);
134
135 auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
136 return AnyOperation<RetType>( //
137 pimpl_->executeRepeatedly(
138 millis, [fn = std::forward<decltype(fn)>(fn)] mutable -> impl::Any {
139 std::invoke(std::forward<decltype(fn)>(fn));
140 return {};
141 }
142 )
143 );
144 }
145
152 void
154 {
155 pimpl_->submit(std::forward<decltype(fn)>(fn));
156 }
157
158private:
159 struct Concept {
160 virtual ~Concept() = default;
161
162 [[nodiscard]] virtual impl::ErasedOperation
163 execute(
164 std::function<impl::Any(AnyStopToken)>,
165 std::optional<std::chrono::milliseconds> timeout = std::nullopt
166 ) = 0;
167 [[nodiscard]] virtual impl::ErasedOperation execute(std::function<impl::Any()>) = 0;
168 [[nodiscard]] virtual impl::ErasedOperation
169 executeRepeatedly(std::chrono::milliseconds, std::function<impl::Any()>) = 0;
170 virtual void submit(std::function<void()>) = 0;
171 };
172
173 template <typename StrandType>
174 struct Model : Concept {
175 StrandType strand;
176
177 template <typename SType>
178 requires std::is_same_v<SType, StrandType>
179 Model(SType&& strand) : strand{std::forward<SType>(strand)}
180 {
181 }
182
183 [[nodiscard]] impl::ErasedOperation
184 execute(
185 std::function<impl::Any(AnyStopToken)> fn,
186 std::optional<std::chrono::milliseconds> timeout
187 ) override
188 {
189 return strand.execute(std::move(fn), timeout);
190 }
191
192 [[nodiscard]] impl::ErasedOperation
193 execute(std::function<impl::Any()> fn) override
194 {
195 return strand.execute(std::move(fn));
196 }
197
198 impl::ErasedOperation
199 executeRepeatedly(
200 std::chrono::milliseconds interval,
201 std::function<impl::Any()> fn
202 ) override
203 {
204 return strand.executeRepeatedly(interval, std::move(fn));
205 }
206
207 void
208 submit(std::function<void()> fn) override
209 {
210 return strand.submit(std::move(fn));
211 }
212 };
213
214private:
215 std::shared_ptr<Concept> pimpl_;
216};
217
218} // namespace util::async
A type-erased operation that can be executed via AnyExecutionContext.
Definition AnyOperation.hpp:26
A type-erased stop token.
Definition AnyStopToken.hpp:18
A type-erased execution context.
Definition AnyStrand.hpp:22
auto executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto &&fn)
Schedule a repeating operation on the execution context.
Definition AnyStrand.hpp:130
void submit(SomeHandlerWithoutStopToken auto &&fn)
Schedule an operation on the execution context without expectations of a result.
Definition AnyStrand.hpp:153
AnyStrand(StrandType &&strand)
Construct a new Any Strand object.
Definition AnyStrand.hpp:31
auto execute(SomeHandlerWithoutStopToken auto &&fn)
Execute a function without a stop token on the strand.
Definition AnyStrand.hpp:47
auto execute(SomeHandlerWith< AnyStopToken > auto &&fn)
Execute a function taking a stop token on the strand.
Definition AnyStrand.hpp:71
auto execute(SomeHandlerWith< AnyStopToken > auto &&fn, SomeStdDuration auto timeout)
Execute a function taking a stop token on the strand with a timeout.
Definition AnyStrand.hpp:100
A wrapper for std::any used as the type-erased transport for async operation results.
Definition Any.hpp:20
Definition ErasedOperation.hpp:15
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
This namespace implements an async framework built on top of execution contexts.
Definition AnyExecutionContext.hpp:18