58 err.
thread_id = std::this_thread::get_id();
59 err.
timestamp = std::chrono::steady_clock::now();
74 [[nodiscard]]
auto what() const -> std::
string
83 catch (std::exception
const& e)
89 return "Unknown exception";
91 return "No exception";
160 template <
typename Callback,
161 std::enable_if_t<!std::is_same_v<detail::remove_cvref_t<Callback>,
ErrorCallback>,
int> = 0>
164 static_assert(std::is_invocable_r_v<void, Callback&, TaskError const&>,
165 "Error callback must be invocable with TaskError const&");
177 std::lock_guard<std::mutex> lock(mutex_);
178 return callbacks_.erase(
id) > 0;
186 std::lock_guard<std::mutex> lock(mutex_);
187 return callbacks_.count(
id) > 0;
198 std::lock_guard<std::mutex> lock(mutex_);
213 std::vector<ErrorCallbackStorage> snapshot;
215 std::lock_guard<std::mutex> lock(mutex_);
217 snapshot.reserve(callbacks_.size());
218 for (
auto const& [
id, callback] : callbacks_)
219 snapshot.push_back(callback);
222 for (
auto& callback : snapshot)
244 std::lock_guard<std::mutex> lock(mutex_);
253 std::lock_guard<std::mutex> lock(mutex_);
260 std::lock_guard<std::mutex> lock(mutex_);
261 size_t const id = next_callback_id_++;
262 callbacks_.emplace(
id, std::move(callback));
266 mutable std::mutex mutex_;
267 std::map<size_t, ErrorCallbackStorage> callbacks_;
268 size_t next_callback_id_{0};
269 size_t error_count_{0};
290template <
typename Func>
294 ErrorHandledTask(Func&& func, std::shared_ptr<ErrorHandler> handler, std::string description =
"")
295 : func_(std::forward<Func>(func)), handler_(std::move(handler)), description_(std::move(description))
314 std::shared_ptr<ErrorHandler> handler_;
315 std::string description_;
327template <
typename Func>
357 : future_(std::move(future)), error_callback_(nullptr), has_callback_(false)
379 has_callback_ =
true;
383 template <
typename Callback,
384 std::enable_if_t<!std::is_same_v<detail::remove_cvref_t<Callback>, std::function<void(std::exception_ptr)>>,
388 static_assert(std::is_invocable_r_v<void, Callback&, std::exception_ptr>,
389 "Error callback must be invocable with std::exception_ptr");
391 has_callback_ =
true;
408 if constexpr (std::is_void_v<T>)
411 return future_.get();
415 if (has_callback_ && error_callback_)
417 error_callback_(std::current_exception());
440 template <
typename Rep,
typename Period>
441 auto wait_for(std::chrono::duration<Rep, Period>
const& timeout_duration)
const
443 return future_.wait_for(timeout_duration);
453 template <
typename Clock,
typename Duration>
454 auto wait_until(std::chrono::time_point<Clock, Duration>
const& timeout_time)
const
456 return future_.wait_until(timeout_time);
464 [[nodiscard]]
auto valid() const ->
bool
466 return future_.valid();
470 std::future<T> future_;
472 bool has_callback_{
false};
Feature-gated callable storage aliases for modern C++ builds.
Callable wrapper that catches exceptions and routes them to an ErrorHandler.
ErrorHandledTask(Func &&func, std::shared_ptr< ErrorHandler > handler, std::string description="")
Central registry and dispatcher for task-error callbacks.
auto remove_callback(size_t id) -> bool
Remove a single callback by its ID.
auto has_callback(size_t id) const -> bool
Check whether a callback with the given ID is registered.
void reset_error_count()
Reset the cumulative error count to zero.
auto add_callback(Callback &&callback) -> size_t
void handle_error(TaskError const &error)
Dispatch an error to all registered callbacks.
void clear_callbacks()
Remove all registered error callbacks.
auto error_count() const -> size_t
Return the total number of errors handled since the last reset.
auto add_callback(ErrorCallback callback) -> size_t
Register an error callback.
auto on_error(std::function< void(std::exception_ptr)> callback) -> FutureWithErrorHandler &
Attach an error callback.
auto wait_until(std::chrono::time_point< Clock, Duration > const &timeout_time) const
Block until the result is ready or the given time point is reached.
auto on_error(Callback &&callback) -> FutureWithErrorHandler &
auto operator=(FutureWithErrorHandler const &) -> FutureWithErrorHandler &=delete
auto get() -> T
Retrieve the result, invoking the error callback on failure.
auto valid() const -> bool
Check whether the future refers to a shared state.
auto operator=(FutureWithErrorHandler &&) -> FutureWithErrorHandler &=default
FutureWithErrorHandler(std::future< T > future)
FutureWithErrorHandler(FutureWithErrorHandler &&)=default
auto wait_for(std::chrono::duration< Rep, Period > const &timeout_duration) const
Block until the result is ready or the timeout elapses.
FutureWithErrorHandler(FutureWithErrorHandler const &)=delete
void wait() const
Block until the result is ready.
std::function< Signature > copyable_callable
auto make_move_callable(Callable &&callable) -> move_callable< Signature >
std::function< Signature > move_callable
auto make_copyable_callable(Callable &&callable) -> copyable_callable< Signature >
detail::copyable_callable< void(TaskError const &)> ErrorCallback
Signature for error-handling callbacks registered with ErrorHandler.
auto make_error_handled_task(Func &&func, std::shared_ptr< ErrorHandler > handler, std::string description="")
Factory function that creates an ErrorHandledTask with perfect forwarding.
detail::move_callable< void(std::exception_ptr)> FutureErrorCallback
ErrorCallback ErrorCallbackStorage
Holds diagnostic information captured from a failed task.
std::string task_description
Optional human-readable label supplied when the task was submitted.
void rethrow() const
Re-throw the original exception.
static auto capture(std::string description={}) -> TaskError
Capture the current in-flight exception into a TaskError.
std::exception_ptr exception
The captured exception. Never null when produced by the library.
auto what() const -> std::string
Extract the message string from the stored exception.
std::thread::id thread_id
Id of the thread on which the exception was thrown.
std::chrono::steady_clock::time_point timestamp
Monotonic timestamp recorded immediately after the exception was caught.