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 |
42 | 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) |
52 | exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) |
53 | |
54 | static std::string name(const std::string& ename, int id_) |
55 | { |
56 | return concat(args: "[json.exception." , args: ename, args: '.', args: std::to_string(val: id_), args: "] " ); |
57 | } |
58 | |
59 | static std::string diagnostics(std::nullptr_t /*leaf_element*/) |
60 | { |
61 | return "" ; |
62 | } |
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 (¤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> |
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(ename: "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> |
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(ename: "parse_error" , id_), "parse error" , |
160 | (byte_ != 0 ? (concat(args: " at byte " , args: std::to_string(val: 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: |
177 | parse_error(int id_, std::size_t byte_, const char* what_arg) |
178 | : exception(id_, what_arg), byte(byte_) {} |
179 | |
180 | static std::string position_string(const position_t& pos) |
181 | { |
182 | return concat(args: " at line " , args: std::to_string(val: pos.lines_read + 1), |
183 | args: ", column " , args: std::to_string(val: 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> |
193 | static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context) |
194 | { |
195 | const std::string w = concat(exception::name(ename: "invalid_iterator" , id_), exception::diagnostics(context), what_arg); |
196 | return {id_, w.c_str()}; |
197 | } |
198 | |
199 | private: |
200 | JSON_HEDLEY_NON_NULL(3) |
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> |
211 | static type_error create(int id_, const std::string& what_arg, BasicJsonContext context) |
212 | { |
213 | const std::string w = concat(exception::name(ename: "type_error" , id_), exception::diagnostics(context), what_arg); |
214 | return {id_, w.c_str()}; |
215 | } |
216 | |
217 | private: |
218 | JSON_HEDLEY_NON_NULL(3) |
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> |
228 | static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context) |
229 | { |
230 | const std::string w = concat(exception::name(ename: "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) |
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> |
245 | static other_error create(int id_, const std::string& what_arg, BasicJsonContext context) |
246 | { |
247 | const std::string w = concat(exception::name(ename: "other_error" , id_), exception::diagnostics(context), what_arg); |
248 | return {id_, w.c_str()}; |
249 | } |
250 | |
251 | private: |
252 | JSON_HEDLEY_NON_NULL(3) |
253 | other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} |
254 | }; |
255 | |
256 | } // namespace detail |
257 | NLOHMANN_JSON_NAMESPACE_END |
258 | |