// __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ // | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2013-2026 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once #include // all_of #include // isdigit #include // errno, ERANGE #include // strtoull #ifndef JSON_NO_IO #include // ostream #endif // JSON_NO_IO #include // max #include // accumulate #include // set #include // string #include // move #include // vector #include #include #include #include #include NLOHMANN_JSON_NAMESPACE_BEGIN /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document /// @sa https://json.nlohmann.me/api/json_pointer/ template class json_pointer { // allow basic_json to access private members NLOHMANN_BASIC_JSON_TPL_DECLARATION friend class basic_json; template friend class json_pointer; template struct string_t_helper { using type = T; }; NLOHMANN_BASIC_JSON_TPL_DECLARATION struct string_t_helper { using type = StringType; }; public: // for backwards compatibility accept BasicJsonType using string_t = typename string_t_helper::type; /// @brief create JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ explicit json_pointer(const string_t& s = "") : reference_tokens(split(s)) {} /// @brief return a string representation of the JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/to_string/ string_t to_string() const { return std::accumulate(reference_tokens.begin(), reference_tokens.end(), string_t{}, [](const string_t& a, const string_t& b) { return detail::concat(a, '/', detail::escape(b)); }); } /// @brief return a string representation of the JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/ JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) operator string_t() const { return to_string(); } #ifndef JSON_NO_IO /// @brief write string representation of the JSON pointer to stream /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr) { o << ptr.to_string(); return o; } #endif /// @brief append another JSON pointer at the end of this JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ json_pointer& operator/=(const json_pointer& ptr) { reference_tokens.insert(reference_tokens.end(), ptr.reference_tokens.begin(), ptr.reference_tokens.end()); return *this; } /// @brief append an unescaped reference token at the end of this JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ json_pointer& operator/=(string_t token) { push_back(std::move(token)); return *this; } /// @brief append an array index at the end of this JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ json_pointer& operator/=(std::size_t array_idx) { return *this /= std::to_string(array_idx); } /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ friend json_pointer operator/(const json_pointer& lhs, const json_pointer& rhs) { return json_pointer(lhs) /= rhs; } /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param) { return json_pointer(lhs) /= std::move(token); } /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx) { return json_pointer(lhs) /= array_idx; } /// @brief returns the parent of this JSON pointer /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/ json_pointer parent_pointer() const { if (empty()) { return *this; } json_pointer res = *this; res.pop_back(); return res; } /// @brief remove first reference token /// @sa https://json.nlohmann.me/api/json_pointer/pop_front/ void pop_front() { if (JSON_HEDLEY_UNLIKELY(empty())) { JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); } reference_tokens.erase(reference_tokens.begin()); } /// @brief return first reference token /// @sa https://json.nlohmann.me/api/json_pointer/front/ const string_t& front() const { if (JSON_HEDLEY_UNLIKELY(empty())) { JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); } return reference_tokens.front(); } /// @brief append an unescaped token at the start of the reference pointer /// @sa https://json.nlohmann.me/api/json_pointer/push_front/ void push_front(const string_t& token) { reference_tokens.insert(reference_tokens.begin(), token); } /// @brief append an unescaped token at the start of the reference pointer /// @sa https://json.nlohmann.me/api/json_pointer/push_front/ void push_front(string_t&& token) { reference_tokens.insert(reference_tokens.begin(), std::move(token)); } /// @brief remove last reference token /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/ void pop_back() { if (JSON_HEDLEY_UNLIKELY(empty())) { JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); } reference_tokens.pop_back(); } /// @brief return last reference token /// @sa https://json.nlohmann.me/api/json_pointer/back/ const string_t& back() const { if (JSON_HEDLEY_UNLIKELY(empty())) { JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); } return reference_tokens.back(); } /// @brief append an unescaped token at the end of the reference pointer /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ void push_back(const string_t& token) { reference_tokens.push_back(token); } /// @brief append an unescaped token at the end of the reference pointer /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ void push_back(string_t&& token) { reference_tokens.push_back(std::move(token)); } /// @brief return whether pointer points to the root document /// @sa https://json.nlohmann.me/api/json_pointer/empty/ bool empty() const noexcept { return reference_tokens.empty(); } private: /*! @param[in] s reference token to be converted into an array index @return integer representation of @a s @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index begins not with a digit @throw out_of_range.404 if string @a s could not be converted to an integer @throw out_of_range.410 if an array index exceeds size_type */ template static typename BasicJsonType::size_type array_index(const string_t& s) { using size_type = typename BasicJsonType::size_type; // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) { JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); } // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) { JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); } const char* p = s.c_str(); char* p_end = nullptr; // NOLINT(misc-const-correctness) errno = 0; // strtoull doesn't reset errno const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) if (p == p_end // invalid input or empty string || errno == ERANGE // out of range || JSON_HEDLEY_UNLIKELY(static_cast(p_end - p) != s.size())) // incomplete read { JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr)); } // only triggered on special platforms (like 32bit), see also // https://github.com/nlohmann/json/pull/2203 if (res >= static_cast((std::numeric_limits::max)())) // NOLINT(runtime/int) { JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE } return static_cast(res); } JSON_PRIVATE_UNLESS_TESTED: json_pointer top() const { if (JSON_HEDLEY_UNLIKELY(empty())) { JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); } json_pointer result = *this; result.reference_tokens = {reference_tokens[0]}; return result; } private: /*! @brief the reference token sequences that denote arrays @ref unflatten collects the pointer prefixes that have a reference token 0 among their children; @ref get_and_create creates arrays exactly below those prefixes and objects everywhere else. Deciding this up front keeps the result independent of the order in which the flattened object is iterated, which is unspecified for some object types. */ using array_parents_t = std::set>; /*! @brief create and return a reference to the pointed to value @complexity Linear in the number of reference tokens. @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if array index is not a number @throw type_error.313 if value cannot be unflattened */ template BasicJsonType& get_and_create(BasicJsonType& j, const array_parents_t& array_parents) const { auto* result = &j; // the reference tokens that have been consumed so far; used to look up // whether the value to be created below is an array or an object std::vector prefix; // in case no reference tokens exist, return a reference to the JSON value // j which will be overwritten by a primitive value for (const auto& reference_token : reference_tokens) { switch (result->type()) { case detail::value_t::null: { if (array_parents.find(prefix) != array_parents.end()) { // some reference token below this position is 0, so the // value is an array result = &result->operator[](array_index(reference_token)); } else { // start a new object otherwise result = &result->operator[](reference_token); } break; } case detail::value_t::object: { // create an entry in the object result = &result->operator[](reference_token); break; } case detail::value_t::array: { // create an entry in the array result = &result->operator[](array_index(reference_token)); break; } /* The following code is only reached if there exists a reference token _and_ the current value is primitive. In this case, we have an error situation, because primitive values may only occur as a single value; that is, with an empty list of reference tokens. */ case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); } prefix.push_back(reference_token); } return *result; } /*! @brief return a reference to the pointed to value @note This version does not throw if a value is not present, but tries to create nested values instead. For instance, calling this function with pointer `"/this/that"` on a null value is equivalent to calling `operator[]("this").operator[]("that")` on that value, effectively changing the null value to an object. @param[in] ptr a JSON value @return reference to the JSON value pointed to by the JSON pointer @complexity Linear in the length of the JSON pointer. @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.404 if the JSON pointer can not be resolved */ template BasicJsonType& get_unchecked(BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { // convert null values to arrays or objects before continuing if (ptr->is_null()) { // check if the reference token is a number const bool nums = std::all_of(reference_token.begin(), reference_token.end(), [](const unsigned char x) { return std::isdigit(x); }); // change value to an array for numbers or "-" or to object otherwise *ptr = (nums || reference_token == "-") ? detail::value_t::array : detail::value_t::object; } switch (ptr->type()) { case detail::value_t::object: { // use unchecked object access ptr = &ptr->operator[](reference_token); break; } case detail::value_t::array: { if (reference_token == "-") { // explicitly treat "-" as index beyond the end ptr = &ptr->operator[](ptr->m_data.m_value.array->size()); } else { // convert array index to number; unchecked access ptr = &ptr->operator[](array_index(reference_token)); } break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); } } return *ptr; } /*! @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.402 if the array index '-' is used @throw out_of_range.404 if the JSON pointer can not be resolved */ template BasicJsonType& get_checked(BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { // note: at performs range check ptr = &ptr->at(reference_token); break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check JSON_THROW(detail::out_of_range::create(402, detail::concat( "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } const auto idx = array_index(reference_token); // Bounds check before access to avoid exception with JSON_NOEXCEPTION if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size())) { JSON_THROW(detail::out_of_range::create(401, detail::concat( "array index ", std::to_string(idx), " is out of range"), ptr)); } ptr = &ptr->operator[](idx); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); } } return *ptr; } /*! @brief return a const reference to the pointed to value @param[in] ptr a JSON value @return const reference to the JSON value pointed to by the JSON pointer @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.402 if the array index '-' is used @throw out_of_range.404 if the JSON pointer can not be resolved */ template const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { // use unchecked object access ptr = &ptr->operator[](reference_token); break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" cannot be used for const access JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } // use unchecked array access ptr = &ptr->operator[](array_index(reference_token)); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); } } return *ptr; } /*! @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.402 if the array index '-' is used @throw out_of_range.404 if the JSON pointer can not be resolved */ template const BasicJsonType& get_checked(const BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { // note: at performs range check ptr = &ptr->at(reference_token); break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check JSON_THROW(detail::out_of_range::create(402, detail::concat( "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } const auto idx = array_index(reference_token); // Bounds check before access to avoid exception with JSON_NOEXCEPTION if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size())) { JSON_THROW(detail::out_of_range::create(401, detail::concat( "array index ", std::to_string(idx), " is out of range"), ptr)); } ptr = &ptr->operator[](idx); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); } } return *ptr; } /*! @brief return a pointer to the pointed to value, or `nullptr` if the pointer cannot be resolved because a key is missing, an array index is out of range, or the array index is "-" @note unlike get_checked(), this never throws for those cases, so it can be used to implement a non-throwing fallback (e.g. value()) that also works when exceptions are disabled @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number */ template const BasicJsonType* get_checked_or_null(const BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { const auto it = ptr->find(reference_token); if (JSON_HEDLEY_UNLIKELY(it == ptr->end())) { return nullptr; } ptr = &*it; break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check return nullptr; } // may throw parse_error.106/109 for a malformed index; an // index that is syntactically valid but cannot be // represented (out_of_range.404/410) is treated like an // out-of-range index below typename BasicJsonType::size_type idx{}; JSON_TRY { idx = array_index(reference_token); } JSON_INTERNAL_CATCH (detail::out_of_range&) { return nullptr; } if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size())) { return nullptr; } ptr = &ptr->operator[](idx); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: return nullptr; } } return ptr; } /*! @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number */ template bool contains(const BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { if (!ptr->contains(reference_token)) { // we did not find the key in the object return false; } ptr = &ptr->operator[](reference_token); break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check return false; } if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) { // invalid char return false; } if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) { if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) { // the first char should be between '1' and '9' return false; } for (std::size_t i = 1; i < reference_token.size(); i++) { if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) { // other char should be between '0' and '9' return false; } } } const auto idx = array_index(reference_token); if (idx >= ptr->size()) { // index out of range return false; } ptr = &ptr->operator[](idx); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: { // we do not expect primitive values if there is still a // reference token to process return false; } } } // no reference token left means we found a primitive value return true; } /*! @brief split the string input to reference tokens @note This function is only called by the json_pointer constructor. All exceptions below are documented there. @throw parse_error.107 if the pointer is not empty or begins with '/' @throw parse_error.108 if character '~' is not followed by '0' or '1' */ static std::vector split(const string_t& reference_string) { std::vector result; // special case: empty reference string -> no reference tokens if (reference_string.empty()) { return result; } // check if a nonempty reference string begins with slash if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) { JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); } // extract the reference tokens: // - slash: position of the last read slash (or end of string) // - start: position after the previous slash for ( // search for the first slash after the first character std::size_t slash = reference_string.find_first_of('/', 1), // set the beginning of the first reference token start = 1; // we can stop if start == 0 (if slash == string_t::npos) start != 0; // set the beginning of the next reference token // (will eventually be 0 if slash == string_t::npos) start = (slash == string_t::npos) ? 0 : slash + 1, // find next slash slash = reference_string.find_first_of('/', start)) { // use the text between the beginning of the reference token // (start) and the last slash (slash). auto reference_token = reference_string.substr(start, slash - start); // check reference tokens are properly escaped for (std::size_t pos = reference_token.find_first_of('~'); pos != string_t::npos; pos = reference_token.find_first_of('~', pos + 1)) { JSON_ASSERT(reference_token[pos] == '~'); // ~ must be followed by 0 or 1 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || (reference_token[pos + 1] != '0' && reference_token[pos + 1] != '1'))) { JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); } } // finally, store the reference token detail::unescape(reference_token); result.push_back(reference_token); } return result; } private: /*! @param[in] reference_string the reference string to the current value @param[in] value the value to consider @param[in,out] result the result object to insert values to @note Empty objects or arrays are flattened to `null`. */ template static void flatten(const string_t& reference_string, const BasicJsonType& value, BasicJsonType& result) { switch (value.type()) { case detail::value_t::array: { if (value.m_data.m_value.array->empty()) { // flatten empty array as null result[reference_string] = nullptr; } else { // iterate array and use index as a reference string for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) { flatten(detail::concat(reference_string, '/', std::to_string(i)), value.m_data.m_value.array->operator[](i), result); } } break; } case detail::value_t::object: { if (value.m_data.m_value.object->empty()) { // flatten empty object as null result[reference_string] = nullptr; } else { // iterate object and use keys as reference string for (const auto& element : *value.m_data.m_value.object) { flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); } } break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: { // add a primitive value with its reference string result[reference_string] = value; break; } } } /*! @param[in] value flattened JSON @return unflattened JSON @throw parse_error.109 if array index is not a number @throw type_error.314 if value is not an object @throw type_error.315 if object values are not primitive @throw type_error.313 if value cannot be unflattened */ template static BasicJsonType unflatten(const BasicJsonType& value) { if (JSON_HEDLEY_UNLIKELY(!value.is_object())) { JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); } BasicJsonType result; // collect the pointer prefixes that have a reference token 0 among // their children; the values below them are arrays, all others are // objects (see array_parents_t) array_parents_t array_parents; for (const auto& element : *value.m_data.m_value.object) { json_pointer ptr(element.first); std::vector prefix; for (auto& reference_token : ptr.reference_tokens) { if (reference_token == "0") { array_parents.insert(prefix); } prefix.push_back(std::move(reference_token)); } } // iterate the JSON object values for (const auto& element : *value.m_data.m_value.object) { if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) { JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); } // Assign the value to the reference pointed to by JSON pointer. Note // that if the JSON pointer is "" (i.e., points to the whole value), // function get_and_create returns a reference to the result itself. // An assignment will then create a primitive value. json_pointer(element.first).get_and_create(result, array_parents) = element.second; } return result; } // can't use the conversion operator because of ambiguity json_pointer convert() const& { json_pointer result; result.reference_tokens = reference_tokens; return result; } json_pointer convert()&& { json_pointer result; result.reference_tokens = std::move(reference_tokens); return result; } public: #if JSON_HAS_THREE_WAY_COMPARISON /// @brief compares two JSON pointers for equality /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ template bool operator==(const json_pointer& rhs) const noexcept { return reference_tokens == rhs.reference_tokens; } /// @brief compares JSON pointer and string for equality /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) bool operator==(const string_t& rhs) const { return *this == json_pointer(rhs); } /// @brief 3-way compares two JSON pointers template std::strong_ordering operator<=>(const json_pointer& rhs) const noexcept // *NOPAD* { return reference_tokens <=> rhs.reference_tokens; // *NOPAD* } #else /// @brief compares two JSON pointers for equality /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ template // NOLINTNEXTLINE(readability-redundant-declaration) friend bool operator==(const json_pointer& lhs, const json_pointer& rhs) noexcept; /// @brief compares JSON pointer and string for equality /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ template // NOLINTNEXTLINE(readability-redundant-declaration) friend bool operator==(const json_pointer& lhs, const StringType& rhs); /// @brief compares string and JSON pointer for equality /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ template // NOLINTNEXTLINE(readability-redundant-declaration) friend bool operator==(const StringType& lhs, const json_pointer& rhs); /// @brief compares two JSON pointers for inequality /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ template // NOLINTNEXTLINE(readability-redundant-declaration) friend bool operator!=(const json_pointer& lhs, const json_pointer& rhs) noexcept; /// @brief compares JSON pointer and string for inequality /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ template // NOLINTNEXTLINE(readability-redundant-declaration) friend bool operator!=(const json_pointer& lhs, const StringType& rhs); /// @brief compares string and JSON pointer for inequality /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ template // NOLINTNEXTLINE(readability-redundant-declaration) friend bool operator!=(const StringType& lhs, const json_pointer& rhs); /// @brief compares two JSON pointer for less-than template // NOLINTNEXTLINE(readability-redundant-declaration) friend bool operator<(const json_pointer& lhs, const json_pointer& rhs) noexcept; #endif private: /// the reference tokens std::vector reference_tokens; }; #if !JSON_HAS_THREE_WAY_COMPARISON // functions cannot be defined inside the class due to ODR violations template inline bool operator==(const json_pointer& lhs, const json_pointer& rhs) noexcept { return lhs.reference_tokens == rhs.reference_tokens; } template::string_t> JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) inline bool operator==(const json_pointer& lhs, const StringType& rhs) { return lhs == json_pointer(rhs); } template::string_t> JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) inline bool operator==(const StringType& lhs, const json_pointer& rhs) { return json_pointer(lhs) == rhs; } template inline bool operator!=(const json_pointer& lhs, const json_pointer& rhs) noexcept { return !(lhs == rhs); } template::string_t> JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) inline bool operator!=(const json_pointer& lhs, const StringType& rhs) { return !(lhs == rhs); } template::string_t> JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) inline bool operator!=(const StringType& lhs, const json_pointer& rhs) { return !(lhs == rhs); } template inline bool operator<(const json_pointer& lhs, const json_pointer& rhs) noexcept { return lhs.reference_tokens < rhs.reference_tokens; } #endif NLOHMANN_JSON_NAMESPACE_END