diff options
Diffstat (limited to 'build/utility')
-rw-r--r-- | build/utility | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/build/utility b/build/utility index bcbf834..5523e8b 100644 --- a/build/utility +++ b/build/utility @@ -5,9 +5,12 @@ #ifndef BUILD_UTILITY #define BUILD_UTILITY +#include <tuple> #include <string> -#include <unordered_set> +#include <utility> #include <cstring> // strcmp +#include <exception> +#include <unordered_set> namespace build @@ -26,6 +29,54 @@ namespace build bool operator() (const P& x, const P& y) const {return *x < *y;} }; + // Call a function if there is an exception. + // + + // Means we are in the body of a destructor that is being called + // as part of the exception stack unwindining. Used to compensate + // for the deficiencies of uncaught_exception() until C++17 + // uncaught_exceptions() becomes available. + // + // @@ MT: will have to be TLS. + // + extern bool exception_unwinding_dtor; + + template <typename F, typename T> + struct exception_guard; + + template <typename F, typename... A> + inline exception_guard<F, std::tuple<A&&...>> + make_exception_guard (F f, A&&... a) + { + return exception_guard<F, std::tuple<A&&...>> ( + std::move (f), std::forward_as_tuple (a...)); + } + + template <typename F, typename... A> + struct exception_guard<F, std::tuple<A...>> + { + typedef std::tuple<A...> T; + + exception_guard (F f, T a): f_ (std::move (f)), a_ (std::move (a)) {} + ~exception_guard () + { + if (std::uncaught_exception ()) + { + exception_unwinding_dtor = true; + call (std::index_sequence_for<A...> ()); + exception_unwinding_dtor = false; + } + } + + private: + template <std::size_t... I> + void + call (std::index_sequence<I...>) {f_ (std::get<I> (a_)...);} + + F f_; + T a_; + }; + // Pools (@@ perhaps move into a separate header). // struct string_pool: std::unordered_set<std::string> |