11 #include <nlohmann/detail/exceptions.hpp>
12 #include <nlohmann/detail/macro_scope.hpp>
13 #include <nlohmann/detail/value_t.hpp>
17 template<
typename BasicJsonType>
21 NLOHMANN_BASIC_JSON_TPL_DECLARATION
22 friend class basic_json;
47 : reference_tokens(split(s))
66 return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
68 [](
const std::string & a,
const std::string & b)
70 return a +
"/" + escape(b);
75 operator std::string()
const
98 reference_tokens.insert(reference_tokens.end(),
99 ptr.reference_tokens.begin(),
100 ptr.reference_tokens.end());
144 return *
this /= std::to_string(array_index);
248 if (JSON_HEDLEY_UNLIKELY(
empty()))
250 JSON_THROW(detail::out_of_range::create(405,
"JSON pointer has no parent"));
253 reference_tokens.pop_back();
270 const std::string&
back()
const
272 if (JSON_HEDLEY_UNLIKELY(
empty()))
274 JSON_THROW(detail::out_of_range::create(405,
"JSON pointer has no parent"));
277 return reference_tokens.back();
294 reference_tokens.push_back(token);
300 reference_tokens.push_back(std::move(token));
319 return reference_tokens.empty();
330 static int array_index(
const std::string& s)
332 std::size_t processed_chars = 0;
333 const int res = std::stoi(s, &processed_chars);
336 if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size()))
338 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + s +
"'"));
346 if (JSON_HEDLEY_UNLIKELY(
empty()))
348 JSON_THROW(detail::out_of_range::create(405,
"JSON pointer has no parent"));
352 result.reference_tokens = {reference_tokens[0]};
364 BasicJsonType& get_and_create(BasicJsonType& j)
const
366 using size_type =
typename BasicJsonType::size_type;
371 for (
const auto& reference_token : reference_tokens)
373 switch (result->type())
377 if (reference_token ==
"0")
380 result = &result->operator[](0);
385 result = &result->operator[](reference_token);
393 result = &result->operator[](reference_token);
402 result = &result->operator[](
static_cast<size_type
>(array_index(reference_token)));
404 JSON_CATCH(std::invalid_argument&)
418 JSON_THROW(detail::type_error::create(313,
"invalid value to unflatten"));
444 BasicJsonType& get_unchecked(BasicJsonType* ptr)
const
446 using size_type =
typename BasicJsonType::size_type;
447 for (
const auto& reference_token : reference_tokens)
454 std::all_of(reference_token.begin(), reference_token.end(),
455 [](
const unsigned char x)
457 return std::isdigit(x);
461 *ptr = (nums or reference_token ==
"-")
471 ptr = &ptr->operator[](reference_token);
478 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
481 "array index '" + reference_token +
482 "' must not begin with '0'"));
485 if (reference_token ==
"-")
488 ptr = &ptr->operator[](ptr->m_value.array->size());
495 ptr = &ptr->operator[](
496 static_cast<size_type
>(array_index(reference_token)));
498 JSON_CATCH(std::invalid_argument&)
507 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
520 BasicJsonType& get_checked(BasicJsonType* ptr)
const
522 using size_type =
typename BasicJsonType::size_type;
523 for (
const auto& reference_token : reference_tokens)
530 ptr = &ptr->at(reference_token);
536 if (JSON_HEDLEY_UNLIKELY(reference_token ==
"-"))
539 JSON_THROW(detail::out_of_range::create(402,
540 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
541 ") is out of range"));
545 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
548 "array index '" + reference_token +
549 "' must not begin with '0'"));
555 ptr = &ptr->at(
static_cast<size_type
>(array_index(reference_token)));
557 JSON_CATCH(std::invalid_argument&)
565 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
585 const BasicJsonType& get_unchecked(
const BasicJsonType* ptr)
const
587 using size_type =
typename BasicJsonType::size_type;
588 for (
const auto& reference_token : reference_tokens)
595 ptr = &ptr->operator[](reference_token);
601 if (JSON_HEDLEY_UNLIKELY(reference_token ==
"-"))
604 JSON_THROW(detail::out_of_range::create(402,
605 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
606 ") is out of range"));
610 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
613 "array index '" + reference_token +
614 "' must not begin with '0'"));
620 ptr = &ptr->operator[](
621 static_cast<size_type
>(array_index(reference_token)));
623 JSON_CATCH(std::invalid_argument&)
631 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
644 const BasicJsonType& get_checked(
const BasicJsonType* ptr)
const
646 using size_type =
typename BasicJsonType::size_type;
647 for (
const auto& reference_token : reference_tokens)
654 ptr = &ptr->at(reference_token);
660 if (JSON_HEDLEY_UNLIKELY(reference_token ==
"-"))
663 JSON_THROW(detail::out_of_range::create(402,
664 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
665 ") is out of range"));
669 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
672 "array index '" + reference_token +
673 "' must not begin with '0'"));
679 ptr = &ptr->at(
static_cast<size_type
>(array_index(reference_token)));
681 JSON_CATCH(std::invalid_argument&)
689 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
700 bool contains(
const BasicJsonType* ptr)
const
702 using size_type =
typename BasicJsonType::size_type;
703 for (
const auto& reference_token : reference_tokens)
709 if (not ptr->contains(reference_token))
715 ptr = &ptr->operator[](reference_token);
721 if (JSON_HEDLEY_UNLIKELY(reference_token ==
"-"))
728 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] ==
'0'))
731 "array index '" + reference_token +
732 "' must not begin with '0'"));
737 const auto idx =
static_cast<size_type
>(array_index(reference_token));
738 if (idx >= ptr->size())
744 ptr = &ptr->operator[](idx);
747 JSON_CATCH(std::invalid_argument&)
776 static std::vector<std::string> split(
const std::string& reference_string)
778 std::vector<std::string> result;
781 if (reference_string.empty())
787 if (JSON_HEDLEY_UNLIKELY(reference_string[0] !=
'/'))
790 "JSON pointer must be empty or begin with '/' - was: '" +
791 reference_string +
"'"));
799 std::size_t slash = reference_string.find_first_of(
'/', 1),
806 start = (slash == std::string::npos) ? 0 : slash + 1,
808 slash = reference_string.find_first_of(
'/', start))
812 auto reference_token = reference_string.substr(start, slash - start);
815 for (std::size_t pos = reference_token.find_first_of(
'~');
816 pos != std::string::npos;
817 pos = reference_token.find_first_of(
'~', pos + 1))
819 assert(reference_token[pos] ==
'~');
822 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or
823 (reference_token[pos + 1] !=
'0' and
824 reference_token[pos + 1] !=
'1')))
831 unescape(reference_token);
832 result.push_back(reference_token);
851 static void replace_substring(std::string& s,
const std::string& f,
852 const std::string& t)
854 assert(not f.empty());
855 for (
auto pos = s.find(f);
856 pos != std::string::npos;
857 s.replace(pos, f.size(), t),
858 pos = s.find(f, pos + t.size()))
863 static std::string escape(std::string s)
865 replace_substring(s,
"~",
"~0");
866 replace_substring(s,
"/",
"~1");
871 static void unescape(std::string& s)
873 replace_substring(s,
"~1",
"/");
874 replace_substring(s,
"~0",
"~");
884 static void flatten(
const std::string& reference_string,
885 const BasicJsonType& value,
886 BasicJsonType& result)
888 switch (value.type())
892 if (value.m_value.array->empty())
895 result[reference_string] =
nullptr;
900 for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
902 flatten(reference_string +
"/" + std::to_string(i),
903 value.m_value.array->operator[](i), result);
911 if (value.m_value.object->empty())
914 result[reference_string] =
nullptr;
919 for (
const auto& element : *value.m_value.object)
921 flatten(reference_string +
"/" + escape(element.first), element.second, result);
930 result[reference_string] = value;
947 unflatten(
const BasicJsonType& value)
949 if (JSON_HEDLEY_UNLIKELY(not value.is_object()))
951 JSON_THROW(detail::type_error::create(314,
"only objects can be unflattened"));
954 BasicJsonType result;
957 for (
const auto& element : *value.m_value.object)
959 if (JSON_HEDLEY_UNLIKELY(not element.second.is_primitive()))
961 JSON_THROW(detail::type_error::create(315,
"values in object must be primitive"));
968 json_pointer(element.first).get_and_create(result) = element.second;
988 return lhs.reference_tokens == rhs.reference_tokens;
1005 return not (lhs == rhs);
1009 std::vector<std::string> reference_tokens;