Skip to content

Instantly share code, notes, and snippets.

@patstew
Last active July 26, 2016 20:30
Show Gist options
  • Save patstew/c4f1489769a84411e933201b2f328df7 to your computer and use it in GitHub Desktop.
Save patstew/c4f1489769a84411e933201b2f328df7 to your computer and use it in GitHub Desktop.
#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