WPILibC++ 2024.3.2
json_pointer.h
Go to the documentation of this file.
1// __ _____ _____ _____
2// __| | __| | | | JSON for Modern C++
3// | | |__ | | | | | | version 3.11.2
4// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#pragma once
10
11#include <algorithm> // all_of
12#include <cctype> // isdigit
13#include <cerrno> // errno, ERANGE
14#include <cstdlib> // strtoull
15#ifndef JSON_NO_IO
16 #include <iosfwd> // ostream
17#endif // JSON_NO_IO
18#include <limits> // max
19#include <numeric> // accumulate
20#include <string> // string
21#include <utility> // move
22#include <vector> // vector
23
28#include <wpi/detail/value_t.h>
29
31
32/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
33/// @sa https://json.nlohmann.me/api/json_pointer/
34template<typename RefStringType>
36{
37 // allow basic_json to access private members
39 friend class basic_json;
40
41 template<typename>
42 friend class json_pointer;
43
44 template<typename T>
45 struct string_t_helper
46 {
47 using type = T;
48 };
49
51 struct string_t_helper<WPI_BASIC_JSON_TPL>
52 {
53 using type = StringType;
54 };
55
56 public:
57 // for backwards compatibility accept BasicJsonType
58 using string_t = typename string_t_helper<RefStringType>::type;
59
60 /// @brief create JSON pointer
61 /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/
62 explicit json_pointer(const string_t& s = "")
63 : reference_tokens(split(s))
64 {}
65
66 /// @brief return a string representation of the JSON pointer
67 /// @sa https://json.nlohmann.me/api/json_pointer/to_string/
69 {
70 return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
71 string_t{},
72 [](const string_t& a, const string_t& b)
73 {
74 return detail::concat(a, '/', detail::escape(b));
75 });
76 }
77
78 /// @brief return a string representation of the JSON pointer
79 /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/
81 operator string_t() const
82 {
83 return to_string();
84 }
85
86#ifndef JSON_NO_IO
87 /// @brief write string representation of the JSON pointer to stream
88 /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
89 friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
90 {
91 o << ptr.to_string();
92 return o;
93 }
94#endif
95
96 /// @brief append another JSON pointer at the end of this JSON pointer
97 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
99 {
100 reference_tokens.insert(reference_tokens.end(),
101 ptr.reference_tokens.begin(),
102 ptr.reference_tokens.end());
103 return *this;
104 }
105
106 /// @brief append an unescaped reference token at the end of this JSON pointer
107 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
109 {
110 push_back(std::move(token));
111 return *this;
112 }
113
114 /// @brief append an array index at the end of this JSON pointer
115 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
116 json_pointer& operator/=(std::size_t array_idx)
117 {
118 return *this /= std::to_string(array_idx);
119 }
120
121 /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
122 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
124 const json_pointer& rhs)
125 {
126 return json_pointer(lhs) /= rhs;
127 }
128
129 /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
130 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
131 friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)
132 {
133 return json_pointer(lhs) /= std::move(token);
134 }
135
136 /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
137 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
138 friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)
139 {
140 return json_pointer(lhs) /= array_idx;
141 }
142
143 /// @brief returns the parent of this JSON pointer
144 /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/
146 {
147 if (empty())
148 {
149 return *this;
150 }
151
152 json_pointer res = *this;
153 res.pop_back();
154 return res;
155 }
156
157 /// @brief remove last reference token
158 /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/
159 void pop_back()
160 {
162 {
163 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
164 }
165
166 reference_tokens.pop_back();
167 }
168
169 /// @brief return last reference token
170 /// @sa https://json.nlohmann.me/api/json_pointer/back/
171 const string_t& back() const
172 {
174 {
175 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
176 }
177
178 return reference_tokens.back();
179 }
180
181 /// @brief append an unescaped token at the end of the reference pointer
182 /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
183 void push_back(const string_t& token)
184 {
185 reference_tokens.push_back(token);
186 }
187
188 /// @brief append an unescaped token at the end of the reference pointer
189 /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
190 void push_back(string_t&& token)
191 {
192 reference_tokens.push_back(std::move(token));
193 }
194
195 /// @brief return whether pointer points to the root document
196 /// @sa https://json.nlohmann.me/api/json_pointer/empty/
197 bool empty() const noexcept
198 {
199 return reference_tokens.empty();
200 }
201
202 private:
203 /*!
204 @param[in] s reference token to be converted into an array index
205
206 @return integer representation of @a s
207
208 @throw parse_error.106 if an array index begins with '0'
209 @throw parse_error.109 if an array index begins not with a digit
210 @throw out_of_range.404 if string @a s could not be converted to an integer
211 @throw out_of_range.410 if an array index exceeds size_type
212 */
213 template<typename BasicJsonType>
214 static typename BasicJsonType::size_type array_index(const string_t& s)
215 {
216 using size_type = typename BasicJsonType::size_type;
217
218 // error condition (cf. RFC 6901, Sect. 4)
219 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
220 {
221 JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
222 }
223
224 // error condition (cf. RFC 6901, Sect. 4)
225 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
226 {
227 JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
228 }
229
230 const char* p = s.c_str();
231 char* p_end = nullptr;
232 errno = 0; // strtoull doesn't reset errno
233 unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
234 if (p == p_end // invalid input or empty string
235 || errno == ERANGE // out of range
236 || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
237 {
238 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
239 }
240
241 // only triggered on special platforms (like 32bit), see also
242 // https://github.com/nlohmann/json/pull/2203
243 if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int)
244 {
245 JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE
246 }
247
248 return static_cast<size_type>(res);
249 }
250
252 json_pointer top() const
253 {
255 {
256 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
257 }
258
259 json_pointer result = *this;
260 result.reference_tokens = {reference_tokens[0]};
261 return result;
262 }
263
264 private:
265 /*!
266 @brief create and return a reference to the pointed to value
267
268 @complexity Linear in the number of reference tokens.
269
270 @throw parse_error.109 if array index is not a number
271 @throw type_error.313 if value cannot be unflattened
272 */
273 template<typename BasicJsonType>
274 BasicJsonType& get_and_create(BasicJsonType& j) const
275 {
276 auto* result = &j;
277
278 // in case no reference tokens exist, return a reference to the JSON value
279 // j which will be overwritten by a primitive value
280 for (const auto& reference_token : reference_tokens)
281 {
282 switch (result->type())
283 {
285 {
286 if (reference_token == "0")
287 {
288 // start a new array if reference token is 0
289 result = &result->operator[](0);
290 }
291 else
292 {
293 // start a new object otherwise
294 result = &result->operator[](reference_token);
295 }
296 break;
297 }
298
300 {
301 // create an entry in the object
302 result = &result->operator[](reference_token);
303 break;
304 }
305
307 {
308 // create an entry in the array
309 result = &result->operator[](array_index<BasicJsonType>(reference_token));
310 break;
311 }
312
313 /*
314 The following code is only reached if there exists a reference
315 token _and_ the current value is primitive. In this case, we have
316 an error situation, because primitive values may only occur as
317 single value; that is, with an empty list of reference tokens.
318 */
326 default:
327 JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
328 }
329 }
330
331 return *result;
332 }
333
334 /*!
335 @brief return a reference to the pointed to value
336
337 @note This version does not throw if a value is not present, but tries to
338 create nested values instead. For instance, calling this function
339 with pointer `"/this/that"` on a null value is equivalent to calling
340 `operator[]("this").operator[]("that")` on that value, effectively
341 changing the null value to an object.
342
343 @param[in] ptr a JSON value
344
345 @return reference to the JSON value pointed to by the JSON pointer
346
347 @complexity Linear in the length of the JSON pointer.
348
349 @throw parse_error.106 if an array index begins with '0'
350 @throw parse_error.109 if an array index was not a number
351 @throw out_of_range.404 if the JSON pointer can not be resolved
352 */
353 template<typename BasicJsonType>
354 BasicJsonType& get_unchecked(BasicJsonType* ptr) const
355 {
356 for (const auto& reference_token : reference_tokens)
357 {
358 // convert null values to arrays or objects before continuing
359 if (ptr->is_null())
360 {
361 // check if reference token is a number
362 const bool nums =
363 std::all_of(reference_token.begin(), reference_token.end(),
364 [](const unsigned char x)
365 {
366 return std::isdigit(x);
367 });
368
369 // change value to array for numbers or "-" or to object otherwise
370 *ptr = (nums || reference_token == "-")
373 }
374
375 switch (ptr->type())
376 {
378 {
379 // use unchecked object access
380 ptr = &ptr->operator[](reference_token);
381 break;
382 }
383
385 {
386 if (reference_token == "-")
387 {
388 // explicitly treat "-" as index beyond the end
389 ptr = &ptr->operator[](ptr->m_value.array->size());
390 }
391 else
392 {
393 // convert array index to number; unchecked access
394 ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
395 }
396 break;
397 }
398
407 default:
408 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
409 }
410 }
411
412 return *ptr;
413 }
414
415 /*!
416 @throw parse_error.106 if an array index begins with '0'
417 @throw parse_error.109 if an array index was not a number
418 @throw out_of_range.402 if the array index '-' is used
419 @throw out_of_range.404 if the JSON pointer can not be resolved
420 */
421 template<typename BasicJsonType>
422 BasicJsonType& get_checked(BasicJsonType* ptr) const
423 {
424 for (const auto& reference_token : reference_tokens)
425 {
426 switch (ptr->type())
427 {
429 {
430 // note: at performs range check
431 ptr = &ptr->at(reference_token);
432 break;
433 }
434
436 {
437 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
438 {
439 // "-" always fails the range check
441 "array index '-' (", std::to_string(ptr->m_value.array->size()),
442 ") is out of range"), ptr));
443 }
444
445 // note: at performs range check
446 ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
447 break;
448 }
449
458 default:
459 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
460 }
461 }
462
463 return *ptr;
464 }
465
466 /*!
467 @brief return a const reference to the pointed to value
468
469 @param[in] ptr a JSON value
470
471 @return const reference to the JSON value pointed to by the JSON
472 pointer
473
474 @throw parse_error.106 if an array index begins with '0'
475 @throw parse_error.109 if an array index was not a number
476 @throw out_of_range.402 if the array index '-' is used
477 @throw out_of_range.404 if the JSON pointer can not be resolved
478 */
479 template<typename BasicJsonType>
480 const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
481 {
482 for (const auto& reference_token : reference_tokens)
483 {
484 switch (ptr->type())
485 {
487 {
488 // use unchecked object access
489 ptr = &ptr->operator[](reference_token);
490 break;
491 }
492
494 {
495 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
496 {
497 // "-" cannot be used for const access
498 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));
499 }
500
501 // use unchecked array access
502 ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
503 break;
504 }
505
514 default:
515 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
516 }
517 }
518
519 return *ptr;
520 }
521
522 /*!
523 @throw parse_error.106 if an array index begins with '0'
524 @throw parse_error.109 if an array index was not a number
525 @throw out_of_range.402 if the array index '-' is used
526 @throw out_of_range.404 if the JSON pointer can not be resolved
527 */
528 template<typename BasicJsonType>
529 const BasicJsonType& get_checked(const BasicJsonType* ptr) const
530 {
531 for (const auto& reference_token : reference_tokens)
532 {
533 switch (ptr->type())
534 {
536 {
537 // note: at performs range check
538 ptr = &ptr->at(reference_token);
539 break;
540 }
541
543 {
544 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
545 {
546 // "-" always fails the range check
548 "array index '-' (", std::to_string(ptr->m_value.array->size()),
549 ") is out of range"), ptr));
550 }
551
552 // note: at performs range check
553 ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
554 break;
555 }
556
565 default:
566 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
567 }
568 }
569
570 return *ptr;
571 }
572
573 /*!
574 @throw parse_error.106 if an array index begins with '0'
575 @throw parse_error.109 if an array index was not a number
576 */
577 template<typename BasicJsonType>
578 bool contains(const BasicJsonType* ptr) const
579 {
580 for (const auto& reference_token : reference_tokens)
581 {
582 switch (ptr->type())
583 {
585 {
586 if (!ptr->contains(reference_token))
587 {
588 // we did not find the key in the object
589 return false;
590 }
591
592 ptr = &ptr->operator[](reference_token);
593 break;
594 }
595
597 {
598 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
599 {
600 // "-" always fails the range check
601 return false;
602 }
603 if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
604 {
605 // invalid char
606 return false;
607 }
608 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
609 {
610 if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
611 {
612 // first char should be between '1' and '9'
613 return false;
614 }
615 for (std::size_t i = 1; i < reference_token.size(); i++)
616 {
617 if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
618 {
619 // other char should be between '0' and '9'
620 return false;
621 }
622 }
623 }
624
625 const auto idx = array_index<BasicJsonType>(reference_token);
626 if (idx >= ptr->size())
627 {
628 // index out of range
629 return false;
630 }
631
632 ptr = &ptr->operator[](idx);
633 break;
634 }
635
644 default:
645 {
646 // we do not expect primitive values if there is still a
647 // reference token to process
648 return false;
649 }
650 }
651 }
652
653 // no reference token left means we found a primitive value
654 return true;
655 }
656
657 /*!
658 @brief split the string input to reference tokens
659
660 @note This function is only called by the json_pointer constructor.
661 All exceptions below are documented there.
662
663 @throw parse_error.107 if the pointer is not empty or begins with '/'
664 @throw parse_error.108 if character '~' is not followed by '0' or '1'
665 */
666 static std::vector<string_t> split(const string_t& reference_string)
667 {
668 std::vector<string_t> result;
669
670 // special case: empty reference string -> no reference tokens
671 if (reference_string.empty())
672 {
673 return result;
674 }
675
676 // check if nonempty reference string begins with slash
677 if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
678 {
679 JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
680 }
681
682 // extract the reference tokens:
683 // - slash: position of the last read slash (or end of string)
684 // - start: position after the previous slash
685 for (
686 // search for the first slash after the first character
687 std::size_t slash = reference_string.find_first_of('/', 1),
688 // set the beginning of the first reference token
689 start = 1;
690 // we can stop if start == 0 (if slash == string_t::npos)
691 start != 0;
692 // set the beginning of the next reference token
693 // (will eventually be 0 if slash == string_t::npos)
694 start = (slash == string_t::npos) ? 0 : slash + 1,
695 // find next slash
696 slash = reference_string.find_first_of('/', start))
697 {
698 // use the text between the beginning of the reference token
699 // (start) and the last slash (slash).
700 auto reference_token = reference_string.substr(start, slash - start);
701
702 // check reference tokens are properly escaped
703 for (std::size_t pos = reference_token.find_first_of('~');
704 pos != string_t::npos;
705 pos = reference_token.find_first_of('~', pos + 1))
706 {
707 JSON_ASSERT(reference_token[pos] == '~');
708
709 // ~ must be followed by 0 or 1
710 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
711 (reference_token[pos + 1] != '0' &&
712 reference_token[pos + 1] != '1')))
713 {
714 JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
715 }
716 }
717
718 // finally, store the reference token
719 detail::unescape(reference_token);
720 result.push_back(reference_token);
721 }
722
723 return result;
724 }
725
726 private:
727 /*!
728 @param[in] reference_string the reference string to the current value
729 @param[in] value the value to consider
730 @param[in,out] result the result object to insert values to
731
732 @note Empty objects or arrays are flattened to `null`.
733 */
734 template<typename BasicJsonType>
735 static void flatten(const string_t& reference_string,
736 const BasicJsonType& value,
737 BasicJsonType& result)
738 {
739 switch (value.type())
740 {
742 {
743 if (value.m_value.array->empty())
744 {
745 // flatten empty array as null
746 result[reference_string] = nullptr;
747 }
748 else
749 {
750 // iterate array and use index as reference string
751 for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
752 {
753 flatten(detail::concat(reference_string, '/', std::to_string(i)),
754 value.m_value.array->operator[](i), result);
755 }
756 }
757 break;
758 }
759
761 {
762 if (value.m_value.object->empty())
763 {
764 // flatten empty object as null
765 result[reference_string] = nullptr;
766 }
767 else
768 {
769 // iterate object and use keys as reference string
770 for (const auto& element : *value.m_value.object)
771 {
772 flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
773 }
774 }
775 break;
776 }
777
786 default:
787 {
788 // add primitive value with its reference string
789 result[reference_string] = value;
790 break;
791 }
792 }
793 }
794
795 /*!
796 @param[in] value flattened JSON
797
798 @return unflattened JSON
799
800 @throw parse_error.109 if array index is not a number
801 @throw type_error.314 if value is not an object
802 @throw type_error.315 if object values are not primitive
803 @throw type_error.313 if value cannot be unflattened
804 */
805 template<typename BasicJsonType>
806 static BasicJsonType
807 unflatten(const BasicJsonType& value)
808 {
809 if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
810 {
811 JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
812 }
813
814 BasicJsonType result;
815
816 // iterate the JSON object values
817 for (const auto& element : *value.m_value.object)
818 {
819 if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
820 {
821 JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
822 }
823
824 // assign value to reference pointed to by JSON pointer; Note that if
825 // the JSON pointer is "" (i.e., points to the whole value), function
826 // get_and_create returns a reference to result itself. An assignment
827 // will then create a primitive value.
828 json_pointer(element.first).get_and_create(result) = element.second;
829 }
830
831 return result;
832 }
833
834 // can't use conversion operator because of ambiguity
835 json_pointer<string_t> convert() const&
836 {
838 result.reference_tokens = reference_tokens;
839 return result;
840 }
841
842 json_pointer<string_t> convert()&&
843 {
845 result.reference_tokens = std::move(reference_tokens);
846 return result;
847 }
848
849 public:
850#if JSON_HAS_THREE_WAY_COMPARISON
851 /// @brief compares two JSON pointers for equality
852 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
853 template<typename RefStringTypeRhs>
854 bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
855 {
856 return reference_tokens == rhs.reference_tokens;
857 }
858
859 /// @brief compares JSON pointer and string for equality
860 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
861 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
862 bool operator==(const string_t& rhs) const
863 {
864 return *this == json_pointer(rhs);
865 }
866
867 /// @brief 3-way compares two JSON pointers
868 template<typename RefStringTypeRhs>
869 std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
870 {
871 return reference_tokens <=> rhs.reference_tokens; // *NOPAD*
872 }
873#else
874 /// @brief compares two JSON pointers for equality
875 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
876 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
877 // NOLINTNEXTLINE(readability-redundant-declaration)
878 friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
879 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
880
881 /// @brief compares JSON pointer and string for equality
882 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
883 template<typename RefStringTypeLhs, typename StringType>
884 // NOLINTNEXTLINE(readability-redundant-declaration)
885 friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
886 const StringType& rhs);
887
888 /// @brief compares string and JSON pointer for equality
889 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
890 template<typename RefStringTypeRhs, typename StringType>
891 // NOLINTNEXTLINE(readability-redundant-declaration)
892 friend bool operator==(const StringType& lhs,
894
895 /// @brief compares two JSON pointers for inequality
896 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
897 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
898 // NOLINTNEXTLINE(readability-redundant-declaration)
899 friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
900 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
901
902 /// @brief compares JSON pointer and string for inequality
903 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
904 template<typename RefStringTypeLhs, typename StringType>
905 // NOLINTNEXTLINE(readability-redundant-declaration)
906 friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
907 const StringType& rhs);
908
909 /// @brief compares string and JSON pointer for inequality
910 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
911 template<typename RefStringTypeRhs, typename StringType>
912 // NOLINTNEXTLINE(readability-redundant-declaration)
913 friend bool operator!=(const StringType& lhs,
915
916 /// @brief compares two JSON pointer for less-than
917 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
918 // NOLINTNEXTLINE(readability-redundant-declaration)
919 friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
920 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
921#endif
922
923 private:
924 /// the reference tokens
925 std::vector<string_t> reference_tokens;
926};
927
928#if !JSON_HAS_THREE_WAY_COMPARISON
929// functions cannot be defined inside class due to ODR violations
930template<typename RefStringTypeLhs, typename RefStringTypeRhs>
932 const json_pointer<RefStringTypeRhs>& rhs) noexcept
933{
934 return lhs.reference_tokens == rhs.reference_tokens;
935}
936
937template<typename RefStringTypeLhs,
938 typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
940inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
941 const StringType& rhs)
942{
943 return lhs == json_pointer<RefStringTypeLhs>(rhs);
944}
945
946template<typename RefStringTypeRhs,
947 typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
949inline bool operator==(const StringType& lhs,
950 const json_pointer<RefStringTypeRhs>& rhs)
951{
952 return json_pointer<RefStringTypeRhs>(lhs) == rhs;
953}
954
955template<typename RefStringTypeLhs, typename RefStringTypeRhs>
957 const json_pointer<RefStringTypeRhs>& rhs) noexcept
958{
959 return !(lhs == rhs);
960}
961
962template<typename RefStringTypeLhs,
963 typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
965inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
966 const StringType& rhs)
967{
968 return !(lhs == rhs);
969}
970
971template<typename RefStringTypeRhs,
972 typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
974inline bool operator!=(const StringType& lhs,
975 const json_pointer<RefStringTypeRhs>& rhs)
976{
977 return !(lhs == rhs);
978}
979
980template<typename RefStringTypeLhs, typename RefStringTypeRhs>
982 const json_pointer<RefStringTypeRhs>& rhs) noexcept
983{
984 return lhs.reference_tokens < rhs.reference_tokens;
985}
986#endif
987
#define WPI_JSON_NAMESPACE_END
Definition: abi_macros.h:59
#define WPI_JSON_NAMESPACE_BEGIN
Definition: abi_macros.h:53
a class to store JSON values
Definition: json.h:96
static out_of_range create(int id_, const std::string &what_arg, BasicJsonContext context)
Definition: exceptions.h:226
static parse_error create(int id_, const position_t &pos, const std::string &what_arg, BasicJsonContext context)
create a parse error exception
Definition: exceptions.h:147
static type_error create(int id_, const std::string &what_arg, BasicJsonContext context)
Definition: exceptions.h:209
JSON Pointer defines a string syntax for identifying a specific value within a JSON document.
Definition: json_pointer.h:36
friend json_pointer operator/(const json_pointer &lhs, string_t token)
create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
Definition: json_pointer.h:131
typename string_t_helper< RefStringType >::type string_t
Definition: json_pointer.h:58
friend json_pointer operator/(const json_pointer &lhs, 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.h:138
json_pointer(const string_t &s="")
create JSON pointer
Definition: json_pointer.h:62
bool empty() const noexcept
return whether pointer points to the root document
Definition: json_pointer.h:197
friend bool operator==(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
compares two JSON pointers for equality
Definition: json_pointer.h:931
void pop_back()
remove last reference token
Definition: json_pointer.h:159
string_t to_string() const
return a string representation of the JSON pointer
Definition: json_pointer.h:68
json_pointer & operator/=(std::size_t array_idx)
append an array index at the end of this JSON pointer
Definition: json_pointer.h:116
void push_back(string_t &&token)
append an unescaped token at the end of the reference pointer
Definition: json_pointer.h:190
json_pointer & operator/=(const json_pointer &ptr)
append another JSON pointer at the end of this JSON pointer
Definition: json_pointer.h:98
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.h:123
json_pointer parent_pointer() const
returns the parent of this JSON pointer
Definition: json_pointer.h:145
friend bool operator!=(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
compares two JSON pointers for inequality
Definition: json_pointer.h:956
json_pointer & operator/=(string_t token)
append an unescaped reference token at the end of this JSON pointer
Definition: json_pointer.h:108
friend class json_pointer
Definition: json_pointer.h:42
const string_t & back() const
return last reference token
Definition: json_pointer.h:171
friend std::ostream & operator<<(std::ostream &o, const json_pointer &ptr)
write string representation of the JSON pointer to stream
Definition: json_pointer.h:89
void push_back(const string_t &token)
append an unescaped token at the end of the reference pointer
Definition: json_pointer.h:183
friend bool operator<(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
compares two JSON pointer for less-than
Definition: json_pointer.h:981
auto ptr(T p) -> const void *
\rst Converts p to const void* for pointer formatting.
Definition: format.h:4100
#define JSON_HEDLEY_UNLIKELY(expr)
Definition: hedley.h:1396
#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)
Definition: hedley.h:1078
bool operator==(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
Definition: json_pointer.h:931
bool operator!=(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
Definition: json_pointer.h:956
bool operator<(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
Definition: json_pointer.h:981
#define WPI_BASIC_JSON_TPL_DECLARATION
Definition: macro_scope.h:236
#define JSON_PRIVATE_UNLESS_TESTED
Definition: macro_scope.h:199
#define JSON_ASSERT(x)
Definition: macro_scope.h:192
#define JSON_THROW(exception)
Definition: macro_scope.h:163
#define WPI_BASIC_JSON_TPL
Definition: macro_scope.h:245
static void unescape(StringType &s)
string unescaping as described in RFC 6901 (Sect. 4)
Definition: string_escape.h:65
OutStringType concat(Args &&... args)
Definition: string_concat.h:137
@ value
the parser finished reading a JSON value
@ null
null value
@ number_integer
number value (signed integer)
@ boolean
boolean value
@ discarded
discarded by the parser callback function
@ binary
binary array (ordered collection of bytes)
@ object
object (unordered set of name/value pairs)
@ string
string value
@ number_float
number value (floating-point)
@ number_unsigned
number value (unsigned integer)
@ array
array (ordered collection of values)
type
Definition: core.h:556
StringType escape(StringType s)
string escaping as described in RFC 6901 (Sect. 4)
Definition: string_escape.h:50
std::string to_string(const T &t)
Definition: base.h:92
UnitTypeLhs() max(const UnitTypeLhs &lhs, const UnitTypeRhs &rhs)
Definition: base.h:3417
b
Definition: data.h:44