diff --git a/configure.ac b/configure.ac index 3f814fee7..1c8f890dc 100644 --- a/configure.ac +++ b/configure.ac @@ -583,6 +583,7 @@ RB_CHK_SYSHEADER(functional, [FUNCTIONAL]) RB_CHK_SYSHEADER(algorithm, [ALGORITHM]) RB_CHK_SYSHEADER(numeric, [NUMERIC]) RB_CHK_SYSHEADER(cmath, [CMATH]) +RB_CHK_SYSHEADER(cfenv, [CFENV]) RB_CHK_SYSHEADER(memory, [MEMORY]) RB_CHK_SYSHEADER(exception, [EXCEPTION]) RB_CHK_SYSHEADER(cerrno, [CERRNO]) diff --git a/include/ircd/fpe.h b/include/ircd/fpe.h new file mode 100644 index 000000000..c2687696a --- /dev/null +++ b/include/ircd/fpe.h @@ -0,0 +1,34 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2018 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_FPE_H + +namespace ircd::fpe +{ + struct errors_handle; + + string_view reflect(const ushort &flag); + string_view reflect(const mutable_buffer &, const ushort &flags); + void throw_errors(const ushort &flags); +} + +struct ircd::fpe::errors_handle +{ + fexcept_t theirs; + + public: + ushort pending() const; + void throw_pending() const; + void clear_pending(); + + errors_handle(); + ~errors_handle() noexcept(false); +}; diff --git a/include/ircd/ircd.h b/include/ircd/ircd.h index f2c9e8a7e..1092009a5 100644 --- a/include/ircd/ircd.h +++ b/include/ircd/ircd.h @@ -36,6 +36,7 @@ namespace ircd #include "allocator.h" #include "util/util.h" #include "exception.h" +#include "fpe.h" #include "demangle.h" #include "localee.h" #include "date.h" diff --git a/include/ircd/stdinc.h b/include/ircd/stdinc.h index 77106e715..269b05e06 100644 --- a/include/ircd/stdinc.h +++ b/include/ircd/stdinc.h @@ -59,6 +59,7 @@ extern "C" #include +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#ifndef __GNUC__ +#pragma STDC FENV_ACCESS on +#endif + +ircd::fpe::errors_handle::errors_handle() +{ + syscall(std::fegetexceptflag, &theirs, FE_ALL_EXCEPT); + clear_pending(); +} + +ircd::fpe::errors_handle::~errors_handle() +noexcept(false) +{ + const auto pending(this->pending()); + syscall(std::fesetexceptflag, &theirs, FE_ALL_EXCEPT); + throw_errors(pending); +} + +void +ircd::fpe::errors_handle::clear_pending() +{ + syscall(std::feclearexcept, FE_ALL_EXCEPT); +} + +void +ircd::fpe::errors_handle::throw_pending() +const +{ + throw_errors(pending()); +} + +ushort +ircd::fpe::errors_handle::pending() +const +{ + return std::fetestexcept(FE_ALL_EXCEPT); +} + +// +// util +// + +void +ircd::fpe::throw_errors(const ushort &flags) +{ + if(!flags) + return; + + thread_local char buf[128]; + throw std::domain_error + { + reflect(buf, flags) + }; +} + +ircd::string_view +ircd::fpe::reflect(const mutable_buffer &buf, + const ushort &flags) +{ + window_buffer wb{buf}; + const auto append{[&wb](const auto &flag) + { + wb([&flag](const mutable_buffer &buf) + { + return strlcpy(buf, reflect(flag)); + }); + }}; + + for(size_t i(0); i < sizeof(flags) * 8; ++i) + if(flags & (1 << i)) + append(1 << i); + + return wb.completed(); +} + +ircd::string_view +ircd::fpe::reflect(const ushort &flag) +{ + switch(flag) + { + case 0: return ""; + case FE_INVALID: return "INVALID"; + case FE_DIVBYZERO: return "DIVBYZERO"; + case FE_UNDERFLOW: return "UNDERFLOW"; + case FE_OVERFLOW: return "OVERFLOW"; + case FE_INEXACT: return "INEXACT"; + } + + return "?????"; +}