You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 rivejä
4.0 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 PrintFlag
  14. {
  15. ResolveAddress,
  16. };
  17. using PrintFlags = ShiftedFlags<PrintFlag>;
  18. public:
  19. static constexpr size_t StackSize = 15;
  20. static const PrintFlags& defaultPrintFlags()
  21. {
  22. static const PrintFlags value({ PrintFlag::ResolveAddress });
  23. return value;
  24. };
  25. private:
  26. mutable bool _msgCacheEmpty;
  27. mutable std::string _msgCache;
  28. protected:
  29. virtual void printMessage(std::ostream& os) const
  30. {
  31. os << message;
  32. }
  33. public:
  34. std::string message;
  35. void* stack[StackSize];
  36. int stackSize;
  37. public:
  38. void print(std::ostream& os, const PrintFlags& flags = defaultPrintFlags()) const
  39. {
  40. printMessage(os);
  41. os << std::endl;
  42. char** lines = nullptr;
  43. if (flags.isSet(PrintFlag::ResolveAddress))
  44. lines = backtrace_symbols(stack, stackSize);
  45. for (int i = 0; i < stackSize; ++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 PrintFlags& flags = defaultPrintFlags()) 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 (_msgCacheEmpty)
  62. {
  63. _msgCache = print();
  64. _msgCacheEmpty = false;
  65. }
  66. return _msgCache.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. _msgCacheEmpty (true)
  80. {
  81. stackSize = backtrace(stack, StackSize);
  82. }
  83. };
  84. struct ErrorException : public Exception
  85. {
  86. public:
  87. int error;
  88. ErrorException(int e) :
  89. Exception(std::to_string(e) + " - " + strerror(e)),
  90. error(e)
  91. { }
  92. ErrorException(const std::string& msg, int e) :
  93. Exception(msg + ": " + std::to_string(e) + " - " + strerror(e)),
  94. error(e)
  95. { }
  96. };
  97. struct EOutOfRange : public Exception
  98. {
  99. protected:
  100. void printMessage(std::ostream& os) const override
  101. {
  102. os << "index out of range (min=" << min << "; max=" << max << "; index=" << index << ")";
  103. if (!message.empty())
  104. os << " - " << message;
  105. }
  106. public:
  107. size_t min;
  108. size_t max;
  109. size_t index;
  110. EOutOfRange(size_t mi, size_t ma, size_t idx, std::string msg = "") :
  111. Exception (msg),
  112. min (mi),
  113. max (ma),
  114. index (idx)
  115. { }
  116. };
  117. struct EArgument : public Exception
  118. {
  119. protected:
  120. void printMessage(std::ostream& os) const override
  121. {
  122. os << "invalid argument";
  123. if (!argument.empty())
  124. os << "(" << argument << ")";
  125. if (!message.empty())
  126. os << " - " << message;
  127. }
  128. public:
  129. std::string argument;
  130. EArgument(std::string arg, std::string msg) :
  131. Exception (message),
  132. argument (arg)
  133. { }
  134. };
  135. struct EInvalidOperation : public Exception
  136. {
  137. public:
  138. EInvalidOperation(std::string msg) :
  139. Exception(msg)
  140. { }
  141. };
  142. }