34#if defined(__STDC_IEC_559__) and defined(__GLIBC__) and defined(__x86_64__)
35#define ESPRESSO_FPE_USING_GLIBC_X86_64
36#elif defined(__arm64__) and defined(__APPLE__)
37#define ESPRESSO_FPE_USING_APPLE_ARM_64
40fe_trap::global_state_params fe_trap::global_state{{}, {}};
46#if defined(ESPRESSO_FPE_USING_GLIBC_X86_64)
48 [[maybe_unused]]
auto const status = feenableexcept(m_flags);
52#elif defined(ESPRESSO_FPE_USING_APPLE_ARM_64)
54 using fpcr_t =
decltype(std::fenv_t::__fpcr);
57 [[maybe_unused]]
auto const status = std::fegetenv(&env);
60 env.__fpcr |=
static_cast<fpcr_t
>(m_flags);
62 [[maybe_unused]]
auto const status = std::fesetenv(&env);
67#error "FE not supported"
76#if defined(ESPRESSO_FPE_USING_GLIBC_X86_64)
78 [[maybe_unused]]
auto const status = fedisableexcept(m_flags);
80 assert(status == 0 or status == m_flags);
82#elif defined(ESPRESSO_FPE_USING_APPLE_ARM_64)
84 using fpcr_t =
decltype(std::fenv_t::__fpcr);
87 [[maybe_unused]]
auto const status = std::fegetenv(&env);
90 assert((env.__fpcr &
static_cast<fpcr_t
>(m_flags)) ==
91 static_cast<fpcr_t
>(m_flags));
92 env.__fpcr &=
static_cast<fpcr_t
>(~m_flags);
94 [[maybe_unused]]
auto const status = std::fesetenv(&env);
99#error "FE not supported"
104int fe_trap::parse_excepts(std::optional<int> excepts) {
105 auto const fallback = FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW;
106 int retval = excepts ? *excepts : fallback;
107#if defined(ESPRESSO_FPE_USING_APPLE_ARM_64)
113fe_trap::scoped_instance
115 std::lock_guard<std::mutex> lock(fe_trap::global_state.mutex);
116 if (fe_trap::global_state.observer.lock()) {
117 throw std::runtime_error(
"Cannot create more than 1 instance of fe_trap");
119 auto raw_ptr =
new fe_trap(excepts,
true);
120 auto watched = std::shared_ptr<fe_trap>(raw_ptr, deleter{});
121 fe_trap::global_state.observer = watched;
122 return fe_trap::scoped_instance(watched);
125fe_trap::scoped_instance
127 std::lock_guard<std::mutex> lock(fe_trap::global_state.mutex);
128 if (
auto watched = fe_trap::global_state.observer.lock()) {
129 if (watched->is_unique()) {
130 throw std::runtime_error(
"Cannot create more than 1 instance of fe_trap");
132 if (watched->get_flags() != parse_excepts(excepts)) {
133 throw std::invalid_argument(
134 "Cannot mix different exceptions with fe_trap");
136 return fe_trap::scoped_instance(watched);
138 auto raw_ptr =
new fe_trap(excepts,
false);
139 auto watched = std::shared_ptr<fe_trap>(raw_ptr, deleter{});
140 fe_trap::global_state.observer = watched;
141 return fe_trap::scoped_instance(watched);
145 std::lock_guard<std::mutex> lock(fe_trap::global_state.mutex);
146 if (
auto watched = fe_trap::global_state.observer.lock()) {
147 if (
auto pause = watched->m_pause.lock()) {
150 auto pause = std::make_shared<scoped_pause>(watched);
151 watched->m_pause = pause;
Floating-point exception trap.
void activate()
Manually activate the exception trap.
void deactivate()
Manually deactivate the exception trap.
static std::shared_ptr< scoped_pause > make_shared_pause_scoped()
Generate a shared handle to temporarily disable any currently active exception trap for the lifetime ...
static scoped_instance make_shared_scoped(std::optional< int > excepts=std::nullopt)
Generate a shared trap with the lifetime of the current scope.
static scoped_instance make_unique_scoped(std::optional< int > excepts=std::nullopt)
Generate a unique trap with the lifetime of the current scope.