blob: ba9cd8ef7ad8dc5bda4028e5d96be1594f54e06a [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7/*
8 __ _____ _____ _____
9 __| | __| | | | JSON for Modern C++
10| | |__ | | | | | | version 3.1.2
11|_____|_____|_____|_|___| https://github.com/nlohmann/json
12
13Licensed under the MIT License <http://opensource.org/licenses/MIT>.
14Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
15
16Permission is hereby granted, free of charge, to any person obtaining a copy
17of this software and associated documentation files (the "Software"), to deal
18in the Software without restriction, including without limitation the rights
19to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20copies of the Software, and to permit persons to whom the Software is
21furnished to do so, subject to the following conditions:
22
23The above copyright notice and this permission notice shall be included in all
24copies or substantial portions of the Software.
25
26THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32SOFTWARE.
33*/
34#define WPI_JSON_IMPLEMENTATION
35#include "wpi/json.h"
36
37#include "wpi/raw_ostream.h"
38
39namespace wpi {
40namespace detail {
41
42exception::exception(int id_, const Twine& what_arg)
43 : id(id_), m(what_arg.str()) {}
44
45parse_error parse_error::create(int id_, std::size_t byte_, const Twine& what_arg)
46{
47 return parse_error(id_, byte_, "[json.exception.parse_error." + Twine(id_) + "] parse error" +
48 (byte_ != 0 ? (" at " + Twine(byte_)) : Twine("")) +
49 ": " + what_arg);
50}
51
52invalid_iterator invalid_iterator::create(int id_, const Twine& what_arg)
53{
54 return invalid_iterator(id_, "[json.exception.invalid_iterator." + Twine(id_) + "] " + what_arg);
55}
56
57type_error type_error::create(int id_, const Twine& what_arg)
58{
59 return type_error(id_, "[json.exception.type_error." + Twine(id_) + "] " + what_arg);
60}
61
62out_of_range out_of_range::create(int id_, const Twine& what_arg)
63{
64 return out_of_range(id_, "[json.exception.out_of_range." + Twine(id_) + "] " + what_arg);
65}
66
67other_error other_error::create(int id_, const Twine& what_arg)
68{
69 return other_error(id_, "[json.exception.other_error." + Twine(id_) + "] " + what_arg);
70}
71
72} // namespace detail
73
74json::json_value::json_value(value_t t)
75{
76 switch (t)
77 {
78 case value_t::object:
79 {
80 object = create<object_t>();
81 break;
82 }
83
84 case value_t::array:
85 {
86 array = create<array_t>();
87 break;
88 }
89
90 case value_t::string:
91 {
92 string = create<std::string>("");
93 break;
94 }
95
96 case value_t::boolean:
97 {
98 boolean = false;
99 break;
100 }
101
102 case value_t::number_integer:
103 {
104 number_integer = 0;
105 break;
106 }
107
108 case value_t::number_unsigned:
109 {
110 number_unsigned = 0u;
111 break;
112 }
113
114 case value_t::number_float:
115 {
116 number_float = 0.0;
117 break;
118 }
119
120 case value_t::null:
121 {
122 object = nullptr; // silence warning, see #821
123 break;
124 }
125
126 default:
127 {
128 object = nullptr; // silence warning, see #821
129 if (JSON_UNLIKELY(t == value_t::null))
130 {
131 JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2")); // LCOV_EXCL_LINE
132 }
133 break;
134 }
135 }
136}
137
138void json::json_value::destroy(value_t t) noexcept
139{
140 switch (t)
141 {
142 case value_t::object:
143 {
144 std::allocator<object_t> alloc;
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800145 std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
146 std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800147 break;
148 }
149
150 case value_t::array:
151 {
152 std::allocator<array_t> alloc;
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800153 std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
154 std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800155 break;
156 }
157
158 case value_t::string:
159 {
160 std::allocator<std::string> alloc;
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800161 std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
162 std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800163 break;
164 }
165
166 default:
167 {
168 break;
169 }
170 }
171}
172
173json::json(initializer_list_t init,
174 bool type_deduction,
175 value_t manual_type)
176{
177 // check if each element is an array with two elements whose first
178 // element is a string
179 bool is_an_object = std::all_of(init.begin(), init.end(),
180 [](const detail::json_ref<json>& element_ref)
181 {
182 return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string());
183 });
184
185 // adjust type if type deduction is not wanted
186 if (not type_deduction)
187 {
188 // if array is wanted, do not create an object though possible
189 if (manual_type == value_t::array)
190 {
191 is_an_object = false;
192 }
193
194 // if object is wanted but impossible, throw an exception
195 if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object))
196 {
197 JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
198 }
199 }
200
201 if (is_an_object)
202 {
203 // the initializer list is a list of pairs -> create object
204 m_type = value_t::object;
205 m_value = value_t::object;
206
207 std::for_each(init.begin(), init.end(), [this](const detail::json_ref<json>& element_ref)
208 {
209 auto element = element_ref.moved_or_copied();
210 m_value.object->try_emplace(
211 *((*element.m_value.array)[0].m_value.string),
212 std::move((*element.m_value.array)[1]));
213 });
214 }
215 else
216 {
217 // the initializer list describes an array -> create array
218 m_type = value_t::array;
219 m_value.array = create<array_t>(init.begin(), init.end());
220 }
221
222 assert_invariant();
223}
224
225json::json(size_type cnt, const json& val)
226 : m_type(value_t::array)
227{
228 m_value.array = create<array_t>(cnt, val);
229 assert_invariant();
230}
231
232json::json(const json& other)
233 : m_type(other.m_type)
234{
235 // check of passed value is valid
236 other.assert_invariant();
237
238 switch (m_type)
239 {
240 case value_t::object:
241 {
242 m_value = *other.m_value.object;
243 break;
244 }
245
246 case value_t::array:
247 {
248 m_value = *other.m_value.array;
249 break;
250 }
251
252 case value_t::string:
253 {
254 m_value = *other.m_value.string;
255 break;
256 }
257
258 case value_t::boolean:
259 {
260 m_value = other.m_value.boolean;
261 break;
262 }
263
264 case value_t::number_integer:
265 {
266 m_value = other.m_value.number_integer;
267 break;
268 }
269
270 case value_t::number_unsigned:
271 {
272 m_value = other.m_value.number_unsigned;
273 break;
274 }
275
276 case value_t::number_float:
277 {
278 m_value = other.m_value.number_float;
279 break;
280 }
281
282 default:
283 break;
284 }
285
286 assert_invariant();
287}
288
289json json::meta()
290{
291 json result;
292
293 result["copyright"] = "(C) 2013-2017 Niels Lohmann, (C) 2017-2018 FIRST";
294 result["name"] = "WPI version of JSON for Modern C++";
295 result["url"] = "https://github.com/wpilibsuite/allwpilib";
296 result["version"]["string"] =
297 std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." +
298 std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." +
299 std::to_string(NLOHMANN_JSON_VERSION_PATCH);
300 result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
301 result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
302 result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
303
304#ifdef _WIN32
305 result["platform"] = "win32";
306#elif defined __linux__
307 result["platform"] = "linux";
308#elif defined __APPLE__
309 result["platform"] = "apple";
310#elif defined __unix__
311 result["platform"] = "unix";
312#else
313 result["platform"] = "unknown";
314#endif
315
316#if defined(__ICC) || defined(__INTEL_COMPILER)
317 result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
318#elif defined(__clang__)
319 result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
320#elif defined(__GNUC__) || defined(__GNUG__)
321 result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}};
322#elif defined(__HP_cc) || defined(__HP_aCC)
323 result["compiler"] = "hp"
324#elif defined(__IBMCPP__)
325 result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
326#elif defined(_MSC_VER)
327 result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
328#elif defined(__PGI)
329 result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
330#elif defined(__SUNPRO_CC)
331 result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
332#else
333 result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
334#endif
335
336#ifdef __cplusplus
337 result["compiler"]["c++"] = std::to_string(__cplusplus);
338#else
339 result["compiler"]["c++"] = "unknown";
340#endif
341 return result;
342}
343
344json::reference json::at(size_type idx)
345{
346 // at only works for arrays
347 if (JSON_LIKELY(is_array()))
348 {
349 JSON_TRY
350 {
351 return m_value.array->at(idx);
352 }
353 JSON_CATCH (std::out_of_range&)
354 {
355 // create better exception explanation
356 JSON_THROW(out_of_range::create(401, "array index " + Twine(idx) + " is out of range"));
357 }
358 }
359 else
360 {
361 JSON_THROW(type_error::create(304, "cannot use at() with " + Twine(type_name())));
362 }
363}
364
365json::const_reference json::at(size_type idx) const
366{
367 // at only works for arrays
368 if (JSON_LIKELY(is_array()))
369 {
370 JSON_TRY
371 {
372 return m_value.array->at(idx);
373 }
374 JSON_CATCH (std::out_of_range&)
375 {
376 // create better exception explanation
377 JSON_THROW(out_of_range::create(401, "array index " + Twine(idx) + " is out of range"));
378 }
379 }
380 else
381 {
382 JSON_THROW(type_error::create(304, "cannot use at() with " + Twine(type_name())));
383 }
384}
385
386json::reference json::at(StringRef key)
387{
388 // at only works for objects
389 if (JSON_LIKELY(is_object()))
390 {
391 auto it = m_value.object->find(key);
392 if (it == m_value.object->end())
393 {
394 // create better exception explanation
395 JSON_THROW(out_of_range::create(403, "key '" + Twine(key) + "' not found"));
396 }
397 return it->second;
398 }
399 else
400 {
401 JSON_THROW(type_error::create(304, "cannot use at() with " + Twine(type_name())));
402 }
403}
404
405json::const_reference json::at(StringRef key) const
406{
407 // at only works for objects
408 if (JSON_LIKELY(is_object()))
409 {
410 auto it = m_value.object->find(key);
411 if (it == m_value.object->end())
412 {
413 // create better exception explanation
414 JSON_THROW(out_of_range::create(403, "key '" + Twine(key) + "' not found"));
415 }
416 return it->second;
417 }
418 else
419 {
420 JSON_THROW(type_error::create(304, "cannot use at() with " + Twine(type_name())));
421 }
422}
423
424json::reference json::operator[](size_type idx)
425{
426 // implicitly convert null value to an empty array
427 if (is_null())
428 {
429 m_type = value_t::array;
430 m_value.array = create<array_t>();
431 assert_invariant();
432 }
433
434 // operator[] only works for arrays
435 if (JSON_LIKELY(is_array()))
436 {
437 // fill up array with null values if given idx is outside range
438 if (idx >= m_value.array->size())
439 {
440 m_value.array->insert(m_value.array->end(),
441 idx - m_value.array->size() + 1,
442 json());
443 }
444
445 return m_value.array->operator[](idx);
446 }
447
448 JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
449}
450
451json::const_reference json::operator[](size_type idx) const
452{
453 // const operator[] only works for arrays
454 if (JSON_LIKELY(is_array()))
455 {
456 return m_value.array->operator[](idx);
457 }
458
459 JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
460}
461
462json::reference json::operator[](StringRef key)
463{
464 // implicitly convert null value to an empty object
465 if (is_null())
466 {
467 m_type = value_t::object;
468 m_value.object = create<object_t>();
469 assert_invariant();
470 }
471
472 // operator[] only works for objects
473 if (JSON_LIKELY(is_object()))
474 {
475 return m_value.object->operator[](key);
476 }
477
478 JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
479}
480
481json::const_reference json::operator[](StringRef key) const
482{
483 // const operator[] only works for objects
484 if (JSON_LIKELY(is_object()))
485 {
486 assert(m_value.object->find(key) != m_value.object->end());
487 return m_value.object->find(key)->second;
488 }
489
490 JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
491}
492
493json::size_type json::erase(StringRef key)
494{
495 // this erase only works for objects
496 if (JSON_LIKELY(is_object()))
497 {
498 return m_value.object->erase(key);
499 }
500
501 JSON_THROW(type_error::create(307, "cannot use erase() with " + Twine(type_name())));
502}
503
504void json::erase(const size_type idx)
505{
506 // this erase only works for arrays
507 if (JSON_LIKELY(is_array()))
508 {
509 if (JSON_UNLIKELY(idx >= size()))
510 {
511 JSON_THROW(out_of_range::create(401, "array index " + Twine(idx) + " is out of range"));
512 }
513
514 m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
515 }
516 else
517 {
518 JSON_THROW(type_error::create(307, "cannot use erase() with " + Twine(type_name())));
519 }
520}
521
522json::iterator json::find(StringRef key)
523{
524 auto result = end();
525
526 if (is_object())
527 {
528 result.m_it.object_iterator = m_value.object->find(key);
529 }
530
531 return result;
532}
533
534json::const_iterator json::find(StringRef key) const
535{
536 auto result = cend();
537
538 if (is_object())
539 {
540 result.m_it.object_iterator = m_value.object->find(key);
541 }
542
543 return result;
544}
545
546json::size_type json::count(StringRef key) const
547{
548 // return 0 for all nonobject types
549 return is_object() ? m_value.object->count(key) : 0;
550}
551
552bool json::empty() const noexcept
553{
554 switch (m_type)
555 {
556 case value_t::null:
557 {
558 // null values are empty
559 return true;
560 }
561
562 case value_t::array:
563 {
564 // delegate call to array_t::empty()
565 return m_value.array->empty();
566 }
567
568 case value_t::object:
569 {
570 // delegate call to object_t::empty()
571 return m_value.object->empty();
572 }
573
574 default:
575 {
576 // all other types are nonempty
577 return false;
578 }
579 }
580}
581
582json::size_type json::size() const noexcept
583{
584 switch (m_type)
585 {
586 case value_t::null:
587 {
588 // null values are empty
589 return 0;
590 }
591
592 case value_t::array:
593 {
594 // delegate call to array_t::size()
595 return m_value.array->size();
596 }
597
598 case value_t::object:
599 {
600 // delegate call to object_t::size()
601 return m_value.object->size();
602 }
603
604 default:
605 {
606 // all other types have size 1
607 return 1;
608 }
609 }
610}
611
612json::size_type json::max_size() const noexcept
613{
614 switch (m_type)
615 {
616 case value_t::array:
617 {
618 // delegate call to array_t::max_size()
619 return m_value.array->max_size();
620 }
621
622 case value_t::object:
623 {
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800624 // delegate call to std::allocator<object_t>::max_size()
625 return std::allocator_traits<object_t>::max_size(*m_value.object);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800626 }
627
628 default:
629 {
630 // all other types have max_size() == size()
631 return size();
632 }
633 }
634}
635
636void json::clear() noexcept
637{
638 switch (m_type)
639 {
640 case value_t::number_integer:
641 {
642 m_value.number_integer = 0;
643 break;
644 }
645
646 case value_t::number_unsigned:
647 {
648 m_value.number_unsigned = 0;
649 break;
650 }
651
652 case value_t::number_float:
653 {
654 m_value.number_float = 0.0;
655 break;
656 }
657
658 case value_t::boolean:
659 {
660 m_value.boolean = false;
661 break;
662 }
663
664 case value_t::string:
665 {
666 m_value.string->clear();
667 break;
668 }
669
670 case value_t::array:
671 {
672 m_value.array->clear();
673 break;
674 }
675
676 case value_t::object:
677 {
678 m_value.object->clear();
679 break;
680 }
681
682 default:
683 break;
684 }
685}
686
687void json::push_back(json&& val)
688{
689 // push_back only works for null objects or arrays
690 if (JSON_UNLIKELY(not(is_null() or is_array())))
691 {
692 JSON_THROW(type_error::create(308, "cannot use push_back() with " + Twine(type_name())));
693 }
694
695 // transform null object into an array
696 if (is_null())
697 {
698 m_type = value_t::array;
699 m_value = value_t::array;
700 assert_invariant();
701 }
702
703 // add element to array (move semantics)
704 m_value.array->push_back(std::move(val));
705 // invalidate object
706 val.m_type = value_t::null;
707}
708
709void json::push_back(const json& val)
710{
711 // push_back only works for null objects or arrays
712 if (JSON_UNLIKELY(not(is_null() or is_array())))
713 {
714 JSON_THROW(type_error::create(308, "cannot use push_back() with " + Twine(type_name())));
715 }
716
717 // transform null object into an array
718 if (is_null())
719 {
720 m_type = value_t::array;
721 m_value = value_t::array;
722 assert_invariant();
723 }
724
725 // add element to array
726 m_value.array->push_back(val);
727}
728
729void json::push_back(initializer_list_t init)
730{
731 if (is_object() and init.size() == 2 and (*init.begin())->is_string())
732 {
733 std::string key = init.begin()->moved_or_copied();
734 push_back(std::pair<StringRef, json>(key, (init.begin() + 1)->moved_or_copied()));
735 }
736 else
737 {
738 push_back(json(init));
739 }
740}
741
742json::iterator json::insert(const_iterator pos, const json& val)
743{
744 // insert only works for arrays
745 if (JSON_LIKELY(is_array()))
746 {
747 // check if iterator pos fits to this JSON value
748 if (JSON_UNLIKELY(pos.m_object != this))
749 {
750 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
751 }
752
753 // insert to array and return iterator
754 iterator result(this);
755 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
756 return result;
757 }
758
759 JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
760}
761
762json::iterator json::insert(const_iterator pos, size_type cnt, const json& val)
763{
764 // insert only works for arrays
765 if (JSON_LIKELY(is_array()))
766 {
767 // check if iterator pos fits to this JSON value
768 if (JSON_UNLIKELY(pos.m_object != this))
769 {
770 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
771 }
772
773 // insert to array and return iterator
774 iterator result(this);
775 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
776 return result;
777 }
778
779 JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
780}
781
782json::iterator json::insert(const_iterator pos, const_iterator first, const_iterator last)
783{
784 // insert only works for arrays
785 if (JSON_UNLIKELY(not is_array()))
786 {
787 JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
788 }
789
790 // check if iterator pos fits to this JSON value
791 if (JSON_UNLIKELY(pos.m_object != this))
792 {
793 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
794 }
795
796 // check if range iterators belong to the same JSON object
797 if (JSON_UNLIKELY(first.m_object != last.m_object))
798 {
799 JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
800 }
801
802 if (JSON_UNLIKELY(first.m_object == this))
803 {
804 JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container"));
805 }
806
807 // insert to array and return iterator
808 iterator result(this);
809 result.m_it.array_iterator = m_value.array->insert(
810 pos.m_it.array_iterator,
811 first.m_it.array_iterator,
812 last.m_it.array_iterator);
813 return result;
814}
815
816json::iterator json::insert(const_iterator pos, initializer_list_t ilist)
817{
818 // insert only works for arrays
819 if (JSON_UNLIKELY(not is_array()))
820 {
821 JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
822 }
823
824 // check if iterator pos fits to this JSON value
825 if (JSON_UNLIKELY(pos.m_object != this))
826 {
827 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
828 }
829
830 // insert to array and return iterator
831 iterator result(this);
832 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end());
833 return result;
834}
835
836void json::insert(const_iterator first, const_iterator last)
837{
838 // insert only works for objects
839 if (JSON_UNLIKELY(not is_object()))
840 {
841 JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
842 }
843
844 // check if range iterators belong to the same JSON object
845 if (JSON_UNLIKELY(first.m_object != last.m_object))
846 {
847 JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
848 }
849
850 // passed iterators must belong to objects
851 if (JSON_UNLIKELY(not first.m_object->is_object()))
852 {
853 JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
854 }
855
856 for (auto it = first.m_it.object_iterator, end = last.m_it.object_iterator; it != end; ++it)
857 {
858 m_value.object->insert(std::make_pair(it->first(), it->second));
859 }
860}
861
862void json::update(const_reference j)
863{
864 // implicitly convert null value to an empty object
865 if (is_null())
866 {
867 m_type = value_t::object;
868 m_value.object = create<object_t>();
869 assert_invariant();
870 }
871
872 if (JSON_UNLIKELY(not is_object()))
873 {
874 JSON_THROW(type_error::create(312, "cannot use update() with " + Twine(type_name())));
875 }
876 if (JSON_UNLIKELY(not j.is_object()))
877 {
878 JSON_THROW(type_error::create(312, "cannot use update() with " + Twine(j.type_name())));
879 }
880
881 for (auto it = j.cbegin(); it != j.cend(); ++it)
882 {
883 m_value.object->operator[](it.key()) = it.value();
884 }
885}
886
887void json::update(const_iterator first, const_iterator last)
888{
889 // implicitly convert null value to an empty object
890 if (is_null())
891 {
892 m_type = value_t::object;
893 m_value.object = create<object_t>();
894 assert_invariant();
895 }
896
897 if (JSON_UNLIKELY(not is_object()))
898 {
899 JSON_THROW(type_error::create(312, "cannot use update() with " + Twine(type_name())));
900 }
901
902 // check if range iterators belong to the same JSON object
903 if (JSON_UNLIKELY(first.m_object != last.m_object))
904 {
905 JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
906 }
907
908 // passed iterators must belong to objects
909 if (JSON_UNLIKELY(not first.m_object->is_object()
910 or not last.m_object->is_object()))
911 {
912 JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
913 }
914
915 for (auto it = first; it != last; ++it)
916 {
917 m_value.object->operator[](it.key()) = it.value();
918 }
919}
920
921bool operator==(json::const_reference lhs, json::const_reference rhs) noexcept
922{
923 const auto lhs_type = lhs.type();
924 const auto rhs_type = rhs.type();
925
926 if (lhs_type == rhs_type)
927 {
928 switch (lhs_type)
929 {
930 case json::value_t::array:
931 return (*lhs.m_value.array == *rhs.m_value.array);
932
933 case json::value_t::object:
934 return (*lhs.m_value.object == *rhs.m_value.object);
935
936 case json::value_t::null:
937 return true;
938
939 case json::value_t::string:
940 return (*lhs.m_value.string == *rhs.m_value.string);
941
942 case json::value_t::boolean:
943 return (lhs.m_value.boolean == rhs.m_value.boolean);
944
945 case json::value_t::number_integer:
946 return (lhs.m_value.number_integer == rhs.m_value.number_integer);
947
948 case json::value_t::number_unsigned:
949 return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned);
950
951 case json::value_t::number_float:
952 return (lhs.m_value.number_float == rhs.m_value.number_float);
953
954 default:
955 return false;
956 }
957 }
958 else if (lhs_type == json::value_t::number_integer and rhs_type == json::value_t::number_float)
959 {
960 return (static_cast<double>(lhs.m_value.number_integer) == rhs.m_value.number_float);
961 }
962 else if (lhs_type == json::value_t::number_float and rhs_type == json::value_t::number_integer)
963 {
964 return (lhs.m_value.number_float == static_cast<double>(rhs.m_value.number_integer));
965 }
966 else if (lhs_type == json::value_t::number_unsigned and rhs_type == json::value_t::number_float)
967 {
968 return (static_cast<double>(lhs.m_value.number_unsigned) == rhs.m_value.number_float);
969 }
970 else if (lhs_type == json::value_t::number_float and rhs_type == json::value_t::number_unsigned)
971 {
972 return (lhs.m_value.number_float == static_cast<double>(rhs.m_value.number_unsigned));
973 }
974 else if (lhs_type == json::value_t::number_unsigned and rhs_type == json::value_t::number_integer)
975 {
976 return (static_cast<int64_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer);
977 }
978 else if (lhs_type == json::value_t::number_integer and rhs_type == json::value_t::number_unsigned)
979 {
980 return (lhs.m_value.number_integer == static_cast<int64_t>(rhs.m_value.number_unsigned));
981 }
982
983 return false;
984}
985
986bool operator<(json::const_reference lhs, json::const_reference rhs) noexcept
987{
988 const auto lhs_type = lhs.type();
989 const auto rhs_type = rhs.type();
990
991 if (lhs_type == rhs_type)
992 {
993 switch (lhs_type)
994 {
995 case json::value_t::array:
996 return (*lhs.m_value.array) < (*rhs.m_value.array);
997
998 case json::value_t::object:
999 return *lhs.m_value.object < *rhs.m_value.object;
1000
1001 case json::value_t::null:
1002 return false;
1003
1004 case json::value_t::string:
1005 return *lhs.m_value.string < *rhs.m_value.string;
1006
1007 case json::value_t::boolean:
1008 return lhs.m_value.boolean < rhs.m_value.boolean;
1009
1010 case json::value_t::number_integer:
1011 return lhs.m_value.number_integer < rhs.m_value.number_integer;
1012
1013 case json::value_t::number_unsigned:
1014 return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
1015
1016 case json::value_t::number_float:
1017 return lhs.m_value.number_float < rhs.m_value.number_float;
1018
1019 default:
1020 return false;
1021 }
1022 }
1023 else if (lhs_type == json::value_t::number_integer and rhs_type == json::value_t::number_float)
1024 {
1025 return static_cast<double>(lhs.m_value.number_integer) < rhs.m_value.number_float;
1026 }
1027 else if (lhs_type == json::value_t::number_float and rhs_type == json::value_t::number_integer)
1028 {
1029 return lhs.m_value.number_float < static_cast<double>(rhs.m_value.number_integer);
1030 }
1031 else if (lhs_type == json::value_t::number_unsigned and rhs_type == json::value_t::number_float)
1032 {
1033 return static_cast<double>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
1034 }
1035 else if (lhs_type == json::value_t::number_float and rhs_type == json::value_t::number_unsigned)
1036 {
1037 return lhs.m_value.number_float < static_cast<double>(rhs.m_value.number_unsigned);
1038 }
1039 else if (lhs_type == json::value_t::number_integer and rhs_type == json::value_t::number_unsigned)
1040 {
1041 return lhs.m_value.number_integer < static_cast<int64_t>(rhs.m_value.number_unsigned);
1042 }
1043 else if (lhs_type == json::value_t::number_unsigned and rhs_type == json::value_t::number_integer)
1044 {
1045 return static_cast<int64_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
1046 }
1047
1048 // We only reach this line if we cannot compare values. In that case,
1049 // we compare types. Note we have to call the operator explicitly,
1050 // because MSVC has problems otherwise.
1051 return operator<(lhs_type, rhs_type);
1052}
1053
1054const char* json::type_name() const noexcept
1055{
1056 {
1057 switch (m_type)
1058 {
1059 case value_t::null:
1060 return "null";
1061 case value_t::object:
1062 return "object";
1063 case value_t::array:
1064 return "array";
1065 case value_t::string:
1066 return "string";
1067 case value_t::boolean:
1068 return "boolean";
1069 case value_t::discarded:
1070 return "discarded";
1071 default:
1072 return "number";
1073 }
1074 }
1075}
1076
1077json json::patch(const json& json_patch) const
1078{
1079 // make a working copy to apply the patch to
1080 json result = *this;
1081
1082 // the valid JSON Patch operations
1083 enum class patch_operations {add, remove, replace, move, copy, test, invalid};
1084
1085 const auto get_op = [](const std::string & op)
1086 {
1087 if (op == "add")
1088 {
1089 return patch_operations::add;
1090 }
1091 if (op == "remove")
1092 {
1093 return patch_operations::remove;
1094 }
1095 if (op == "replace")
1096 {
1097 return patch_operations::replace;
1098 }
1099 if (op == "move")
1100 {
1101 return patch_operations::move;
1102 }
1103 if (op == "copy")
1104 {
1105 return patch_operations::copy;
1106 }
1107 if (op == "test")
1108 {
1109 return patch_operations::test;
1110 }
1111
1112 return patch_operations::invalid;
1113 };
1114
1115 // wrapper for "add" operation; add value at ptr
1116 const auto operation_add = [&result](json_pointer & ptr, json val)
1117 {
1118 // adding to the root of the target document means replacing it
1119 if (ptr.is_root())
1120 {
1121 result = val;
1122 }
1123 else
1124 {
1125 // make sure the top element of the pointer exists
1126 json_pointer top_pointer = ptr.top();
1127 if (top_pointer != ptr)
1128 {
1129 result.at(top_pointer);
1130 }
1131
1132 // get reference to parent of JSON pointer ptr
1133 const auto last_path = ptr.pop_back();
1134 json& parent = result[ptr];
1135
1136 switch (parent.m_type)
1137 {
1138 case value_t::null:
1139 case value_t::object:
1140 {
1141 // use operator[] to add value
1142 parent[last_path] = val;
1143 break;
1144 }
1145
1146 case value_t::array:
1147 {
1148 if (last_path == "-")
1149 {
1150 // special case: append to back
1151 parent.push_back(val);
1152 }
1153 else
1154 {
1155 const auto idx = json_pointer::array_index(last_path);
1156 if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
1157 {
1158 // avoid undefined behavior
1159 JSON_THROW(out_of_range::create(401, "array index " + Twine(idx) + " is out of range"));
1160 }
1161 else
1162 {
1163 // default case: insert add offset
1164 parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
1165 }
1166 }
1167 break;
1168 }
1169
1170 default:
1171 {
1172 // if there exists a parent it cannot be primitive
1173 assert(false); // LCOV_EXCL_LINE
1174 }
1175 }
1176 }
1177 };
1178
1179 // wrapper for "remove" operation; remove value at ptr
1180 const auto operation_remove = [&result](json_pointer & ptr)
1181 {
1182 // get reference to parent of JSON pointer ptr
1183 const auto last_path = ptr.pop_back();
1184 json& parent = result.at(ptr);
1185
1186 // remove child
1187 if (parent.is_object())
1188 {
1189 // perform range check
1190 auto it = parent.find(last_path);
1191 if (JSON_LIKELY(it != parent.end()))
1192 {
1193 parent.erase(it);
1194 }
1195 else
1196 {
1197 JSON_THROW(out_of_range::create(403, "key '" + Twine(last_path) + "' not found"));
1198 }
1199 }
1200 else if (parent.is_array())
1201 {
1202 // note erase performs range check
1203 parent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));
1204 }
1205 };
1206
1207 // type check: top level value must be an array
1208 if (JSON_UNLIKELY(not json_patch.is_array()))
1209 {
1210 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
1211 }
1212
1213 // iterate and apply the operations
1214 for (const auto& val : json_patch)
1215 {
1216 // wrapper to get a value for an operation
1217 const auto get_value = [&val](const std::string & op,
1218 const std::string & member,
1219 bool string_type) -> json &
1220 {
1221 // find value
1222 auto it = val.m_value.object->find(member);
1223
1224 // context-sensitive error message
1225 const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
1226
1227 // check if desired value is present
1228 if (JSON_UNLIKELY(it == val.m_value.object->end()))
1229 {
1230 JSON_THROW(parse_error::create(105, 0, Twine(error_msg) + " must have member '" + Twine(member) + "'"));
1231 }
1232
1233 // check if result is of type string
1234 if (JSON_UNLIKELY(string_type and not it->second.is_string()))
1235 {
1236 JSON_THROW(parse_error::create(105, 0, Twine(error_msg) + " must have string member '" + Twine(member) + "'"));
1237 }
1238
1239 // no error: return value
1240 return it->second;
1241 };
1242
1243 // type check: every element of the array must be an object
1244 if (JSON_UNLIKELY(not val.is_object()))
1245 {
1246 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
1247 }
1248
1249 // collect mandatory members
1250 const std::string op = get_value("op", "op", true);
1251 const std::string path = get_value(op, "path", true);
1252 json_pointer ptr(path);
1253
1254 switch (get_op(op))
1255 {
1256 case patch_operations::add:
1257 {
1258 operation_add(ptr, get_value("add", "value", false));
1259 break;
1260 }
1261
1262 case patch_operations::remove:
1263 {
1264 operation_remove(ptr);
1265 break;
1266 }
1267
1268 case patch_operations::replace:
1269 {
1270 // the "path" location must exist - use at()
1271 result.at(ptr) = get_value("replace", "value", false);
1272 break;
1273 }
1274
1275 case patch_operations::move:
1276 {
1277 const std::string from_path = get_value("move", "from", true);
1278 json_pointer from_ptr(from_path);
1279
1280 // the "from" location must exist - use at()
1281 json v = result.at(from_ptr);
1282
1283 // The move operation is functionally identical to a
1284 // "remove" operation on the "from" location, followed
1285 // immediately by an "add" operation at the target
1286 // location with the value that was just removed.
1287 operation_remove(from_ptr);
1288 operation_add(ptr, v);
1289 break;
1290 }
1291
1292 case patch_operations::copy:
1293 {
1294 const std::string from_path = get_value("copy", "from", true);
1295 const json_pointer from_ptr(from_path);
1296
1297 // the "from" location must exist - use at()
1298 json v = result.at(from_ptr);
1299
1300 // The copy is functionally identical to an "add"
1301 // operation at the target location using the value
1302 // specified in the "from" member.
1303 operation_add(ptr, v);
1304 break;
1305 }
1306
1307 case patch_operations::test:
1308 {
1309 bool success = false;
1310 JSON_TRY
1311 {
1312 // check if "value" matches the one at "path"
1313 // the "path" location must exist - use at()
1314 success = (result.at(ptr) == get_value("test", "value", false));
1315 }
1316 JSON_CATCH (out_of_range&)
1317 {
1318 // ignore out of range errors: success remains false
1319 }
1320
1321 // throw an exception if test fails
1322 if (JSON_UNLIKELY(not success))
1323 {
1324 JSON_THROW(other_error::create(501, "unsuccessful: " + Twine(val.dump())));
1325 }
1326
1327 break;
1328 }
1329
1330 case patch_operations::invalid:
1331 {
1332 // op must be "add", "remove", "replace", "move", "copy", or
1333 // "test"
1334 JSON_THROW(parse_error::create(105, 0, "operation value '" + Twine(op) + "' is invalid"));
1335 }
1336 }
1337 }
1338
1339 return result;
1340}
1341
1342json json::diff(const json& source, const json& target,
1343 const std::string& path)
1344{
1345 // the patch
1346 json result(value_t::array);
1347
1348 // if the values are the same, return empty patch
1349 if (source == target)
1350 {
1351 return result;
1352 }
1353
1354 if (source.type() != target.type())
1355 {
1356 // different types: replace value
1357 result.push_back(
1358 {
1359 {"op", "replace"}, {"path", path}, {"value", target}
1360 });
1361 }
1362 else
1363 {
1364 switch (source.type())
1365 {
1366 case value_t::array:
1367 {
1368 // first pass: traverse common elements
1369 std::size_t i = 0;
1370 while (i < source.size() and i < target.size())
1371 {
1372 // recursive call to compare array values at index i
1373 auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
1374 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
1375 ++i;
1376 }
1377
1378 // i now reached the end of at least one array
1379 // in a second pass, traverse the remaining elements
1380
1381 // remove my remaining elements
1382 const auto end_index = static_cast<difference_type>(result.size());
1383 while (i < source.size())
1384 {
1385 // add operations in reverse order to avoid invalid
1386 // indices
1387 result.insert(result.begin() + end_index, object(
1388 {
1389 {"op", "remove"},
1390 {"path", path + "/" + std::to_string(i)}
1391 }));
1392 ++i;
1393 }
1394
1395 // add other remaining elements
1396 while (i < target.size())
1397 {
1398 result.push_back(
1399 {
1400 {"op", "add"},
1401 {"path", path + "/" + std::to_string(i)},
1402 {"value", target[i]}
1403 });
1404 ++i;
1405 }
1406
1407 break;
1408 }
1409
1410 case value_t::object:
1411 {
1412 // first pass: traverse this object's elements
1413 for (auto it = source.cbegin(); it != source.cend(); ++it)
1414 {
1415 // escape the key name to be used in a JSON patch
1416 const auto key = json_pointer::escape(it.key());
1417
1418 if (target.find(it.key()) != target.end())
1419 {
1420 // recursive call to compare object values at key it
1421 auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
1422 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
1423 }
1424 else
1425 {
1426 // found a key that is not in o -> remove it
1427 result.push_back(object(
1428 {
1429 {"op", "remove"}, {"path", path + "/" + key}
1430 }));
1431 }
1432 }
1433
1434 // second pass: traverse other object's elements
1435 for (auto it = target.cbegin(); it != target.cend(); ++it)
1436 {
1437 if (source.find(it.key()) == source.end())
1438 {
1439 // found a key that is not in this -> add it
1440 const auto key = json_pointer::escape(it.key());
1441 result.push_back(
1442 {
1443 {"op", "add"}, {"path", path + "/" + key},
1444 {"value", it.value()}
1445 });
1446 }
1447 }
1448
1449 break;
1450 }
1451
1452 default:
1453 {
1454 // both primitive type: replace value
1455 result.push_back(
1456 {
1457 {"op", "replace"}, {"path", path}, {"value", target}
1458 });
1459 break;
1460 }
1461 }
1462 }
1463
1464 return result;
1465}
1466
1467void json::merge_patch(const json& patch)
1468{
1469 if (patch.is_object())
1470 {
1471 if (not is_object())
1472 {
1473 *this = object();
1474 }
1475 for (auto it = patch.begin(); it != patch.end(); ++it)
1476 {
1477 if (it.value().is_null())
1478 {
1479 erase(it.key());
1480 }
1481 else
1482 {
1483 operator[](it.key()).merge_patch(it.value());
1484 }
1485 }
1486 }
1487 else
1488 {
1489 *this = patch;
1490 }
1491}
1492
1493} // namespace wpi