Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-03-13 09:15:36

0001 //     __ _____ _____ _____
0002 //  __|  |   __|     |   | |  JSON for Modern C++
0003 // |  |  |__   |  |  | | | |  version 3.11.2
0004 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
0005 //
0006 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
0007 // SPDX-License-Identifier: MIT
0008 
0009 #pragma once
0010 
0011 #include <algorithm> // all_of
0012 #include <cctype> // isdigit
0013 #include <cerrno> // errno, ERANGE
0014 #include <cstdlib> // strtoull
0015 #ifndef JSON_NO_IO
0016     #include <iosfwd> // ostream
0017 #endif  // JSON_NO_IO
0018 #include <limits> // max
0019 #include <numeric> // accumulate
0020 #include <string> // string
0021 #include <utility> // move
0022 #include <vector> // vector
0023 
0024 #include <nlohmann/detail/exceptions.hpp>
0025 #include <nlohmann/detail/macro_scope.hpp>
0026 #include <nlohmann/detail/string_concat.hpp>
0027 #include <nlohmann/detail/string_escape.hpp>
0028 #include <nlohmann/detail/value_t.hpp>
0029 
0030 NLOHMANN_JSON_NAMESPACE_BEGIN
0031 
0032 /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
0033 /// @sa https://json.nlohmann.me/api/json_pointer/
0034 template<typename RefStringType>
0035 class json_pointer
0036 {
0037     // allow basic_json to access private members
0038     NLOHMANN_BASIC_JSON_TPL_DECLARATION
0039     friend class basic_json;
0040 
0041     template<typename>
0042     friend class json_pointer;
0043 
0044     template<typename T>
0045     struct string_t_helper
0046     {
0047         using type = T;
0048     };
0049 
0050     NLOHMANN_BASIC_JSON_TPL_DECLARATION
0051     struct string_t_helper<NLOHMANN_BASIC_JSON_TPL>
0052     {
0053         using type = StringType;
0054     };
0055 
0056   public:
0057     // for backwards compatibility accept BasicJsonType
0058     using string_t = typename string_t_helper<RefStringType>::type;
0059 
0060     /// @brief create JSON pointer
0061     /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/
0062     explicit json_pointer(const string_t& s = "")
0063         : reference_tokens(split(s))
0064     {}
0065 
0066     /// @brief return a string representation of the JSON pointer
0067     /// @sa https://json.nlohmann.me/api/json_pointer/to_string/
0068     string_t to_string() const
0069     {
0070         return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
0071                                string_t{},
0072                                [](const string_t& a, const string_t& b)
0073         {
0074             return detail::concat(a, '/', detail::escape(b));
0075         });
0076     }
0077 
0078     /// @brief return a string representation of the JSON pointer
0079     /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/
0080     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
0081     operator string_t() const
0082     {
0083         return to_string();
0084     }
0085 
0086 #ifndef JSON_NO_IO
0087     /// @brief write string representation of the JSON pointer to stream
0088     /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
0089     friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
0090     {
0091         o << ptr.to_string();
0092         return o;
0093     }
0094 #endif
0095 
0096     /// @brief append another JSON pointer at the end of this JSON pointer
0097     /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
0098     json_pointer& operator/=(const json_pointer& ptr)
0099     {
0100         reference_tokens.insert(reference_tokens.end(),
0101                                 ptr.reference_tokens.begin(),
0102                                 ptr.reference_tokens.end());
0103         return *this;
0104     }
0105 
0106     /// @brief append an unescaped reference token at the end of this JSON pointer
0107     /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
0108     json_pointer& operator/=(string_t token)
0109     {
0110         push_back(std::move(token));
0111         return *this;
0112     }
0113 
0114     /// @brief append an array index at the end of this JSON pointer
0115     /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
0116     json_pointer& operator/=(std::size_t array_idx)
0117     {
0118         return *this /= std::to_string(array_idx);
0119     }
0120 
0121     /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
0122     /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
0123     friend json_pointer operator/(const json_pointer& lhs,
0124                                   const json_pointer& rhs)
0125     {
0126         return json_pointer(lhs) /= rhs;
0127     }
0128 
0129     /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
0130     /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
0131     friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)
0132     {
0133         return json_pointer(lhs) /= std::move(token);
0134     }
0135 
0136     /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
0137     /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
0138     friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)
0139     {
0140         return json_pointer(lhs) /= array_idx;
0141     }
0142 
0143     /// @brief returns the parent of this JSON pointer
0144     /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/
0145     json_pointer parent_pointer() const
0146     {
0147         if (empty())
0148         {
0149             return *this;
0150         }
0151 
0152         json_pointer res = *this;
0153         res.pop_back();
0154         return res;
0155     }
0156 
0157     /// @brief remove last reference token
0158     /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/
0159     void pop_back()
0160     {
0161         if (JSON_HEDLEY_UNLIKELY(empty()))
0162         {
0163             JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
0164         }
0165 
0166         reference_tokens.pop_back();
0167     }
0168 
0169     /// @brief return last reference token
0170     /// @sa https://json.nlohmann.me/api/json_pointer/back/
0171     const string_t& back() const
0172     {
0173         if (JSON_HEDLEY_UNLIKELY(empty()))
0174         {
0175             JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
0176         }
0177 
0178         return reference_tokens.back();
0179     }
0180 
0181     /// @brief append an unescaped token at the end of the reference pointer
0182     /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
0183     void push_back(const string_t& token)
0184     {
0185         reference_tokens.push_back(token);
0186     }
0187 
0188     /// @brief append an unescaped token at the end of the reference pointer
0189     /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
0190     void push_back(string_t&& token)
0191     {
0192         reference_tokens.push_back(std::move(token));
0193     }
0194 
0195     /// @brief return whether pointer points to the root document
0196     /// @sa https://json.nlohmann.me/api/json_pointer/empty/
0197     bool empty() const noexcept
0198     {
0199         return reference_tokens.empty();
0200     }
0201 
0202   private:
0203     /*!
0204     @param[in] s  reference token to be converted into an array index
0205 
0206     @return integer representation of @a s
0207 
0208     @throw parse_error.106  if an array index begins with '0'
0209     @throw parse_error.109  if an array index begins not with a digit
0210     @throw out_of_range.404 if string @a s could not be converted to an integer
0211     @throw out_of_range.410 if an array index exceeds size_type
0212     */
0213     template<typename BasicJsonType>
0214     static typename BasicJsonType::size_type array_index(const string_t& s)
0215     {
0216         using size_type = typename BasicJsonType::size_type;
0217 
0218         // error condition (cf. RFC 6901, Sect. 4)
0219         if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
0220         {
0221             JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
0222         }
0223 
0224         // error condition (cf. RFC 6901, Sect. 4)
0225         if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
0226         {
0227             JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
0228         }
0229 
0230         const char* p = s.c_str();
0231         char* p_end = nullptr;
0232         errno = 0; // strtoull doesn't reset errno
0233         unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
0234         if (p == p_end // invalid input or empty string
0235                 || errno == ERANGE // out of range
0236                 || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
0237         {
0238             JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
0239         }
0240 
0241         // only triggered on special platforms (like 32bit), see also
0242         // https://github.com/nlohmann/json/pull/2203
0243         if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))  // NOLINT(runtime/int)
0244         {
0245             JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr));   // LCOV_EXCL_LINE
0246         }
0247 
0248         return static_cast<size_type>(res);
0249     }
0250 
0251   JSON_PRIVATE_UNLESS_TESTED:
0252     json_pointer top() const
0253     {
0254         if (JSON_HEDLEY_UNLIKELY(empty()))
0255         {
0256             JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
0257         }
0258 
0259         json_pointer result = *this;
0260         result.reference_tokens = {reference_tokens[0]};
0261         return result;
0262     }
0263 
0264   private:
0265     /*!
0266     @brief create and return a reference to the pointed to value
0267 
0268     @complexity Linear in the number of reference tokens.
0269 
0270     @throw parse_error.109 if array index is not a number
0271     @throw type_error.313 if value cannot be unflattened
0272     */
0273     template<typename BasicJsonType>
0274     BasicJsonType& get_and_create(BasicJsonType& j) const
0275     {
0276         auto* result = &j;
0277 
0278         // in case no reference tokens exist, return a reference to the JSON value
0279         // j which will be overwritten by a primitive value
0280         for (const auto& reference_token : reference_tokens)
0281         {
0282             switch (result->type())
0283             {
0284                 case detail::value_t::null:
0285                 {
0286                     if (reference_token == "0")
0287                     {
0288                         // start a new array if reference token is 0
0289                         result = &result->operator[](0);
0290                     }
0291                     else
0292                     {
0293                         // start a new object otherwise
0294                         result = &result->operator[](reference_token);
0295                     }
0296                     break;
0297                 }
0298 
0299                 case detail::value_t::object:
0300                 {
0301                     // create an entry in the object
0302                     result = &result->operator[](reference_token);
0303                     break;
0304                 }
0305 
0306                 case detail::value_t::array:
0307                 {
0308                     // create an entry in the array
0309                     result = &result->operator[](array_index<BasicJsonType>(reference_token));
0310                     break;
0311                 }
0312 
0313                 /*
0314                 The following code is only reached if there exists a reference
0315                 token _and_ the current value is primitive. In this case, we have
0316                 an error situation, because primitive values may only occur as
0317                 single value; that is, with an empty list of reference tokens.
0318                 */
0319                 case detail::value_t::string:
0320                 case detail::value_t::boolean:
0321                 case detail::value_t::number_integer:
0322                 case detail::value_t::number_unsigned:
0323                 case detail::value_t::number_float:
0324                 case detail::value_t::binary:
0325                 case detail::value_t::discarded:
0326                 default:
0327                     JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
0328             }
0329         }
0330 
0331         return *result;
0332     }
0333 
0334     /*!
0335     @brief return a reference to the pointed to value
0336 
0337     @note This version does not throw if a value is not present, but tries to
0338           create nested values instead. For instance, calling this function
0339           with pointer `"/this/that"` on a null value is equivalent to calling
0340           `operator[]("this").operator[]("that")` on that value, effectively
0341           changing the null value to an object.
0342 
0343     @param[in] ptr  a JSON value
0344 
0345     @return reference to the JSON value pointed to by the JSON pointer
0346 
0347     @complexity Linear in the length of the JSON pointer.
0348 
0349     @throw parse_error.106   if an array index begins with '0'
0350     @throw parse_error.109   if an array index was not a number
0351     @throw out_of_range.404  if the JSON pointer can not be resolved
0352     */
0353     template<typename BasicJsonType>
0354     BasicJsonType& get_unchecked(BasicJsonType* ptr) const
0355     {
0356         for (const auto& reference_token : reference_tokens)
0357         {
0358             // convert null values to arrays or objects before continuing
0359             if (ptr->is_null())
0360             {
0361                 // check if reference token is a number
0362                 const bool nums =
0363                     std::all_of(reference_token.begin(), reference_token.end(),
0364                                 [](const unsigned char x)
0365                 {
0366                     return std::isdigit(x);
0367                 });
0368 
0369                 // change value to array for numbers or "-" or to object otherwise
0370                 *ptr = (nums || reference_token == "-")
0371                        ? detail::value_t::array
0372                        : detail::value_t::object;
0373             }
0374 
0375             switch (ptr->type())
0376             {
0377                 case detail::value_t::object:
0378                 {
0379                     // use unchecked object access
0380                     ptr = &ptr->operator[](reference_token);
0381                     break;
0382                 }
0383 
0384                 case detail::value_t::array:
0385                 {
0386                     if (reference_token == "-")
0387                     {
0388                         // explicitly treat "-" as index beyond the end
0389                         ptr = &ptr->operator[](ptr->m_value.array->size());
0390                     }
0391                     else
0392                     {
0393                         // convert array index to number; unchecked access
0394                         ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
0395                     }
0396                     break;
0397                 }
0398 
0399                 case detail::value_t::null:
0400                 case detail::value_t::string:
0401                 case detail::value_t::boolean:
0402                 case detail::value_t::number_integer:
0403                 case detail::value_t::number_unsigned:
0404                 case detail::value_t::number_float:
0405                 case detail::value_t::binary:
0406                 case detail::value_t::discarded:
0407                 default:
0408                     JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
0409             }
0410         }
0411 
0412         return *ptr;
0413     }
0414 
0415     /*!
0416     @throw parse_error.106   if an array index begins with '0'
0417     @throw parse_error.109   if an array index was not a number
0418     @throw out_of_range.402  if the array index '-' is used
0419     @throw out_of_range.404  if the JSON pointer can not be resolved
0420     */
0421     template<typename BasicJsonType>
0422     BasicJsonType& get_checked(BasicJsonType* ptr) const
0423     {
0424         for (const auto& reference_token : reference_tokens)
0425         {
0426             switch (ptr->type())
0427             {
0428                 case detail::value_t::object:
0429                 {
0430                     // note: at performs range check
0431                     ptr = &ptr->at(reference_token);
0432                     break;
0433                 }
0434 
0435                 case detail::value_t::array:
0436                 {
0437                     if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
0438                     {
0439                         // "-" always fails the range check
0440                         JSON_THROW(detail::out_of_range::create(402, detail::concat(
0441                                 "array index '-' (", std::to_string(ptr->m_value.array->size()),
0442                                 ") is out of range"), ptr));
0443                     }
0444 
0445                     // note: at performs range check
0446                     ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
0447                     break;
0448                 }
0449 
0450                 case detail::value_t::null:
0451                 case detail::value_t::string:
0452                 case detail::value_t::boolean:
0453                 case detail::value_t::number_integer:
0454                 case detail::value_t::number_unsigned:
0455                 case detail::value_t::number_float:
0456                 case detail::value_t::binary:
0457                 case detail::value_t::discarded:
0458                 default:
0459                     JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
0460             }
0461         }
0462 
0463         return *ptr;
0464     }
0465 
0466     /*!
0467     @brief return a const reference to the pointed to value
0468 
0469     @param[in] ptr  a JSON value
0470 
0471     @return const reference to the JSON value pointed to by the JSON
0472     pointer
0473 
0474     @throw parse_error.106   if an array index begins with '0'
0475     @throw parse_error.109   if an array index was not a number
0476     @throw out_of_range.402  if the array index '-' is used
0477     @throw out_of_range.404  if the JSON pointer can not be resolved
0478     */
0479     template<typename BasicJsonType>
0480     const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
0481     {
0482         for (const auto& reference_token : reference_tokens)
0483         {
0484             switch (ptr->type())
0485             {
0486                 case detail::value_t::object:
0487                 {
0488                     // use unchecked object access
0489                     ptr = &ptr->operator[](reference_token);
0490                     break;
0491                 }
0492 
0493                 case detail::value_t::array:
0494                 {
0495                     if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
0496                     {
0497                         // "-" cannot be used for const access
0498                         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));
0499                     }
0500 
0501                     // use unchecked array access
0502                     ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
0503                     break;
0504                 }
0505 
0506                 case detail::value_t::null:
0507                 case detail::value_t::string:
0508                 case detail::value_t::boolean:
0509                 case detail::value_t::number_integer:
0510                 case detail::value_t::number_unsigned:
0511                 case detail::value_t::number_float:
0512                 case detail::value_t::binary:
0513                 case detail::value_t::discarded:
0514                 default:
0515                     JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
0516             }
0517         }
0518 
0519         return *ptr;
0520     }
0521 
0522     /*!
0523     @throw parse_error.106   if an array index begins with '0'
0524     @throw parse_error.109   if an array index was not a number
0525     @throw out_of_range.402  if the array index '-' is used
0526     @throw out_of_range.404  if the JSON pointer can not be resolved
0527     */
0528     template<typename BasicJsonType>
0529     const BasicJsonType& get_checked(const BasicJsonType* ptr) const
0530     {
0531         for (const auto& reference_token : reference_tokens)
0532         {
0533             switch (ptr->type())
0534             {
0535                 case detail::value_t::object:
0536                 {
0537                     // note: at performs range check
0538                     ptr = &ptr->at(reference_token);
0539                     break;
0540                 }
0541 
0542                 case detail::value_t::array:
0543                 {
0544                     if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
0545                     {
0546                         // "-" always fails the range check
0547                         JSON_THROW(detail::out_of_range::create(402, detail::concat(
0548                                 "array index '-' (", std::to_string(ptr->m_value.array->size()),
0549                                 ") is out of range"), ptr));
0550                     }
0551 
0552                     // note: at performs range check
0553                     ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
0554                     break;
0555                 }
0556 
0557                 case detail::value_t::null:
0558                 case detail::value_t::string:
0559                 case detail::value_t::boolean:
0560                 case detail::value_t::number_integer:
0561                 case detail::value_t::number_unsigned:
0562                 case detail::value_t::number_float:
0563                 case detail::value_t::binary:
0564                 case detail::value_t::discarded:
0565                 default:
0566                     JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
0567             }
0568         }
0569 
0570         return *ptr;
0571     }
0572 
0573     /*!
0574     @throw parse_error.106   if an array index begins with '0'
0575     @throw parse_error.109   if an array index was not a number
0576     */
0577     template<typename BasicJsonType>
0578     bool contains(const BasicJsonType* ptr) const
0579     {
0580         for (const auto& reference_token : reference_tokens)
0581         {
0582             switch (ptr->type())
0583             {
0584                 case detail::value_t::object:
0585                 {
0586                     if (!ptr->contains(reference_token))
0587                     {
0588                         // we did not find the key in the object
0589                         return false;
0590                     }
0591 
0592                     ptr = &ptr->operator[](reference_token);
0593                     break;
0594                 }
0595 
0596                 case detail::value_t::array:
0597                 {
0598                     if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
0599                     {
0600                         // "-" always fails the range check
0601                         return false;
0602                     }
0603                     if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
0604                     {
0605                         // invalid char
0606                         return false;
0607                     }
0608                     if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
0609                     {
0610                         if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
0611                         {
0612                             // first char should be between '1' and '9'
0613                             return false;
0614                         }
0615                         for (std::size_t i = 1; i < reference_token.size(); i++)
0616                         {
0617                             if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
0618                             {
0619                                 // other char should be between '0' and '9'
0620                                 return false;
0621                             }
0622                         }
0623                     }
0624 
0625                     const auto idx = array_index<BasicJsonType>(reference_token);
0626                     if (idx >= ptr->size())
0627                     {
0628                         // index out of range
0629                         return false;
0630                     }
0631 
0632                     ptr = &ptr->operator[](idx);
0633                     break;
0634                 }
0635 
0636                 case detail::value_t::null:
0637                 case detail::value_t::string:
0638                 case detail::value_t::boolean:
0639                 case detail::value_t::number_integer:
0640                 case detail::value_t::number_unsigned:
0641                 case detail::value_t::number_float:
0642                 case detail::value_t::binary:
0643                 case detail::value_t::discarded:
0644                 default:
0645                 {
0646                     // we do not expect primitive values if there is still a
0647                     // reference token to process
0648                     return false;
0649                 }
0650             }
0651         }
0652 
0653         // no reference token left means we found a primitive value
0654         return true;
0655     }
0656 
0657     /*!
0658     @brief split the string input to reference tokens
0659 
0660     @note This function is only called by the json_pointer constructor.
0661           All exceptions below are documented there.
0662 
0663     @throw parse_error.107  if the pointer is not empty or begins with '/'
0664     @throw parse_error.108  if character '~' is not followed by '0' or '1'
0665     */
0666     static std::vector<string_t> split(const string_t& reference_string)
0667     {
0668         std::vector<string_t> result;
0669 
0670         // special case: empty reference string -> no reference tokens
0671         if (reference_string.empty())
0672         {
0673             return result;
0674         }
0675 
0676         // check if nonempty reference string begins with slash
0677         if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
0678         {
0679             JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
0680         }
0681 
0682         // extract the reference tokens:
0683         // - slash: position of the last read slash (or end of string)
0684         // - start: position after the previous slash
0685         for (
0686             // search for the first slash after the first character
0687             std::size_t slash = reference_string.find_first_of('/', 1),
0688             // set the beginning of the first reference token
0689             start = 1;
0690             // we can stop if start == 0 (if slash == string_t::npos)
0691             start != 0;
0692             // set the beginning of the next reference token
0693             // (will eventually be 0 if slash == string_t::npos)
0694             start = (slash == string_t::npos) ? 0 : slash + 1,
0695             // find next slash
0696             slash = reference_string.find_first_of('/', start))
0697         {
0698             // use the text between the beginning of the reference token
0699             // (start) and the last slash (slash).
0700             auto reference_token = reference_string.substr(start, slash - start);
0701 
0702             // check reference tokens are properly escaped
0703             for (std::size_t pos = reference_token.find_first_of('~');
0704                     pos != string_t::npos;
0705                     pos = reference_token.find_first_of('~', pos + 1))
0706             {
0707                 JSON_ASSERT(reference_token[pos] == '~');
0708 
0709                 // ~ must be followed by 0 or 1
0710                 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
0711                                          (reference_token[pos + 1] != '0' &&
0712                                           reference_token[pos + 1] != '1')))
0713                 {
0714                     JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
0715                 }
0716             }
0717 
0718             // finally, store the reference token
0719             detail::unescape(reference_token);
0720             result.push_back(reference_token);
0721         }
0722 
0723         return result;
0724     }
0725 
0726   private:
0727     /*!
0728     @param[in] reference_string  the reference string to the current value
0729     @param[in] value             the value to consider
0730     @param[in,out] result        the result object to insert values to
0731 
0732     @note Empty objects or arrays are flattened to `null`.
0733     */
0734     template<typename BasicJsonType>
0735     static void flatten(const string_t& reference_string,
0736                         const BasicJsonType& value,
0737                         BasicJsonType& result)
0738     {
0739         switch (value.type())
0740         {
0741             case detail::value_t::array:
0742             {
0743                 if (value.m_value.array->empty())
0744                 {
0745                     // flatten empty array as null
0746                     result[reference_string] = nullptr;
0747                 }
0748                 else
0749                 {
0750                     // iterate array and use index as reference string
0751                     for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
0752                     {
0753                         flatten(detail::concat(reference_string, '/', std::to_string(i)),
0754                                 value.m_value.array->operator[](i), result);
0755                     }
0756                 }
0757                 break;
0758             }
0759 
0760             case detail::value_t::object:
0761             {
0762                 if (value.m_value.object->empty())
0763                 {
0764                     // flatten empty object as null
0765                     result[reference_string] = nullptr;
0766                 }
0767                 else
0768                 {
0769                     // iterate object and use keys as reference string
0770                     for (const auto& element : *value.m_value.object)
0771                     {
0772                         flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
0773                     }
0774                 }
0775                 break;
0776             }
0777 
0778             case detail::value_t::null:
0779             case detail::value_t::string:
0780             case detail::value_t::boolean:
0781             case detail::value_t::number_integer:
0782             case detail::value_t::number_unsigned:
0783             case detail::value_t::number_float:
0784             case detail::value_t::binary:
0785             case detail::value_t::discarded:
0786             default:
0787             {
0788                 // add primitive value with its reference string
0789                 result[reference_string] = value;
0790                 break;
0791             }
0792         }
0793     }
0794 
0795     /*!
0796     @param[in] value  flattened JSON
0797 
0798     @return unflattened JSON
0799 
0800     @throw parse_error.109 if array index is not a number
0801     @throw type_error.314  if value is not an object
0802     @throw type_error.315  if object values are not primitive
0803     @throw type_error.313  if value cannot be unflattened
0804     */
0805     template<typename BasicJsonType>
0806     static BasicJsonType
0807     unflatten(const BasicJsonType& value)
0808     {
0809         if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
0810         {
0811             JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
0812         }
0813 
0814         BasicJsonType result;
0815 
0816         // iterate the JSON object values
0817         for (const auto& element : *value.m_value.object)
0818         {
0819             if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
0820             {
0821                 JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
0822             }
0823 
0824             // assign value to reference pointed to by JSON pointer; Note that if
0825             // the JSON pointer is "" (i.e., points to the whole value), function
0826             // get_and_create returns a reference to result itself. An assignment
0827             // will then create a primitive value.
0828             json_pointer(element.first).get_and_create(result) = element.second;
0829         }
0830 
0831         return result;
0832     }
0833 
0834     // can't use conversion operator because of ambiguity
0835     json_pointer<string_t> convert() const&
0836     {
0837         json_pointer<string_t> result;
0838         result.reference_tokens = reference_tokens;
0839         return result;
0840     }
0841 
0842     json_pointer<string_t> convert()&&
0843     {
0844         json_pointer<string_t> result;
0845         result.reference_tokens = std::move(reference_tokens);
0846         return result;
0847     }
0848 
0849   public:
0850 #if JSON_HAS_THREE_WAY_COMPARISON
0851     /// @brief compares two JSON pointers for equality
0852     /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
0853     template<typename RefStringTypeRhs>
0854     bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
0855     {
0856         return reference_tokens == rhs.reference_tokens;
0857     }
0858 
0859     /// @brief compares JSON pointer and string for equality
0860     /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
0861     JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
0862     bool operator==(const string_t& rhs) const
0863     {
0864         return *this == json_pointer(rhs);
0865     }
0866 
0867     /// @brief 3-way compares two JSON pointers
0868     template<typename RefStringTypeRhs>
0869     std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
0870     {
0871         return  reference_tokens <=> rhs.reference_tokens; // *NOPAD*
0872     }
0873 #else
0874     /// @brief compares two JSON pointers for equality
0875     /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
0876     template<typename RefStringTypeLhs, typename RefStringTypeRhs>
0877     // NOLINTNEXTLINE(readability-redundant-declaration)
0878     friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
0879                            const json_pointer<RefStringTypeRhs>& rhs) noexcept;
0880 
0881     /// @brief compares JSON pointer and string for equality
0882     /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
0883     template<typename RefStringTypeLhs, typename StringType>
0884     // NOLINTNEXTLINE(readability-redundant-declaration)
0885     friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
0886                            const StringType& rhs);
0887 
0888     /// @brief compares string and JSON pointer for equality
0889     /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
0890     template<typename RefStringTypeRhs, typename StringType>
0891     // NOLINTNEXTLINE(readability-redundant-declaration)
0892     friend bool operator==(const StringType& lhs,
0893                            const json_pointer<RefStringTypeRhs>& rhs);
0894 
0895     /// @brief compares two JSON pointers for inequality
0896     /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
0897     template<typename RefStringTypeLhs, typename RefStringTypeRhs>
0898     // NOLINTNEXTLINE(readability-redundant-declaration)
0899     friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
0900                            const json_pointer<RefStringTypeRhs>& rhs) noexcept;
0901 
0902     /// @brief compares JSON pointer and string for inequality
0903     /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
0904     template<typename RefStringTypeLhs, typename StringType>
0905     // NOLINTNEXTLINE(readability-redundant-declaration)
0906     friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
0907                            const StringType& rhs);
0908 
0909     /// @brief compares string and JSON pointer for inequality
0910     /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
0911     template<typename RefStringTypeRhs, typename StringType>
0912     // NOLINTNEXTLINE(readability-redundant-declaration)
0913     friend bool operator!=(const StringType& lhs,
0914                            const json_pointer<RefStringTypeRhs>& rhs);
0915 
0916     /// @brief compares two JSON pointer for less-than
0917     template<typename RefStringTypeLhs, typename RefStringTypeRhs>
0918     // NOLINTNEXTLINE(readability-redundant-declaration)
0919     friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
0920                           const json_pointer<RefStringTypeRhs>& rhs) noexcept;
0921 #endif
0922 
0923   private:
0924     /// the reference tokens
0925     std::vector<string_t> reference_tokens;
0926 };
0927 
0928 #if !JSON_HAS_THREE_WAY_COMPARISON
0929 // functions cannot be defined inside class due to ODR violations
0930 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
0931 inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
0932                        const json_pointer<RefStringTypeRhs>& rhs) noexcept
0933 {
0934     return lhs.reference_tokens == rhs.reference_tokens;
0935 }
0936 
0937 template<typename RefStringTypeLhs,
0938          typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
0939 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
0940 inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
0941                        const StringType& rhs)
0942 {
0943     return lhs == json_pointer<RefStringTypeLhs>(rhs);
0944 }
0945 
0946 template<typename RefStringTypeRhs,
0947          typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
0948 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
0949 inline bool operator==(const StringType& lhs,
0950                        const json_pointer<RefStringTypeRhs>& rhs)
0951 {
0952     return json_pointer<RefStringTypeRhs>(lhs) == rhs;
0953 }
0954 
0955 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
0956 inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
0957                        const json_pointer<RefStringTypeRhs>& rhs) noexcept
0958 {
0959     return !(lhs == rhs);
0960 }
0961 
0962 template<typename RefStringTypeLhs,
0963          typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
0964 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
0965 inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
0966                        const StringType& rhs)
0967 {
0968     return !(lhs == rhs);
0969 }
0970 
0971 template<typename RefStringTypeRhs,
0972          typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
0973 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
0974 inline bool operator!=(const StringType& lhs,
0975                        const json_pointer<RefStringTypeRhs>& rhs)
0976 {
0977     return !(lhs == rhs);
0978 }
0979 
0980 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
0981 inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
0982                       const json_pointer<RefStringTypeRhs>& rhs) noexcept
0983 {
0984     return lhs.reference_tokens < rhs.reference_tokens;
0985 }
0986 #endif
0987 
0988 NLOHMANN_JSON_NAMESPACE_END