dxjson 1.0
JSON library for C++
Loading...
Searching...
No Matches
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
53namespace 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
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
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
std::string toString(bool onlyTopLevel=false) const
Definition dxjson.cpp:640
size_t length() const
Definition dxjson.h:480
const_object_iterator object_begin() const
Definition dxjson.cpp:894
void resize_array(size_t desired_size)
Definition dxjson.cpp:991
void readFromString(const std::string &jstr)
Definition dxjson.cpp:466
const_object_iterator object_end() const
Definition dxjson.cpp:918
const_array_reverse_iterator array_rbegin() const
Definition dxjson.cpp:949
bool has(const T &indx) const
Definition dxjson.h:488
bool operator==(const JSON &other) const
Definition dxjson.cpp:888
const_array_iterator array_begin() const
Definition dxjson.cpp:900
static JSON parse(const std::string &str)
Definition dxjson.h:167
JSONValue type() const
Definition dxjson.h:450
size_t size() const
Definition dxjson.cpp:611
void push_back(const JSON &j)
Definition dxjson.cpp:632
T get() const
Definition dxjson.h:442
void write(std::ostream &out) const
Definition dxjson.cpp:457
~JSON()
Definition dxjson.h:611
void clear()
Definition dxjson.h:197
static double getEpsilon()
Definition dxjson.cpp:27
const JSON & operator[](const size_t &indx) const
Definition dxjson.cpp:501
const_array_reverse_iterator array_rend() const
Definition dxjson.cpp:973
bool operator!=(const JSON &other) const
Definition dxjson.h:272
const_array_iterator array_end() const
Definition dxjson.cpp:924
void erase(const size_t &indx)
Definition dxjson.cpp:682
Value * val
Definition dxjson.h:152
void read(std::istream &in)
Definition dxjson.cpp:678
JSON & operator=(const T &rhs)
Definition dxjson.h:766
JSONValue
Definition dxjson.h:100