選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

168 行
4.2 KiB

  1. #pragma once
  2. #include <string>
  3. #include <cstdint>
  4. #include <iomanip>
  5. #include <string.h>
  6. #include <execinfo.h>
  7. #include "flags.h"
  8. namespace utl
  9. {
  10. struct exception : public std::exception
  11. {
  12. public:
  13. enum class print_flag
  14. {
  15. ResolveAddress,
  16. };
  17. using print_flags = shifted_flags<print_flag>;
  18. public:
  19. static constexpr size_t max_stack_size = 15;
  20. static const print_flags& default_print_flag()
  21. {
  22. static const print_flags value({ print_flag::ResolveAddress });
  23. return value;
  24. };
  25. private:
  26. mutable bool _msg_cache_empty;
  27. mutable std::string _msg_cache;
  28. protected:
  29. virtual void print_message(std::ostream& os) const
  30. {
  31. os << message;
  32. }
  33. public:
  34. std::string message;
  35. void* stack[max_stack_size];
  36. int stack_size;
  37. public:
  38. void print(std::ostream& os, const print_flags& flags = default_print_flag()) const
  39. {
  40. print_message(os);
  41. os << std::endl;
  42. char** lines = nullptr;
  43. if (flags.is_set(print_flag::ResolveAddress))
  44. lines = backtrace_symbols(stack, stack_size);
  45. for (int i = 0; i < stack_size; ++i)
  46. {
  47. os << " [0x" << std::setw(2 * sizeof(void*)) << std::setfill('0') << std::hex << reinterpret_cast<uintptr_t>(stack[i]) << "]";
  48. if (lines && lines[i])
  49. os << " " << lines[i];
  50. os << std::endl;
  51. }
  52. }
  53. std::string print(const print_flags& flags = default_print_flag()) const
  54. {
  55. std::ostringstream os;
  56. print(os, flags);
  57. return os.str();
  58. }
  59. const char* what() const throw() override
  60. {
  61. if (_msg_cache_empty)
  62. {
  63. _msg_cache = print();
  64. _msg_cache_empty = false;
  65. }
  66. return _msg_cache.c_str();
  67. }
  68. inline friend std::ostream& operator <<(std::ostream& os, const exception& ex)
  69. {
  70. ex.print(os);
  71. return os;
  72. }
  73. public:
  74. exception() :
  75. exception("")
  76. { }
  77. exception(std::string msg) :
  78. message (msg),
  79. stack_size (0),
  80. _msg_cache_empty(true)
  81. {
  82. stack_size = backtrace(&stack[0], max_stack_size);
  83. }
  84. };
  85. struct error_exception : public exception
  86. {
  87. public:
  88. int error;
  89. error_exception(int e) :
  90. exception(std::to_string(e) + " - " + strerror(e)),
  91. error(e)
  92. { }
  93. error_exception(const std::string& msg, int e) :
  94. exception(msg + ": " + std::to_string(e) + " - " + strerror(e)),
  95. error(e)
  96. { }
  97. };
  98. struct out_of_range_exception : public exception
  99. {
  100. protected:
  101. void print_message(std::ostream& os) const override
  102. {
  103. os << "index out of range (min=" << min << "; max=" << max << "; index=" << index << ")";
  104. if (!message.empty())
  105. os << " - " << message;
  106. }
  107. public:
  108. size_t min;
  109. size_t max;
  110. size_t index;
  111. out_of_range_exception(size_t mi, size_t ma, size_t idx, std::string msg = "") :
  112. exception (msg),
  113. min (mi),
  114. max (ma),
  115. index (idx)
  116. { }
  117. };
  118. struct argument_exception : public exception
  119. {
  120. protected:
  121. void print_message(std::ostream& os) const override
  122. {
  123. os << "invalid argument";
  124. if (!argument.empty())
  125. os << "(" << argument << ")";
  126. if (!message.empty())
  127. os << " - " << message;
  128. }
  129. public:
  130. std::string argument;
  131. argument_exception(std::string arg, std::string msg) :
  132. exception (msg),
  133. argument (arg)
  134. { }
  135. };
  136. struct invalid_operation_exception : public exception
  137. {
  138. public:
  139. invalid_operation_exception(std::string msg) :
  140. exception(msg)
  141. { }
  142. };
  143. }