8 #include <nlohmann/detail/macro_scope.hpp>
9 #include <nlohmann/detail/exceptions.hpp>
10 #include <nlohmann/detail/value_t.hpp>
14 template<
typename BasicJsonType>
18 NLOHMANN_BASIC_JSON_TPL_DECLARATION
44 : reference_tokens(split(s))
64 return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
66 [](
const std::string & a,
const std::string & b)
68 return a +
"/" + escape(b);
73 operator std::string()
const
87 std::size_t processed_chars = 0;
88 const int res = std::stoi(s, &processed_chars);
91 if (JSON_UNLIKELY(processed_chars != s.size()))
93 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + s +
"'"));
104 std::string pop_back()
106 if (JSON_UNLIKELY(is_root()))
108 JSON_THROW(detail::out_of_range::create(405,
"JSON pointer has no parent"));
111 auto last = reference_tokens.back();
112 reference_tokens.pop_back();
119 return reference_tokens.empty();
124 if (JSON_UNLIKELY(is_root()))
126 JSON_THROW(detail::out_of_range::create(405,
"JSON pointer has no parent"));
130 result.reference_tokens = {reference_tokens[0]};
142 BasicJsonType& get_and_create(BasicJsonType& j)
const
144 using size_type =
typename BasicJsonType::size_type;
149 for (
const auto& reference_token : reference_tokens)
151 switch (result->m_type)
155 if (reference_token ==
"0")
158 result = &result->operator[](0);
163 result = &result->operator[](reference_token);
171 result = &result->operator[](reference_token);
180 result = &result->operator[](static_cast<size_type>(
array_index(reference_token)));
182 JSON_CATCH(std::invalid_argument&)
196 JSON_THROW(detail::type_error::create(313,
"invalid value to unflatten"));
222 BasicJsonType& get_unchecked(BasicJsonType* ptr)
const
224 using size_type =
typename BasicJsonType::size_type;
225 for (
const auto& reference_token : reference_tokens)
232 std::all_of(reference_token.begin(), reference_token.end(),
235 return (x >=
'0' and x <=
'9');
239 *ptr = (nums or reference_token ==
"-")
249 ptr = &ptr->operator[](reference_token);
256 if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
259 "array index '" + reference_token +
260 "' must not begin with '0'"));
263 if (reference_token ==
"-")
266 ptr = &ptr->operator[](ptr->m_value.array->size());
273 ptr = &ptr->operator[](
274 static_cast<size_type>(
array_index(reference_token)));
276 JSON_CATCH(std::invalid_argument&)
285 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
298 BasicJsonType& get_checked(BasicJsonType* ptr)
const
300 using size_type =
typename BasicJsonType::size_type;
301 for (
const auto& reference_token : reference_tokens)
308 ptr = &ptr->at(reference_token);
314 if (JSON_UNLIKELY(reference_token ==
"-"))
317 JSON_THROW(detail::out_of_range::create(402,
318 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
319 ") is out of range"));
323 if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
326 "array index '" + reference_token +
327 "' must not begin with '0'"));
333 ptr = &ptr->at(static_cast<size_type>(
array_index(reference_token)));
335 JSON_CATCH(std::invalid_argument&)
343 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
363 const BasicJsonType& get_unchecked(
const BasicJsonType* ptr)
const
365 using size_type =
typename BasicJsonType::size_type;
366 for (
const auto& reference_token : reference_tokens)
373 ptr = &ptr->operator[](reference_token);
379 if (JSON_UNLIKELY(reference_token ==
"-"))
382 JSON_THROW(detail::out_of_range::create(402,
383 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
384 ") is out of range"));
388 if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
391 "array index '" + reference_token +
392 "' must not begin with '0'"));
398 ptr = &ptr->operator[](
399 static_cast<size_type>(
array_index(reference_token)));
401 JSON_CATCH(std::invalid_argument&)
409 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
422 const BasicJsonType& get_checked(
const BasicJsonType* ptr)
const
424 using size_type =
typename BasicJsonType::size_type;
425 for (
const auto& reference_token : reference_tokens)
432 ptr = &ptr->at(reference_token);
438 if (JSON_UNLIKELY(reference_token ==
"-"))
441 JSON_THROW(detail::out_of_range::create(402,
442 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
443 ") is out of range"));
447 if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
450 "array index '" + reference_token +
451 "' must not begin with '0'"));
457 ptr = &ptr->at(static_cast<size_type>(
array_index(reference_token)));
459 JSON_CATCH(std::invalid_argument&)
467 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
483 static std::vector<std::string> split(
const std::string& reference_string)
485 std::vector<std::string> result;
488 if (reference_string.empty())
494 if (JSON_UNLIKELY(reference_string[0] !=
'/'))
497 "JSON pointer must be empty or begin with '/' - was: '" +
498 reference_string +
"'"));
506 std::size_t slash = reference_string.find_first_of(
'/', 1),
515 slash = reference_string.find_first_of(
'/', start))
519 auto reference_token = reference_string.substr(start, slash - start);
522 for (std::size_t pos = reference_token.find_first_of(
'~');
523 pos != std::string::npos;
524 pos = reference_token.find_first_of(
'~', pos + 1))
526 assert(reference_token[pos] ==
'~');
529 if (JSON_UNLIKELY(pos == reference_token.size() - 1 or
530 (reference_token[pos + 1] !=
'0' and
531 reference_token[pos + 1] !=
'1')))
538 unescape(reference_token);
539 result.push_back(reference_token);
558 static void replace_substring(std::string& s,
const std::string& f,
559 const std::string& t)
561 assert(not f.empty());
562 for (
auto pos = s.find(f);
563 pos != std::string::npos;
564 s.replace(pos, f.size(), t),
565 pos = s.find(f, pos + t.size()))
570 static std::string escape(std::string s)
572 replace_substring(s,
"~",
"~0");
573 replace_substring(s,
"/",
"~1");
578 static void unescape(std::string& s)
580 replace_substring(s,
"~1",
"/");
581 replace_substring(s,
"~0",
"~");
591 static void flatten(
const std::string& reference_string,
592 const BasicJsonType& value,
593 BasicJsonType& result)
595 switch (value.m_type)
599 if (value.m_value.array->empty())
602 result[reference_string] =
nullptr;
607 for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
609 flatten(reference_string +
"/" + std::to_string(i),
610 value.m_value.array->operator[](i), result);
618 if (value.m_value.object->empty())
621 result[reference_string] =
nullptr;
626 for (
const auto& element : *value.m_value.object)
628 flatten(reference_string +
"/" + escape(element.first), element.second, result);
637 result[reference_string] = value;
654 unflatten(
const BasicJsonType& value)
656 if (JSON_UNLIKELY(not value.is_object()))
658 JSON_THROW(detail::type_error::create(314,
"only objects can be unflattened"));
661 BasicJsonType result;
664 for (
const auto& element : *value.m_value.object)
666 if (JSON_UNLIKELY(not element.second.is_primitive()))
668 JSON_THROW(detail::type_error::create(315,
"values in object must be primitive"));
675 json_pointer(element.first).get_and_create(result) = element.second;
684 return (lhs.reference_tokens == rhs.reference_tokens);
690 return not (lhs == rhs);
694 std::vector<std::string> reference_tokens;