dxjson  1.0
JSON library for C++
dxjson.h
Go to the documentation of this file.
1 // Copyright (C) 2013-2016 DNAnexus, Inc.
2 //
3 // This file is part of dx-toolkit (DNAnexus platform client libraries).
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License"); you may
6 // not use this file except in compliance with the License. You may obtain a
7 // copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 // License for the specific language governing permissions and limitations
15 // under the License.
16 
17 #ifndef __DXJSON_H__
18 #define __DXJSON_H__
19 
20 #include <cstdio>
21 #include <cstring>
22 #include <vector>
23 #include <map>
24 #include <cstdlib>
25 #include <string>
26 #include <iostream>
27 #include <cstdio>
28 #include <exception>
29 #include <cassert>
30 #include <sstream>
31 #include <istream>
32 #include <ostream>
33 #include <limits>
34 #include <typeinfo>
35 #include <cmath>
36 #include <algorithm>
37 #include <stdint.h>
38 #include <boost/math/special_functions/fpclassify.hpp>
39 #include <boost/lexical_cast.hpp>
40 
41 #include "utf8/utf8.h"
42 
43 
44 // NOTE:
45 // 1) UTF-8 validity is checked while reading JSON from a string;
46 // 2) UTF-8
47 
53 namespace dx {
54 
58  class JSONException:public std::exception {
59  public:
60  std::string err;
61  JSONException(const std::string &e): err(e) {}
62  const char* what() const throw() {
63  return (const char*)err.c_str();
64  }
65  ~JSONException() throw() { }
66  };
67 
72  template<typename T> void assertValidityOfNumericType(const T &value) {
73  assert (std::numeric_limits<T>::is_specialized); // We should never call this function for non-numeric types
74  if (boost::math::isnan(value) || !boost::math::isfinite(value)) {
75  throw JSONException("Illegal floating point value. JSON spec do not allow NaN/Inifnity values for numbers. Value provided = '" + boost::lexical_cast<std::string>(value) + "'");
76  }
77  }
78 
100  enum JSONValue {
101  JSON_UNDEFINED = 0,
102  JSON_OBJECT = 1,
103  JSON_HASH = 1, // JSON_HASH and JSON_OBJECT are aliases (both have value = 1)
104  JSON_ARRAY = 2,
105  JSON_INTEGER = 3,
106  JSON_REAL = 4,
107  JSON_STRING = 5,
108  JSON_BOOLEAN = 6,
109  JSON_NULL = 7
110  };
111 
115  class Value {
116  public:
117  virtual JSONValue type() const = 0; // Return type of particular derived class
118  virtual void write(std::ostream &out) const = 0;
119  virtual Value* returnMyNewCopy() const = 0;
120  virtual void read(std::istream &in) = 0;
121  virtual bool isEqual(const Value* other) const = 0;
122  virtual ~Value() { }
123  };
124 
125  // Forward declarations
126  class Integer;
127  class Real;
128  class Null;
129  class Boolean;
130  class String;
131  class Array;
132  class Object;
133 
137  class JSON {
138  public:
139 
140  typedef std::map<std::string, JSON>::iterator object_iterator;
141  typedef std::map<std::string, JSON>::const_iterator const_object_iterator;
142  typedef std::vector<JSON>::iterator array_iterator;
143  typedef std::vector<JSON>::const_iterator const_array_iterator;
144 
145  typedef std::map<std::string, JSON>::const_reverse_iterator object_reverse_iterator;
146  typedef std::map<std::string, JSON>::reverse_iterator const_object_reverse_iterator;
147  typedef std::vector<JSON>::reverse_iterator array_reverse_iterator;
148  typedef std::vector<JSON>::const_reverse_iterator const_array_reverse_iterator;
149 
152  Value *val;
153 
160  static double getEpsilon();
161 
167  static JSON parse(const std::string &str) {
168  JSON tmp;
169  tmp.readFromString(str);
170  return tmp;
171  }
172 
175  JSON():val(NULL) {}
176 
180  JSON(const JSON &rhs);
181 
185  JSON(const JSONValue &rhs);
186 
192  template<typename T>
193  JSON(const T& x);
194 
197  void clear() { delete val; val=NULL; }
198 
205  void write(std::ostream &out) const;
206 
236  void read(std::istream &in);
237 
245  void readFromString(const std::string &jstr); // Populate JSON from a string
246 
256  std::string toString(bool onlyTopLevel = false) const;
257 
265  bool operator ==(const JSON& other) const;
266 
272  bool operator !=(const JSON& other) const { return !(*this == other); }
273 
279  const JSON& operator [](const size_t &indx) const;
280 
286  const JSON& operator [](const std::string &s) const;
287 
297  const JSON& operator [](const JSON &j) const;
298 
304  const JSON& operator [](const char *str) const;
305 
313  template<typename T>
314  const JSON& operator [](const T&x) const;
315 
320  JSON& operator [](const size_t &indx);
321 
328  JSON& operator [](const std::string &s);
329 
337  JSON& operator [](const JSON &j);
338 
343  JSON& operator [](const char *str);
344 
349  template<typename T>
350  JSON& operator [](const T& x) { return const_cast<JSON&>( (*(const_cast<const JSON*>(this)))[x]); }
351 
360  template<typename T> JSON& operator =(const T &rhs);
361 
367  JSON& operator =(const JSON &);
368 
375  JSON& operator =(const JSONValue&);
376 
382  JSON& operator =(const char &c);
383 
389  JSON& operator =(const std::string &s);
390 
396  JSON& operator =(const bool &x);
397 
403  JSON& operator =(const char s[]);
404 
410  JSON& operator =(const Null &x);
411 
417  template<typename T>
418  JSON& operator =(const std::vector<T> &vec);
419 
425  template<typename T>
426  JSON& operator =(const std::map<std::string, T> &m);
427 
432  template<typename T>
433  operator T() const;
434 
441  template<typename T>
442  T get() const {
443  // Reuses the conversion operator: operator T()
444  return static_cast<T>(*this);
445  }
446 
450  JSONValue type() const { return (val == NULL) ? JSON_UNDEFINED : val->type(); }
451 
466  void resize_array(size_t desired_size);
467 
475  size_t size() const;
476 
480  size_t length() const { return size(); }
481 
487  template<typename T>
488  bool has(const T &indx) const { return has(static_cast<size_t>(indx)); }
489 
495  bool has(const size_t &indx) const;
496 
503  bool has(const std::string &key) const;
504 
508  bool has(const JSON &j) const;
509 
515  bool has(const char *key) const;
516 
521  void push_back(const JSON &j);
522 
527  void erase(const size_t &indx);
528 
534  void erase(const std::string &key);
535 
540  const_object_iterator object_begin() const;
541 
546  object_iterator object_begin();
547 
552  const_array_iterator array_begin() const;
553 
558  array_iterator array_begin();
559 
564  const_object_iterator object_end() const;
565 
570  object_iterator object_end();
571 
576  const_array_iterator array_end() const;
577 
582  array_iterator array_end();
583 
588  const_array_reverse_iterator array_rbegin() const;
589 
594  array_reverse_iterator array_rbegin();
595 
601  const_array_reverse_iterator array_rend() const;
602 
608  array_reverse_iterator array_rend();
609 
611  ~JSON() { clear(); }
612  };
613 
614  class Integer: public Value {
615  public:
616  int64_t val;
617 
618  Integer() {}
619  Integer(const int64_t &v): val(v) {}
620  void write(std::ostream &out) const { out << val; }
621  JSONValue type() const { return JSON_INTEGER; }
622  size_t returnAsArrayIndex() const { return static_cast<size_t>(val);}
623  Value* returnMyNewCopy() const { return new Integer(*this); }
624  operator const Value* () { return this; }
625  bool isEqual(const Value *other) const;
626  bool operator ==(const Integer& other) const { return isEqual(&other); }
627  bool operator !=(const Integer &other) const { return !(*this == other); }
628 
629  // read() Should not be called for Integer and Real,
630  // use ReadNumberValue() instead for these two "special" classes
631  void read(std::istream &in __attribute__ ((unused)) ) { assert(false); }
632  };
633 
634  class Real: public Value {
635  public:
636  double val;
637 
638  Real() {}
639  Real(const double &v) {
640  assertValidityOfNumericType(v);
641  val = v;
642  }
643  void write(std::ostream &out) const { out << val; }
644  JSONValue type() const { return JSON_REAL; }
645  size_t returnAsArrayIndex() const { return static_cast<size_t>(val);}
646  Value* returnMyNewCopy() const { return new Real(*this); }
647  bool isEqual(const Value *other) const;
648  bool operator ==(const Real& other) const { return isEqual(&other); }
649  bool operator !=(const Real& other) const { return !(*this == other); }
650 
651  // read() Should not be called for Integer and Real,
652  // use ReadNumberValue() instead for these two "special" classes
653  void read(std::istream &in __attribute__ ((unused)) ) { assert(false); }
654  };
655 
656  class String: public Value {
657  public:
658  std::string val;
659 
660  String() {}
661  String(const std::string &v):val(v) {}
662  // TODO: Make sure cout << stl::string works as expected;
663  void write(std::ostream &out) const;
664  JSONValue type() const { return JSON_STRING; }
665  std::string returnString() const { return val; }
666  Value* returnMyNewCopy() const { return new String(*this); }
667  void read(std::istream &in);
668  bool isEqual(const Value *other) const;
669  bool operator ==(const String& other) const { return isEqual(&other); }
670  bool operator !=(const String& other) const { return !(*this == other); }
671 
672  // Should have a constructor which allows creation from std::string directly.
673  };
674 
675  class Object: public Value {
676  public:
677  std::map<std::string, JSON> val;
678 
679  Object() { }
680  Object(const Object &rhs): val(rhs.val) {}
681 
682  template<typename T>
683  Object(const std::map<std::string, T> &v) {
684  val.insert(v.begin(), v.end());
685  }
686 
687  JSON& jsonAtKey(const std::string &s);
688  const JSON& jsonAtKey(const std::string &s) const;
689  void write(std::ostream &out) const;
690  JSONValue type() const { return JSON_OBJECT; }
691  Value* returnMyNewCopy() const { return new Object(*this); }
692  void read(std::istream &in);
693  void erase(const std::string &key);
694  bool isEqual(const Value *other) const;
695  bool operator ==(const Object& other) const { return isEqual(&other); }
696  bool operator !=(const Object& other) const { return !(*this == other); }
697  };
698 
699  class Array: public Value {
700  public:
701  std::vector<JSON> val;
702 
703  Array() { }
704  Array(const Array& arr): val(arr.val) {}
705 
706  template<typename T>
707  Array(const std::vector<T> &vec) {
708  for (unsigned i = 0;i < vec.size(); i++) {
709  JSON tmp(vec[i]);
710  val.push_back(tmp);
711  }
712  }
713 
714  const JSON& jsonAtIndex(size_t i) const;
715  void write(std::ostream &out) const;
716  JSONValue type() const { return JSON_ARRAY; }
717  Value* returnMyNewCopy() const { return new Array(*this); }
718  void read(std::istream &in);
719  void push_back(const JSON &j) {
720  val.push_back(j);
721  }
722  void erase(const size_t &i);
723  bool isEqual(const Value* other) const;
724  bool operator ==(const Array& other) const { return isEqual(&other); }
725  bool operator !=(const Array& other) const { return !(*this == other); }
726 
727  };
728 
729  class Boolean: public Value {
730  public:
731  bool val;
732 
733  Boolean() {}
734  Boolean(const bool &v):val(v) {}
735  JSON& jsonAtKey(const std::string &s);
736  const JSON& jsonAtKey(const std::string &s) const;
737  JSONValue type() const { return JSON_BOOLEAN; }
738  void write(std::ostream &out) const { out << ((val) ? "true" : "false"); }
739  Value* returnMyNewCopy() const { return new Boolean(*this); }
740  void read(std::istream &in);
741  bool isEqual(const Value* other) const;
742  bool operator ==(const Boolean& other) const { return isEqual(&other); }
743  bool operator !=(const Boolean& other) const { return !(*this == other); }
744  };
745 
746  class Null: public Value {
747  public:
748  void write(std::ostream &out) const { out << "null"; }
749  JSONValue type() const { return JSON_NULL; }
750  Value* returnMyNewCopy() const { return new Null(*this); }
751  void read(std::istream &in);
752  bool isEqual(const Value* other) const;
753  bool operator ==(const Null& other) const { return isEqual(&other); }
754  bool operator !=(const Null& other) const { return !(*this == other); }
755 
756  };
757 
758  template<typename T>
759  JSON::JSON(const T& x) {
760  val = NULL; // So that clear() works fine on this, else we will be deallocating some arbitrary memory - dangerous!
761  *this = operator=(x);
762  }
763 
764 
765  template<typename T>
766  JSON& JSON::operator =(const T &x) {
767  if (!std::numeric_limits<T>::is_specialized)
768  throw JSONException("Sorry! We do not allow creating a JSON object from " + std::string(typeid(x).name()) + " type.");
769 
770  if (!std::numeric_limits<T>::is_integer)
771  assertValidityOfNumericType(x);
772 
773  clear();
774  if(std::numeric_limits<T>::is_integer)
775  this->val = new Integer(static_cast<int64_t>(x));
776  else
777  this->val = new Real(static_cast<double>(x));
778  return *this;
779  }
780 
781  template<typename T>
782  JSON& JSON::operator =(const std::vector<T> &vec) {
783  clear();
784  this->val = new Array(vec);
785  return *this;
786  }
787 
788  template<typename T>
789  JSON& JSON::operator =(const std::map<std::string, T> &m) {
790  clear();
791  this->val = new Object(m);
792  return *this;
793  }
794 
795  template<typename T>
796  JSON::operator T() const {
797  JSONValue typ = this->type();
798  if (typ != JSON_INTEGER && typ != JSON_REAL && typ != JSON_BOOLEAN)
799  throw JSONException("No typecast available for this JSON object to a Numeric/Boolean type");
800 
801  if (!std::numeric_limits<T>::is_specialized)
802  throw JSONException("You cannot convert this JSON object to Numeric/Boolean type.");
803 
804  switch(typ) {
805  case JSON_INTEGER:
806  return static_cast<T>( ((Integer*)this->val)->val);
807  case JSON_REAL:
808  return static_cast<T>( ((Real*)this->val)->val);
809  case JSON_BOOLEAN:
810  return static_cast<T>( ((Boolean*)this->val)->val);
811  default: assert(false); // Should never happen (already checked at top)
812  }
813  }
814 
815  template<typename T>
816  const JSON& JSON::operator [](const T&x) const {
817  return (*(const_cast<const JSON*>(this)))[static_cast<size_t>(x)];
818  }
819 
827  template<>
828  inline std::string JSON::get<std::string>() const {
829  if (this->type() != JSON_STRING)
830  throw JSONException("You cannot use get<std::string>/get<char*> for a non JSON_STRING value");
831  return ((String*)this->val)->val;
832  }
833 
834 }
835 
836 #endif
size_t length() const
Definition: dxjson.h:480
Value * val
Definition: dxjson.h:152
JSON & operator=(const T &rhs)
Definition: dxjson.h:766
static JSON parse(const std::string &str)
Definition: dxjson.h:167
JSONValue type() const
Definition: dxjson.h:450
bool has(const T &indx) const
Definition: dxjson.h:488
JSON()
Definition: dxjson.h:175
JSONValue
Definition: dxjson.h:100
const JSON & operator[](const size_t &indx) const
Definition: dxjson.cpp:501
void readFromString(const std::string &jstr)
Definition: dxjson.cpp:466
~JSON()
Definition: dxjson.h:611
void clear()
Definition: dxjson.h:197