exceptions.hpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #pragma once
  2. #include <exception> // exception
  3. #include <stdexcept> // runtime_error
  4. #include <string> // to_string
  5. #include <vector> // vector
  6. #include <nlohmann/detail/value_t.hpp>
  7. #include <nlohmann/detail/string_escape.hpp>
  8. #include <nlohmann/detail/input/position_t.hpp>
  9. #include <nlohmann/detail/macro_scope.hpp>
  10. namespace nlohmann
  11. {
  12. namespace detail
  13. {
  14. ////////////////
  15. // exceptions //
  16. ////////////////
  17. /// @brief general exception of the @ref basic_json class
  18. /// @sa https://json.nlohmann.me/api/basic_json/exception/
  19. class exception : public std::exception
  20. {
  21. public:
  22. /// returns the explanatory string
  23. const char* what() const noexcept override
  24. {
  25. return m.what();
  26. }
  27. /// the id of the exception
  28. const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
  29. protected:
  30. JSON_HEDLEY_NON_NULL(3)
  31. exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
  32. static std::string name(const std::string& ename, int id_)
  33. {
  34. return "[json.exception." + ename + "." + std::to_string(id_) + "] ";
  35. }
  36. template<typename BasicJsonType>
  37. static std::string diagnostics(const BasicJsonType& leaf_element)
  38. {
  39. #if JSON_DIAGNOSTICS
  40. std::vector<std::string> tokens;
  41. for (const auto* current = &leaf_element; current->m_parent != nullptr; current = current->m_parent)
  42. {
  43. switch (current->m_parent->type())
  44. {
  45. case value_t::array:
  46. {
  47. for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)
  48. {
  49. if (&current->m_parent->m_value.array->operator[](i) == current)
  50. {
  51. tokens.emplace_back(std::to_string(i));
  52. break;
  53. }
  54. }
  55. break;
  56. }
  57. case value_t::object:
  58. {
  59. for (const auto& element : *current->m_parent->m_value.object)
  60. {
  61. if (&element.second == current)
  62. {
  63. tokens.emplace_back(element.first.c_str());
  64. break;
  65. }
  66. }
  67. break;
  68. }
  69. case value_t::null: // LCOV_EXCL_LINE
  70. case value_t::string: // LCOV_EXCL_LINE
  71. case value_t::boolean: // LCOV_EXCL_LINE
  72. case value_t::number_integer: // LCOV_EXCL_LINE
  73. case value_t::number_unsigned: // LCOV_EXCL_LINE
  74. case value_t::number_float: // LCOV_EXCL_LINE
  75. case value_t::binary: // LCOV_EXCL_LINE
  76. case value_t::discarded: // LCOV_EXCL_LINE
  77. default: // LCOV_EXCL_LINE
  78. break; // LCOV_EXCL_LINE
  79. }
  80. }
  81. if (tokens.empty())
  82. {
  83. return "";
  84. }
  85. return "(" + std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
  86. [](const std::string & a, const std::string & b)
  87. {
  88. return a + "/" + detail::escape(b);
  89. }) + ") ";
  90. #else
  91. static_cast<void>(leaf_element);
  92. return "";
  93. #endif
  94. }
  95. private:
  96. /// an exception object as storage for error messages
  97. std::runtime_error m;
  98. };
  99. /// @brief exception indicating a parse error
  100. /// @sa https://json.nlohmann.me/api/basic_json/parse_error/
  101. class parse_error : public exception
  102. {
  103. public:
  104. /*!
  105. @brief create a parse error exception
  106. @param[in] id_ the id of the exception
  107. @param[in] pos the position where the error occurred (or with
  108. chars_read_total=0 if the position cannot be
  109. determined)
  110. @param[in] what_arg the explanatory string
  111. @return parse_error object
  112. */
  113. template<typename BasicJsonType>
  114. static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context)
  115. {
  116. std::string w = exception::name("parse_error", id_) + "parse error" +
  117. position_string(pos) + ": " + exception::diagnostics(context) + what_arg;
  118. return {id_, pos.chars_read_total, w.c_str()};
  119. }
  120. template<typename BasicJsonType>
  121. static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, const BasicJsonType& context)
  122. {
  123. std::string w = exception::name("parse_error", id_) + "parse error" +
  124. (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") +
  125. ": " + exception::diagnostics(context) + what_arg;
  126. return {id_, byte_, w.c_str()};
  127. }
  128. /*!
  129. @brief byte index of the parse error
  130. The byte index of the last read character in the input file.
  131. @note For an input with n bytes, 1 is the index of the first character and
  132. n+1 is the index of the terminating null byte or the end of file.
  133. This also holds true when reading a byte vector (CBOR or MessagePack).
  134. */
  135. const std::size_t byte;
  136. private:
  137. parse_error(int id_, std::size_t byte_, const char* what_arg)
  138. : exception(id_, what_arg), byte(byte_) {}
  139. static std::string position_string(const position_t& pos)
  140. {
  141. return " at line " + std::to_string(pos.lines_read + 1) +
  142. ", column " + std::to_string(pos.chars_read_current_line);
  143. }
  144. };
  145. /// @brief exception indicating errors with iterators
  146. /// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/
  147. class invalid_iterator : public exception
  148. {
  149. public:
  150. template<typename BasicJsonType>
  151. static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context)
  152. {
  153. std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg;
  154. return {id_, w.c_str()};
  155. }
  156. private:
  157. JSON_HEDLEY_NON_NULL(3)
  158. invalid_iterator(int id_, const char* what_arg)
  159. : exception(id_, what_arg) {}
  160. };
  161. /// @brief exception indicating executing a member function with a wrong type
  162. /// @sa https://json.nlohmann.me/api/basic_json/type_error/
  163. class type_error : public exception
  164. {
  165. public:
  166. template<typename BasicJsonType>
  167. static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context)
  168. {
  169. std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg;
  170. return {id_, w.c_str()};
  171. }
  172. private:
  173. JSON_HEDLEY_NON_NULL(3)
  174. type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
  175. };
  176. /// @brief exception indicating access out of the defined range
  177. /// @sa https://json.nlohmann.me/api/basic_json/out_of_range/
  178. class out_of_range : public exception
  179. {
  180. public:
  181. template<typename BasicJsonType>
  182. static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context)
  183. {
  184. std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg;
  185. return {id_, w.c_str()};
  186. }
  187. private:
  188. JSON_HEDLEY_NON_NULL(3)
  189. out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
  190. };
  191. /// @brief exception indicating other library errors
  192. /// @sa https://json.nlohmann.me/api/basic_json/other_error/
  193. class other_error : public exception
  194. {
  195. public:
  196. template<typename BasicJsonType>
  197. static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context)
  198. {
  199. std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg;
  200. return {id_, w.c_str()};
  201. }
  202. private:
  203. JSON_HEDLEY_NON_NULL(3)
  204. other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
  205. };
  206. } // namespace detail
  207. } // namespace nlohmann