exceptions.hpp 9.0 KB

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