| // __ _____ _____ _____ | |
| // __| | __| | | | JSON for Modern C++ | |
| // | | |__ | | | | | | version 3.12.0 | |
| // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
| // | |
| // SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me> | |
| // SPDX-License-Identifier: MIT | |
| #pragma once | |
| #include <cstddef> // size_t | |
| #include <cstdint> // uint64_t | |
| #include <limits> // numeric_limits | |
| #include <string> // string, to_string | |
| #include <nlohmann/json.hpp> | |
| #include <nlohmann/detail/view/errors.hpp> | |
| #include <nlohmann/detail/view/macro_scope.hpp> | |
| NLOHMANN_JSON_NAMESPACE_BEGIN | |
| namespace detail | |
| { | |
| namespace view | |
| { | |
| /// what resolving a JSON pointer does where it cannot continue | |
| enum class pointer_mode | |
| { | |
| unchecked, ///< as const basic_json::operator[]: a discarded view where basic_json's behavior is undefined | |
| checked, ///< as basic_json::at(): out_of_range.401/403 | |
| value, ///< as basic_json::value(): no out_of_range exceptions (the default value is used) | |
| contains, ///< as basic_json::contains(): no exceptions at all | |
| }; | |
| /// the outcome of reading an array index: detail::parse_array_index(), shared with json_pointer | |
| using index_status = detail::array_index_status; | |
| /// reads an array index like json_pointer::array_index (RFC 6901, Sect. 4), | |
| /// but reports errors instead of throwing them | |
| template<typename StringType> | |
| index_status array_index(const StringType& s, std::size_t& idx) noexcept | |
| { | |
| return detail::parse_array_index(s, idx); | |
| } | |
| /// throws the exception json_pointer::array_index throws for this status | |
| template<typename StringType> | |
| [[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_array_index_error(index_status status, const StringType& s) | |
| { | |
| switch (status) | |
| { | |
| case index_status::leading_zero: | |
| throw_parse_error(exception_id::pointer_index_leading_zero, concat("array index '", s, "' must not begin with '0'")); | |
| case index_status::not_a_number: | |
| throw_parse_error(exception_id::pointer_index_not_a_number, concat("array index '", s, "' is not a number")); | |
| case index_status::exceeds_size_type: | |
| throw_out_of_range(exception_id::value_out_of_range, concat("array index ", s, " exceeds size_type")); // LCOV_EXCL_LINE | |
| case index_status::unresolved: | |
| case index_status::ok: | |
| default: | |
| throw_out_of_range(exception_id::pointer_unresolved, concat("unresolved reference token '", s, "'")); | |
| } | |
| } | |
| /*! | |
| @brief resolve the reference tokens of a JSON pointer, starting at a view | |
| The exceptions are those basic_json throws for the same pointer; where | |
| basic_json's behavior is undefined (a missing key or an index out of range | |
| with const operator[]), the result is a discarded view. | |
| */ | |
| template<typename View, typename Tokens> | |
| View resolve_pointer(View cur, const Tokens& tokens, pointer_mode mode) | |
| { | |
| using string_view_t = typename View::string_view_t; | |
| const bool throwing = mode == pointer_mode::unchecked || mode == pointer_mode::checked; | |
| for (const auto& token : tokens) | |
| { | |
| if (cur.is_object()) | |
| { | |
| const auto it = cur.find(string_view_t(token.data(), token.size())); | |
| if (it == cur.end()) | |
| { | |
| if (mode == pointer_mode::checked) | |
| { | |
| throw_key_not_found(token); | |
| } | |
| return View(); | |
| } | |
| cur = *it; | |
| } | |
| else if (cur.is_array()) | |
| { | |
| if (token.size() == 1 && token[0] == '-') | |
| { | |
| if (throwing) | |
| { | |
| throw_array_index_past_end(cur.size()); | |
| } | |
| return View(); | |
| } | |
| std::size_t idx = 0; | |
| const index_status status = array_index(token, idx); | |
| if (status != index_status::ok) | |
| { | |
| const bool parse_error = status == index_status::leading_zero || status == index_status::not_a_number; | |
| if (throwing || (mode == pointer_mode::value && parse_error)) | |
| { | |
| throw_array_index_error(status, token); | |
| } | |
| return View(); | |
| } | |
| if (idx >= cur.size()) | |
| { | |
| if (mode == pointer_mode::checked) | |
| { | |
| throw_array_index_out_of_range(idx); | |
| } | |
| return View(); | |
| } | |
| cur = cur[idx]; | |
| } | |
| else | |
| { | |
| if (throwing) | |
| { | |
| throw_out_of_range(exception_id::pointer_unresolved, concat("unresolved reference token '", token, "'")); | |
| } | |
| return View(); | |
| } | |
| } | |
| return cur; | |
| } | |
| } // namespace view | |
| } // namespace detail | |
| NLOHMANN_JSON_NAMESPACE_END |