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