• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (&current->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