exceptions.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // __ _____ _____ _____
  2. // __| | __| | | | JSON for Modern C++
  3. // | | |__ | | | | | | version 3.12.0
  4. // |_____|_____|_____|_|___| https://github.com/nlohmann/json
  5. //
  6. // SPDX-FileCopyrightText: 2013 - 2025 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. // With -Wweak-vtables, Clang will complain about the exception classes as they
  25. // have no out-of-line virtual method definitions and their vtable will be
  26. // emitted in every translation unit. This issue cannot be fixed with a
  27. // header-only library as there is no implementation file to move these
  28. // functions to. As a result, we suppress this warning here to avoid client
  29. // code to stumble over this. See https://github.com/nlohmann/json/issues/4087
  30. // for a discussion.
  31. #if defined(__clang__)
  32. #pragma clang diagnostic push
  33. #pragma clang diagnostic ignored "-Wweak-vtables"
  34. #endif
  35. NLOHMANN_JSON_NAMESPACE_BEGIN
  36. namespace detail
  37. {
  38. ////////////////
  39. // exceptions //
  40. ////////////////
  41. /// @brief general exception of the @ref basic_json class
  42. /// @sa https://json.nlohmann.me/api/basic_json/exception/
  43. class exception : public std::exception
  44. {
  45. public:
  46. /// returns the explanatory string
  47. const char* what() const noexcept override
  48. {
  49. return m.what();
  50. }
  51. /// the id of the exception
  52. const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
  53. protected:
  54. JSON_HEDLEY_NON_NULL(3)
  55. exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
  56. static std::string name(const std::string& ename, int id_)
  57. {
  58. return concat("[json.exception.", ename, '.', std::to_string(id_), "] ");
  59. }
  60. static std::string diagnostics(std::nullptr_t /*leaf_element*/)
  61. {
  62. return "";
  63. }
  64. template<typename BasicJsonType>
  65. static std::string diagnostics(const BasicJsonType* leaf_element)
  66. {
  67. #if JSON_DIAGNOSTICS
  68. std::vector<std::string> tokens;
  69. for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent)
  70. {
  71. switch (current->m_parent->type())
  72. {
  73. case value_t::array:
  74. {
  75. for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i)
  76. {
  77. if (&current->m_parent->m_data.m_value.array->operator[](i) == current)
  78. {
  79. tokens.emplace_back(std::to_string(i));
  80. break;
  81. }
  82. }
  83. break;
  84. }
  85. case value_t::object:
  86. {
  87. for (const auto& element : *current->m_parent->m_data.m_value.object)
  88. {
  89. if (&element.second == current)
  90. {
  91. tokens.emplace_back(element.first.c_str());
  92. break;
  93. }
  94. }
  95. break;
  96. }
  97. case value_t::null: // LCOV_EXCL_LINE
  98. case value_t::string: // LCOV_EXCL_LINE
  99. case value_t::boolean: // LCOV_EXCL_LINE
  100. case value_t::number_integer: // LCOV_EXCL_LINE
  101. case value_t::number_unsigned: // LCOV_EXCL_LINE
  102. case value_t::number_float: // LCOV_EXCL_LINE
  103. case value_t::binary: // LCOV_EXCL_LINE
  104. case value_t::discarded: // LCOV_EXCL_LINE
  105. default: // LCOV_EXCL_LINE
  106. break; // LCOV_EXCL_LINE
  107. }
  108. }
  109. if (tokens.empty())
  110. {
  111. return "";
  112. }
  113. auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
  114. [](const std::string & a, const std::string & b)
  115. {
  116. return concat(a, '/', detail::escape(b));
  117. });
  118. return concat('(', str, ") ", get_byte_positions(leaf_element));
  119. #else
  120. return get_byte_positions(leaf_element);
  121. #endif
  122. }
  123. private:
  124. /// an exception object as storage for error messages
  125. std::runtime_error m;
  126. #if JSON_DIAGNOSTIC_POSITIONS
  127. template<typename BasicJsonType>
  128. static std::string get_byte_positions(const BasicJsonType* leaf_element)
  129. {
  130. if ((leaf_element->start_pos() != std::string::npos) && (leaf_element->end_pos() != std::string::npos))
  131. {
  132. return concat("(bytes ", std::to_string(leaf_element->start_pos()), "-", std::to_string(leaf_element->end_pos()), ") ");
  133. }
  134. return "";
  135. }
  136. #else
  137. template<typename BasicJsonType>
  138. static std::string get_byte_positions(const BasicJsonType* leaf_element)
  139. {
  140. static_cast<void>(leaf_element);
  141. return "";
  142. }
  143. #endif
  144. };
  145. /// @brief exception indicating a parse error
  146. /// @sa https://json.nlohmann.me/api/basic_json/parse_error/
  147. class parse_error : public exception
  148. {
  149. public:
  150. /*!
  151. @brief create a parse error exception
  152. @param[in] id_ the id of the exception
  153. @param[in] pos the position where the error occurred (or with
  154. chars_read_total=0 if the position cannot be
  155. determined)
  156. @param[in] what_arg the explanatory string
  157. @return parse_error object
  158. */
  159. template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
  160. static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
  161. {
  162. const std::string w = concat(exception::name("parse_error", id_), "parse error",
  163. position_string(pos), ": ", exception::diagnostics(context), what_arg);
  164. return {id_, pos.chars_read_total, w.c_str()};
  165. }
  166. template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
  167. static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
  168. {
  169. const std::string w = concat(exception::name("parse_error", id_), "parse error",
  170. (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
  171. ": ", exception::diagnostics(context), what_arg);
  172. return {id_, byte_, w.c_str()};
  173. }
  174. /*!
  175. @brief byte index of the parse error
  176. The byte index of the last read character in the input file.
  177. @note For an input with n bytes, 1 is the index of the first character and
  178. n+1 is the index of the terminating null byte or the end of file.
  179. This also holds true when reading a byte vector (CBOR or MessagePack).
  180. */
  181. const std::size_t byte;
  182. private:
  183. parse_error(int id_, std::size_t byte_, const char* what_arg)
  184. : exception(id_, what_arg), byte(byte_) {}
  185. static std::string position_string(const position_t& pos)
  186. {
  187. return concat(" at line ", std::to_string(pos.lines_read + 1),
  188. ", column ", std::to_string(pos.chars_read_current_line));
  189. }
  190. };
  191. /// @brief exception indicating errors with iterators
  192. /// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/
  193. class invalid_iterator : public exception
  194. {
  195. public:
  196. template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
  197. static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)
  198. {
  199. const std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
  200. return {id_, w.c_str()};
  201. }
  202. private:
  203. JSON_HEDLEY_NON_NULL(3)
  204. invalid_iterator(int id_, const char* what_arg)
  205. : exception(id_, what_arg) {}
  206. };
  207. /// @brief exception indicating executing a member function with a wrong type
  208. /// @sa https://json.nlohmann.me/api/basic_json/type_error/
  209. class type_error : public exception
  210. {
  211. public:
  212. template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
  213. static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)
  214. {
  215. const std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
  216. return {id_, w.c_str()};
  217. }
  218. private:
  219. JSON_HEDLEY_NON_NULL(3)
  220. type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
  221. };
  222. /// @brief exception indicating access out of the defined range
  223. /// @sa https://json.nlohmann.me/api/basic_json/out_of_range/
  224. class out_of_range : public exception
  225. {
  226. public:
  227. template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
  228. static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)
  229. {
  230. const std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
  231. return {id_, w.c_str()};
  232. }
  233. private:
  234. JSON_HEDLEY_NON_NULL(3)
  235. out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
  236. };
  237. /// @brief exception indicating other library errors
  238. /// @sa https://json.nlohmann.me/api/basic_json/other_error/
  239. class other_error : public exception
  240. {
  241. public:
  242. template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
  243. static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)
  244. {
  245. const std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
  246. return {id_, w.c_str()};
  247. }
  248. private:
  249. JSON_HEDLEY_NON_NULL(3)
  250. other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
  251. };
  252. } // namespace detail
  253. NLOHMANN_JSON_NAMESPACE_END
  254. #if defined(__clang__)
  255. #pragma clang diagnostic pop
  256. #endif