1 // license:GPL-2.0+ 2 // copyright-holders:Couriersud 3 4 #include "pexception.h" 5 #include "pfmtlog.h" 6 7 #include <cfenv> 8 #include <cfloat> 9 #include <iostream> 10 11 #if (defined(__x86_64__) || defined(__i386__)) && defined(__linux__) 12 #define HAS_FEENABLE_EXCEPT (1) 13 #else 14 #define HAS_FEENABLE_EXCEPT (0) 15 #endif 16 17 namespace plib { 18 19 //============================================================ 20 // terminate 21 //============================================================ 22 terminate(const char * msg)23 void terminate(const char *msg) noexcept 24 { 25 try 26 { 27 std::cerr << msg << "\n"; 28 } 29 catch (...) 30 { 31 /* ignore */ 32 } 33 std::terminate(); 34 } 35 passert_fail(const char * assertion,const char * file,int lineno,const char * msg)36 void passert_fail(const char *assertion, const char *file, int lineno, const char *msg) noexcept 37 { 38 try 39 { 40 std::cerr << file << ":" << lineno << ": "; 41 if (msg != nullptr) 42 std::cerr << msg << "\n"; 43 else 44 std::cerr << "Assertion '" << assertion << "' failed.\n"; 45 } 46 catch (...) 47 { 48 /* ignore */ 49 } 50 std::terminate(); 51 } 52 53 //============================================================ 54 // Exceptions 55 //============================================================ 56 pexception(const pstring & text)57 pexception::pexception(const pstring &text) 58 : m_text(text) 59 { 60 } 61 62 file_e(const pstring & fmt,const pstring & filename)63 file_e::file_e(const pstring &fmt, const pstring &filename) 64 : pexception(pfmt(fmt)(filename)) 65 { 66 } 67 68 file_open_e(const pstring & filename)69 file_open_e::file_open_e(const pstring &filename) 70 : file_e("File open failed: {}", filename) 71 { 72 } 73 74 file_read_e(const pstring & filename)75 file_read_e::file_read_e(const pstring &filename) 76 : file_e("File read failed: {}", filename) 77 { 78 } 79 80 file_write_e(const pstring & filename)81 file_write_e::file_write_e(const pstring &filename) 82 : file_e("File write failed: {}", filename) 83 { 84 } 85 86 null_argument_e(const pstring & argument)87 null_argument_e::null_argument_e(const pstring &argument) 88 : pexception(pfmt("Null argument passed: {}")(argument)) 89 { 90 } 91 92 out_of_mem_e(const pstring & location)93 out_of_mem_e::out_of_mem_e(const pstring &location) 94 : pexception(pfmt("Out of memory: {}")(location)) 95 { 96 } 97 98 fpexception_e(const pstring & text)99 fpexception_e::fpexception_e(const pstring &text) 100 : pexception(pfmt("Exception error: {}")(text)) 101 { 102 } 103 104 105 bool fpsignalenabler::m_enable = false; // NOLINT 106 107 //FIXME: mingw needs to be compiled with "-fnon-call-exceptions" 108 fpsignalenabler(unsigned fpexceptions)109 fpsignalenabler::fpsignalenabler(unsigned fpexceptions) 110 { 111 #if HAS_FEENABLE_EXCEPT 112 if (m_enable) 113 { 114 int b = 0; 115 if (fpexceptions & plib::FP_INEXACT) b = b | FE_INEXACT; 116 if (fpexceptions & plib::FP_DIVBYZERO) b = b | FE_DIVBYZERO; 117 if (fpexceptions & plib::FP_UNDERFLOW) b = b | FE_UNDERFLOW; 118 if (fpexceptions & plib::FP_OVERFLOW) b = b | FE_OVERFLOW; 119 if (fpexceptions & plib::FP_INVALID) b = b | FE_INVALID; 120 if ((b & m_last_enabled) != b) 121 m_last_enabled = feenableexcept(b); 122 } 123 #elif defined(_WIN32) && defined(_EM_INEXACT) 124 if (m_enable) 125 { 126 int b = _EM_DENORMAL | _EM_INEXACT | _EM_ZERODIVIDE | _EM_UNDERFLOW | _EM_OVERFLOW | _EM_INVALID; 127 if (fpexceptions & plib::FP_INEXACT) b &= ~_EM_INEXACT; 128 if (fpexceptions & plib::FP_DIVBYZERO) b &= ~_EM_ZERODIVIDE; 129 if (fpexceptions & plib::FP_UNDERFLOW) b &= ~_EM_UNDERFLOW; 130 if (fpexceptions & plib::FP_OVERFLOW) b &= ~_EM_OVERFLOW; 131 if (fpexceptions & plib::FP_INVALID) b &= ~_EM_INVALID; 132 m_last_enabled = _controlfp(0, 0); 133 _controlfp(b, _MCW_EM ); 134 } 135 #else 136 m_last_enabled = 0; 137 #endif 138 } 139 ~fpsignalenabler()140 fpsignalenabler::~fpsignalenabler() 141 { 142 #if HAS_FEENABLE_EXCEPT 143 if (m_enable) 144 { 145 fedisableexcept(FE_ALL_EXCEPT); // Enable all floating point exceptions but FE_INEXACT 146 feenableexcept(m_last_enabled); // Enable all floating point exceptions but FE_INEXACT 147 } 148 #elif defined(_WIN32) && defined(_EM_INEXACT) 149 if (m_enable) 150 { 151 _controlfp(m_last_enabled, _MCW_EM); 152 } 153 #endif 154 } 155 supported()156 bool fpsignalenabler::supported() 157 { 158 #if HAS_FEENABLE_EXCEPT 159 return true; 160 #elif defined(_WIN32) && defined(_EM_INEXACT) 161 return true; 162 #else 163 return false; 164 #endif 165 } 166 global_enable(bool enable)167 bool fpsignalenabler::global_enable(bool enable) 168 { 169 bool old = m_enable; 170 m_enable = enable; 171 return old; 172 } 173 174 175 } // namespace plib 176