yexception.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #pragma once
  2. #include "bt_exception.h"
  3. #include "strbuf.h"
  4. #include "string.h"
  5. #include "utility.h"
  6. #include "va_args.h"
  7. #include <utility>
  8. #include <util/stream/tempbuf.h>
  9. #include <util/system/compat.h>
  10. #include <util/system/compiler.h>
  11. #include <util/system/defaults.h>
  12. #include <util/system/error.h>
  13. #include <util/system/src_location.h>
  14. #include <util/system/platform.h>
  15. #include <exception>
  16. #include <cstdio>
  17. class TBackTrace;
  18. namespace NPrivateException {
  19. class TTempBufCuttingWrapperOutput: public IOutputStream {
  20. public:
  21. TTempBufCuttingWrapperOutput(TTempBuf& tempbuf)
  22. : TempBuf_(tempbuf)
  23. {
  24. }
  25. void DoWrite(const void* data, size_t len) override {
  26. TempBuf_.Append(data, Min(len, TempBuf_.Left()));
  27. }
  28. private:
  29. TTempBuf& TempBuf_;
  30. };
  31. class yexception: public std::exception {
  32. public:
  33. yexception();
  34. yexception(const yexception&) = default;
  35. yexception(yexception&&) = default;
  36. yexception& operator=(const yexception&) = default;
  37. yexception& operator=(yexception&&) = default;
  38. const char* what() const noexcept override;
  39. virtual const TBackTrace* BackTrace() const noexcept;
  40. template <class T>
  41. inline void Append(const T& t) {
  42. TTempBufCuttingWrapperOutput tempBuf(Buf_);
  43. static_cast<IOutputStream&>(tempBuf) << t;
  44. ZeroTerminate();
  45. }
  46. TStringBuf AsStrBuf() const;
  47. private:
  48. void ZeroTerminate() noexcept;
  49. private:
  50. TTempBuf Buf_;
  51. };
  52. template <class E, class T>
  53. static inline std::enable_if_t<std::is_base_of<yexception, std::decay_t<E>>::value, E&&>
  54. operator<<(E&& e, const T& t) {
  55. e.Append(t);
  56. return std::forward<E>(e);
  57. }
  58. template <class T>
  59. static inline T&& operator+(const TSourceLocation& sl, T&& t) {
  60. return std::forward<T>(t << sl << TStringBuf(": "));
  61. }
  62. }
  63. class yexception: public NPrivateException::yexception {
  64. };
  65. Y_DECLARE_OUT_SPEC(inline, yexception, stream, value) {
  66. stream << value.AsStrBuf();
  67. }
  68. class TSystemError: public yexception {
  69. public:
  70. TSystemError(int status)
  71. : Status_(status)
  72. {
  73. Init();
  74. }
  75. TSystemError()
  76. : TSystemError(LastSystemError())
  77. {
  78. }
  79. int Status() const noexcept {
  80. return Status_;
  81. }
  82. private:
  83. void Init();
  84. private:
  85. int Status_;
  86. };
  87. class TIoException: public TSystemError {
  88. };
  89. class TIoSystemError: public TIoException {
  90. };
  91. class TFileError: public TIoSystemError {
  92. };
  93. /**
  94. * TBadArgumentException should be thrown when an argument supplied to some function (or constructor)
  95. * is invalid or incorrect.
  96. *
  97. * \note
  98. * A special case when such argument is given to a function which performs type casting
  99. * (e.g. integer from string) is covered by the TBadCastException class which is derived from
  100. * TBadArgumentException.
  101. */
  102. struct TBadArgumentException: public virtual yexception {
  103. };
  104. /**
  105. * TBadCastException should be thrown to indicate the failure of some type casting procedure
  106. * (e.g. reading an integer parameter from string).
  107. */
  108. struct TBadCastException: public virtual TBadArgumentException {
  109. };
  110. #define ythrow throw __LOCATION__ +
  111. namespace NPrivate {
  112. /// Encapsulates data for one of the most common case in which
  113. /// exception message consists of single constant string
  114. struct TSimpleExceptionMessage {
  115. TSourceLocation Location;
  116. TStringBuf Message;
  117. };
  118. [[noreturn]] void ThrowYException(const TSimpleExceptionMessage& sm);
  119. [[noreturn]] void ThrowYExceptionWithBacktrace(const TSimpleExceptionMessage& sm);
  120. }
  121. void fputs(const std::exception& e, FILE* f = stderr);
  122. TString CurrentExceptionMessage();
  123. /**
  124. * Formats current exception for logging purposes. Includes formatted backtrace if it is stored
  125. * alongside the exception.
  126. * The output format is a subject to change, do not depend or canonize it.
  127. * The speed of this method is not guaranteed either. Do not call it in hot paths of your code.
  128. *
  129. * The lack of current exception prior to the invocation indicates logical bug in the client code.
  130. * Y_ABORT_UNLESS asserts the existence of exception, otherwise panic and abort.
  131. */
  132. TString FormatCurrentException();
  133. void FormatCurrentExceptionTo(IOutputStream& out);
  134. /*
  135. * A neat method that detects whether stack unwinding is in progress.
  136. * As its std counterpart (that is std::uncaught_exception())
  137. * was removed from the standard, this method uses std::uncaught_exceptions() internally.
  138. *
  139. * If you are struggling to use this method, please, consider reading
  140. *
  141. * http://www.gotw.ca/gotw/047.htm
  142. * and
  143. * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4152.pdf
  144. *
  145. * DO NOT USE THIS METHOD IN DESTRUCTORS.
  146. */
  147. bool UncaughtException() noexcept;
  148. std::string CurrentExceptionTypeName();
  149. TString FormatExc(const std::exception& exception);
  150. #define Y_THROW_UNLESS_EX(CONDITION, THROW_EXPRESSION) \
  151. do { \
  152. if (Y_UNLIKELY(!(CONDITION))) { \
  153. ythrow THROW_EXPRESSION; \
  154. } \
  155. } while (false)
  156. #define Y_ENSURE_EX Y_THROW_UNLESS_EX
  157. /// @def Y_ENSURE_SIMPLE
  158. /// This macro works like the Y_ENSURE, but requires the second argument to be a constant string view.
  159. /// Should not be used directly.
  160. #define Y_ENSURE_SIMPLE(CONDITION, MESSAGE, THROW_FUNCTION) \
  161. do { \
  162. if (Y_UNLIKELY(!(CONDITION))) { \
  163. /* use variable to guarantee evaluation at compile time */ \
  164. static constexpr const ::NPrivate::TSimpleExceptionMessage __SIMPLE_EXCEPTION_MESSAGE{__LOCATION__, (MESSAGE)}; \
  165. THROW_FUNCTION(__SIMPLE_EXCEPTION_MESSAGE); \
  166. } \
  167. } while (false)
  168. #define Y_ENSURE_IMPL_1(CONDITION) Y_ENSURE_SIMPLE(CONDITION, ::TStringBuf("Condition violated: `" Y_STRINGIZE(CONDITION) "'"), ::NPrivate::ThrowYException)
  169. #define Y_ENSURE_IMPL_2(CONDITION, MESSAGE) Y_ENSURE_EX(CONDITION, yexception() << MESSAGE)
  170. #define Y_ENSURE_BT_IMPL_1(CONDITION) Y_ENSURE_SIMPLE(CONDITION, ::TStringBuf("Condition violated: `" Y_STRINGIZE(CONDITION) "'"), ::NPrivate::ThrowYExceptionWithBacktrace)
  171. #define Y_ENSURE_BT_IMPL_2(CONDITION, MESSAGE) Y_ENSURE_EX(CONDITION, TWithBackTrace<yexception>() << MESSAGE)
  172. /**
  173. * @def Y_ENSURE
  174. *
  175. * This macro is intended to be used as a shortcut for `if () { throw }`.
  176. *
  177. * @code
  178. * void DoSomethingLovely(const int x, const int y) {
  179. * Y_ENSURE(x > y, "`x` must be greater than `y`");
  180. * Y_ENSURE(x > y); // if you are too lazy
  181. * // actually doing something nice here
  182. * }
  183. * @endcode
  184. */
  185. #define Y_THROW_UNLESS(...) Y_PASS_VA_ARGS(Y_MACRO_IMPL_DISPATCHER_2(__VA_ARGS__, Y_ENSURE_IMPL_2, Y_ENSURE_IMPL_1)(__VA_ARGS__))
  186. #define Y_ENSURE Y_THROW_UNLESS
  187. /**
  188. * @def Y_ENSURE_BT
  189. *
  190. * This macro is intended to be used as a shortcut for `if () { throw TWithBackTrace<yexception>() << "message"; }`.
  191. *
  192. * @code
  193. * void DoSomethingLovely(const int x, const int y) {
  194. * Y_ENSURE_BT(x > y, "`x` must be greater than `y`");
  195. * Y_ENSURE_BT(x > y); // if you are too lazy
  196. * // actually doing something nice here
  197. * }
  198. * @endcode
  199. */
  200. #define Y_ENSURE_BT(...) Y_PASS_VA_ARGS(Y_MACRO_IMPL_DISPATCHER_2(__VA_ARGS__, Y_ENSURE_BT_IMPL_2, Y_ENSURE_BT_IMPL_1)(__VA_ARGS__))