107 lines
3.4 KiB
C++
107 lines
3.4 KiB
C++
/*
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
* https://www.boost.org/LICENSE_1_0.txt)
|
|
*
|
|
* Copyright (c) 2023 Andrey Semashev
|
|
*/
|
|
/*!
|
|
* \file scope/exception_checker.hpp
|
|
*
|
|
* This header contains definition of \c exception_checker type.
|
|
*/
|
|
|
|
#ifndef BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_
|
|
#define BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_
|
|
|
|
#include <boost/assert.hpp>
|
|
#include <boost/scope/detail/config.hpp>
|
|
#include <boost/core/uncaught_exceptions.hpp>
|
|
#include <boost/scope/detail/header.hpp>
|
|
|
|
#ifdef BOOST_HAS_PRAGMA_ONCE
|
|
#pragma once
|
|
#endif
|
|
|
|
namespace boost {
|
|
namespace scope {
|
|
|
|
/*!
|
|
* \brief A predicate for checking whether an exception is being thrown.
|
|
*
|
|
* On construction, the predicate captures the current number of uncaught exceptions,
|
|
* which it then compares with the number of uncaught exceptions at the point when it
|
|
* is called. If the number increased then a new exception is detected and the predicate
|
|
* returns \c true.
|
|
*
|
|
* \note This predicate is designed for a specific use case with scope guards created on
|
|
* the stack. It is incompatible with C++20 coroutines and similar facilities (e.g.
|
|
* fibers and userspace context switching), where the thread of execution may be
|
|
* suspended after the predicate captures the number of uncaught exceptions and
|
|
* then resumed in a different context, where the number of uncaught exceptions
|
|
* has changed. Similarly, it is incompatible with usage patterns where the predicate
|
|
* is cached after construction and is invoked after the thread has left the scope
|
|
* where the predicate was constructed (e.g. when the predicate is stored as a class
|
|
* data member or a namespace-scope variable).
|
|
*/
|
|
class exception_checker
|
|
{
|
|
public:
|
|
//! Predicate result type
|
|
using result_type = bool;
|
|
|
|
private:
|
|
unsigned int m_uncaught_count;
|
|
|
|
public:
|
|
/*!
|
|
* \brief Constructs the predicate.
|
|
*
|
|
* Upon construction, the predicate saves the current number of uncaught exceptions.
|
|
* This information will be used when calling the predicate to detect if a new
|
|
* exception is being thrown.
|
|
*
|
|
* **Throws:** Nothing.
|
|
*/
|
|
exception_checker() noexcept :
|
|
m_uncaught_count(boost::core::uncaught_exceptions())
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks if an exception is being thrown.
|
|
*
|
|
* **Throws:** Nothing.
|
|
*
|
|
* \returns \c true if the number of uncaught exceptions at the point of call is
|
|
* greater than that at the point of construction of the predicate,
|
|
* otherwise \c false.
|
|
*/
|
|
result_type operator()() const noexcept
|
|
{
|
|
const unsigned int uncaught_count = boost::core::uncaught_exceptions();
|
|
// If this assertion fails, the predicate is likely being used in an unsupported
|
|
// way, where it is called in a different scope or thread context from where
|
|
// it was constructed.
|
|
BOOST_ASSERT((uncaught_count - m_uncaught_count) <= 1u);
|
|
return uncaught_count > m_uncaught_count;
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* \brief Creates a predicate for checking whether an exception is being thrown
|
|
*
|
|
* **Throws:** Nothing.
|
|
*/
|
|
inline exception_checker check_exception() noexcept
|
|
{
|
|
return exception_checker();
|
|
}
|
|
|
|
} // namespace scope
|
|
} // namespace boost
|
|
|
|
#include <boost/scope/detail/footer.hpp>
|
|
|
|
#endif // BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_
|