Last active
July 26, 2016 20:30
-
-
Save patstew/c4f1489769a84411e933201b2f328df7 to your computer and use it in GitHub Desktop.
Nicked from https://github.com/panaseleus/stack_unwinding/blob/master/examples/self_contained_cpp11.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SCOPEGUARD_H | |
#define SCOPEGUARD_H | |
#define ANON_VAR__(a,b) a##b | |
#define ANON_VAR_(a,b) ANON_VAR__(a,b) | |
#define ANON_VAR ANON_VAR_(_anonvar, __LINE__) | |
// ____________________________________[ uncaught_exception_count.hpp ]____________________________________ | |
// Copyright Evgeny Panasyuk 2012. | |
// Distributed under the Boost Software License, Version 1.0. | |
// (See accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
// e-mail: E?????[dot]P???????[at]gmail.??? | |
//MSVC wrongly warns about unused scope() variables | |
#ifdef _MSC_VER | |
#pragma warning( disable : 4189 ) | |
#endif | |
#ifndef BOOST_UNCAUGHT_EXCEPTION_COUNT_HPP_39A1E90FC11647e08D5F6ED16CD34B34 | |
#define BOOST_UNCAUGHT_EXCEPTION_COUNT_HPP_39A1E90FC11647e08D5F6ED16CD34B34 | |
#if defined(_MSC_VER) || defined(__GNUG__) || defined(__CLANG__) | |
#define BOOST_UNCAUGHT_EXCEPTION_COUNT_SUPPORTED 1 | |
#endif | |
namespace boost | |
{ | |
namespace exception_detail | |
{ | |
template<typename To> inline | |
To *unrelated_pointer_cast(void *from) | |
{ | |
return static_cast<To*>(from); | |
} | |
} | |
// uncaught_exception_count is a function similar to std::uncaught_exception from standard library, | |
// but instead of boolean result it returns unsigned int showing current count of uncaught exceptions. | |
#if defined(_MSC_VER) && _MSC_VER < 1900 | |
namespace exception_detail | |
{ | |
extern "C" char * __cdecl _getptd(); | |
} | |
inline unsigned uncaught_exception_count() | |
{ | |
// MSVC specific. Tested on {MSVC2005SP1,MSVC2008SP1,MSVC2010SP1,MSVC2012}x{x32,x64}. | |
return *exception_detail::unrelated_pointer_cast<unsigned> | |
( | |
exception_detail::_getptd() + (sizeof(void*)==8 ? 0x100 : 0x90) | |
); | |
} | |
#elif (defined(__GNUG__) || defined(__CLANG__)) && __cplusplus < 201700L | |
namespace exception_detail | |
{ | |
extern "C" char * __cxa_get_globals(); | |
} | |
inline unsigned uncaught_exception_count() | |
{ | |
// Tested on {Clang 3.2,GCC 3.4.6,GCC 4.1.2,GCC 4.4.6,GCC 4.4.7}x{x32,x64} | |
return *exception_detail::unrelated_pointer_cast<unsigned> | |
( | |
exception_detail::__cxa_get_globals() + (sizeof(void*)==8 ? 0x8 : 0x4) | |
); | |
} | |
#else | |
inline unsigned uncaught_exception_count() | |
{ | |
return std::uncaught_exceptions(); | |
} | |
#endif | |
// Within one scope uncaught_exception_count can be changed only by +1. | |
// uncaught_exception_count_latch is primitive which helps to determine such transition. | |
// Internally it stores and compares only last bit of uncaught_exception_count value | |
#ifdef BOOST_UNCAUGHT_EXCEPTION_COUNT_SUPPORTED | |
class uncaught_exception_count_latch | |
{ | |
unsigned char enter_state; | |
public: | |
uncaught_exception_count_latch() | |
: enter_state(static_cast<unsigned char>( uncaught_exception_count() & 1 )) | |
{ | |
} | |
bool transitioned() const | |
{ | |
return enter_state != ( uncaught_exception_count() & 1 ); | |
} | |
}; | |
#endif | |
} | |
#endif | |
// ________________________________________________________________________________________________________ | |
#include <type_traits> | |
#include <iostream> | |
#include <ostream> | |
#include <utility> | |
#include <string> | |
// Proof-of-concept: | |
class NonCopyableNonMovable | |
{ | |
NonCopyableNonMovable(const NonCopyableNonMovable&) = delete; | |
NonCopyableNonMovable(NonCopyableNonMovable&&) = delete; | |
NonCopyableNonMovable &operator=(const NonCopyableNonMovable&) = delete; | |
NonCopyableNonMovable &operator=(NonCopyableNonMovable&&) = delete; | |
public: | |
NonCopyableNonMovable() = default; | |
}; | |
enum Scope {scope_exit, scope_failure, scope_success}; | |
template<Scope scope_type, typename F = void, typename enable = void> | |
class Guard : NonCopyableNonMovable | |
{ | |
boost::uncaught_exception_count_latch latch; | |
F f; | |
public: | |
Guard(F &&f) | |
: f(std::move(f)) | |
{} | |
~Guard() noexcept(noexcept(f())) | |
{ | |
if(latch.transitioned() != (scope_type == scope_success)) | |
f(); | |
} | |
}; | |
template<typename F> | |
class Guard<scope_exit, F, std::enable_if_t<!std::is_void<F>::value>> : NonCopyableNonMovable | |
{ | |
F f; | |
public: | |
Guard(F &&f) | |
: f(std::move(f)) | |
{} | |
~Guard() noexcept(noexcept(f())) | |
{ | |
f(); | |
} | |
}; | |
// http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C | |
template<Scope scope_type> | |
class Guard<scope_type> | |
{ | |
public: | |
template<typename F> | |
Guard<scope_type, typename std::decay_t<F>> operator*(F &&f) const | |
{ | |
return { std::forward<F>(f) }; | |
} | |
}; | |
#define scope(scope_type) auto&& ANON_VAR = Guard<scope_##scope_type>()*[&] | |
#ifdef _MSC_VER | |
#pragma warning( default : 4189 ) | |
#endif | |
#endif // SCOPEGUARD_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment