1c5f01b2fSopenharmony_ci// __ _____ _____ _____ 2c5f01b2fSopenharmony_ci// __| | __| | | | JSON for Modern C++ 3c5f01b2fSopenharmony_ci// | | |__ | | | | | | version 3.11.2 4c5f01b2fSopenharmony_ci// |_____|_____|_____|_|___| https://github.com/nlohmann/json 5c5f01b2fSopenharmony_ci// 6c5f01b2fSopenharmony_ci// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> 7c5f01b2fSopenharmony_ci// SPDX-License-Identifier: MIT 8c5f01b2fSopenharmony_ci 9c5f01b2fSopenharmony_ci#pragma once 10c5f01b2fSopenharmony_ci 11c5f01b2fSopenharmony_ci#include <algorithm> // all_of 12c5f01b2fSopenharmony_ci#include <cctype> // isdigit 13c5f01b2fSopenharmony_ci#include <cerrno> // errno, ERANGE 14c5f01b2fSopenharmony_ci#include <cstdlib> // strtoull 15c5f01b2fSopenharmony_ci#ifndef JSON_NO_IO 16c5f01b2fSopenharmony_ci #include <iosfwd> // ostream 17c5f01b2fSopenharmony_ci#endif // JSON_NO_IO 18c5f01b2fSopenharmony_ci#include <limits> // max 19c5f01b2fSopenharmony_ci#include <numeric> // accumulate 20c5f01b2fSopenharmony_ci#include <string> // string 21c5f01b2fSopenharmony_ci#include <utility> // move 22c5f01b2fSopenharmony_ci#include <vector> // vector 23c5f01b2fSopenharmony_ci 24c5f01b2fSopenharmony_ci#include <nlohmann/detail/exceptions.hpp> 25c5f01b2fSopenharmony_ci#include <nlohmann/detail/macro_scope.hpp> 26c5f01b2fSopenharmony_ci#include <nlohmann/detail/string_concat.hpp> 27c5f01b2fSopenharmony_ci#include <nlohmann/detail/string_escape.hpp> 28c5f01b2fSopenharmony_ci#include <nlohmann/detail/value_t.hpp> 29c5f01b2fSopenharmony_ci 30c5f01b2fSopenharmony_ciNLOHMANN_JSON_NAMESPACE_BEGIN 31c5f01b2fSopenharmony_ci 32c5f01b2fSopenharmony_ci/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document 33c5f01b2fSopenharmony_ci/// @sa https://json.nlohmann.me/api/json_pointer/ 34c5f01b2fSopenharmony_citemplate<typename RefStringType> 35c5f01b2fSopenharmony_ciclass json_pointer 36c5f01b2fSopenharmony_ci{ 37c5f01b2fSopenharmony_ci // allow basic_json to access private members 38c5f01b2fSopenharmony_ci NLOHMANN_BASIC_JSON_TPL_DECLARATION 39c5f01b2fSopenharmony_ci friend class basic_json; 40c5f01b2fSopenharmony_ci 41c5f01b2fSopenharmony_ci template<typename> 42c5f01b2fSopenharmony_ci friend class json_pointer; 43c5f01b2fSopenharmony_ci 44c5f01b2fSopenharmony_ci template<typename T> 45c5f01b2fSopenharmony_ci struct string_t_helper 46c5f01b2fSopenharmony_ci { 47c5f01b2fSopenharmony_ci using type = T; 48c5f01b2fSopenharmony_ci }; 49c5f01b2fSopenharmony_ci 50c5f01b2fSopenharmony_ci NLOHMANN_BASIC_JSON_TPL_DECLARATION 51c5f01b2fSopenharmony_ci struct string_t_helper<NLOHMANN_BASIC_JSON_TPL> 52c5f01b2fSopenharmony_ci { 53c5f01b2fSopenharmony_ci using type = StringType; 54c5f01b2fSopenharmony_ci }; 55c5f01b2fSopenharmony_ci 56c5f01b2fSopenharmony_ci public: 57c5f01b2fSopenharmony_ci // for backwards compatibility accept BasicJsonType 58c5f01b2fSopenharmony_ci using string_t = typename string_t_helper<RefStringType>::type; 59c5f01b2fSopenharmony_ci 60c5f01b2fSopenharmony_ci /// @brief create JSON pointer 61c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ 62c5f01b2fSopenharmony_ci explicit json_pointer(const string_t& s = "") 63c5f01b2fSopenharmony_ci : reference_tokens(split(s)) 64c5f01b2fSopenharmony_ci {} 65c5f01b2fSopenharmony_ci 66c5f01b2fSopenharmony_ci /// @brief return a string representation of the JSON pointer 67c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/to_string/ 68c5f01b2fSopenharmony_ci string_t to_string() const 69c5f01b2fSopenharmony_ci { 70c5f01b2fSopenharmony_ci return std::accumulate(reference_tokens.begin(), reference_tokens.end(), 71c5f01b2fSopenharmony_ci string_t{}, 72c5f01b2fSopenharmony_ci [](const string_t& a, const string_t& b) 73c5f01b2fSopenharmony_ci { 74c5f01b2fSopenharmony_ci return detail::concat(a, '/', detail::escape(b)); 75c5f01b2fSopenharmony_ci }); 76c5f01b2fSopenharmony_ci } 77c5f01b2fSopenharmony_ci 78c5f01b2fSopenharmony_ci /// @brief return a string representation of the JSON pointer 79c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/ 80c5f01b2fSopenharmony_ci JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) 81c5f01b2fSopenharmony_ci operator string_t() const 82c5f01b2fSopenharmony_ci { 83c5f01b2fSopenharmony_ci return to_string(); 84c5f01b2fSopenharmony_ci } 85c5f01b2fSopenharmony_ci 86c5f01b2fSopenharmony_ci#ifndef JSON_NO_IO 87c5f01b2fSopenharmony_ci /// @brief write string representation of the JSON pointer to stream 88c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ 89c5f01b2fSopenharmony_ci friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr) 90c5f01b2fSopenharmony_ci { 91c5f01b2fSopenharmony_ci o << ptr.to_string(); 92c5f01b2fSopenharmony_ci return o; 93c5f01b2fSopenharmony_ci } 94c5f01b2fSopenharmony_ci#endif 95c5f01b2fSopenharmony_ci 96c5f01b2fSopenharmony_ci /// @brief append another JSON pointer at the end of this JSON pointer 97c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ 98c5f01b2fSopenharmony_ci json_pointer& operator/=(const json_pointer& ptr) 99c5f01b2fSopenharmony_ci { 100c5f01b2fSopenharmony_ci reference_tokens.insert(reference_tokens.end(), 101c5f01b2fSopenharmony_ci ptr.reference_tokens.begin(), 102c5f01b2fSopenharmony_ci ptr.reference_tokens.end()); 103c5f01b2fSopenharmony_ci return *this; 104c5f01b2fSopenharmony_ci } 105c5f01b2fSopenharmony_ci 106c5f01b2fSopenharmony_ci /// @brief append an unescaped reference token at the end of this JSON pointer 107c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ 108c5f01b2fSopenharmony_ci json_pointer& operator/=(string_t token) 109c5f01b2fSopenharmony_ci { 110c5f01b2fSopenharmony_ci push_back(std::move(token)); 111c5f01b2fSopenharmony_ci return *this; 112c5f01b2fSopenharmony_ci } 113c5f01b2fSopenharmony_ci 114c5f01b2fSopenharmony_ci /// @brief append an array index at the end of this JSON pointer 115c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ 116c5f01b2fSopenharmony_ci json_pointer& operator/=(std::size_t array_idx) 117c5f01b2fSopenharmony_ci { 118c5f01b2fSopenharmony_ci return *this /= std::to_string(array_idx); 119c5f01b2fSopenharmony_ci } 120c5f01b2fSopenharmony_ci 121c5f01b2fSopenharmony_ci /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer 122c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ 123c5f01b2fSopenharmony_ci friend json_pointer operator/(const json_pointer& lhs, 124c5f01b2fSopenharmony_ci const json_pointer& rhs) 125c5f01b2fSopenharmony_ci { 126c5f01b2fSopenharmony_ci return json_pointer(lhs) /= rhs; 127c5f01b2fSopenharmony_ci } 128c5f01b2fSopenharmony_ci 129c5f01b2fSopenharmony_ci /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer 130c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ 131c5f01b2fSopenharmony_ci friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param) 132c5f01b2fSopenharmony_ci { 133c5f01b2fSopenharmony_ci return json_pointer(lhs) /= std::move(token); 134c5f01b2fSopenharmony_ci } 135c5f01b2fSopenharmony_ci 136c5f01b2fSopenharmony_ci /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer 137c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ 138c5f01b2fSopenharmony_ci friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx) 139c5f01b2fSopenharmony_ci { 140c5f01b2fSopenharmony_ci return json_pointer(lhs) /= array_idx; 141c5f01b2fSopenharmony_ci } 142c5f01b2fSopenharmony_ci 143c5f01b2fSopenharmony_ci /// @brief returns the parent of this JSON pointer 144c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/ 145c5f01b2fSopenharmony_ci json_pointer parent_pointer() const 146c5f01b2fSopenharmony_ci { 147c5f01b2fSopenharmony_ci if (empty()) 148c5f01b2fSopenharmony_ci { 149c5f01b2fSopenharmony_ci return *this; 150c5f01b2fSopenharmony_ci } 151c5f01b2fSopenharmony_ci 152c5f01b2fSopenharmony_ci json_pointer res = *this; 153c5f01b2fSopenharmony_ci res.pop_back(); 154c5f01b2fSopenharmony_ci return res; 155c5f01b2fSopenharmony_ci } 156c5f01b2fSopenharmony_ci 157c5f01b2fSopenharmony_ci /// @brief remove last reference token 158c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/ 159c5f01b2fSopenharmony_ci void pop_back() 160c5f01b2fSopenharmony_ci { 161c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(empty())) 162c5f01b2fSopenharmony_ci { 163c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); 164c5f01b2fSopenharmony_ci } 165c5f01b2fSopenharmony_ci 166c5f01b2fSopenharmony_ci reference_tokens.pop_back(); 167c5f01b2fSopenharmony_ci } 168c5f01b2fSopenharmony_ci 169c5f01b2fSopenharmony_ci /// @brief return last reference token 170c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/back/ 171c5f01b2fSopenharmony_ci const string_t& back() const 172c5f01b2fSopenharmony_ci { 173c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(empty())) 174c5f01b2fSopenharmony_ci { 175c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); 176c5f01b2fSopenharmony_ci } 177c5f01b2fSopenharmony_ci 178c5f01b2fSopenharmony_ci return reference_tokens.back(); 179c5f01b2fSopenharmony_ci } 180c5f01b2fSopenharmony_ci 181c5f01b2fSopenharmony_ci /// @brief append an unescaped token at the end of the reference pointer 182c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ 183c5f01b2fSopenharmony_ci void push_back(const string_t& token) 184c5f01b2fSopenharmony_ci { 185c5f01b2fSopenharmony_ci reference_tokens.push_back(token); 186c5f01b2fSopenharmony_ci } 187c5f01b2fSopenharmony_ci 188c5f01b2fSopenharmony_ci /// @brief append an unescaped token at the end of the reference pointer 189c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ 190c5f01b2fSopenharmony_ci void push_back(string_t&& token) 191c5f01b2fSopenharmony_ci { 192c5f01b2fSopenharmony_ci reference_tokens.push_back(std::move(token)); 193c5f01b2fSopenharmony_ci } 194c5f01b2fSopenharmony_ci 195c5f01b2fSopenharmony_ci /// @brief return whether pointer points to the root document 196c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/empty/ 197c5f01b2fSopenharmony_ci bool empty() const noexcept 198c5f01b2fSopenharmony_ci { 199c5f01b2fSopenharmony_ci return reference_tokens.empty(); 200c5f01b2fSopenharmony_ci } 201c5f01b2fSopenharmony_ci 202c5f01b2fSopenharmony_ci private: 203c5f01b2fSopenharmony_ci /*! 204c5f01b2fSopenharmony_ci @param[in] s reference token to be converted into an array index 205c5f01b2fSopenharmony_ci 206c5f01b2fSopenharmony_ci @return integer representation of @a s 207c5f01b2fSopenharmony_ci 208c5f01b2fSopenharmony_ci @throw parse_error.106 if an array index begins with '0' 209c5f01b2fSopenharmony_ci @throw parse_error.109 if an array index begins not with a digit 210c5f01b2fSopenharmony_ci @throw out_of_range.404 if string @a s could not be converted to an integer 211c5f01b2fSopenharmony_ci @throw out_of_range.410 if an array index exceeds size_type 212c5f01b2fSopenharmony_ci */ 213c5f01b2fSopenharmony_ci template<typename BasicJsonType> 214c5f01b2fSopenharmony_ci static typename BasicJsonType::size_type array_index(const string_t& s) 215c5f01b2fSopenharmony_ci { 216c5f01b2fSopenharmony_ci using size_type = typename BasicJsonType::size_type; 217c5f01b2fSopenharmony_ci 218c5f01b2fSopenharmony_ci // error condition (cf. RFC 6901, Sect. 4) 219c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) 220c5f01b2fSopenharmony_ci { 221c5f01b2fSopenharmony_ci JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); 222c5f01b2fSopenharmony_ci } 223c5f01b2fSopenharmony_ci 224c5f01b2fSopenharmony_ci // error condition (cf. RFC 6901, Sect. 4) 225c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) 226c5f01b2fSopenharmony_ci { 227c5f01b2fSopenharmony_ci JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); 228c5f01b2fSopenharmony_ci } 229c5f01b2fSopenharmony_ci 230c5f01b2fSopenharmony_ci const char* p = s.c_str(); 231c5f01b2fSopenharmony_ci char* p_end = nullptr; 232c5f01b2fSopenharmony_ci errno = 0; // strtoull doesn't reset errno 233c5f01b2fSopenharmony_ci unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) 234c5f01b2fSopenharmony_ci if (p == p_end // invalid input or empty string 235c5f01b2fSopenharmony_ci || errno == ERANGE // out of range 236c5f01b2fSopenharmony_ci || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read 237c5f01b2fSopenharmony_ci { 238c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr)); 239c5f01b2fSopenharmony_ci } 240c5f01b2fSopenharmony_ci 241c5f01b2fSopenharmony_ci // only triggered on special platforms (like 32bit), see also 242c5f01b2fSopenharmony_ci // https://github.com/nlohmann/json/pull/2203 243c5f01b2fSopenharmony_ci if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int) 244c5f01b2fSopenharmony_ci { 245c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE 246c5f01b2fSopenharmony_ci } 247c5f01b2fSopenharmony_ci 248c5f01b2fSopenharmony_ci return static_cast<size_type>(res); 249c5f01b2fSopenharmony_ci } 250c5f01b2fSopenharmony_ci 251c5f01b2fSopenharmony_ci JSON_PRIVATE_UNLESS_TESTED: 252c5f01b2fSopenharmony_ci json_pointer top() const 253c5f01b2fSopenharmony_ci { 254c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(empty())) 255c5f01b2fSopenharmony_ci { 256c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); 257c5f01b2fSopenharmony_ci } 258c5f01b2fSopenharmony_ci 259c5f01b2fSopenharmony_ci json_pointer result = *this; 260c5f01b2fSopenharmony_ci result.reference_tokens = {reference_tokens[0]}; 261c5f01b2fSopenharmony_ci return result; 262c5f01b2fSopenharmony_ci } 263c5f01b2fSopenharmony_ci 264c5f01b2fSopenharmony_ci private: 265c5f01b2fSopenharmony_ci /*! 266c5f01b2fSopenharmony_ci @brief create and return a reference to the pointed to value 267c5f01b2fSopenharmony_ci 268c5f01b2fSopenharmony_ci @complexity Linear in the number of reference tokens. 269c5f01b2fSopenharmony_ci 270c5f01b2fSopenharmony_ci @throw parse_error.109 if array index is not a number 271c5f01b2fSopenharmony_ci @throw type_error.313 if value cannot be unflattened 272c5f01b2fSopenharmony_ci */ 273c5f01b2fSopenharmony_ci template<typename BasicJsonType> 274c5f01b2fSopenharmony_ci BasicJsonType& get_and_create(BasicJsonType& j) const 275c5f01b2fSopenharmony_ci { 276c5f01b2fSopenharmony_ci auto* result = &j; 277c5f01b2fSopenharmony_ci 278c5f01b2fSopenharmony_ci // in case no reference tokens exist, return a reference to the JSON value 279c5f01b2fSopenharmony_ci // j which will be overwritten by a primitive value 280c5f01b2fSopenharmony_ci for (const auto& reference_token : reference_tokens) 281c5f01b2fSopenharmony_ci { 282c5f01b2fSopenharmony_ci switch (result->type()) 283c5f01b2fSopenharmony_ci { 284c5f01b2fSopenharmony_ci case detail::value_t::null: 285c5f01b2fSopenharmony_ci { 286c5f01b2fSopenharmony_ci if (reference_token == "0") 287c5f01b2fSopenharmony_ci { 288c5f01b2fSopenharmony_ci // start a new array if reference token is 0 289c5f01b2fSopenharmony_ci result = &result->operator[](0); 290c5f01b2fSopenharmony_ci } 291c5f01b2fSopenharmony_ci else 292c5f01b2fSopenharmony_ci { 293c5f01b2fSopenharmony_ci // start a new object otherwise 294c5f01b2fSopenharmony_ci result = &result->operator[](reference_token); 295c5f01b2fSopenharmony_ci } 296c5f01b2fSopenharmony_ci break; 297c5f01b2fSopenharmony_ci } 298c5f01b2fSopenharmony_ci 299c5f01b2fSopenharmony_ci case detail::value_t::object: 300c5f01b2fSopenharmony_ci { 301c5f01b2fSopenharmony_ci // create an entry in the object 302c5f01b2fSopenharmony_ci result = &result->operator[](reference_token); 303c5f01b2fSopenharmony_ci break; 304c5f01b2fSopenharmony_ci } 305c5f01b2fSopenharmony_ci 306c5f01b2fSopenharmony_ci case detail::value_t::array: 307c5f01b2fSopenharmony_ci { 308c5f01b2fSopenharmony_ci // create an entry in the array 309c5f01b2fSopenharmony_ci result = &result->operator[](array_index<BasicJsonType>(reference_token)); 310c5f01b2fSopenharmony_ci break; 311c5f01b2fSopenharmony_ci } 312c5f01b2fSopenharmony_ci 313c5f01b2fSopenharmony_ci /* 314c5f01b2fSopenharmony_ci The following code is only reached if there exists a reference 315c5f01b2fSopenharmony_ci token _and_ the current value is primitive. In this case, we have 316c5f01b2fSopenharmony_ci an error situation, because primitive values may only occur as 317c5f01b2fSopenharmony_ci single value; that is, with an empty list of reference tokens. 318c5f01b2fSopenharmony_ci */ 319c5f01b2fSopenharmony_ci case detail::value_t::string: 320c5f01b2fSopenharmony_ci case detail::value_t::boolean: 321c5f01b2fSopenharmony_ci case detail::value_t::number_integer: 322c5f01b2fSopenharmony_ci case detail::value_t::number_unsigned: 323c5f01b2fSopenharmony_ci case detail::value_t::number_float: 324c5f01b2fSopenharmony_ci case detail::value_t::binary: 325c5f01b2fSopenharmony_ci case detail::value_t::discarded: 326c5f01b2fSopenharmony_ci default: 327c5f01b2fSopenharmony_ci JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); 328c5f01b2fSopenharmony_ci } 329c5f01b2fSopenharmony_ci } 330c5f01b2fSopenharmony_ci 331c5f01b2fSopenharmony_ci return *result; 332c5f01b2fSopenharmony_ci } 333c5f01b2fSopenharmony_ci 334c5f01b2fSopenharmony_ci /*! 335c5f01b2fSopenharmony_ci @brief return a reference to the pointed to value 336c5f01b2fSopenharmony_ci 337c5f01b2fSopenharmony_ci @note This version does not throw if a value is not present, but tries to 338c5f01b2fSopenharmony_ci create nested values instead. For instance, calling this function 339c5f01b2fSopenharmony_ci with pointer `"/this/that"` on a null value is equivalent to calling 340c5f01b2fSopenharmony_ci `operator[]("this").operator[]("that")` on that value, effectively 341c5f01b2fSopenharmony_ci changing the null value to an object. 342c5f01b2fSopenharmony_ci 343c5f01b2fSopenharmony_ci @param[in] ptr a JSON value 344c5f01b2fSopenharmony_ci 345c5f01b2fSopenharmony_ci @return reference to the JSON value pointed to by the JSON pointer 346c5f01b2fSopenharmony_ci 347c5f01b2fSopenharmony_ci @complexity Linear in the length of the JSON pointer. 348c5f01b2fSopenharmony_ci 349c5f01b2fSopenharmony_ci @throw parse_error.106 if an array index begins with '0' 350c5f01b2fSopenharmony_ci @throw parse_error.109 if an array index was not a number 351c5f01b2fSopenharmony_ci @throw out_of_range.404 if the JSON pointer can not be resolved 352c5f01b2fSopenharmony_ci */ 353c5f01b2fSopenharmony_ci template<typename BasicJsonType> 354c5f01b2fSopenharmony_ci BasicJsonType& get_unchecked(BasicJsonType* ptr) const 355c5f01b2fSopenharmony_ci { 356c5f01b2fSopenharmony_ci for (const auto& reference_token : reference_tokens) 357c5f01b2fSopenharmony_ci { 358c5f01b2fSopenharmony_ci // convert null values to arrays or objects before continuing 359c5f01b2fSopenharmony_ci if (ptr->is_null()) 360c5f01b2fSopenharmony_ci { 361c5f01b2fSopenharmony_ci // check if reference token is a number 362c5f01b2fSopenharmony_ci const bool nums = 363c5f01b2fSopenharmony_ci std::all_of(reference_token.begin(), reference_token.end(), 364c5f01b2fSopenharmony_ci [](const unsigned char x) 365c5f01b2fSopenharmony_ci { 366c5f01b2fSopenharmony_ci return std::isdigit(x); 367c5f01b2fSopenharmony_ci }); 368c5f01b2fSopenharmony_ci 369c5f01b2fSopenharmony_ci // change value to array for numbers or "-" or to object otherwise 370c5f01b2fSopenharmony_ci *ptr = (nums || reference_token == "-") 371c5f01b2fSopenharmony_ci ? detail::value_t::array 372c5f01b2fSopenharmony_ci : detail::value_t::object; 373c5f01b2fSopenharmony_ci } 374c5f01b2fSopenharmony_ci 375c5f01b2fSopenharmony_ci switch (ptr->type()) 376c5f01b2fSopenharmony_ci { 377c5f01b2fSopenharmony_ci case detail::value_t::object: 378c5f01b2fSopenharmony_ci { 379c5f01b2fSopenharmony_ci // use unchecked object access 380c5f01b2fSopenharmony_ci ptr = &ptr->operator[](reference_token); 381c5f01b2fSopenharmony_ci break; 382c5f01b2fSopenharmony_ci } 383c5f01b2fSopenharmony_ci 384c5f01b2fSopenharmony_ci case detail::value_t::array: 385c5f01b2fSopenharmony_ci { 386c5f01b2fSopenharmony_ci if (reference_token == "-") 387c5f01b2fSopenharmony_ci { 388c5f01b2fSopenharmony_ci // explicitly treat "-" as index beyond the end 389c5f01b2fSopenharmony_ci ptr = &ptr->operator[](ptr->m_value.array->size()); 390c5f01b2fSopenharmony_ci } 391c5f01b2fSopenharmony_ci else 392c5f01b2fSopenharmony_ci { 393c5f01b2fSopenharmony_ci // convert array index to number; unchecked access 394c5f01b2fSopenharmony_ci ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token)); 395c5f01b2fSopenharmony_ci } 396c5f01b2fSopenharmony_ci break; 397c5f01b2fSopenharmony_ci } 398c5f01b2fSopenharmony_ci 399c5f01b2fSopenharmony_ci case detail::value_t::null: 400c5f01b2fSopenharmony_ci case detail::value_t::string: 401c5f01b2fSopenharmony_ci case detail::value_t::boolean: 402c5f01b2fSopenharmony_ci case detail::value_t::number_integer: 403c5f01b2fSopenharmony_ci case detail::value_t::number_unsigned: 404c5f01b2fSopenharmony_ci case detail::value_t::number_float: 405c5f01b2fSopenharmony_ci case detail::value_t::binary: 406c5f01b2fSopenharmony_ci case detail::value_t::discarded: 407c5f01b2fSopenharmony_ci default: 408c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); 409c5f01b2fSopenharmony_ci } 410c5f01b2fSopenharmony_ci } 411c5f01b2fSopenharmony_ci 412c5f01b2fSopenharmony_ci return *ptr; 413c5f01b2fSopenharmony_ci } 414c5f01b2fSopenharmony_ci 415c5f01b2fSopenharmony_ci /*! 416c5f01b2fSopenharmony_ci @throw parse_error.106 if an array index begins with '0' 417c5f01b2fSopenharmony_ci @throw parse_error.109 if an array index was not a number 418c5f01b2fSopenharmony_ci @throw out_of_range.402 if the array index '-' is used 419c5f01b2fSopenharmony_ci @throw out_of_range.404 if the JSON pointer can not be resolved 420c5f01b2fSopenharmony_ci */ 421c5f01b2fSopenharmony_ci template<typename BasicJsonType> 422c5f01b2fSopenharmony_ci BasicJsonType& get_checked(BasicJsonType* ptr) const 423c5f01b2fSopenharmony_ci { 424c5f01b2fSopenharmony_ci for (const auto& reference_token : reference_tokens) 425c5f01b2fSopenharmony_ci { 426c5f01b2fSopenharmony_ci switch (ptr->type()) 427c5f01b2fSopenharmony_ci { 428c5f01b2fSopenharmony_ci case detail::value_t::object: 429c5f01b2fSopenharmony_ci { 430c5f01b2fSopenharmony_ci // note: at performs range check 431c5f01b2fSopenharmony_ci ptr = &ptr->at(reference_token); 432c5f01b2fSopenharmony_ci break; 433c5f01b2fSopenharmony_ci } 434c5f01b2fSopenharmony_ci 435c5f01b2fSopenharmony_ci case detail::value_t::array: 436c5f01b2fSopenharmony_ci { 437c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) 438c5f01b2fSopenharmony_ci { 439c5f01b2fSopenharmony_ci // "-" always fails the range check 440c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(402, detail::concat( 441c5f01b2fSopenharmony_ci "array index '-' (", std::to_string(ptr->m_value.array->size()), 442c5f01b2fSopenharmony_ci ") is out of range"), ptr)); 443c5f01b2fSopenharmony_ci } 444c5f01b2fSopenharmony_ci 445c5f01b2fSopenharmony_ci // note: at performs range check 446c5f01b2fSopenharmony_ci ptr = &ptr->at(array_index<BasicJsonType>(reference_token)); 447c5f01b2fSopenharmony_ci break; 448c5f01b2fSopenharmony_ci } 449c5f01b2fSopenharmony_ci 450c5f01b2fSopenharmony_ci case detail::value_t::null: 451c5f01b2fSopenharmony_ci case detail::value_t::string: 452c5f01b2fSopenharmony_ci case detail::value_t::boolean: 453c5f01b2fSopenharmony_ci case detail::value_t::number_integer: 454c5f01b2fSopenharmony_ci case detail::value_t::number_unsigned: 455c5f01b2fSopenharmony_ci case detail::value_t::number_float: 456c5f01b2fSopenharmony_ci case detail::value_t::binary: 457c5f01b2fSopenharmony_ci case detail::value_t::discarded: 458c5f01b2fSopenharmony_ci default: 459c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); 460c5f01b2fSopenharmony_ci } 461c5f01b2fSopenharmony_ci } 462c5f01b2fSopenharmony_ci 463c5f01b2fSopenharmony_ci return *ptr; 464c5f01b2fSopenharmony_ci } 465c5f01b2fSopenharmony_ci 466c5f01b2fSopenharmony_ci /*! 467c5f01b2fSopenharmony_ci @brief return a const reference to the pointed to value 468c5f01b2fSopenharmony_ci 469c5f01b2fSopenharmony_ci @param[in] ptr a JSON value 470c5f01b2fSopenharmony_ci 471c5f01b2fSopenharmony_ci @return const reference to the JSON value pointed to by the JSON 472c5f01b2fSopenharmony_ci pointer 473c5f01b2fSopenharmony_ci 474c5f01b2fSopenharmony_ci @throw parse_error.106 if an array index begins with '0' 475c5f01b2fSopenharmony_ci @throw parse_error.109 if an array index was not a number 476c5f01b2fSopenharmony_ci @throw out_of_range.402 if the array index '-' is used 477c5f01b2fSopenharmony_ci @throw out_of_range.404 if the JSON pointer can not be resolved 478c5f01b2fSopenharmony_ci */ 479c5f01b2fSopenharmony_ci template<typename BasicJsonType> 480c5f01b2fSopenharmony_ci const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const 481c5f01b2fSopenharmony_ci { 482c5f01b2fSopenharmony_ci for (const auto& reference_token : reference_tokens) 483c5f01b2fSopenharmony_ci { 484c5f01b2fSopenharmony_ci switch (ptr->type()) 485c5f01b2fSopenharmony_ci { 486c5f01b2fSopenharmony_ci case detail::value_t::object: 487c5f01b2fSopenharmony_ci { 488c5f01b2fSopenharmony_ci // use unchecked object access 489c5f01b2fSopenharmony_ci ptr = &ptr->operator[](reference_token); 490c5f01b2fSopenharmony_ci break; 491c5f01b2fSopenharmony_ci } 492c5f01b2fSopenharmony_ci 493c5f01b2fSopenharmony_ci case detail::value_t::array: 494c5f01b2fSopenharmony_ci { 495c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) 496c5f01b2fSopenharmony_ci { 497c5f01b2fSopenharmony_ci // "-" cannot be used for const access 498c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_value.array->size()), ") is out of range"), ptr)); 499c5f01b2fSopenharmony_ci } 500c5f01b2fSopenharmony_ci 501c5f01b2fSopenharmony_ci // use unchecked array access 502c5f01b2fSopenharmony_ci ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token)); 503c5f01b2fSopenharmony_ci break; 504c5f01b2fSopenharmony_ci } 505c5f01b2fSopenharmony_ci 506c5f01b2fSopenharmony_ci case detail::value_t::null: 507c5f01b2fSopenharmony_ci case detail::value_t::string: 508c5f01b2fSopenharmony_ci case detail::value_t::boolean: 509c5f01b2fSopenharmony_ci case detail::value_t::number_integer: 510c5f01b2fSopenharmony_ci case detail::value_t::number_unsigned: 511c5f01b2fSopenharmony_ci case detail::value_t::number_float: 512c5f01b2fSopenharmony_ci case detail::value_t::binary: 513c5f01b2fSopenharmony_ci case detail::value_t::discarded: 514c5f01b2fSopenharmony_ci default: 515c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); 516c5f01b2fSopenharmony_ci } 517c5f01b2fSopenharmony_ci } 518c5f01b2fSopenharmony_ci 519c5f01b2fSopenharmony_ci return *ptr; 520c5f01b2fSopenharmony_ci } 521c5f01b2fSopenharmony_ci 522c5f01b2fSopenharmony_ci /*! 523c5f01b2fSopenharmony_ci @throw parse_error.106 if an array index begins with '0' 524c5f01b2fSopenharmony_ci @throw parse_error.109 if an array index was not a number 525c5f01b2fSopenharmony_ci @throw out_of_range.402 if the array index '-' is used 526c5f01b2fSopenharmony_ci @throw out_of_range.404 if the JSON pointer can not be resolved 527c5f01b2fSopenharmony_ci */ 528c5f01b2fSopenharmony_ci template<typename BasicJsonType> 529c5f01b2fSopenharmony_ci const BasicJsonType& get_checked(const BasicJsonType* ptr) const 530c5f01b2fSopenharmony_ci { 531c5f01b2fSopenharmony_ci for (const auto& reference_token : reference_tokens) 532c5f01b2fSopenharmony_ci { 533c5f01b2fSopenharmony_ci switch (ptr->type()) 534c5f01b2fSopenharmony_ci { 535c5f01b2fSopenharmony_ci case detail::value_t::object: 536c5f01b2fSopenharmony_ci { 537c5f01b2fSopenharmony_ci // note: at performs range check 538c5f01b2fSopenharmony_ci ptr = &ptr->at(reference_token); 539c5f01b2fSopenharmony_ci break; 540c5f01b2fSopenharmony_ci } 541c5f01b2fSopenharmony_ci 542c5f01b2fSopenharmony_ci case detail::value_t::array: 543c5f01b2fSopenharmony_ci { 544c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) 545c5f01b2fSopenharmony_ci { 546c5f01b2fSopenharmony_ci // "-" always fails the range check 547c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(402, detail::concat( 548c5f01b2fSopenharmony_ci "array index '-' (", std::to_string(ptr->m_value.array->size()), 549c5f01b2fSopenharmony_ci ") is out of range"), ptr)); 550c5f01b2fSopenharmony_ci } 551c5f01b2fSopenharmony_ci 552c5f01b2fSopenharmony_ci // note: at performs range check 553c5f01b2fSopenharmony_ci ptr = &ptr->at(array_index<BasicJsonType>(reference_token)); 554c5f01b2fSopenharmony_ci break; 555c5f01b2fSopenharmony_ci } 556c5f01b2fSopenharmony_ci 557c5f01b2fSopenharmony_ci case detail::value_t::null: 558c5f01b2fSopenharmony_ci case detail::value_t::string: 559c5f01b2fSopenharmony_ci case detail::value_t::boolean: 560c5f01b2fSopenharmony_ci case detail::value_t::number_integer: 561c5f01b2fSopenharmony_ci case detail::value_t::number_unsigned: 562c5f01b2fSopenharmony_ci case detail::value_t::number_float: 563c5f01b2fSopenharmony_ci case detail::value_t::binary: 564c5f01b2fSopenharmony_ci case detail::value_t::discarded: 565c5f01b2fSopenharmony_ci default: 566c5f01b2fSopenharmony_ci JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); 567c5f01b2fSopenharmony_ci } 568c5f01b2fSopenharmony_ci } 569c5f01b2fSopenharmony_ci 570c5f01b2fSopenharmony_ci return *ptr; 571c5f01b2fSopenharmony_ci } 572c5f01b2fSopenharmony_ci 573c5f01b2fSopenharmony_ci /*! 574c5f01b2fSopenharmony_ci @throw parse_error.106 if an array index begins with '0' 575c5f01b2fSopenharmony_ci @throw parse_error.109 if an array index was not a number 576c5f01b2fSopenharmony_ci */ 577c5f01b2fSopenharmony_ci template<typename BasicJsonType> 578c5f01b2fSopenharmony_ci bool contains(const BasicJsonType* ptr) const 579c5f01b2fSopenharmony_ci { 580c5f01b2fSopenharmony_ci for (const auto& reference_token : reference_tokens) 581c5f01b2fSopenharmony_ci { 582c5f01b2fSopenharmony_ci switch (ptr->type()) 583c5f01b2fSopenharmony_ci { 584c5f01b2fSopenharmony_ci case detail::value_t::object: 585c5f01b2fSopenharmony_ci { 586c5f01b2fSopenharmony_ci if (!ptr->contains(reference_token)) 587c5f01b2fSopenharmony_ci { 588c5f01b2fSopenharmony_ci // we did not find the key in the object 589c5f01b2fSopenharmony_ci return false; 590c5f01b2fSopenharmony_ci } 591c5f01b2fSopenharmony_ci 592c5f01b2fSopenharmony_ci ptr = &ptr->operator[](reference_token); 593c5f01b2fSopenharmony_ci break; 594c5f01b2fSopenharmony_ci } 595c5f01b2fSopenharmony_ci 596c5f01b2fSopenharmony_ci case detail::value_t::array: 597c5f01b2fSopenharmony_ci { 598c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) 599c5f01b2fSopenharmony_ci { 600c5f01b2fSopenharmony_ci // "-" always fails the range check 601c5f01b2fSopenharmony_ci return false; 602c5f01b2fSopenharmony_ci } 603c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) 604c5f01b2fSopenharmony_ci { 605c5f01b2fSopenharmony_ci // invalid char 606c5f01b2fSopenharmony_ci return false; 607c5f01b2fSopenharmony_ci } 608c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) 609c5f01b2fSopenharmony_ci { 610c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) 611c5f01b2fSopenharmony_ci { 612c5f01b2fSopenharmony_ci // first char should be between '1' and '9' 613c5f01b2fSopenharmony_ci return false; 614c5f01b2fSopenharmony_ci } 615c5f01b2fSopenharmony_ci for (std::size_t i = 1; i < reference_token.size(); i++) 616c5f01b2fSopenharmony_ci { 617c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) 618c5f01b2fSopenharmony_ci { 619c5f01b2fSopenharmony_ci // other char should be between '0' and '9' 620c5f01b2fSopenharmony_ci return false; 621c5f01b2fSopenharmony_ci } 622c5f01b2fSopenharmony_ci } 623c5f01b2fSopenharmony_ci } 624c5f01b2fSopenharmony_ci 625c5f01b2fSopenharmony_ci const auto idx = array_index<BasicJsonType>(reference_token); 626c5f01b2fSopenharmony_ci if (idx >= ptr->size()) 627c5f01b2fSopenharmony_ci { 628c5f01b2fSopenharmony_ci // index out of range 629c5f01b2fSopenharmony_ci return false; 630c5f01b2fSopenharmony_ci } 631c5f01b2fSopenharmony_ci 632c5f01b2fSopenharmony_ci ptr = &ptr->operator[](idx); 633c5f01b2fSopenharmony_ci break; 634c5f01b2fSopenharmony_ci } 635c5f01b2fSopenharmony_ci 636c5f01b2fSopenharmony_ci case detail::value_t::null: 637c5f01b2fSopenharmony_ci case detail::value_t::string: 638c5f01b2fSopenharmony_ci case detail::value_t::boolean: 639c5f01b2fSopenharmony_ci case detail::value_t::number_integer: 640c5f01b2fSopenharmony_ci case detail::value_t::number_unsigned: 641c5f01b2fSopenharmony_ci case detail::value_t::number_float: 642c5f01b2fSopenharmony_ci case detail::value_t::binary: 643c5f01b2fSopenharmony_ci case detail::value_t::discarded: 644c5f01b2fSopenharmony_ci default: 645c5f01b2fSopenharmony_ci { 646c5f01b2fSopenharmony_ci // we do not expect primitive values if there is still a 647c5f01b2fSopenharmony_ci // reference token to process 648c5f01b2fSopenharmony_ci return false; 649c5f01b2fSopenharmony_ci } 650c5f01b2fSopenharmony_ci } 651c5f01b2fSopenharmony_ci } 652c5f01b2fSopenharmony_ci 653c5f01b2fSopenharmony_ci // no reference token left means we found a primitive value 654c5f01b2fSopenharmony_ci return true; 655c5f01b2fSopenharmony_ci } 656c5f01b2fSopenharmony_ci 657c5f01b2fSopenharmony_ci /*! 658c5f01b2fSopenharmony_ci @brief split the string input to reference tokens 659c5f01b2fSopenharmony_ci 660c5f01b2fSopenharmony_ci @note This function is only called by the json_pointer constructor. 661c5f01b2fSopenharmony_ci All exceptions below are documented there. 662c5f01b2fSopenharmony_ci 663c5f01b2fSopenharmony_ci @throw parse_error.107 if the pointer is not empty or begins with '/' 664c5f01b2fSopenharmony_ci @throw parse_error.108 if character '~' is not followed by '0' or '1' 665c5f01b2fSopenharmony_ci */ 666c5f01b2fSopenharmony_ci static std::vector<string_t> split(const string_t& reference_string) 667c5f01b2fSopenharmony_ci { 668c5f01b2fSopenharmony_ci std::vector<string_t> result; 669c5f01b2fSopenharmony_ci 670c5f01b2fSopenharmony_ci // special case: empty reference string -> no reference tokens 671c5f01b2fSopenharmony_ci if (reference_string.empty()) 672c5f01b2fSopenharmony_ci { 673c5f01b2fSopenharmony_ci return result; 674c5f01b2fSopenharmony_ci } 675c5f01b2fSopenharmony_ci 676c5f01b2fSopenharmony_ci // check if nonempty reference string begins with slash 677c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) 678c5f01b2fSopenharmony_ci { 679c5f01b2fSopenharmony_ci JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); 680c5f01b2fSopenharmony_ci } 681c5f01b2fSopenharmony_ci 682c5f01b2fSopenharmony_ci // extract the reference tokens: 683c5f01b2fSopenharmony_ci // - slash: position of the last read slash (or end of string) 684c5f01b2fSopenharmony_ci // - start: position after the previous slash 685c5f01b2fSopenharmony_ci for ( 686c5f01b2fSopenharmony_ci // search for the first slash after the first character 687c5f01b2fSopenharmony_ci std::size_t slash = reference_string.find_first_of('/', 1), 688c5f01b2fSopenharmony_ci // set the beginning of the first reference token 689c5f01b2fSopenharmony_ci start = 1; 690c5f01b2fSopenharmony_ci // we can stop if start == 0 (if slash == string_t::npos) 691c5f01b2fSopenharmony_ci start != 0; 692c5f01b2fSopenharmony_ci // set the beginning of the next reference token 693c5f01b2fSopenharmony_ci // (will eventually be 0 if slash == string_t::npos) 694c5f01b2fSopenharmony_ci start = (slash == string_t::npos) ? 0 : slash + 1, 695c5f01b2fSopenharmony_ci // find next slash 696c5f01b2fSopenharmony_ci slash = reference_string.find_first_of('/', start)) 697c5f01b2fSopenharmony_ci { 698c5f01b2fSopenharmony_ci // use the text between the beginning of the reference token 699c5f01b2fSopenharmony_ci // (start) and the last slash (slash). 700c5f01b2fSopenharmony_ci auto reference_token = reference_string.substr(start, slash - start); 701c5f01b2fSopenharmony_ci 702c5f01b2fSopenharmony_ci // check reference tokens are properly escaped 703c5f01b2fSopenharmony_ci for (std::size_t pos = reference_token.find_first_of('~'); 704c5f01b2fSopenharmony_ci pos != string_t::npos; 705c5f01b2fSopenharmony_ci pos = reference_token.find_first_of('~', pos + 1)) 706c5f01b2fSopenharmony_ci { 707c5f01b2fSopenharmony_ci JSON_ASSERT(reference_token[pos] == '~'); 708c5f01b2fSopenharmony_ci 709c5f01b2fSopenharmony_ci // ~ must be followed by 0 or 1 710c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || 711c5f01b2fSopenharmony_ci (reference_token[pos + 1] != '0' && 712c5f01b2fSopenharmony_ci reference_token[pos + 1] != '1'))) 713c5f01b2fSopenharmony_ci { 714c5f01b2fSopenharmony_ci JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); 715c5f01b2fSopenharmony_ci } 716c5f01b2fSopenharmony_ci } 717c5f01b2fSopenharmony_ci 718c5f01b2fSopenharmony_ci // finally, store the reference token 719c5f01b2fSopenharmony_ci detail::unescape(reference_token); 720c5f01b2fSopenharmony_ci result.push_back(reference_token); 721c5f01b2fSopenharmony_ci } 722c5f01b2fSopenharmony_ci 723c5f01b2fSopenharmony_ci return result; 724c5f01b2fSopenharmony_ci } 725c5f01b2fSopenharmony_ci 726c5f01b2fSopenharmony_ci private: 727c5f01b2fSopenharmony_ci /*! 728c5f01b2fSopenharmony_ci @param[in] reference_string the reference string to the current value 729c5f01b2fSopenharmony_ci @param[in] value the value to consider 730c5f01b2fSopenharmony_ci @param[in,out] result the result object to insert values to 731c5f01b2fSopenharmony_ci 732c5f01b2fSopenharmony_ci @note Empty objects or arrays are flattened to `null`. 733c5f01b2fSopenharmony_ci */ 734c5f01b2fSopenharmony_ci template<typename BasicJsonType> 735c5f01b2fSopenharmony_ci static void flatten(const string_t& reference_string, 736c5f01b2fSopenharmony_ci const BasicJsonType& value, 737c5f01b2fSopenharmony_ci BasicJsonType& result) 738c5f01b2fSopenharmony_ci { 739c5f01b2fSopenharmony_ci switch (value.type()) 740c5f01b2fSopenharmony_ci { 741c5f01b2fSopenharmony_ci case detail::value_t::array: 742c5f01b2fSopenharmony_ci { 743c5f01b2fSopenharmony_ci if (value.m_value.array->empty()) 744c5f01b2fSopenharmony_ci { 745c5f01b2fSopenharmony_ci // flatten empty array as null 746c5f01b2fSopenharmony_ci result[reference_string] = nullptr; 747c5f01b2fSopenharmony_ci } 748c5f01b2fSopenharmony_ci else 749c5f01b2fSopenharmony_ci { 750c5f01b2fSopenharmony_ci // iterate array and use index as reference string 751c5f01b2fSopenharmony_ci for (std::size_t i = 0; i < value.m_value.array->size(); ++i) 752c5f01b2fSopenharmony_ci { 753c5f01b2fSopenharmony_ci flatten(detail::concat(reference_string, '/', std::to_string(i)), 754c5f01b2fSopenharmony_ci value.m_value.array->operator[](i), result); 755c5f01b2fSopenharmony_ci } 756c5f01b2fSopenharmony_ci } 757c5f01b2fSopenharmony_ci break; 758c5f01b2fSopenharmony_ci } 759c5f01b2fSopenharmony_ci 760c5f01b2fSopenharmony_ci case detail::value_t::object: 761c5f01b2fSopenharmony_ci { 762c5f01b2fSopenharmony_ci if (value.m_value.object->empty()) 763c5f01b2fSopenharmony_ci { 764c5f01b2fSopenharmony_ci // flatten empty object as null 765c5f01b2fSopenharmony_ci result[reference_string] = nullptr; 766c5f01b2fSopenharmony_ci } 767c5f01b2fSopenharmony_ci else 768c5f01b2fSopenharmony_ci { 769c5f01b2fSopenharmony_ci // iterate object and use keys as reference string 770c5f01b2fSopenharmony_ci for (const auto& element : *value.m_value.object) 771c5f01b2fSopenharmony_ci { 772c5f01b2fSopenharmony_ci flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); 773c5f01b2fSopenharmony_ci } 774c5f01b2fSopenharmony_ci } 775c5f01b2fSopenharmony_ci break; 776c5f01b2fSopenharmony_ci } 777c5f01b2fSopenharmony_ci 778c5f01b2fSopenharmony_ci case detail::value_t::null: 779c5f01b2fSopenharmony_ci case detail::value_t::string: 780c5f01b2fSopenharmony_ci case detail::value_t::boolean: 781c5f01b2fSopenharmony_ci case detail::value_t::number_integer: 782c5f01b2fSopenharmony_ci case detail::value_t::number_unsigned: 783c5f01b2fSopenharmony_ci case detail::value_t::number_float: 784c5f01b2fSopenharmony_ci case detail::value_t::binary: 785c5f01b2fSopenharmony_ci case detail::value_t::discarded: 786c5f01b2fSopenharmony_ci default: 787c5f01b2fSopenharmony_ci { 788c5f01b2fSopenharmony_ci // add primitive value with its reference string 789c5f01b2fSopenharmony_ci result[reference_string] = value; 790c5f01b2fSopenharmony_ci break; 791c5f01b2fSopenharmony_ci } 792c5f01b2fSopenharmony_ci } 793c5f01b2fSopenharmony_ci } 794c5f01b2fSopenharmony_ci 795c5f01b2fSopenharmony_ci /*! 796c5f01b2fSopenharmony_ci @param[in] value flattened JSON 797c5f01b2fSopenharmony_ci 798c5f01b2fSopenharmony_ci @return unflattened JSON 799c5f01b2fSopenharmony_ci 800c5f01b2fSopenharmony_ci @throw parse_error.109 if array index is not a number 801c5f01b2fSopenharmony_ci @throw type_error.314 if value is not an object 802c5f01b2fSopenharmony_ci @throw type_error.315 if object values are not primitive 803c5f01b2fSopenharmony_ci @throw type_error.313 if value cannot be unflattened 804c5f01b2fSopenharmony_ci */ 805c5f01b2fSopenharmony_ci template<typename BasicJsonType> 806c5f01b2fSopenharmony_ci static BasicJsonType 807c5f01b2fSopenharmony_ci unflatten(const BasicJsonType& value) 808c5f01b2fSopenharmony_ci { 809c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(!value.is_object())) 810c5f01b2fSopenharmony_ci { 811c5f01b2fSopenharmony_ci JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); 812c5f01b2fSopenharmony_ci } 813c5f01b2fSopenharmony_ci 814c5f01b2fSopenharmony_ci BasicJsonType result; 815c5f01b2fSopenharmony_ci 816c5f01b2fSopenharmony_ci // iterate the JSON object values 817c5f01b2fSopenharmony_ci for (const auto& element : *value.m_value.object) 818c5f01b2fSopenharmony_ci { 819c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) 820c5f01b2fSopenharmony_ci { 821c5f01b2fSopenharmony_ci JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); 822c5f01b2fSopenharmony_ci } 823c5f01b2fSopenharmony_ci 824c5f01b2fSopenharmony_ci // assign value to reference pointed to by JSON pointer; Note that if 825c5f01b2fSopenharmony_ci // the JSON pointer is "" (i.e., points to the whole value), function 826c5f01b2fSopenharmony_ci // get_and_create returns a reference to result itself. An assignment 827c5f01b2fSopenharmony_ci // will then create a primitive value. 828c5f01b2fSopenharmony_ci json_pointer(element.first).get_and_create(result) = element.second; 829c5f01b2fSopenharmony_ci } 830c5f01b2fSopenharmony_ci 831c5f01b2fSopenharmony_ci return result; 832c5f01b2fSopenharmony_ci } 833c5f01b2fSopenharmony_ci 834c5f01b2fSopenharmony_ci // can't use conversion operator because of ambiguity 835c5f01b2fSopenharmony_ci json_pointer<string_t> convert() const& 836c5f01b2fSopenharmony_ci { 837c5f01b2fSopenharmony_ci json_pointer<string_t> result; 838c5f01b2fSopenharmony_ci result.reference_tokens = reference_tokens; 839c5f01b2fSopenharmony_ci return result; 840c5f01b2fSopenharmony_ci } 841c5f01b2fSopenharmony_ci 842c5f01b2fSopenharmony_ci json_pointer<string_t> convert()&& 843c5f01b2fSopenharmony_ci { 844c5f01b2fSopenharmony_ci json_pointer<string_t> result; 845c5f01b2fSopenharmony_ci result.reference_tokens = std::move(reference_tokens); 846c5f01b2fSopenharmony_ci return result; 847c5f01b2fSopenharmony_ci } 848c5f01b2fSopenharmony_ci 849c5f01b2fSopenharmony_ci public: 850c5f01b2fSopenharmony_ci#if JSON_HAS_THREE_WAY_COMPARISON 851c5f01b2fSopenharmony_ci /// @brief compares two JSON pointers for equality 852c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ 853c5f01b2fSopenharmony_ci template<typename RefStringTypeRhs> 854c5f01b2fSopenharmony_ci bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept 855c5f01b2fSopenharmony_ci { 856c5f01b2fSopenharmony_ci return reference_tokens == rhs.reference_tokens; 857c5f01b2fSopenharmony_ci } 858c5f01b2fSopenharmony_ci 859c5f01b2fSopenharmony_ci /// @brief compares JSON pointer and string for equality 860c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ 861c5f01b2fSopenharmony_ci JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) 862c5f01b2fSopenharmony_ci bool operator==(const string_t& rhs) const 863c5f01b2fSopenharmony_ci { 864c5f01b2fSopenharmony_ci return *this == json_pointer(rhs); 865c5f01b2fSopenharmony_ci } 866c5f01b2fSopenharmony_ci 867c5f01b2fSopenharmony_ci /// @brief 3-way compares two JSON pointers 868c5f01b2fSopenharmony_ci template<typename RefStringTypeRhs> 869c5f01b2fSopenharmony_ci std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD* 870c5f01b2fSopenharmony_ci { 871c5f01b2fSopenharmony_ci return reference_tokens <=> rhs.reference_tokens; // *NOPAD* 872c5f01b2fSopenharmony_ci } 873c5f01b2fSopenharmony_ci#else 874c5f01b2fSopenharmony_ci /// @brief compares two JSON pointers for equality 875c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ 876c5f01b2fSopenharmony_ci template<typename RefStringTypeLhs, typename RefStringTypeRhs> 877c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-redundant-declaration) 878c5f01b2fSopenharmony_ci friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs, 879c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs) noexcept; 880c5f01b2fSopenharmony_ci 881c5f01b2fSopenharmony_ci /// @brief compares JSON pointer and string for equality 882c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ 883c5f01b2fSopenharmony_ci template<typename RefStringTypeLhs, typename StringType> 884c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-redundant-declaration) 885c5f01b2fSopenharmony_ci friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs, 886c5f01b2fSopenharmony_ci const StringType& rhs); 887c5f01b2fSopenharmony_ci 888c5f01b2fSopenharmony_ci /// @brief compares string and JSON pointer for equality 889c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ 890c5f01b2fSopenharmony_ci template<typename RefStringTypeRhs, typename StringType> 891c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-redundant-declaration) 892c5f01b2fSopenharmony_ci friend bool operator==(const StringType& lhs, 893c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs); 894c5f01b2fSopenharmony_ci 895c5f01b2fSopenharmony_ci /// @brief compares two JSON pointers for inequality 896c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ 897c5f01b2fSopenharmony_ci template<typename RefStringTypeLhs, typename RefStringTypeRhs> 898c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-redundant-declaration) 899c5f01b2fSopenharmony_ci friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, 900c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs) noexcept; 901c5f01b2fSopenharmony_ci 902c5f01b2fSopenharmony_ci /// @brief compares JSON pointer and string for inequality 903c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ 904c5f01b2fSopenharmony_ci template<typename RefStringTypeLhs, typename StringType> 905c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-redundant-declaration) 906c5f01b2fSopenharmony_ci friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, 907c5f01b2fSopenharmony_ci const StringType& rhs); 908c5f01b2fSopenharmony_ci 909c5f01b2fSopenharmony_ci /// @brief compares string and JSON pointer for inequality 910c5f01b2fSopenharmony_ci /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ 911c5f01b2fSopenharmony_ci template<typename RefStringTypeRhs, typename StringType> 912c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-redundant-declaration) 913c5f01b2fSopenharmony_ci friend bool operator!=(const StringType& lhs, 914c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs); 915c5f01b2fSopenharmony_ci 916c5f01b2fSopenharmony_ci /// @brief compares two JSON pointer for less-than 917c5f01b2fSopenharmony_ci template<typename RefStringTypeLhs, typename RefStringTypeRhs> 918c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-redundant-declaration) 919c5f01b2fSopenharmony_ci friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs, 920c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs) noexcept; 921c5f01b2fSopenharmony_ci#endif 922c5f01b2fSopenharmony_ci 923c5f01b2fSopenharmony_ci private: 924c5f01b2fSopenharmony_ci /// the reference tokens 925c5f01b2fSopenharmony_ci std::vector<string_t> reference_tokens; 926c5f01b2fSopenharmony_ci}; 927c5f01b2fSopenharmony_ci 928c5f01b2fSopenharmony_ci#if !JSON_HAS_THREE_WAY_COMPARISON 929c5f01b2fSopenharmony_ci// functions cannot be defined inside class due to ODR violations 930c5f01b2fSopenharmony_citemplate<typename RefStringTypeLhs, typename RefStringTypeRhs> 931c5f01b2fSopenharmony_ciinline bool operator==(const json_pointer<RefStringTypeLhs>& lhs, 932c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs) noexcept 933c5f01b2fSopenharmony_ci{ 934c5f01b2fSopenharmony_ci return lhs.reference_tokens == rhs.reference_tokens; 935c5f01b2fSopenharmony_ci} 936c5f01b2fSopenharmony_ci 937c5f01b2fSopenharmony_citemplate<typename RefStringTypeLhs, 938c5f01b2fSopenharmony_ci typename StringType = typename json_pointer<RefStringTypeLhs>::string_t> 939c5f01b2fSopenharmony_ciJSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) 940c5f01b2fSopenharmony_ciinline bool operator==(const json_pointer<RefStringTypeLhs>& lhs, 941c5f01b2fSopenharmony_ci const StringType& rhs) 942c5f01b2fSopenharmony_ci{ 943c5f01b2fSopenharmony_ci return lhs == json_pointer<RefStringTypeLhs>(rhs); 944c5f01b2fSopenharmony_ci} 945c5f01b2fSopenharmony_ci 946c5f01b2fSopenharmony_citemplate<typename RefStringTypeRhs, 947c5f01b2fSopenharmony_ci typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> 948c5f01b2fSopenharmony_ciJSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) 949c5f01b2fSopenharmony_ciinline bool operator==(const StringType& lhs, 950c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs) 951c5f01b2fSopenharmony_ci{ 952c5f01b2fSopenharmony_ci return json_pointer<RefStringTypeRhs>(lhs) == rhs; 953c5f01b2fSopenharmony_ci} 954c5f01b2fSopenharmony_ci 955c5f01b2fSopenharmony_citemplate<typename RefStringTypeLhs, typename RefStringTypeRhs> 956c5f01b2fSopenharmony_ciinline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, 957c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs) noexcept 958c5f01b2fSopenharmony_ci{ 959c5f01b2fSopenharmony_ci return !(lhs == rhs); 960c5f01b2fSopenharmony_ci} 961c5f01b2fSopenharmony_ci 962c5f01b2fSopenharmony_citemplate<typename RefStringTypeLhs, 963c5f01b2fSopenharmony_ci typename StringType = typename json_pointer<RefStringTypeLhs>::string_t> 964c5f01b2fSopenharmony_ciJSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) 965c5f01b2fSopenharmony_ciinline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, 966c5f01b2fSopenharmony_ci const StringType& rhs) 967c5f01b2fSopenharmony_ci{ 968c5f01b2fSopenharmony_ci return !(lhs == rhs); 969c5f01b2fSopenharmony_ci} 970c5f01b2fSopenharmony_ci 971c5f01b2fSopenharmony_citemplate<typename RefStringTypeRhs, 972c5f01b2fSopenharmony_ci typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> 973c5f01b2fSopenharmony_ciJSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) 974c5f01b2fSopenharmony_ciinline bool operator!=(const StringType& lhs, 975c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs) 976c5f01b2fSopenharmony_ci{ 977c5f01b2fSopenharmony_ci return !(lhs == rhs); 978c5f01b2fSopenharmony_ci} 979c5f01b2fSopenharmony_ci 980c5f01b2fSopenharmony_citemplate<typename RefStringTypeLhs, typename RefStringTypeRhs> 981c5f01b2fSopenharmony_ciinline bool operator<(const json_pointer<RefStringTypeLhs>& lhs, 982c5f01b2fSopenharmony_ci const json_pointer<RefStringTypeRhs>& rhs) noexcept 983c5f01b2fSopenharmony_ci{ 984c5f01b2fSopenharmony_ci return lhs.reference_tokens < rhs.reference_tokens; 985c5f01b2fSopenharmony_ci} 986c5f01b2fSopenharmony_ci#endif 987c5f01b2fSopenharmony_ci 988c5f01b2fSopenharmony_ciNLOHMANN_JSON_NAMESPACE_END 989