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