123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988 |
- #pragma once
- #include <algorithm> // all_of
- #include <cctype> // isdigit
- #include <cerrno> // errno, ERANGE
- #include <cstdlib> // strtoull
- #ifndef JSON_NO_IO
- #include <iosfwd> // ostream
- #endif
- #include <limits> // max
- #include <numeric> // accumulate
- #include <string> // string
- #include <utility> // move
- #include <vector> // vector
- #include <nlohmann/detail/exceptions.hpp>
- #include <nlohmann/detail/macro_scope.hpp>
- #include <nlohmann/detail/string_concat.hpp>
- #include <nlohmann/detail/string_escape.hpp>
- #include <nlohmann/detail/value_t.hpp>
- NLOHMANN_JSON_NAMESPACE_BEGIN
- template<typename RefStringType>
- class json_pointer
- {
-
- NLOHMANN_BASIC_JSON_TPL_DECLARATION
- friend class basic_json;
- template<typename>
- friend class json_pointer;
- template<typename T>
- struct string_t_helper
- {
- using type = T;
- };
- NLOHMANN_BASIC_JSON_TPL_DECLARATION
- struct string_t_helper<NLOHMANN_BASIC_JSON_TPL>
- {
- using type = StringType;
- };
- public:
-
- using string_t = typename string_t_helper<RefStringType>::type;
-
-
- explicit json_pointer(const string_t& s = "")
- : reference_tokens(split(s))
- {}
-
-
- string_t to_string() const
- {
- return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
- string_t{},
- [](const string_t& a, const string_t& b)
- {
- return detail::concat(a, '/', detail::escape(b));
- });
- }
-
-
- JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
- operator string_t() const
- {
- return to_string();
- }
- #ifndef JSON_NO_IO
-
-
- friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
- {
- o << ptr.to_string();
- return o;
- }
- #endif
-
-
- json_pointer& operator/=(const json_pointer& ptr)
- {
- reference_tokens.insert(reference_tokens.end(),
- ptr.reference_tokens.begin(),
- ptr.reference_tokens.end());
- return *this;
- }
-
-
- json_pointer& operator/=(string_t token)
- {
- push_back(std::move(token));
- return *this;
- }
-
-
- json_pointer& operator/=(std::size_t array_idx)
- {
- return *this /= std::to_string(array_idx);
- }
-
-
- friend json_pointer operator/(const json_pointer& lhs,
- const json_pointer& rhs)
- {
- return json_pointer(lhs) /= rhs;
- }
-
-
- friend json_pointer operator/(const json_pointer& lhs, string_t token)
- {
- return json_pointer(lhs) /= std::move(token);
- }
-
-
- friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)
- {
- return json_pointer(lhs) /= array_idx;
- }
-
-
- json_pointer parent_pointer() const
- {
- if (empty())
- {
- return *this;
- }
- json_pointer res = *this;
- res.pop_back();
- return res;
- }
-
-
- void pop_back()
- {
- if (JSON_HEDLEY_UNLIKELY(empty()))
- {
- JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
- }
- reference_tokens.pop_back();
- }
-
-
- const string_t& back() const
- {
- if (JSON_HEDLEY_UNLIKELY(empty()))
- {
- JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
- }
- return reference_tokens.back();
- }
-
-
- void push_back(const string_t& token)
- {
- reference_tokens.push_back(token);
- }
-
-
- void push_back(string_t&& token)
- {
- reference_tokens.push_back(std::move(token));
- }
-
-
- bool empty() const noexcept
- {
- return reference_tokens.empty();
- }
- private:
-
- template<typename BasicJsonType>
- static typename BasicJsonType::size_type array_index(const string_t& s)
- {
- using size_type = typename BasicJsonType::size_type;
-
- if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
- {
- JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
- }
-
- if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
- {
- JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
- }
- const char* p = s.c_str();
- char* p_end = nullptr;
- errno = 0;
- const unsigned long long res = std::strtoull(p, &p_end, 10);
- if (p == p_end
- || errno == ERANGE
- || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size()))
- {
- JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
- }
-
-
- if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))
- {
- JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr));
- }
- return static_cast<size_type>(res);
- }
- JSON_PRIVATE_UNLESS_TESTED:
- json_pointer top() const
- {
- if (JSON_HEDLEY_UNLIKELY(empty()))
- {
- JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
- }
- json_pointer result = *this;
- result.reference_tokens = {reference_tokens[0]};
- return result;
- }
- private:
-
- template<typename BasicJsonType>
- BasicJsonType& get_and_create(BasicJsonType& j) const
- {
- auto* result = &j;
-
-
- for (const auto& reference_token : reference_tokens)
- {
- switch (result->type())
- {
- case detail::value_t::null:
- {
- if (reference_token == "0")
- {
-
- result = &result->operator[](0);
- }
- else
- {
-
- result = &result->operator[](reference_token);
- }
- break;
- }
- case detail::value_t::object:
- {
-
- result = &result->operator[](reference_token);
- break;
- }
- case detail::value_t::array:
- {
-
- result = &result->operator[](array_index<BasicJsonType>(reference_token));
- break;
- }
-
- case detail::value_t::string:
- case detail::value_t::boolean:
- case detail::value_t::number_integer:
- case detail::value_t::number_unsigned:
- case detail::value_t::number_float:
- case detail::value_t::binary:
- case detail::value_t::discarded:
- default:
- JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
- }
- }
- return *result;
- }
-
- template<typename BasicJsonType>
- BasicJsonType& get_unchecked(BasicJsonType* ptr) const
- {
- for (const auto& reference_token : reference_tokens)
- {
-
- if (ptr->is_null())
- {
-
- const bool nums =
- std::all_of(reference_token.begin(), reference_token.end(),
- [](const unsigned char x)
- {
- return std::isdigit(x);
- });
-
- *ptr = (nums || reference_token == "-")
- ? detail::value_t::array
- : detail::value_t::object;
- }
- switch (ptr->type())
- {
- case detail::value_t::object:
- {
-
- ptr = &ptr->operator[](reference_token);
- break;
- }
- case detail::value_t::array:
- {
- if (reference_token == "-")
- {
-
- ptr = &ptr->operator[](ptr->m_data.m_value.array->size());
- }
- else
- {
-
- ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
- }
- break;
- }
- case detail::value_t::null:
- case detail::value_t::string:
- case detail::value_t::boolean:
- case detail::value_t::number_integer:
- case detail::value_t::number_unsigned:
- case detail::value_t::number_float:
- case detail::value_t::binary:
- case detail::value_t::discarded:
- default:
- JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
- }
- }
- return *ptr;
- }
-
- template<typename BasicJsonType>
- BasicJsonType& get_checked(BasicJsonType* ptr) const
- {
- for (const auto& reference_token : reference_tokens)
- {
- switch (ptr->type())
- {
- case detail::value_t::object:
- {
-
- ptr = &ptr->at(reference_token);
- break;
- }
- case detail::value_t::array:
- {
- if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
- {
-
- JSON_THROW(detail::out_of_range::create(402, detail::concat(
- "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
- ") is out of range"), ptr));
- }
-
- ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
- break;
- }
- case detail::value_t::null:
- case detail::value_t::string:
- case detail::value_t::boolean:
- case detail::value_t::number_integer:
- case detail::value_t::number_unsigned:
- case detail::value_t::number_float:
- case detail::value_t::binary:
- case detail::value_t::discarded:
- default:
- JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
- }
- }
- return *ptr;
- }
-
- template<typename BasicJsonType>
- const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
- {
- for (const auto& reference_token : reference_tokens)
- {
- switch (ptr->type())
- {
- case detail::value_t::object:
- {
-
- ptr = &ptr->operator[](reference_token);
- break;
- }
- case detail::value_t::array:
- {
- if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
- {
-
- JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
- }
-
- ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
- break;
- }
- case detail::value_t::null:
- case detail::value_t::string:
- case detail::value_t::boolean:
- case detail::value_t::number_integer:
- case detail::value_t::number_unsigned:
- case detail::value_t::number_float:
- case detail::value_t::binary:
- case detail::value_t::discarded:
- default:
- JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
- }
- }
- return *ptr;
- }
-
- template<typename BasicJsonType>
- const BasicJsonType& get_checked(const BasicJsonType* ptr) const
- {
- for (const auto& reference_token : reference_tokens)
- {
- switch (ptr->type())
- {
- case detail::value_t::object:
- {
-
- ptr = &ptr->at(reference_token);
- break;
- }
- case detail::value_t::array:
- {
- if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
- {
-
- JSON_THROW(detail::out_of_range::create(402, detail::concat(
- "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
- ") is out of range"), ptr));
- }
-
- ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
- break;
- }
- case detail::value_t::null:
- case detail::value_t::string:
- case detail::value_t::boolean:
- case detail::value_t::number_integer:
- case detail::value_t::number_unsigned:
- case detail::value_t::number_float:
- case detail::value_t::binary:
- case detail::value_t::discarded:
- default:
- JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
- }
- }
- return *ptr;
- }
-
- template<typename BasicJsonType>
- bool contains(const BasicJsonType* ptr) const
- {
- for (const auto& reference_token : reference_tokens)
- {
- switch (ptr->type())
- {
- case detail::value_t::object:
- {
- if (!ptr->contains(reference_token))
- {
-
- return false;
- }
- ptr = &ptr->operator[](reference_token);
- break;
- }
- case detail::value_t::array:
- {
- if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
- {
-
- return false;
- }
- if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
- {
-
- return false;
- }
- if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
- {
- if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
- {
-
- return false;
- }
- for (std::size_t i = 1; i < reference_token.size(); i++)
- {
- if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
- {
-
- return false;
- }
- }
- }
- const auto idx = array_index<BasicJsonType>(reference_token);
- if (idx >= ptr->size())
- {
-
- return false;
- }
- ptr = &ptr->operator[](idx);
- break;
- }
- case detail::value_t::null:
- case detail::value_t::string:
- case detail::value_t::boolean:
- case detail::value_t::number_integer:
- case detail::value_t::number_unsigned:
- case detail::value_t::number_float:
- case detail::value_t::binary:
- case detail::value_t::discarded:
- default:
- {
-
-
- return false;
- }
- }
- }
-
- return true;
- }
-
- static std::vector<string_t> split(const string_t& reference_string)
- {
- std::vector<string_t> result;
-
- if (reference_string.empty())
- {
- return result;
- }
-
- if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
- {
- JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
- }
-
-
-
- for (
-
- std::size_t slash = reference_string.find_first_of('/', 1),
-
- start = 1;
-
- start != 0;
-
-
- start = (slash == string_t::npos) ? 0 : slash + 1,
-
- slash = reference_string.find_first_of('/', start))
- {
-
-
- auto reference_token = reference_string.substr(start, slash - start);
-
- for (std::size_t pos = reference_token.find_first_of('~');
- pos != string_t::npos;
- pos = reference_token.find_first_of('~', pos + 1))
- {
- JSON_ASSERT(reference_token[pos] == '~');
-
- if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
- (reference_token[pos + 1] != '0' &&
- reference_token[pos + 1] != '1')))
- {
- JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
- }
- }
-
- detail::unescape(reference_token);
- result.push_back(reference_token);
- }
- return result;
- }
- private:
-
- template<typename BasicJsonType>
- static void flatten(const string_t& reference_string,
- const BasicJsonType& value,
- BasicJsonType& result)
- {
- switch (value.type())
- {
- case detail::value_t::array:
- {
- if (value.m_data.m_value.array->empty())
- {
-
- result[reference_string] = nullptr;
- }
- else
- {
-
- for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
- {
- flatten(detail::concat(reference_string, '/', std::to_string(i)),
- value.m_data.m_value.array->operator[](i), result);
- }
- }
- break;
- }
- case detail::value_t::object:
- {
- if (value.m_data.m_value.object->empty())
- {
-
- result[reference_string] = nullptr;
- }
- else
- {
-
- for (const auto& element : *value.m_data.m_value.object)
- {
- flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
- }
- }
- break;
- }
- case detail::value_t::null:
- case detail::value_t::string:
- case detail::value_t::boolean:
- case detail::value_t::number_integer:
- case detail::value_t::number_unsigned:
- case detail::value_t::number_float:
- case detail::value_t::binary:
- case detail::value_t::discarded:
- default:
- {
-
- result[reference_string] = value;
- break;
- }
- }
- }
-
- template<typename BasicJsonType>
- static BasicJsonType
- unflatten(const BasicJsonType& value)
- {
- if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
- {
- JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
- }
- BasicJsonType result;
-
- for (const auto& element : *value.m_data.m_value.object)
- {
- if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
- {
- JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
- }
-
-
-
-
- json_pointer(element.first).get_and_create(result) = element.second;
- }
- return result;
- }
-
- json_pointer<string_t> convert() const&
- {
- json_pointer<string_t> result;
- result.reference_tokens = reference_tokens;
- return result;
- }
- json_pointer<string_t> convert()&&
- {
- json_pointer<string_t> result;
- result.reference_tokens = std::move(reference_tokens);
- return result;
- }
- public:
- #if JSON_HAS_THREE_WAY_COMPARISON
-
-
- template<typename RefStringTypeRhs>
- bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
- {
- return reference_tokens == rhs.reference_tokens;
- }
-
-
- JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
- bool operator==(const string_t& rhs) const
- {
- return *this == json_pointer(rhs);
- }
-
- template<typename RefStringTypeRhs>
- std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
- {
- return reference_tokens <=> rhs.reference_tokens;
- }
- #else
-
-
- template<typename RefStringTypeLhs, typename RefStringTypeRhs>
-
- friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
- const json_pointer<RefStringTypeRhs>& rhs) noexcept;
-
-
- template<typename RefStringTypeLhs, typename StringType>
-
- friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
- const StringType& rhs);
-
-
- template<typename RefStringTypeRhs, typename StringType>
-
- friend bool operator==(const StringType& lhs,
- const json_pointer<RefStringTypeRhs>& rhs);
-
-
- template<typename RefStringTypeLhs, typename RefStringTypeRhs>
-
- friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
- const json_pointer<RefStringTypeRhs>& rhs) noexcept;
-
-
- template<typename RefStringTypeLhs, typename StringType>
-
- friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
- const StringType& rhs);
-
-
- template<typename RefStringTypeRhs, typename StringType>
-
- friend bool operator!=(const StringType& lhs,
- const json_pointer<RefStringTypeRhs>& rhs);
-
- template<typename RefStringTypeLhs, typename RefStringTypeRhs>
-
- friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
- const json_pointer<RefStringTypeRhs>& rhs) noexcept;
- #endif
- private:
-
- std::vector<string_t> reference_tokens;
- };
- #if !JSON_HAS_THREE_WAY_COMPARISON
- template<typename RefStringTypeLhs, typename RefStringTypeRhs>
- inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
- const json_pointer<RefStringTypeRhs>& rhs) noexcept
- {
- return lhs.reference_tokens == rhs.reference_tokens;
- }
- template<typename RefStringTypeLhs,
- typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
- JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
- inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
- const StringType& rhs)
- {
- return lhs == json_pointer<RefStringTypeLhs>(rhs);
- }
- template<typename RefStringTypeRhs,
- typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
- JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
- inline bool operator==(const StringType& lhs,
- const json_pointer<RefStringTypeRhs>& rhs)
- {
- return json_pointer<RefStringTypeRhs>(lhs) == rhs;
- }
- template<typename RefStringTypeLhs, typename RefStringTypeRhs>
- inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
- const json_pointer<RefStringTypeRhs>& rhs) noexcept
- {
- return !(lhs == rhs);
- }
- template<typename RefStringTypeLhs,
- typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
- JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
- inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
- const StringType& rhs)
- {
- return !(lhs == rhs);
- }
- template<typename RefStringTypeRhs,
- typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
- JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
- inline bool operator!=(const StringType& lhs,
- const json_pointer<RefStringTypeRhs>& rhs)
- {
- return !(lhs == rhs);
- }
- template<typename RefStringTypeLhs, typename RefStringTypeRhs>
- inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
- const json_pointer<RefStringTypeRhs>& rhs) noexcept
- {
- return lhs.reference_tokens < rhs.reference_tokens;
- }
- #endif
- NLOHMANN_JSON_NAMESPACE_END
|