fork(4) download
  1. // ____________________________________[ uncaught_exception_count.hpp ]____________________________________
  2. // Copyright Evgeny Panasyuk 2012.
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://w...content-available-to-author-only...t.org/LICENSE_1_0.txt)
  6.  
  7. // e-mail: E?????[dot]P???????[at]gmail.???
  8.  
  9. #ifndef BOOST_UNCAUGHT_EXCEPTION_COUNT_HPP_39A1E90FC11647e08D5F6ED16CD34B34
  10. #define BOOST_UNCAUGHT_EXCEPTION_COUNT_HPP_39A1E90FC11647e08D5F6ED16CD34B34
  11.  
  12. #if defined(_MSC_VER) || defined(__GNUG__) || defined(__CLANG__)
  13. #define BOOST_UNCAUGHT_EXCEPTION_COUNT_SUPPORTED 1
  14. #endif
  15.  
  16. namespace boost
  17. {
  18. namespace exception_detail
  19. {
  20. template<typename To> inline
  21. To *unrelated_pointer_cast(void *from)
  22. {
  23. return static_cast<To*>(from);
  24. }
  25. }
  26.  
  27. // uncaught_exception_count is a function similar to std::uncaught_exception from standard library,
  28. // but instead of boolean result it returns unsigned int showing current count of uncaught exceptions.
  29.  
  30. #if defined(_MSC_VER)
  31. namespace exception_detail
  32. {
  33. extern "C" char * __cdecl _getptd();
  34. }
  35. inline unsigned uncaught_exception_count()
  36. {
  37. // MSVC specific. Tested on {MSVC2005SP1,MSVC2008SP1,MSVC2010SP1,MSVC2012}x{x32,x64}.
  38. return *exception_detail::unrelated_pointer_cast<unsigned>
  39. (
  40. exception_detail::_getptd() + (sizeof(void*)==8 ? 0x100 : 0x90)
  41. );
  42. }
  43. #elif defined(__GNUG__) || defined(__CLANG__)
  44. namespace exception_detail
  45. {
  46. extern "C" char * __cxa_get_globals();
  47. }
  48. inline unsigned uncaught_exception_count()
  49. {
  50. // Tested on {Clang 3.2,GCC 3.4.6,GCC 4.1.2,GCC 4.4.6,GCC 4.4.7}x{x32,x64}
  51. return *exception_detail::unrelated_pointer_cast<unsigned>
  52. (
  53. exception_detail::__cxa_get_globals() + (sizeof(void*)==8 ? 0x8 : 0x4)
  54. );
  55. }
  56. #endif
  57.  
  58. // Within one scope uncaught_exception_count can be changed only by +1.
  59. // uncaught_exception_count_latch is primitive which helps to determine such transition.
  60. // Internally it stores and compares only last bit of uncaught_exception_count value
  61. #ifdef BOOST_UNCAUGHT_EXCEPTION_COUNT_SUPPORTED
  62. class uncaught_exception_count_latch
  63. {
  64. unsigned char enter_state;
  65. public:
  66. uncaught_exception_count_latch()
  67. : enter_state(static_cast<unsigned char>( uncaught_exception_count() & 1 ))
  68. {
  69. }
  70. bool transitioned() const
  71. {
  72. return enter_state != ( uncaught_exception_count() & 1 );
  73. }
  74. };
  75. #endif
  76.  
  77. }
  78.  
  79. #endif
  80. // ________________________________________________________________________________________________________
  81.  
  82. #include <type_traits>
  83. #include <iostream>
  84. #include <ostream>
  85. #include <utility>
  86. #include <string>
  87.  
  88. // Proof-of-concept:
  89.  
  90. class NonCopyableNonMovable
  91. {
  92. NonCopyableNonMovable(const NonCopyableNonMovable&) = delete;
  93. NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
  94. NonCopyableNonMovable &operator=(const NonCopyableNonMovable&) = delete;
  95. NonCopyableNonMovable &operator=(NonCopyableNonMovable&&) = delete;
  96. public:
  97. NonCopyableNonMovable() = default;
  98. };
  99.  
  100. enum Scope {scope_exit, scope_failure, scope_success};
  101.  
  102. template<Scope scope_type, typename F>
  103. class Guard : NonCopyableNonMovable
  104. {
  105. boost::uncaught_exception_count_latch latch;
  106. F f;
  107. public:
  108. Guard(F &&f)
  109. : f(std::move(f))
  110. {}
  111. ~Guard() noexcept(noexcept(f()))
  112. {
  113. if(latch.transitioned() != (scope_type == scope_success))
  114. f();
  115. }
  116. };
  117.  
  118. template<typename F>
  119. class Guard<scope_exit, F> : NonCopyableNonMovable
  120. {
  121. F f;
  122. public:
  123. Guard(F &&f)
  124. : f(std::move(f))
  125. {}
  126. ~Guard() noexcept(noexcept(f()))
  127. {
  128. f();
  129. }
  130. };
  131.  
  132. // http://c...content-available-to-author-only...n.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C
  133. template<Scope scope_type>
  134. struct Aux
  135. {
  136. template<typename F>
  137. Guard<scope_type, typename std::decay<F>::type>
  138. operator*(F &&f) const
  139. {
  140. return { std::forward<F>(f) };
  141. }
  142. };
  143.  
  144. #define CONCAT(x, y) CONCAT2(x, y)
  145. #define CONCAT2(x, y) x ## y
  146.  
  147. #define scope(scope_type) auto &&CONCAT(aux, __LINE__)= Aux<scope_##scope_type>()*[&]
  148.  
  149. int main()
  150. {
  151. using namespace std;
  152. {
  153. cout << "success case:" << endl;
  154. scope(exit)
  155. {
  156. cout << "exit" << endl;
  157. };
  158. scope(success)
  159. {
  160. cout << "success" << endl;
  161. };
  162. scope(failure)
  163. {
  164. cout << "failure" << endl;
  165. };
  166. }
  167. cout << string(16,'_') << endl;
  168. try
  169. {
  170. cout << "failure case:" << endl;
  171. scope(exit)
  172. {
  173. cout << "exit" << endl;
  174. };
  175. scope(success)
  176. {
  177. cout << "success" << endl;
  178. };
  179. scope(failure)
  180. {
  181. cout << "failure" << endl;
  182. };
  183. throw 1;
  184. }
  185. catch(int){}
  186. }
  187.  
Success #stdin #stdout 0s 3476KB
stdin
Standard input is empty
stdout
success case:
success
exit
________________
failure case:
failure
exit