#pragma once #if !defined(INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ALL_OR_EXCEPTION_INL_H) #error "you should never include wait_all_or_exception_inl.h directly" #endif #include "subscription.h" #include namespace NThreading::NWait { namespace NPrivate { class TWaitAllOrException final : public NThreading::NPrivate::TWait { private: size_t Count = 0; static constexpr bool RevertOnSignaled = false; using TBase = NThreading::NPrivate::TWait; friend TBase; private: TWaitAllOrException(TSubscriptionManagerPtr manager) : TBase(std::move(manager)) , Count(0) { } template void BeforeSubscribe(TFutures const& futures) { Count = std::size(futures); Y_ENSURE(Count > 0, "It is meaningless to use this class with empty futures set"); } template void Set(TFuture const& future) { with_lock (TBase::Lock) { try { future.TryRethrow(); if (--Count == 0) { // there is no need to call Unsubscribe here since all futures are signaled TBase::Promise.SetValue(); } } catch (...) { Y_ASSERT(!TBase::Promise.HasValue()); TBase::Unsubscribe(); if (!TBase::Promise.HasException()) { TBase::Promise.SetException(std::current_exception()); } } } } }; } template TFuture WaitAllOrException(TFutures const& futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) { return NThreading::NPrivate::Wait(futures, std::move(manager), std::forward(executor)); } template TFuture WaitAllOrException(std::initializer_list const> futures, TSubscriptionManagerPtr manager , TCallbackExecutor&& executor) { return NThreading::NPrivate::Wait(futures, std::move(manager), std::forward(executor)); } template TFuture WaitAllOrException(TFuture const& future1, TFuture const& future2, TSubscriptionManagerPtr manager , TCallbackExecutor&& executor) { return NThreading::NPrivate::Wait(future1, future2, std::move(manager) , std::forward(executor)); } }