Argo  1.0
A C++ library for handling JSON.
json.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Andrew Haisley
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 
24 
25 #include <string.h>
26 #include <algorithm>
27 
28 #include "common.hpp"
29 #include "json.hpp"
32 #include "unparser.hpp"
33 
34 using namespace NAMESPACE;
35 using namespace std;
36 
37 json::json() noexcept : m_type(null_e)
38 {
39 }
40 
41 json::~json()
42 {
43  reset();
44 }
45 
46 void json::reset()
47 {
48  switch (m_type)
49  {
50  case object_e:
51  delete m_value.u_object;
52  m_value.u_object = nullptr;
53  break;
54  case array_e:
55  delete m_value.u_array;
56  m_value.u_array = nullptr;
57  break;
58  case string_e:
59  delete m_value.u_string;
60  m_value.u_string = nullptr;
61  break;
62  default:
63  break;
64  }
65 
66  m_type = null_e;
67  m_raw_value.clear();
68 }
69 
70 void json::copy_json(const json &other)
71 {
72  if (this != &other)
73  {
74  reset();
75  m_type = other.m_type;
76  m_raw_value = other.m_raw_value;
77 
78  if (m_type == object_e)
79  {
80  m_value.u_object = new map<string, unique_ptr<json>>;
81 
82  for (const auto &p : *other.m_value.u_object)
83  {
84  (*m_value.u_object)[p.first] = unique_ptr<json>(new json(*p.second));
85  }
86  }
87  else if (m_type == array_e)
88  {
89  m_value.u_array = new vector<unique_ptr<json>>;
90 
91  for (const auto &v : *other.m_value.u_array)
92  {
93  m_value.u_array->push_back(unique_ptr<json>(new json(*v)));
94  }
95  }
96  else if (m_type == string_e)
97  {
98  m_value.u_string = other.m_value.u_string == nullptr ? nullptr : new string(*other.m_value.u_string);
99  }
100  else
101  {
102  m_value = other.m_value;
103  }
104  }
105 }
106 
107 json::json(const json &other) : m_type(null_e)
108 {
109  copy_json(other);
110 }
111 
112 json &json::operator=(const json &other)
113 {
114  copy_json(other);
115  return *this;
116 }
117 
118 void json::move_json(json &other)
119 {
120  if (this != &other)
121  {
122  reset();
123  m_type = other.m_type;
124  m_value = other.m_value;
125  m_raw_value = move(other.m_raw_value);
126 
127  other.m_type = null_e;
128  }
129 }
130 
131 json &json::operator=(json &&other) noexcept
132 {
133  move_json(other);
134  return *this;
135 }
136 
137 json::json(json &&other) noexcept : m_type(null_e)
138 {
139  move_json(other);
140 }
141 
142 json::json(type t) : m_type(t)
143 {
144  switch (m_type)
145  {
146  case object_e:
147  m_value.u_object = new map<string, unique_ptr<json>>();
148  break;
149  case array_e:
150  m_value.u_array = new vector<unique_ptr<json>>();
151  break;
152  case string_e:
153  m_value.u_string = new string;
154  break;
155  case boolean_e:
156  m_value.u_boolean = false;
157  break;
158  case number_int_e:
159  m_value.u_number_int = 0;
160  break;
161  case number_double_e:
162  m_value.u_number_double = 0;
163  break;
164  case null_e:
165  break;
166  default:
168  break;
169  }
170 }
171 
172 json::json(type t, const string &raw_value) : m_type(t), m_raw_value(raw_value)
173 {
174  if (t != string_e && t != number_int_e && t != number_double_e)
175  {
177  }
178 
179  // just in case this is a string
180  m_value.u_string = nullptr;
181 }
182 
184 {
185  m_type = number_int_e;
186  m_value.u_number_int = i;
187 }
188 
189 json::json(double d)
190 {
191  m_type = number_double_e;
192  m_value.u_number_double = d;
193 }
194 
195 json::json(bool b)
196 {
197  m_type = boolean_e;
198  m_value.u_boolean = b;
199 }
200 
201 json::json(const string &s)
202 {
203  m_type = string_e;
204  m_value.u_string = new string(s);
205 }
206 
207 json::json(const char *s)
208 {
209  m_type = string_e;
210  m_value.u_string = new string(s);
211 }
212 
213 json::json(null_t) noexcept : m_type(null_e)
214 {
215 }
216 
217 json::json(unique_ptr<string> s)
218 {
219  m_type = string_e;
220  m_value.u_string = s.release();
221 }
222 
224 {
225  reset();
226  m_type = number_int_e;
227  m_value.u_number_int = i;
228  return *this;
229 }
230 
232 {
233  reset();
234  m_type = number_double_e;
235  m_value.u_number_double = d;
236  return *this;
237 }
238 
240 {
241  reset();
242  m_type = boolean_e;
243  m_value.u_boolean = b;
244  return *this;
245 }
246 
247 json &json::operator=(const string &s)
248 {
249  reset();
250  m_type = string_e;
251  m_value.u_string = new string(s);
252  return *this;
253 }
254 
255 json &json::operator=(const char *s)
256 {
257  reset();
258  m_type = string_e;
259  m_value.u_string = new string(s);
260  return *this;
261 }
262 
263 json &json::operator=(unique_ptr<string> s)
264 {
265  reset();
266  m_type = string_e;
267  m_value.u_string = s.release();
268  return *this;
269 }
270 
271 json &json::operator=(const map<string, unique_ptr<json>> &o)
272 {
273  reset();
274  m_type = object_e;
275  for (const auto &p : o)
276  {
277  (*m_value.u_object)[p.first] = unique_ptr<json>(new json(*p.second));
278  }
279  return *this;
280 }
281 
282 json &json::operator=(const vector<unique_ptr<json>> &a)
283 {
284  reset();
285  m_type = array_e;
286  for (const auto &v : a)
287  {
288  m_value.u_array->push_back(unique_ptr<json>(new json(*v)));
289  }
290  return *this;
291 }
292 
294 {
295  reset();
296  m_type = null_e;
297  return *this;
298 }
299 
301 {
302  return m_type;
303 }
304 
305 vector<unique_ptr<json>> &json::get_array()
306 {
307  return *m_value.u_array;
308 }
309 
310 const vector<unique_ptr<json>> &json::get_array() const
311 {
312  return *m_value.u_array;
313 }
314 
315 map<string, unique_ptr<json>> &json::get_object()
316 {
317  return *m_value.u_object;
318 }
319 
320 const map<string, unique_ptr<json>> &json::get_object() const
321 {
322  return *m_value.u_object;
323 }
324 
325 const string &json::get_raw_value() const
326 {
327  return m_raw_value;
328 }
329 
330 json::operator int() const
331 {
332  if (m_raw_value.size() > 0)
333  {
335  }
336  else if (m_type == number_int_e)
337  {
338  return m_value.u_number_int;
339  }
340  else if (m_type == number_double_e)
341  {
342  return static_cast<int>(m_value.u_number_double);
343  }
344  else
345  {
347  }
348 }
349 
350 json::operator double() const
351 {
352  if (m_raw_value.size() > 0)
353  {
355  }
356  else if (m_type == number_double_e)
357  {
358  return m_value.u_number_double;
359  }
360  else if (m_type == number_int_e)
361  {
362  return static_cast<double>(m_value.u_number_int);
363  }
364  else
365  {
367  }
368 }
369 
370 json::operator const std::string&() const
371 {
372  if (m_raw_value.size() > 0)
373  {
375  }
376  else if (m_type == string_e)
377  {
378  return *(m_value.u_string);
379  }
380  else
381  {
383  }
384 }
385 
386 json::operator bool() const
387 {
388  if (m_type == boolean_e)
389  {
390  return m_value.u_boolean;
391  }
392  else if (m_type == number_int_e)
393  {
394  return m_value.u_number_int != 0;
395  }
396  else
397  {
399  }
400 }
401 
402 json &json::operator[](const string &name)
403 {
404  if (m_type == object_e)
405  {
406  auto i = m_value.u_object->find(name);
407  if (i == m_value.u_object->end())
408  {
409  return *((*m_value.u_object)[name] = unique_ptr<json>(new json));
410  }
411  else
412  {
413  return *(i->second);
414  }
415  }
416  else
417  {
419  }
420 }
421 
422 json &json::operator[](const char *name)
423 {
424  return (*this)[string(name)];
425 }
426 
427 json &json::operator[](size_t index)
428 {
429  if (m_type == array_e)
430  {
431  if (index < m_value.u_array->size())
432  {
433  return *(*m_value.u_array)[index];
434  }
435  else
436  {
438  }
439  }
440  else
441  {
443  }
444 }
445 
447 {
448  if (index >= 0)
449  {
450  return (*this)[static_cast<size_t>(index)];
451  }
452  else
453  {
455  }
456 }
457 
458 const json &json::operator[](size_t index) const
459 {
460  if (m_type == array_e)
461  {
462  if (index < m_value.u_array->size())
463  {
464  return *(*m_value.u_array)[index];
465  }
466  else
467  {
469  }
470  }
471  else
472  {
474  }
475 }
476 
477 const json &json::operator[](int index) const
478 {
479  if (index >= 0)
480  {
481  return (*this)[static_cast<size_t>(index)];
482  }
483  else
484  {
486  }
487 }
488 
489 const json &json::operator[](const string &name) const
490 {
491  if (m_type == object_e)
492  {
493  auto i = m_value.u_object->find(name);
494  if (i == m_value.u_object->end())
495  {
497  }
498  else
499  {
500  return *(i->second);
501  }
502  }
503  else
504  {
506  }
507 }
508 
509 const json &json::operator[](const char *name) const
510 {
511  return (*this)[string(name)];
512 }
513 
514 const json &json::append(const json &j)
515 {
516  return append(unique_ptr<json>(new json(j)));
517 }
518 
519 const json &json::append(unique_ptr<json> j)
520 {
521  if (m_type == array_e)
522  {
523  json *jp = j.release();
524  m_value.u_array->push_back(unique_ptr<json>(jp));
525  return *jp;
526  }
527  else
528  {
530  }
531 }
532 
533 const json &json::insert(const string &name, const json &j)
534 {
535  return insert(name, unique_ptr<json>(new json(j)));
536 }
537 
538 const json &json::insert(const string &name, unique_ptr<json> j)
539 {
540  if (m_type == object_e)
541  {
542  json *r;
543  m_value.u_object->insert(pair<string, unique_ptr<json>>(name, unique_ptr<json>(r = j.release())));
544  return *r;
545  }
546  else
547  {
549  }
550 }
551 
552 const char *json::get_instance_type_name() const
553 {
554  switch (m_type)
555  {
556  case object_e:
557  return "object";
558  case array_e:
559  return "array";
560  case boolean_e:
561  return "boolean";
562  case null_e:
563  return "null";
564  case number_int_e:
565  return "number (int)";
566  case number_double_e:
567  return "number (double)";
568  case string_e:
569  return "string";
570  default:
571  return "corrupted";
572  }
573 }
574 
575 bool json::number_equal(const json &other) const
576 {
577  if (m_raw_value.size() == 0 && other.m_raw_value.size() == 0)
578  {
579  if (m_type == number_int_e)
580  {
581  return m_value.u_number_int == other.m_value.u_number_int;
582  }
583  else
584  {
585  // Will only work if they are exactly the same in all bits.
586  return m_value.u_number_double == other.m_value.u_number_double;
587  }
588  }
589  else
590  {
592  }
593 }
594 
595 bool json::string_equal(const json &other) const
596 {
597  if (m_raw_value.size() == 0 && other.m_raw_value.size() == 0)
598  {
599  return *m_value.u_string == *other.m_value.u_string;
600  }
601  else
602  {
604  }
605 }
606 
607 bool json::object_equal(const json &other) const
608 {
609  return m_value.u_object->size() == other.m_value.u_object->size() &&
610  equal(
611  m_value.u_object->begin(),
612  m_value.u_object->end(),
613  other.m_value.u_object->begin(),
614  [] (const pair<const string, unique_ptr<json>> &a, const pair<const string, unique_ptr<json>> &b)
615  { return a.first == b.first && *(a.second) == *(b.second); });
616 }
617 
618 bool json::array_equal(const json &other) const
619 {
620  return m_value.u_array->size() == other.m_value.u_array->size() &&
621  equal(
622  m_value.u_array->begin(),
623  m_value.u_array->end(),
624  other.m_value.u_array->begin(),
625  [] (const unique_ptr<json> &a, const unique_ptr<json> &b)
626  { return *a == *b; });
627 }
628 
629 bool json::operator==(const json &other) const
630 {
631  if (m_type == other.m_type)
632  {
633  switch (m_type)
634  {
635  case object_e:
636  return object_equal(other);
637  case array_e:
638  return array_equal(other);
639  case boolean_e:
640  return m_value.u_boolean == other.m_value.u_boolean;
641  case null_e:
642  return true;
643  case number_int_e:
644  return number_equal(other);
645  case number_double_e:
646  return number_equal(other);
647  case string_e:
648  return string_equal(other);
649  default:
651  }
652  }
653  else if ((m_type == number_int_e && other.m_type == number_double_e) ||
654  (m_type == number_double_e && other.m_type == number_int_e))
655  {
656  return static_cast<double>(*this) == static_cast<double>(other);
657  }
658  else
659  {
660  return false;
661  }
662 }
663 
664 
665 bool json::operator!=(const json &other) const
666 {
667  return !(*this == other);
668 }
669 
670 bool json::operator==(int i) const
671 {
672  return static_cast<int>(*this) == i;
673 }
674 
675 bool json::operator==(double d) const
676 {
677  return static_cast<double>(*this) == d;
678 }
679 
680 bool json::operator==(const std::string &s) const
681 {
682  return static_cast<string>(*this) == s;
683 }
684 
685 bool json::operator==(const char *s) const
686 {
687  return strcmp(static_cast<string>(*this).c_str(), s) == 0;
688 }
689 
690 bool json::operator!=(int i) const
691 {
692  return static_cast<int>(*this) != i;
693 }
694 
695 bool json::operator!=(double d) const
696 {
697  return static_cast<double>(*this) != d;
698 }
699 
700 bool json::operator!=(const std::string &s) const
701 {
702  return static_cast<string>(*this) != s;
703 }
704 
705 bool json::operator!=(const char *s) const
706 {
707  return strcmp(static_cast<string>(*this).c_str(), s) != 0;
708 }
709 
710 bool json::operator<(int i) const
711 {
712  return static_cast<int>(*this) < i;
713 }
714 
715 bool json::operator<(double d) const
716 {
717  return static_cast<double>(*this) < d;
718 }
719 
720 bool json::operator<(const std::string &s) const
721 {
722  return static_cast<string>(*this) < s;
723 }
724 
725 bool json::operator<(const char *s) const
726 {
727  return strcmp(static_cast<string>(*this).c_str(), s) < 0;
728 }
729 
730 bool json::operator<=(int i) const
731 {
732  return static_cast<int>(*this) <= i;
733 }
734 
735 bool json::operator<=(double d) const
736 {
737  return static_cast<double>(*this) <= d;
738 }
739 
740 bool json::operator<=(const std::string &s) const
741 {
742  return static_cast<string>(*this) < s;
743 }
744 
745 bool json::operator<=(const char *s) const
746 {
747  return strcmp(static_cast<string>(*this).c_str(), s) <= 0;
748 }
749 
750 bool json::operator>(int i) const
751 {
752  return static_cast<int>(*this) > i;
753 }
754 
755 bool json::operator>(double d) const
756 {
757  return static_cast<double>(*this) > d;
758 }
759 
760 bool json::operator>(const std::string &s) const
761 {
762  return static_cast<string>(*this) > s;
763 }
764 
765 bool json::operator>(const char *s) const
766 {
767  return strcmp(static_cast<string>(*this).c_str(), s) > 0;
768 }
769 
770 bool json::operator>=(int i) const
771 {
772  return static_cast<int>(*this) >= i;
773 }
774 
775 bool json::operator>=(double d) const
776 {
777  return static_cast<double>(*this) >= d;
778 }
779 
780 bool json::operator>=(const std::string &s) const
781 {
782  return static_cast<string>(*this) >= s;
783 }
784 
785 bool json::operator>=(const char *s) const
786 {
787  return strcmp(static_cast<string>(*this).c_str(), s) >= 0;
788 }
789 
790 bool json::operator<(const json &other) const
791 {
792  if (m_type == string_e && other.m_type == string_e)
793  {
794  return static_cast<string>(*this) < static_cast<string>(other);
795  }
796  else if (m_type == number_int_e && other.m_type == number_int_e)
797  {
798  return static_cast<int>(*this) < static_cast<int>(other);
799  }
800  else if ((m_type == number_double_e && other.m_type == number_double_e) ||
801  (m_type == number_double_e && other.m_type == number_int_e) ||
802  (m_type == number_int_e && other.m_type == number_double_e))
803  {
804  return static_cast<double>(*this) < static_cast<double>(other);
805  }
806  else
807  {
808  throw json_exception(
811  other.get_instance_type_name());
812  }
813 }
814 
815 bool json::operator<=(const json &other) const
816 {
817  if (m_type == string_e && other.m_type == string_e)
818  {
819  return static_cast<string>(*this) <= static_cast<string>(other);
820  }
821  else if (m_type == number_int_e && other.m_type == number_int_e)
822  {
823  return static_cast<int>(*this) <= static_cast<int>(other);
824  }
825  else if ((m_type == number_double_e && other.m_type == number_double_e) ||
826  (m_type == number_double_e && other.m_type == number_int_e) ||
827  (m_type == number_int_e && other.m_type == number_double_e))
828  {
829  return static_cast<double>(*this) <= static_cast<double>(other);
830  }
831  else
832  {
833  throw json_exception(
836  other.get_instance_type_name());
837  }
838 }
839 
840 bool json::operator>(const json &other) const
841 {
842  return !(*this <= other);
843 }
844 
845 bool json::operator>=(const json &other) const
846 {
847  return !(*this < other);
848 }
849 
850 const json &json::find(const pointer &p) const
851 {
852  const json *res = this;
853 
854  for (auto t : p.get_path())
855  {
856  switch (t.get_type())
857  {
858  case pointer::token::all_e:
859  break;
860 
861  case pointer::token::object_e:
862  if (res->m_type == object_e)
863  {
864  auto i = res->m_value.u_object->find(t.get_name());
865  if (i == res->m_value.u_object->end())
866  {
868  }
869  else
870  {
871  res = i->second.get();
872  }
873  }
874  else
875  {
877  }
878  break;
879 
880  case pointer::token::array_e:
881  if (res->m_type == array_e)
882  {
883  if (t.get_index() < res->m_value.u_array->size())
884  {
885  res = (*res->m_value.u_array)[t.get_index()].get();
886  }
887  else
888  {
890  }
891  }
892  else
893  {
895  }
896  break;
897 
898  default:
900  }
901  }
902 
903  return *res;
904 }
The json_array_index_range_exception class.
const std::string & get_raw_value() const
Definition: json.cpp:325
Base class for all exceptions thrown by the library.
std::vector< std::unique_ptr< json > > & get_array()
Definition: json.cpp:305
Specific class of exceptions for an invalid object key.
#define NAMESPACE
You can change the namespace of the whole library by changing this value.
Definition: common.hpp:29
Internal error - the m_type member variable has an invalid value.
bool operator==(const json &other) const
Definition: json.cpp:629
Attempt to to access an index in an array object that is out of range.
STL namespace.
The json class.
Attempt to call a method that assumes the json instance is an array.
const json & insert(const std::string &name, const json &j)
Definition: json.cpp:533
const char * get_instance_type_name() const
Definition: json.cpp:552
const json & append(const json &j)
Definition: json.cpp:514
Attempt to access a non-existent slot in a json instance.
Common defs needed everywhere and, as far as is possible, platform specific changes.
The json_invalid_key_exception class.
const json & find(const pointer &p) const
Definition: json.cpp:850
bool operator<=(const json &other) const
Definition: json.cpp:815
JSON pointers as per the RFT.
Definition: pointer.hpp:41
Attempt to call a method that assumes the json instance is an int or double.
Pointer doesn&#39;t point to anything in the json instance.
Raw values cannot be directly compared.
Attempt to call a method that assumes the json instance is an object.
Attempt to construct an instance with a raw value that isn&#39;t a number or a string.
bool operator>(const json &other) const
Definition: json.cpp:840
json & operator[](const std::string &name)
Definition: json.cpp:402
All json things are represented by instances of this class.
Definition: json.hpp:63
json & operator=(const json &other)
Definition: json.cpp:112
bool operator!=(const json &other) const
Definition: json.cpp:665
std::map< std::string, std::unique_ptr< json > > & get_object()
Definition: json.cpp:315
bool operator>=(const json &other) const
Definition: json.cpp:845
Tried to compare two different types (e.g. int vs string)
The unparser class.
Attempt to call a method that assumes the json instance is a string.
type get_instance_type() const
Definition: json.cpp:300
Raw values cannot be cast.
json() noexcept
Definition: json.cpp:37
bool operator<(const json &other) const
Definition: json.cpp:790
Attempt to call a method that assumes the json instance is a boolean or castable to one...
const std::list< token > & get_path() const
Definition: pointer.cpp:258
Specific class of exceptions for an invalid object key.