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{{}, {}};
42fe_trap::fe_trap(std::optional<int> excepts,
bool unique) {
43#if defined(ESPRESSO_FPE_USING_GLIBC_X86_64)
45 m_flags = parse_excepts(excepts);
46 [[maybe_unused]]
auto const status = feenableexcept(m_flags);
50#elif defined(ESPRESSO_FPE_USING_APPLE_ARM_64)
52 using fpcr_t =
decltype(std::fenv_t::__fpcr);
53 m_flags = parse_excepts(excepts);
56 [[maybe_unused]]
auto const status = std::fegetenv(&env);
59 env.__fpcr |=
static_cast<fpcr_t
>(m_flags);
61 [[maybe_unused]]
auto const status = std::fesetenv(&env);
66#error "FE not supported"
72#if defined(ESPRESSO_FPE_USING_GLIBC_X86_64)
74 [[maybe_unused]]
auto const status = fedisableexcept(m_flags);
76 assert(status == 0 or status == m_flags);
78#elif defined(ESPRESSO_FPE_USING_APPLE_ARM_64)
80 using fpcr_t =
decltype(std::fenv_t::__fpcr);
83 [[maybe_unused]]
auto const status = std::fegetenv(&env);
86 assert((env.__fpcr &
static_cast<fpcr_t
>(m_flags)) ==
87 static_cast<fpcr_t
>(m_flags));
88 env.__fpcr &=
static_cast<fpcr_t
>(~m_flags);
90 [[maybe_unused]]
auto const status = std::fesetenv(&env);
95#error "FE not supported"
99int fe_trap::parse_excepts(std::optional<int> excepts) {
100 auto const fallback = FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW;
101 int retval = excepts ? *excepts : fallback;
102#if defined(ESPRESSO_FPE_USING_APPLE_ARM_64)
108fe_trap::scoped_instance
110 std::lock_guard<std::mutex> lock(fe_trap::global_state.mutex);
111 if (fe_trap::global_state.observer.lock()) {
112 throw std::runtime_error(
"Cannot create more than 1 instance of fe_trap");
114 auto raw_ptr =
new fe_trap(excepts,
true);
115 auto watched = std::shared_ptr<fe_trap>(raw_ptr, deleter{});
116 fe_trap::global_state.observer = watched;
117 return fe_trap::scoped_instance(watched);
120fe_trap::scoped_instance
122 std::lock_guard<std::mutex> lock(fe_trap::global_state.mutex);
123 if (
auto watched = fe_trap::global_state.observer.lock()) {
124 if (watched->is_unique()) {
125 throw std::runtime_error(
"Cannot create more than 1 instance of fe_trap");
127 if (watched->get_flags() != parse_excepts(excepts)) {
128 throw std::invalid_argument(
129 "Cannot mix different exceptions with fe_trap");
131 return fe_trap::scoped_instance(watched);
133 auto raw_ptr =
new fe_trap(excepts,
false);
134 auto watched = std::shared_ptr<fe_trap>(raw_ptr, deleter{});
135 fe_trap::global_state.observer = watched;
136 return fe_trap::scoped_instance(watched);
Floating-point exception trap.
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.
This file contains the defaults for ESPResSo.