Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:45:01

0001 //     __ _____ _____ _____
0002 //  __|  |   __|     |   | |  JSON for Modern C++
0003 // |  |  |__   |  |  | | | |  version 3.12.0
0004 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
0005 //
0006 // SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
0007 // SPDX-License-Identifier: MIT
0008 
0009 #pragma once
0010 
0011 #include <cstddef>
0012 #include <string> // string
0013 #include <type_traits> // enable_if_t
0014 #include <utility> // move
0015 #include <vector> // vector
0016 
0017 #include <nlohmann/detail/exceptions.hpp>
0018 #include <nlohmann/detail/input/lexer.hpp>
0019 #include <nlohmann/detail/macro_scope.hpp>
0020 #include <nlohmann/detail/string_concat.hpp>
0021 NLOHMANN_JSON_NAMESPACE_BEGIN
0022 
0023 /*!
0024 @brief SAX interface
0025 
0026 This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
0027 Each function is called in different situations while the input is parsed. The
0028 boolean return value informs the parser whether to continue processing the
0029 input.
0030 */
0031 template<typename BasicJsonType>
0032 struct json_sax
0033 {
0034     using number_integer_t = typename BasicJsonType::number_integer_t;
0035     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
0036     using number_float_t = typename BasicJsonType::number_float_t;
0037     using string_t = typename BasicJsonType::string_t;
0038     using binary_t = typename BasicJsonType::binary_t;
0039 
0040     /*!
0041     @brief a null value was read
0042     @return whether parsing should proceed
0043     */
0044     virtual bool null() = 0;
0045 
0046     /*!
0047     @brief a boolean value was read
0048     @param[in] val  boolean value
0049     @return whether parsing should proceed
0050     */
0051     virtual bool boolean(bool val) = 0;
0052 
0053     /*!
0054     @brief an integer number was read
0055     @param[in] val  integer value
0056     @return whether parsing should proceed
0057     */
0058     virtual bool number_integer(number_integer_t val) = 0;
0059 
0060     /*!
0061     @brief an unsigned integer number was read
0062     @param[in] val  unsigned integer value
0063     @return whether parsing should proceed
0064     */
0065     virtual bool number_unsigned(number_unsigned_t val) = 0;
0066 
0067     /*!
0068     @brief a floating-point number was read
0069     @param[in] val  floating-point value
0070     @param[in] s    raw token value
0071     @return whether parsing should proceed
0072     */
0073     virtual bool number_float(number_float_t val, const string_t& s) = 0;
0074 
0075     /*!
0076     @brief a string value was read
0077     @param[in] val  string value
0078     @return whether parsing should proceed
0079     @note It is safe to move the passed string value.
0080     */
0081     virtual bool string(string_t& val) = 0;
0082 
0083     /*!
0084     @brief a binary value was read
0085     @param[in] val  binary value
0086     @return whether parsing should proceed
0087     @note It is safe to move the passed binary value.
0088     */
0089     virtual bool binary(binary_t& val) = 0;
0090 
0091     /*!
0092     @brief the beginning of an object was read
0093     @param[in] elements  number of object elements or -1 if unknown
0094     @return whether parsing should proceed
0095     @note binary formats may report the number of elements
0096     */
0097     virtual bool start_object(std::size_t elements) = 0;
0098 
0099     /*!
0100     @brief an object key was read
0101     @param[in] val  object key
0102     @return whether parsing should proceed
0103     @note It is safe to move the passed string.
0104     */
0105     virtual bool key(string_t& val) = 0;
0106 
0107     /*!
0108     @brief the end of an object was read
0109     @return whether parsing should proceed
0110     */
0111     virtual bool end_object() = 0;
0112 
0113     /*!
0114     @brief the beginning of an array was read
0115     @param[in] elements  number of array elements or -1 if unknown
0116     @return whether parsing should proceed
0117     @note binary formats may report the number of elements
0118     */
0119     virtual bool start_array(std::size_t elements) = 0;
0120 
0121     /*!
0122     @brief the end of an array was read
0123     @return whether parsing should proceed
0124     */
0125     virtual bool end_array() = 0;
0126 
0127     /*!
0128     @brief a parse error occurred
0129     @param[in] position    the position in the input where the error occurs
0130     @param[in] last_token  the last read token
0131     @param[in] ex          an exception object describing the error
0132     @return whether parsing should proceed (must return false)
0133     */
0134     virtual bool parse_error(std::size_t position,
0135                              const std::string& last_token,
0136                              const detail::exception& ex) = 0;
0137 
0138     json_sax() = default;
0139     json_sax(const json_sax&) = default;
0140     json_sax(json_sax&&) noexcept = default;
0141     json_sax& operator=(const json_sax&) = default;
0142     json_sax& operator=(json_sax&&) noexcept = default;
0143     virtual ~json_sax() = default;
0144 };
0145 
0146 namespace detail
0147 {
0148 constexpr std::size_t unknown_size()
0149 {
0150     return (std::numeric_limits<std::size_t>::max)();
0151 }
0152 
0153 /*!
0154 @brief SAX implementation to create a JSON value from SAX events
0155 
0156 This class implements the @ref json_sax interface and processes the SAX events
0157 to create a JSON value which makes it basically a DOM parser. The structure or
0158 hierarchy of the JSON value is managed by the stack `ref_stack` which contains
0159 a pointer to the respective array or object for each recursion depth.
0160 
0161 After successful parsing, the value that is passed by reference to the
0162 constructor contains the parsed value.
0163 
0164 @tparam BasicJsonType  the JSON type
0165 */
0166 template<typename BasicJsonType, typename InputAdapterType>
0167 class json_sax_dom_parser
0168 {
0169   public:
0170     using number_integer_t = typename BasicJsonType::number_integer_t;
0171     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
0172     using number_float_t = typename BasicJsonType::number_float_t;
0173     using string_t = typename BasicJsonType::string_t;
0174     using binary_t = typename BasicJsonType::binary_t;
0175     using lexer_t = lexer<BasicJsonType, InputAdapterType>;
0176 
0177     /*!
0178     @param[in,out] r  reference to a JSON value that is manipulated while
0179                        parsing
0180     @param[in] allow_exceptions_  whether parse errors yield exceptions
0181     */
0182     explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true, lexer_t* lexer_ = nullptr)
0183         : root(r), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_)
0184     {}
0185 
0186     // make class move-only
0187     json_sax_dom_parser(const json_sax_dom_parser&) = delete;
0188     json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
0189     json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
0190     json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
0191     ~json_sax_dom_parser() = default;
0192 
0193     bool null()
0194     {
0195         handle_value(nullptr);
0196         return true;
0197     }
0198 
0199     bool boolean(bool val)
0200     {
0201         handle_value(val);
0202         return true;
0203     }
0204 
0205     bool number_integer(number_integer_t val)
0206     {
0207         handle_value(val);
0208         return true;
0209     }
0210 
0211     bool number_unsigned(number_unsigned_t val)
0212     {
0213         handle_value(val);
0214         return true;
0215     }
0216 
0217     bool number_float(number_float_t val, const string_t& /*unused*/)
0218     {
0219         handle_value(val);
0220         return true;
0221     }
0222 
0223     bool string(string_t& val)
0224     {
0225         handle_value(val);
0226         return true;
0227     }
0228 
0229     bool binary(binary_t& val)
0230     {
0231         handle_value(std::move(val));
0232         return true;
0233     }
0234 
0235     bool start_object(std::size_t len)
0236     {
0237         ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
0238 
0239 #if JSON_DIAGNOSTIC_POSITIONS
0240         // Manually set the start position of the object here.
0241         // Ensure this is after the call to handle_value to ensure correct start position.
0242         if (m_lexer_ref)
0243         {
0244             // Lexer has read the first character of the object, so
0245             // subtract 1 from the position to get the correct start position.
0246             ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
0247         }
0248 #endif
0249 
0250         if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
0251         {
0252             JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
0253         }
0254 
0255         return true;
0256     }
0257 
0258     bool key(string_t& val)
0259     {
0260         JSON_ASSERT(!ref_stack.empty());
0261         JSON_ASSERT(ref_stack.back()->is_object());
0262 
0263         // add null at given key and store the reference for later
0264         object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val));
0265         return true;
0266     }
0267 
0268     bool end_object()
0269     {
0270         JSON_ASSERT(!ref_stack.empty());
0271         JSON_ASSERT(ref_stack.back()->is_object());
0272 
0273 #if JSON_DIAGNOSTIC_POSITIONS
0274         if (m_lexer_ref)
0275         {
0276             // Lexer's position is past the closing brace, so set that as the end position.
0277             ref_stack.back()->end_position = m_lexer_ref->get_position();
0278         }
0279 #endif
0280 
0281         ref_stack.back()->set_parents();
0282         ref_stack.pop_back();
0283         return true;
0284     }
0285 
0286     bool start_array(std::size_t len)
0287     {
0288         ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
0289 
0290 #if JSON_DIAGNOSTIC_POSITIONS
0291         // Manually set the start position of the array here.
0292         // Ensure this is after the call to handle_value to ensure correct start position.
0293         if (m_lexer_ref)
0294         {
0295             ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
0296         }
0297 #endif
0298 
0299         if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
0300         {
0301             JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
0302         }
0303 
0304         return true;
0305     }
0306 
0307     bool end_array()
0308     {
0309         JSON_ASSERT(!ref_stack.empty());
0310         JSON_ASSERT(ref_stack.back()->is_array());
0311 
0312 #if JSON_DIAGNOSTIC_POSITIONS
0313         if (m_lexer_ref)
0314         {
0315             // Lexer's position is past the closing bracket, so set that as the end position.
0316             ref_stack.back()->end_position = m_lexer_ref->get_position();
0317         }
0318 #endif
0319 
0320         ref_stack.back()->set_parents();
0321         ref_stack.pop_back();
0322         return true;
0323     }
0324 
0325     template<class Exception>
0326     bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
0327                      const Exception& ex)
0328     {
0329         errored = true;
0330         static_cast<void>(ex);
0331         if (allow_exceptions)
0332         {
0333             JSON_THROW(ex);
0334         }
0335         return false;
0336     }
0337 
0338     constexpr bool is_errored() const
0339     {
0340         return errored;
0341     }
0342 
0343   private:
0344 
0345 #if JSON_DIAGNOSTIC_POSITIONS
0346     void handle_diagnostic_positions_for_json_value(BasicJsonType& v)
0347     {
0348         if (m_lexer_ref)
0349         {
0350             // Lexer has read past the current field value, so set the end position to the current position.
0351             // The start position will be set below based on the length of the string representation
0352             // of the value.
0353             v.end_position = m_lexer_ref->get_position();
0354 
0355             switch (v.type())
0356             {
0357                 case value_t::boolean:
0358                 {
0359                     // 4 and 5 are the string length of "true" and "false"
0360                     v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5);
0361                     break;
0362                 }
0363 
0364                 case value_t::null:
0365                 {
0366                     // 4 is the string length of "null"
0367                     v.start_position = v.end_position - 4;
0368                     break;
0369                 }
0370 
0371                 case value_t::string:
0372                 {
0373                     // include the length of the quotes, which is 2
0374                     v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
0375                     break;
0376                 }
0377 
0378                 // As we handle the start and end positions for values created during parsing,
0379                 // we do not expect the following value type to be called. Regardless, set the positions
0380                 // in case this is created manually or through a different constructor. Exclude from lcov
0381                 // since the exact condition of this switch is esoteric.
0382                 // LCOV_EXCL_START
0383                 case value_t::discarded:
0384                 {
0385                     v.end_position = std::string::npos;
0386                     v.start_position = v.end_position;
0387                     break;
0388                 }
0389                 // LCOV_EXCL_STOP
0390                 case value_t::binary:
0391                 case value_t::number_integer:
0392                 case value_t::number_unsigned:
0393                 case value_t::number_float:
0394                 {
0395                     v.start_position = v.end_position - m_lexer_ref->get_string().size();
0396                     break;
0397                 }
0398                 case value_t::object:
0399                 case value_t::array:
0400                 {
0401                     // object and array are handled in start_object() and start_array() handlers
0402                     // skip setting the values here.
0403                     break;
0404                 }
0405                 default: // LCOV_EXCL_LINE
0406                     // Handle all possible types discretely, default handler should never be reached.
0407                     JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE
0408             }
0409         }
0410     }
0411 #endif
0412 
0413     /*!
0414     @invariant If the ref stack is empty, then the passed value will be the new
0415                root.
0416     @invariant If the ref stack contains a value, then it is an array or an
0417                object to which we can add elements
0418     */
0419     template<typename Value>
0420     JSON_HEDLEY_RETURNS_NON_NULL
0421     BasicJsonType* handle_value(Value&& v)
0422     {
0423         if (ref_stack.empty())
0424         {
0425             root = BasicJsonType(std::forward<Value>(v));
0426 
0427 #if JSON_DIAGNOSTIC_POSITIONS
0428             handle_diagnostic_positions_for_json_value(root);
0429 #endif
0430 
0431             return &root;
0432         }
0433 
0434         JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
0435 
0436         if (ref_stack.back()->is_array())
0437         {
0438             ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));
0439 
0440 #if JSON_DIAGNOSTIC_POSITIONS
0441             handle_diagnostic_positions_for_json_value(ref_stack.back()->m_data.m_value.array->back());
0442 #endif
0443 
0444             return &(ref_stack.back()->m_data.m_value.array->back());
0445         }
0446 
0447         JSON_ASSERT(ref_stack.back()->is_object());
0448         JSON_ASSERT(object_element);
0449         *object_element = BasicJsonType(std::forward<Value>(v));
0450 
0451 #if JSON_DIAGNOSTIC_POSITIONS
0452         handle_diagnostic_positions_for_json_value(*object_element);
0453 #endif
0454 
0455         return object_element;
0456     }
0457 
0458     /// the parsed JSON value
0459     BasicJsonType& root;
0460     /// stack to model hierarchy of values
0461     std::vector<BasicJsonType*> ref_stack {};
0462     /// helper to hold the reference for the next object element
0463     BasicJsonType* object_element = nullptr;
0464     /// whether a syntax error occurred
0465     bool errored = false;
0466     /// whether to throw exceptions in case of errors
0467     const bool allow_exceptions = true;
0468     /// the lexer reference to obtain the current position
0469     lexer_t* m_lexer_ref = nullptr;
0470 };
0471 
0472 template<typename BasicJsonType, typename InputAdapterType>
0473 class json_sax_dom_callback_parser
0474 {
0475   public:
0476     using number_integer_t = typename BasicJsonType::number_integer_t;
0477     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
0478     using number_float_t = typename BasicJsonType::number_float_t;
0479     using string_t = typename BasicJsonType::string_t;
0480     using binary_t = typename BasicJsonType::binary_t;
0481     using parser_callback_t = typename BasicJsonType::parser_callback_t;
0482     using parse_event_t = typename BasicJsonType::parse_event_t;
0483     using lexer_t = lexer<BasicJsonType, InputAdapterType>;
0484 
0485     json_sax_dom_callback_parser(BasicJsonType& r,
0486                                  parser_callback_t cb,
0487                                  const bool allow_exceptions_ = true,
0488                                  lexer_t* lexer_ = nullptr)
0489         : root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_)
0490     {
0491         keep_stack.push_back(true);
0492     }
0493 
0494     // make class move-only
0495     json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
0496     json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
0497     json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
0498     json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
0499     ~json_sax_dom_callback_parser() = default;
0500 
0501     bool null()
0502     {
0503         handle_value(nullptr);
0504         return true;
0505     }
0506 
0507     bool boolean(bool val)
0508     {
0509         handle_value(val);
0510         return true;
0511     }
0512 
0513     bool number_integer(number_integer_t val)
0514     {
0515         handle_value(val);
0516         return true;
0517     }
0518 
0519     bool number_unsigned(number_unsigned_t val)
0520     {
0521         handle_value(val);
0522         return true;
0523     }
0524 
0525     bool number_float(number_float_t val, const string_t& /*unused*/)
0526     {
0527         handle_value(val);
0528         return true;
0529     }
0530 
0531     bool string(string_t& val)
0532     {
0533         handle_value(val);
0534         return true;
0535     }
0536 
0537     bool binary(binary_t& val)
0538     {
0539         handle_value(std::move(val));
0540         return true;
0541     }
0542 
0543     bool start_object(std::size_t len)
0544     {
0545         // check callback for object start
0546         const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
0547         keep_stack.push_back(keep);
0548 
0549         auto val = handle_value(BasicJsonType::value_t::object, true);
0550         ref_stack.push_back(val.second);
0551 
0552         if (ref_stack.back())
0553         {
0554 
0555 #if JSON_DIAGNOSTIC_POSITIONS
0556             // Manually set the start position of the object here.
0557             // Ensure this is after the call to handle_value to ensure correct start position.
0558             if (m_lexer_ref)
0559             {
0560                 // Lexer has read the first character of the object, so
0561                 // subtract 1 from the position to get the correct start position.
0562                 ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
0563             }
0564 #endif
0565 
0566             // check object limit
0567             if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
0568             {
0569                 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
0570             }
0571         }
0572         return true;
0573     }
0574 
0575     bool key(string_t& val)
0576     {
0577         BasicJsonType k = BasicJsonType(val);
0578 
0579         // check callback for key
0580         const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
0581         key_keep_stack.push_back(keep);
0582 
0583         // add discarded value at given key and store the reference for later
0584         if (keep && ref_stack.back())
0585         {
0586             object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded);
0587         }
0588 
0589         return true;
0590     }
0591 
0592     bool end_object()
0593     {
0594         if (ref_stack.back())
0595         {
0596             if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
0597             {
0598                 // discard object
0599                 *ref_stack.back() = discarded;
0600 
0601 #if JSON_DIAGNOSTIC_POSITIONS
0602                 // Set start/end positions for discarded object.
0603                 handle_diagnostic_positions_for_json_value(*ref_stack.back());
0604 #endif
0605             }
0606             else
0607             {
0608 
0609 #if JSON_DIAGNOSTIC_POSITIONS
0610                 if (m_lexer_ref)
0611                 {
0612                     // Lexer's position is past the closing brace, so set that as the end position.
0613                     ref_stack.back()->end_position = m_lexer_ref->get_position();
0614                 }
0615 #endif
0616 
0617                 ref_stack.back()->set_parents();
0618             }
0619         }
0620 
0621         JSON_ASSERT(!ref_stack.empty());
0622         JSON_ASSERT(!keep_stack.empty());
0623         ref_stack.pop_back();
0624         keep_stack.pop_back();
0625 
0626         if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
0627         {
0628             // remove discarded value
0629             for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
0630             {
0631                 if (it->is_discarded())
0632                 {
0633                     ref_stack.back()->erase(it);
0634                     break;
0635                 }
0636             }
0637         }
0638 
0639         return true;
0640     }
0641 
0642     bool start_array(std::size_t len)
0643     {
0644         const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
0645         keep_stack.push_back(keep);
0646 
0647         auto val = handle_value(BasicJsonType::value_t::array, true);
0648         ref_stack.push_back(val.second);
0649 
0650         if (ref_stack.back())
0651         {
0652 
0653 #if JSON_DIAGNOSTIC_POSITIONS
0654             // Manually set the start position of the array here.
0655             // Ensure this is after the call to handle_value to ensure correct start position.
0656             if (m_lexer_ref)
0657             {
0658                 // Lexer has read the first character of the array, so
0659                 // subtract 1 from the position to get the correct start position.
0660                 ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
0661             }
0662 #endif
0663 
0664             // check array limit
0665             if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
0666             {
0667                 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
0668             }
0669         }
0670 
0671         return true;
0672     }
0673 
0674     bool end_array()
0675     {
0676         bool keep = true;
0677 
0678         if (ref_stack.back())
0679         {
0680             keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
0681             if (keep)
0682             {
0683 
0684 #if JSON_DIAGNOSTIC_POSITIONS
0685                 if (m_lexer_ref)
0686                 {
0687                     // Lexer's position is past the closing bracket, so set that as the end position.
0688                     ref_stack.back()->end_position = m_lexer_ref->get_position();
0689                 }
0690 #endif
0691 
0692                 ref_stack.back()->set_parents();
0693             }
0694             else
0695             {
0696                 // discard array
0697                 *ref_stack.back() = discarded;
0698 
0699 #if JSON_DIAGNOSTIC_POSITIONS
0700                 // Set start/end positions for discarded array.
0701                 handle_diagnostic_positions_for_json_value(*ref_stack.back());
0702 #endif
0703             }
0704         }
0705 
0706         JSON_ASSERT(!ref_stack.empty());
0707         JSON_ASSERT(!keep_stack.empty());
0708         ref_stack.pop_back();
0709         keep_stack.pop_back();
0710 
0711         // remove discarded value
0712         if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
0713         {
0714             ref_stack.back()->m_data.m_value.array->pop_back();
0715         }
0716 
0717         return true;
0718     }
0719 
0720     template<class Exception>
0721     bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
0722                      const Exception& ex)
0723     {
0724         errored = true;
0725         static_cast<void>(ex);
0726         if (allow_exceptions)
0727         {
0728             JSON_THROW(ex);
0729         }
0730         return false;
0731     }
0732 
0733     constexpr bool is_errored() const
0734     {
0735         return errored;
0736     }
0737 
0738   private:
0739 
0740 #if JSON_DIAGNOSTIC_POSITIONS
0741     void handle_diagnostic_positions_for_json_value(BasicJsonType& v)
0742     {
0743         if (m_lexer_ref)
0744         {
0745             // Lexer has read past the current field value, so set the end position to the current position.
0746             // The start position will be set below based on the length of the string representation
0747             // of the value.
0748             v.end_position = m_lexer_ref->get_position();
0749 
0750             switch (v.type())
0751             {
0752                 case value_t::boolean:
0753                 {
0754                     // 4 and 5 are the string length of "true" and "false"
0755                     v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5);
0756                     break;
0757                 }
0758 
0759                 case value_t::null:
0760                 {
0761                     // 4 is the string length of "null"
0762                     v.start_position = v.end_position - 4;
0763                     break;
0764                 }
0765 
0766                 case value_t::string:
0767                 {
0768                     // include the length of the quotes, which is 2
0769                     v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
0770                     break;
0771                 }
0772 
0773                 case value_t::discarded:
0774                 {
0775                     v.end_position = std::string::npos;
0776                     v.start_position = v.end_position;
0777                     break;
0778                 }
0779 
0780                 case value_t::binary:
0781                 case value_t::number_integer:
0782                 case value_t::number_unsigned:
0783                 case value_t::number_float:
0784                 {
0785                     v.start_position = v.end_position - m_lexer_ref->get_string().size();
0786                     break;
0787                 }
0788 
0789                 case value_t::object:
0790                 case value_t::array:
0791                 {
0792                     // object and array are handled in start_object() and start_array() handlers
0793                     // skip setting the values here.
0794                     break;
0795                 }
0796                 default: // LCOV_EXCL_LINE
0797                     // Handle all possible types discretely, default handler should never be reached.
0798                     JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE
0799             }
0800         }
0801     }
0802 #endif
0803 
0804     /*!
0805     @param[in] v  value to add to the JSON value we build during parsing
0806     @param[in] skip_callback  whether we should skip calling the callback
0807                function; this is required after start_array() and
0808                start_object() SAX events, because otherwise we would call the
0809                callback function with an empty array or object, respectively.
0810 
0811     @invariant If the ref stack is empty, then the passed value will be the new
0812                root.
0813     @invariant If the ref stack contains a value, then it is an array or an
0814                object to which we can add elements
0815 
0816     @return pair of boolean (whether value should be kept) and pointer (to the
0817             passed value in the ref_stack hierarchy; nullptr if not kept)
0818     */
0819     template<typename Value>
0820     std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
0821     {
0822         JSON_ASSERT(!keep_stack.empty());
0823 
0824         // do not handle this value if we know it would be added to a discarded
0825         // container
0826         if (!keep_stack.back())
0827         {
0828             return {false, nullptr};
0829         }
0830 
0831         // create value
0832         auto value = BasicJsonType(std::forward<Value>(v));
0833 
0834 #if JSON_DIAGNOSTIC_POSITIONS
0835         handle_diagnostic_positions_for_json_value(value);
0836 #endif
0837 
0838         // check callback
0839         const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0840 
0841         // do not handle this value if we just learnt it shall be discarded
0842         if (!keep)
0843         {
0844             return {false, nullptr};
0845         }
0846 
0847         if (ref_stack.empty())
0848         {
0849             root = std::move(value);
0850             return {true, & root};
0851         }
0852 
0853         // skip this value if we already decided to skip the parent
0854         // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0855         if (!ref_stack.back())
0856         {
0857             return {false, nullptr};
0858         }
0859 
0860         // we now only expect arrays and objects
0861         JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
0862 
0863         // array
0864         if (ref_stack.back()->is_array())
0865         {
0866             ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value));
0867             return {true, & (ref_stack.back()->m_data.m_value.array->back())};
0868         }
0869 
0870         // object
0871         JSON_ASSERT(ref_stack.back()->is_object());
0872         // check if we should store an element for the current key
0873         JSON_ASSERT(!key_keep_stack.empty());
0874         const bool store_element = key_keep_stack.back();
0875         key_keep_stack.pop_back();
0876 
0877         if (!store_element)
0878         {
0879             return {false, nullptr};
0880         }
0881 
0882         JSON_ASSERT(object_element);
0883         *object_element = std::move(value);
0884         return {true, object_element};
0885     }
0886 
0887     /// the parsed JSON value
0888     BasicJsonType& root;
0889     /// stack to model hierarchy of values
0890     std::vector<BasicJsonType*> ref_stack {};
0891     /// stack to manage which values to keep
0892     std::vector<bool> keep_stack {}; // NOLINT(readability-redundant-member-init)
0893     /// stack to manage which object keys to keep
0894     std::vector<bool> key_keep_stack {}; // NOLINT(readability-redundant-member-init)
0895     /// helper to hold the reference for the next object element
0896     BasicJsonType* object_element = nullptr;
0897     /// whether a syntax error occurred
0898     bool errored = false;
0899     /// callback function
0900     const parser_callback_t callback = nullptr;
0901     /// whether to throw exceptions in case of errors
0902     const bool allow_exceptions = true;
0903     /// a discarded value for the callback
0904     BasicJsonType discarded = BasicJsonType::value_t::discarded;
0905     /// the lexer reference to obtain the current position
0906     lexer_t* m_lexer_ref = nullptr;
0907 };
0908 
0909 template<typename BasicJsonType>
0910 class json_sax_acceptor
0911 {
0912   public:
0913     using number_integer_t = typename BasicJsonType::number_integer_t;
0914     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
0915     using number_float_t = typename BasicJsonType::number_float_t;
0916     using string_t = typename BasicJsonType::string_t;
0917     using binary_t = typename BasicJsonType::binary_t;
0918 
0919     bool null()
0920     {
0921         return true;
0922     }
0923 
0924     bool boolean(bool /*unused*/)
0925     {
0926         return true;
0927     }
0928 
0929     bool number_integer(number_integer_t /*unused*/)
0930     {
0931         return true;
0932     }
0933 
0934     bool number_unsigned(number_unsigned_t /*unused*/)
0935     {
0936         return true;
0937     }
0938 
0939     bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
0940     {
0941         return true;
0942     }
0943 
0944     bool string(string_t& /*unused*/)
0945     {
0946         return true;
0947     }
0948 
0949     bool binary(binary_t& /*unused*/)
0950     {
0951         return true;
0952     }
0953 
0954     bool start_object(std::size_t /*unused*/ = detail::unknown_size())
0955     {
0956         return true;
0957     }
0958 
0959     bool key(string_t& /*unused*/)
0960     {
0961         return true;
0962     }
0963 
0964     bool end_object()
0965     {
0966         return true;
0967     }
0968 
0969     bool start_array(std::size_t /*unused*/ = detail::unknown_size())
0970     {
0971         return true;
0972     }
0973 
0974     bool end_array()
0975     {
0976         return true;
0977     }
0978 
0979     bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
0980     {
0981         return false;
0982     }
0983 };
0984 
0985 }  // namespace detail
0986 NLOHMANN_JSON_NAMESPACE_END