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
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_idx);
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();
333 static typename BasicJsonType::size_type array_index(
const std::string& s)
335 using size_type =
typename BasicJsonType::size_type;
338 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] ==
'0'))
341 "array index '" + s +
342 "' must not begin with '0'"));
346 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >=
'1' && s[0] <=
'9')))
351 std::size_t processed_chars = 0;
352 unsigned long long res = 0;
355 res = std::stoull(s, &processed_chars);
357 JSON_CATCH(std::out_of_range&)
359 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + s +
"'"));
363 if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size()))
365 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + s +
"'"));
370 if (res >=
static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))
372 JSON_THROW(detail::out_of_range::create(410,
"array index " + s +
" exceeds size_type"));
375 return static_cast<size_type
>(res);
380 if (JSON_HEDLEY_UNLIKELY(
empty()))
382 JSON_THROW(detail::out_of_range::create(405,
"JSON pointer has no parent"));
386 result.reference_tokens = {reference_tokens[0]};
398 BasicJsonType& get_and_create(BasicJsonType& j)
const
404 for (
const auto& reference_token : reference_tokens)
406 switch (result->type())
410 if (reference_token ==
"0")
413 result = &result->operator[](0);
418 result = &result->operator[](reference_token);
426 result = &result->operator[](reference_token);
433 result = &result->operator[](array_index(reference_token));
444 JSON_THROW(detail::type_error::create(313,
"invalid value to unflatten"));
470 BasicJsonType& get_unchecked(BasicJsonType* ptr)
const
472 for (
const auto& reference_token : reference_tokens)
479 std::all_of(reference_token.begin(), reference_token.end(),
480 [](
const unsigned char x)
482 return std::isdigit(x);
486 *ptr = (nums || reference_token ==
"-")
496 ptr = &ptr->operator[](reference_token);
502 if (reference_token ==
"-")
505 ptr = &ptr->operator[](ptr->m_value.array->size());
510 ptr = &ptr->operator[](array_index(reference_token));
516 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
529 BasicJsonType& get_checked(BasicJsonType* ptr)
const
531 for (
const auto& reference_token : reference_tokens)
538 ptr = &ptr->at(reference_token);
544 if (JSON_HEDLEY_UNLIKELY(reference_token ==
"-"))
547 JSON_THROW(detail::out_of_range::create(402,
548 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
549 ") is out of range"));
553 ptr = &ptr->at(array_index(reference_token));
558 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
578 const BasicJsonType& get_unchecked(
const BasicJsonType* ptr)
const
580 for (
const auto& reference_token : reference_tokens)
587 ptr = &ptr->operator[](reference_token);
593 if (JSON_HEDLEY_UNLIKELY(reference_token ==
"-"))
596 JSON_THROW(detail::out_of_range::create(402,
597 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
598 ") is out of range"));
602 ptr = &ptr->operator[](array_index(reference_token));
607 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
620 const BasicJsonType& get_checked(
const BasicJsonType* ptr)
const
622 for (
const auto& reference_token : reference_tokens)
629 ptr = &ptr->at(reference_token);
635 if (JSON_HEDLEY_UNLIKELY(reference_token ==
"-"))
638 JSON_THROW(detail::out_of_range::create(402,
639 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
640 ") is out of range"));
644 ptr = &ptr->at(array_index(reference_token));
649 JSON_THROW(detail::out_of_range::create(404,
"unresolved reference token '" + reference_token +
"'"));
660 bool contains(
const BasicJsonType* ptr)
const
662 for (
const auto& reference_token : reference_tokens)
668 if (!ptr->contains(reference_token))
674 ptr = &ptr->operator[](reference_token);
680 if (JSON_HEDLEY_UNLIKELY(reference_token ==
"-"))
685 if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !(
"0" <= reference_token && reference_token <=
"9")))
690 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
692 if (JSON_HEDLEY_UNLIKELY(!(
'1' <= reference_token[0] && reference_token[0] <=
'9')))
697 for (std::size_t i = 1; i < reference_token.size(); i++)
699 if (JSON_HEDLEY_UNLIKELY(!(
'0' <= reference_token[i] && reference_token[i] <=
'9')))
707 const auto idx = array_index(reference_token);
708 if (idx >= ptr->size())
714 ptr = &ptr->operator[](idx);
740 static std::vector<std::string> split(
const std::string& reference_string)
742 std::vector<std::string> result;
745 if (reference_string.empty())
751 if (JSON_HEDLEY_UNLIKELY(reference_string[0] !=
'/'))
754 "JSON pointer must be empty or begin with '/' - was: '" +
755 reference_string +
"'"));
763 std::size_t slash = reference_string.find_first_of(
'/', 1),
770 start = (slash == std::string::npos) ? 0 : slash + 1,
772 slash = reference_string.find_first_of(
'/', start))
776 auto reference_token = reference_string.substr(start, slash - start);
779 for (std::size_t pos = reference_token.find_first_of(
'~');
780 pos != std::string::npos;
781 pos = reference_token.find_first_of(
'~', pos + 1))
783 JSON_ASSERT(reference_token[pos] ==
'~');
786 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
787 (reference_token[pos + 1] !=
'0' &&
788 reference_token[pos + 1] !=
'1')))
795 unescape(reference_token);
796 result.push_back(reference_token);
815 static void replace_substring(std::string& s,
const std::string& f,
816 const std::string& t)
818 JSON_ASSERT(!f.empty());
819 for (
auto pos = s.find(f);
820 pos != std::string::npos;
821 s.replace(pos, f.size(), t),
822 pos = s.find(f, pos + t.size()))
827 static std::string escape(std::string s)
829 replace_substring(s,
"~",
"~0");
830 replace_substring(s,
"/",
"~1");
835 static void unescape(std::string& s)
837 replace_substring(s,
"~1",
"/");
838 replace_substring(s,
"~0",
"~");
848 static void flatten(
const std::string& reference_string,
849 const BasicJsonType& value,
850 BasicJsonType& result)
852 switch (
value.type())
856 if (
value.m_value.array->empty())
859 result[reference_string] =
nullptr;
864 for (std::size_t i = 0; i <
value.m_value.array->size(); ++i)
866 flatten(reference_string +
"/" + std::to_string(i),
867 value.m_value.array->operator[](i), result);
875 if (
value.m_value.object->empty())
878 result[reference_string] =
nullptr;
883 for (
const auto& element : *
value.m_value.object)
885 flatten(reference_string +
"/" + escape(element.first), element.second, result);
894 result[reference_string] =
value;
911 unflatten(
const BasicJsonType& value)
913 if (JSON_HEDLEY_UNLIKELY(!
value.is_object()))
915 JSON_THROW(detail::type_error::create(314,
"only objects can be unflattened"));
918 BasicJsonType result;
921 for (
const auto& element : *
value.m_value.object)
923 if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
925 JSON_THROW(detail::type_error::create(315,
"values in object must be primitive"));
932 json_pointer(element.first).get_and_create(result) = element.second;
952 return lhs.reference_tokens == rhs.reference_tokens;
969 return !(lhs == rhs);
973 std::vector<std::string> reference_tokens;
a class to store JSON values
Definition: json.hpp:170
static parse_error create(int id_, const position_t &pos, const std::string &what_arg)
create a parse error exception
Definition: exceptions.hpp:130
JSON Pointer.
Definition: json_pointer.hpp:19
const std::string & back() const
return last reference token
Definition: json_pointer.hpp:270
std::string to_string() const
return a string representation of the JSON pointer
Definition: json_pointer.hpp:64
friend bool operator==(json_pointer const &lhs, json_pointer const &rhs) noexcept
compares two JSON pointers for equality
Definition: json_pointer.hpp:949
void pop_back()
remove last reference token
Definition: json_pointer.hpp:246
bool empty() const noexcept
return whether pointer points to the root document
Definition: json_pointer.hpp:317
friend bool operator!=(json_pointer const &lhs, json_pointer const &rhs) noexcept
compares two JSON pointers for inequality
Definition: json_pointer.hpp:966
void push_back(const std::string &token)
append an unescaped token at the end of the reference pointer
Definition: json_pointer.hpp:292
json_pointer & operator/=(const json_pointer &ptr)
append another JSON pointer at the end of this JSON pointer
Definition: json_pointer.hpp:96
json_pointer & operator/=(std::size_t array_idx)
append an array index at the end of this JSON pointer
Definition: json_pointer.hpp:142
json_pointer(const std::string &s="")
create JSON pointer
Definition: json_pointer.hpp:46
friend json_pointer operator/(const json_pointer &lhs, const json_pointer &rhs)
create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
Definition: json_pointer.hpp:162
friend json_pointer operator/(const json_pointer &ptr, std::string token)
create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
Definition: json_pointer.hpp:183
json_pointer & operator/=(std::string token)
append an unescaped reference token at the end of this JSON pointer
Definition: json_pointer.hpp:120
void push_back(std::string &&token)
append an unescaped token at the end of the reference pointer
Definition: json_pointer.hpp:298
friend json_pointer operator/(const json_pointer &ptr, std::size_t array_idx)
create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
Definition: json_pointer.hpp:203
json_pointer parent_pointer() const
returns the parent of this JSON pointer
Definition: json_pointer.hpp:221
@ object
object (unordered set of name/value pairs)
@ array
array (ordered collection of values)
@ value
the parser finished reading a JSON value
namespace for Niels Lohmann
Definition: adl_serializer.hpp:9