File indexing completed on 2024-04-06 12:11:55
0001 #ifndef FWCore_Concurrency_chain_first_h
0002 #define FWCore_Concurrency_chain_first_h
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <atomic>
0025 #include <exception>
0026 #include <memory>
0027 #include <type_traits>
0028
0029
0030 #include "FWCore/Concurrency/interface/WaitingTaskHolder.h"
0031 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0032
0033
0034
0035 namespace edm {
0036 namespace waiting_task::detail {
0037
0038 template <class, class = void>
0039 struct has_exception_handling : std::false_type {};
0040
0041 template <class T>
0042 struct has_exception_handling<T,
0043 std::void_t<decltype(std::declval<T&>()(
0044 static_cast<std::exception_ptr const*>(nullptr), edm::WaitingTaskHolder()))>>
0045 : std::true_type {};
0046
0047 template <typename F>
0048 struct AutoExceptionHandler {
0049 AutoExceptionHandler(F&& iF) : f_{std::forward<F>(iF)} {}
0050
0051 void operator()(std::exception_ptr const* iPtr, edm::WaitingTaskHolder h) noexcept {
0052 if (iPtr) {
0053 h.doneWaiting(*iPtr);
0054 } else {
0055 CMS_SA_ALLOW try { f_(h); } catch (...) {
0056 h.doneWaiting(std::current_exception());
0057 }
0058 }
0059 }
0060
0061 private:
0062 F f_;
0063 };
0064
0065 template <typename E, typename F>
0066 struct ExplicitExceptionHandler {
0067 ExplicitExceptionHandler(E&& iE, F&& iF) : except_(std::forward<E>(iE)), f_{std::forward<F>(iF)} {}
0068
0069 void operator()(std::exception_ptr const* iPtr, edm::WaitingTaskHolder h) noexcept {
0070 if (iPtr) {
0071 except_(*iPtr);
0072 h.doneWaiting(*iPtr);
0073 } else {
0074 CMS_SA_ALLOW try { f_(h); } catch (...) {
0075 h.doneWaiting(std::current_exception());
0076 }
0077 }
0078 }
0079
0080 private:
0081 E except_;
0082 F f_;
0083 };
0084
0085
0086
0087
0088 template <typename E>
0089 struct IfExceptionAdapter {
0090 constexpr IfExceptionAdapter(E&& iE) : except_(std::forward<E>(iE)) {}
0091
0092 template <typename F>
0093 constexpr auto else_(F&& iF) {
0094 return ExplicitExceptionHandler<E, F>(std::move(except_), std::forward<F>(iF));
0095 }
0096
0097 private:
0098 E except_;
0099 };
0100
0101 template <typename... T>
0102 struct WaitingTaskChain;
0103
0104 template <typename F>
0105 struct Conditional {};
0106
0107 template <typename F>
0108 struct ConditionalAdaptor {
0109 constexpr explicit ConditionalAdaptor(bool iCond, F&& iF) : f_(std::forward<F>(iF)), condition_(iCond) {}
0110
0111 template <typename... T>
0112 [[nodiscard]] constexpr auto pipe(WaitingTaskChain<T...> iChain) {
0113 return WaitingTaskChain<Conditional<F>, T...>(condition_, std::move(f_), std::move(iChain));
0114 }
0115
0116 F f_;
0117 bool condition_;
0118 };
0119
0120 template <typename F>
0121 struct ThenAdaptor {
0122 constexpr explicit ThenAdaptor(F&& iF) : f_(std::forward<F>(iF)) {}
0123
0124 template <typename... T>
0125 [[nodiscard]] constexpr auto pipe(WaitingTaskChain<T...> iChain) {
0126 return WaitingTaskChain<F, T...>(std::move(f_), std::move(iChain));
0127 }
0128
0129 private:
0130 F f_;
0131 };
0132
0133 struct RunLastAdaptor {
0134 explicit RunLastAdaptor(edm::WaitingTaskHolder iT) : task_(std::move(iT)) {}
0135
0136 template <typename... T>
0137 constexpr void pipe(WaitingTaskChain<T...>&& iChain) {
0138 iChain.runLast(std::move(task_));
0139 }
0140
0141 private:
0142 edm::WaitingTaskHolder task_;
0143 };
0144
0145 struct LastTaskAdaptor {
0146 explicit LastTaskAdaptor(edm::WaitingTaskHolder iT) : task_(std::move(iT)) {}
0147
0148 template <typename... T>
0149 constexpr auto pipe(WaitingTaskChain<T...>&& iChain) {
0150 return iChain.lastTask(std::move(task_));
0151 }
0152
0153 private:
0154 edm::WaitingTaskHolder task_;
0155 };
0156
0157 template <typename U>
0158 struct WaitingTaskChain<U> {
0159 constexpr explicit WaitingTaskChain(U&& iU) : f_{std::forward<U>(iU)} {}
0160
0161 [[nodiscard]] WaitingTaskHolder lastTask(WaitingTaskHolder iV) {
0162 return WaitingTaskHolder(
0163 *iV.group(),
0164 make_waiting_task([f = std::move(f_), v = std::move(iV)](const std::exception_ptr* iPtr) mutable {
0165 f(iPtr, std::move(v));
0166 }));
0167 }
0168
0169 void runLast(WaitingTaskHolder iH) { f_(nullptr, std::move(iH)); }
0170
0171 template <typename V>
0172 friend auto operator|(WaitingTaskChain<U> iChain, V&& iV) {
0173 return iV.pipe(std::move(iChain));
0174 }
0175
0176 private:
0177 U f_;
0178 };
0179
0180 template <typename U, typename... T>
0181 struct WaitingTaskChain<U, T...> {
0182 explicit constexpr WaitingTaskChain(U&& iU, WaitingTaskChain<T...> iL)
0183 : l_(std::move(iL)), f_{std::forward<U>(iU)} {}
0184
0185 [[nodiscard]] WaitingTaskHolder lastTask(WaitingTaskHolder iV) {
0186 return l_.lastTask(WaitingTaskHolder(
0187 *iV.group(),
0188 make_waiting_task([f = std::move(f_), v = std::move(iV)](std::exception_ptr const* iPtr) mutable {
0189 f(iPtr, std::move(v));
0190 })));
0191 }
0192
0193 void runLast(WaitingTaskHolder iV) {
0194 l_.runLast(WaitingTaskHolder(
0195 *iV.group(),
0196 make_waiting_task([f = std::move(f_), v = std::move(iV)](std::exception_ptr const* iPtr) mutable {
0197 f(iPtr, std::move(v));
0198 })));
0199 }
0200
0201 template <typename V>
0202 friend auto operator|(WaitingTaskChain<U, T...> iChain, V&& iV) {
0203 return iV.pipe(std::move(iChain));
0204 }
0205
0206 private:
0207 WaitingTaskChain<T...> l_;
0208 U f_;
0209 };
0210
0211 template <typename U, typename... T>
0212 struct WaitingTaskChain<Conditional<U>, T...> {
0213 explicit constexpr WaitingTaskChain(bool iCondition, U&& iU, WaitingTaskChain<T...> iL)
0214 : l_(std::move(iL)), f_{std::forward<U>(iU)}, condition_(iCondition) {}
0215
0216 explicit constexpr WaitingTaskChain(Conditional<U> iC, WaitingTaskChain<T...> iL)
0217 : l_(std::move(iL)), f_{std::move<U>(iC.f_)}, condition_(iC.condition_) {}
0218
0219 [[nodiscard]] WaitingTaskHolder lastTask(WaitingTaskHolder iV) {
0220 if (condition_) {
0221 return l_.lastTask(WaitingTaskHolder(
0222 *iV.group(),
0223 make_waiting_task([f = std::move(f_), v = std::move(iV)](std::exception_ptr const* iPtr) mutable {
0224 f(iPtr, std::move(v));
0225 })));
0226 }
0227 return l_.lastTask(iV);
0228 }
0229
0230 void runLast(WaitingTaskHolder iV) {
0231 if (condition_) {
0232 l_.runLast(WaitingTaskHolder(
0233 *iV.group(),
0234 make_waiting_task([f = std::move(f_), v = std::move(iV)](std::exception_ptr const* iPtr) mutable {
0235 f(iPtr, std::move(v));
0236 })));
0237 } else {
0238 l_.runLast(iV);
0239 }
0240 }
0241
0242 template <typename V>
0243 friend auto operator|(WaitingTaskChain<Conditional<U>, T...> iChain, V&& iV) {
0244 return iV.pipe(std::move(iChain));
0245 }
0246
0247 private:
0248 WaitingTaskChain<T...> l_;
0249 U f_;
0250 bool condition_;
0251 };
0252
0253 }
0254 namespace waiting_task::chain {
0255
0256
0257
0258
0259 template <typename F>
0260 [[nodiscard]] constexpr auto first(F&& iF) {
0261 using namespace detail;
0262 if constexpr (has_exception_handling<F>::value) {
0263 return WaitingTaskChain<F>(std::forward<F>(iF));
0264 } else {
0265 return WaitingTaskChain<AutoExceptionHandler<F>>(AutoExceptionHandler<F>(std::forward<F>(iF)));
0266 }
0267 }
0268
0269
0270
0271
0272
0273
0274
0275
0276 template <typename O>
0277 [[nodiscard]] constexpr auto then(O&& iO) {
0278 using namespace detail;
0279 if constexpr (has_exception_handling<O>::value) {
0280 return ThenAdaptor<O>(std::forward<O>(iO));
0281 } else {
0282 return ThenAdaptor<AutoExceptionHandler<O>>(AutoExceptionHandler<O>(std::forward<O>(iO)));
0283 }
0284 }
0285
0286
0287 template <typename O>
0288 [[nodiscard]] constexpr auto ifThen(bool iValue, O&& iO) {
0289 using namespace detail;
0290 if constexpr (has_exception_handling<O>::value) {
0291 return ConditionalAdaptor<O>(iValue, std::forward<O>(iO));
0292 } else {
0293 return ConditionalAdaptor<AutoExceptionHandler<O>>(iValue, AutoExceptionHandler<O>(std::forward<O>(iO)));
0294 }
0295 }
0296
0297 [[nodiscard]] inline auto runLast(edm::WaitingTaskHolder iTask) { return detail::RunLastAdaptor(std::move(iTask)); }
0298
0299 [[nodiscard]] inline auto lastTask(edm::WaitingTaskHolder iTask) {
0300 return detail::LastTaskAdaptor(std::move(iTask));
0301 }
0302
0303
0304
0305
0306 template <typename E>
0307 [[nodiscard]] constexpr auto ifException(E&& iE) {
0308 return detail::IfExceptionAdapter(std::forward<E>(iE));
0309 }
0310
0311 }
0312 }
0313
0314 #endif