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