- tidied code
- added more documentation
This commit is contained in:
parent
52c2cb8ce7
commit
9a567d9d2d
3 changed files with 243 additions and 81 deletions
51
README.md
51
README.md
|
@ -12,9 +12,9 @@ There are myriads of [JSON](http://json.org) libraries out there, and each may e
|
||||||
|
|
||||||
Other aspects were not so important to us:
|
Other aspects were not so important to us:
|
||||||
|
|
||||||
- **Memory efficiency**. Each JSON object has an overhead of one pointer and one enumeration element (1 byte). We use the following C++ data types: `std::string` for strings, `int` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. We know that there are more efficient ways to store the values, but we are happy enough right now. And by the way: [Valgrind](http://valgrind.org) says our code is free of leaks.
|
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). We use the following C++ data types: `std::string` for strings, `int` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. We know that there are more efficient ways to store the values, but we are happy enough right now. And by the way: [Valgrind](http://valgrind.org) says our code is free of leaks.
|
||||||
|
|
||||||
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster.
|
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster (but would consist of more files which makes the integration harder).
|
||||||
|
|
||||||
- **Rigourous standard compliance**. We followed the [specification](http://json.org) as close as possible, but did not invest too much in a 100% compliance with respect to Unicode support. As a result, there might be edge cases of false positives and false negatives, but as long as we have a hand-written parser, we won't invest too much to be fully compliant.
|
- **Rigourous standard compliance**. We followed the [specification](http://json.org) as close as possible, but did not invest too much in a 100% compliance with respect to Unicode support. As a result, there might be edge cases of false positives and false negatives, but as long as we have a hand-written parser, we won't invest too much to be fully compliant.
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ j["name"] = "Niels";
|
||||||
// add an object inside the object
|
// add an object inside the object
|
||||||
j["further"]["entry"] = 42;
|
j["further"]["entry"] = 42;
|
||||||
|
|
||||||
// add an array that is stored as std::vector
|
// add an array that is stored as std::vector (C++11)
|
||||||
j["list"] = { 1, 0, 2 };
|
j["list"] = { 1, 0, 2 };
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -63,6 +63,8 @@ j << "{ \"pi\": 3.141, \"happy\": true }";
|
||||||
std::cout << j;
|
std::cout << j;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
These operators work for any subclases of `std::istream` or `std::ostream`.
|
||||||
|
|
||||||
### STL-like access
|
### STL-like access
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
@ -77,6 +79,11 @@ for (JSON::iterator it = j.begin(); it != j.end(); ++it) {
|
||||||
std::cout << *it << '\n';
|
std::cout << *it << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// C++11 style
|
||||||
|
for (auto element : j) {
|
||||||
|
std::cout << element << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
// getter/setter
|
// getter/setter
|
||||||
std::string tmp = j[0];
|
std::string tmp = j[0];
|
||||||
j[1] = 42;
|
j[1] = 42;
|
||||||
|
@ -85,4 +92,42 @@ j[1] = 42;
|
||||||
j.size(); // 3
|
j.size(); // 3
|
||||||
j.empty(); // false
|
j.empty(); // false
|
||||||
j.type(); // JSON::array
|
j.type(); // JSON::array
|
||||||
|
|
||||||
|
// create an object
|
||||||
|
JSON o;
|
||||||
|
o["foo"] = 23;
|
||||||
|
o["bar"] = false;
|
||||||
|
o["baz"] = 3.141;
|
||||||
|
|
||||||
|
// find an entry
|
||||||
|
if (o.find("foo") != o.end()) {
|
||||||
|
// there is an entry with key "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate the object
|
||||||
|
for (JSON::iterator it = o.begin(); it != o.end(); ++it) {
|
||||||
|
std::cout << it.key() << ':' << it.value() << '\n';
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Implicit conversions
|
||||||
|
|
||||||
|
The type of the JSON object is determined automatically by the expression to store. Likewise, the stored value is implicitly converted
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
/// strings
|
||||||
|
std::string s1 = "Hello, world!";
|
||||||
|
JSON js = s;
|
||||||
|
std::string s2 = j;
|
||||||
|
|
||||||
|
// Booleans
|
||||||
|
bool b1 = true;
|
||||||
|
JSON jb = b1;
|
||||||
|
bool b2 = jb;
|
||||||
|
|
||||||
|
// numbers
|
||||||
|
int i = 42;
|
||||||
|
JSON jn = i;
|
||||||
|
double f = jn;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
205
src/JSON.cc
205
src/JSON.cc
|
@ -10,10 +10,20 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
// allow us to use "nullptr" everywhere
|
||||||
|
#include <cstddef>
|
||||||
|
#ifndef nullptr
|
||||||
|
#define nullptr NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// HELPER FUNCTION //
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
#ifdef __cplusplus11
|
#ifdef __cplusplus11
|
||||||
using std::to_string;
|
using std::to_string;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
inline std::string to_string(double f) {
|
inline std::string to_string(double f) {
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << f;
|
s << f;
|
||||||
|
@ -21,18 +31,20 @@ inline std::string to_string(double f) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/******************
|
|
||||||
* STATIC MEMBERS *
|
////////////////////
|
||||||
******************/
|
// STATIC MEMBERS //
|
||||||
|
////////////////////
|
||||||
|
|
||||||
#ifdef __cplusplus11
|
#ifdef __cplusplus11
|
||||||
/// a mutex to ensure thread safety
|
/// a mutex to ensure thread safety
|
||||||
std::mutex JSON::_token;
|
std::mutex JSON::_token;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*******************************
|
|
||||||
* CONSTRUCTORS AND DESTRUCTOR *
|
/////////////////////////////////
|
||||||
*******************************/
|
// CONSTRUCTORS AND DESTRUCTOR //
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
JSON::JSON() : _type(null) {}
|
JSON::JSON() : _type(null) {}
|
||||||
|
|
||||||
|
@ -133,6 +145,7 @@ JSON& JSON::operator=(const JSON& o) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first delete original value
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case (array): {
|
case (array): {
|
||||||
delete _value.array;
|
delete _value.array;
|
||||||
|
@ -160,6 +173,7 @@ JSON& JSON::operator=(const JSON& o) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// then copy given value from o
|
||||||
_type = o._type;
|
_type = o._type;
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case (array): {
|
case (array): {
|
||||||
|
@ -226,9 +240,9 @@ JSON::~JSON() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************
|
///////////////////////////////
|
||||||
* OPERATORS AND CONVERSIONS *
|
// OPERATORS AND CONVERSIONS //
|
||||||
*****************************/
|
///////////////////////////////
|
||||||
|
|
||||||
JSON::operator const std::string() const {
|
JSON::operator const std::string() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
|
@ -271,6 +285,27 @@ JSON::operator bool() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSON::operator std::vector<JSON>() const {
|
||||||
|
if (_type == array) {
|
||||||
|
return *_value.array;
|
||||||
|
}
|
||||||
|
if (_type == object) {
|
||||||
|
throw std::runtime_error("cannot cast " + _typename() + " to JSON array");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<JSON> result;
|
||||||
|
result.push_back(*this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON::operator std::map<std::string, JSON>() const {
|
||||||
|
if (_type == object) {
|
||||||
|
return *_value.object;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("cannot cast " + _typename() + " to JSON object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::string JSON::toString() const {
|
const std::string JSON::toString() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case (null): {
|
case (null): {
|
||||||
|
@ -322,9 +357,9 @@ const std::string JSON::toString() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************
|
///////////////////////////////////////////
|
||||||
* ADDING ELEMENTS TO OBJECTS AND ARRAYS *
|
// ADDING ELEMENTS TO OBJECTS AND ARRAYS //
|
||||||
*****************************************/
|
///////////////////////////////////////////
|
||||||
|
|
||||||
JSON& JSON::operator+=(const JSON& o) {
|
JSON& JSON::operator+=(const JSON& o) {
|
||||||
push_back(o);
|
push_back(o);
|
||||||
|
@ -483,42 +518,56 @@ const JSON& JSON::operator[](const std::string& key) const {
|
||||||
/// return the number of stored values
|
/// return the number of stored values
|
||||||
size_t JSON::size() const {
|
size_t JSON::size() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return _value.array->size();
|
return _value.array->size();
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return _value.object->size();
|
return _value.object->size();
|
||||||
case (null):
|
}
|
||||||
|
case (null): {
|
||||||
return 0;
|
return 0;
|
||||||
case (string):
|
}
|
||||||
|
case (string): {
|
||||||
return 1;
|
return 1;
|
||||||
case (boolean):
|
}
|
||||||
|
case (boolean): {
|
||||||
return 1;
|
return 1;
|
||||||
case (number):
|
}
|
||||||
|
case (number): {
|
||||||
return 1;
|
return 1;
|
||||||
case (number_float):
|
}
|
||||||
|
case (number_float): {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// checks whether object is empty
|
/// checks whether object is empty
|
||||||
bool JSON::empty() const {
|
bool JSON::empty() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return _value.array->empty();
|
return _value.array->empty();
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return _value.object->empty();
|
return _value.object->empty();
|
||||||
case (null):
|
}
|
||||||
|
case (null): {
|
||||||
return true;
|
return true;
|
||||||
case (string):
|
}
|
||||||
|
case (string): {
|
||||||
return false;
|
return false;
|
||||||
case (boolean):
|
}
|
||||||
|
case (boolean): {
|
||||||
return false;
|
return false;
|
||||||
case (number):
|
}
|
||||||
|
case (number): {
|
||||||
return false;
|
return false;
|
||||||
case (number_float):
|
}
|
||||||
|
case (number_float): {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// return the type of the object
|
/// return the type of the object
|
||||||
JSON::json_t JSON::type() const {
|
JSON::json_t JSON::type() const {
|
||||||
|
@ -624,27 +673,38 @@ bool JSON::operator==(const JSON& o) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// lexicographically compares the values
|
||||||
|
bool JSON::operator!=(const JSON& o) const {
|
||||||
|
return not operator==(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// return the type as string
|
/// return the type as string
|
||||||
std::string JSON::_typename() const {
|
std::string JSON::_typename() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return "array";
|
return "array";
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return "object";
|
return "object";
|
||||||
case (null):
|
}
|
||||||
|
case (null): {
|
||||||
return "null";
|
return "null";
|
||||||
case (string):
|
}
|
||||||
|
case (string): {
|
||||||
return "string";
|
return "string";
|
||||||
case (boolean):
|
}
|
||||||
|
case (boolean): {
|
||||||
return "boolean";
|
return "boolean";
|
||||||
case (number):
|
}
|
||||||
|
case (number): {
|
||||||
return "number";
|
return "number";
|
||||||
case (number_float):
|
}
|
||||||
|
case (number_float): {
|
||||||
return "number";
|
return "number";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
JSON::parser::parser(char* s) : _pos(0) {
|
JSON::parser::parser(char* s) : _pos(0) {
|
||||||
|
@ -683,7 +743,7 @@ JSON::parser::~parser() {
|
||||||
delete [] _buffer;
|
delete [] _buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JSON::parser::error(std::string msg) {
|
void JSON::parser::error(std::string msg = "") {
|
||||||
throw std::runtime_error("parse error at position " + to_string(_pos) + ": " + msg + ", last read: '" + _current + "'");
|
throw std::runtime_error("parse error at position " + to_string(_pos) + ": " + msg + ", last read: '" + _current + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -917,10 +977,11 @@ JSON::iterator::iterator(JSON* j) : _object(j), _vi(nullptr), _oi(nullptr) {
|
||||||
_oi = new object_t::iterator(_object->_value.object->begin());
|
_oi = new object_t::iterator(_object->_value.object->begin());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JSON::iterator::iterator(const JSON::iterator& o) : _object(o._object), _vi(nullptr), _oi(nullptr) {
|
JSON::iterator::iterator(const JSON::iterator& o) : _object(o._object), _vi(nullptr), _oi(nullptr) {
|
||||||
if (_object != nullptr)
|
if (_object != nullptr)
|
||||||
|
@ -933,10 +994,11 @@ JSON::iterator::iterator(const JSON::iterator& o) : _object(o._object), _vi(null
|
||||||
_oi = new object_t::iterator(*(o._oi));
|
_oi = new object_t::iterator(*(o._oi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JSON::iterator::~iterator() {
|
JSON::iterator::~iterator() {
|
||||||
delete _vi;
|
delete _vi;
|
||||||
|
@ -955,9 +1017,10 @@ JSON::iterator& JSON::iterator::operator=(const JSON::iterator& o) {
|
||||||
_oi = new object_t::iterator(*(o._oi));
|
_oi = new object_t::iterator(*(o._oi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,14 +1065,17 @@ JSON& JSON::iterator::operator*() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_object->_type) {
|
switch (_object->_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return **_vi;
|
return **_vi;
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return (*_oi)->second;
|
return (*_oi)->second;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
return *_object;
|
return *_object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JSON* JSON::iterator::operator->() const {
|
JSON* JSON::iterator::operator->() const {
|
||||||
if (_object == nullptr) {
|
if (_object == nullptr) {
|
||||||
|
@ -1017,14 +1083,17 @@ JSON* JSON::iterator::operator->() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_object->_type) {
|
switch (_object->_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return &(**_vi);
|
return &(**_vi);
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return &((*_oi)->second);
|
return &((*_oi)->second);
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
return _object;
|
return _object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string JSON::iterator::key() const {
|
std::string JSON::iterator::key() const {
|
||||||
if (_object != nullptr and _object->_type == object) {
|
if (_object != nullptr and _object->_type == object) {
|
||||||
|
@ -1040,14 +1109,17 @@ JSON& JSON::iterator::value() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_object->_type) {
|
switch (_object->_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return **_vi;
|
return **_vi;
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return (*_oi)->second;
|
return (*_oi)->second;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
return *_object;
|
return *_object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1079,10 +1151,11 @@ JSON::const_iterator::const_iterator(const JSON* j) : _object(j), _vi(nullptr),
|
||||||
_oi = new object_t::const_iterator(_object->_value.object->begin());
|
_oi = new object_t::const_iterator(_object->_value.object->begin());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JSON::const_iterator::const_iterator(const JSON::const_iterator& o) : _object(o._object), _vi(nullptr), _oi(nullptr) {
|
JSON::const_iterator::const_iterator(const JSON::const_iterator& o) : _object(o._object), _vi(nullptr), _oi(nullptr) {
|
||||||
if (_object != nullptr)
|
if (_object != nullptr)
|
||||||
|
@ -1095,10 +1168,11 @@ JSON::const_iterator::const_iterator(const JSON::const_iterator& o) : _object(o.
|
||||||
_oi = new object_t::const_iterator(*(o._oi));
|
_oi = new object_t::const_iterator(*(o._oi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JSON::const_iterator::const_iterator(const JSON::iterator& o) : _object(o._object), _vi(nullptr), _oi(nullptr) {
|
JSON::const_iterator::const_iterator(const JSON::iterator& o) : _object(o._object), _vi(nullptr), _oi(nullptr) {
|
||||||
if (_object != nullptr)
|
if (_object != nullptr)
|
||||||
|
@ -1111,10 +1185,11 @@ JSON::const_iterator::const_iterator(const JSON::iterator& o) : _object(o._objec
|
||||||
_oi = new object_t::const_iterator(*(o._oi));
|
_oi = new object_t::const_iterator(*(o._oi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JSON::const_iterator::~const_iterator() {
|
JSON::const_iterator::~const_iterator() {
|
||||||
delete _vi;
|
delete _vi;
|
||||||
|
@ -1133,9 +1208,10 @@ JSON::const_iterator& JSON::const_iterator::operator=(const JSON::const_iterator
|
||||||
_oi = new object_t::const_iterator(*(o._oi));
|
_oi = new object_t::const_iterator(*(o._oi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1180,14 +1256,17 @@ const JSON& JSON::const_iterator::operator*() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_object->_type) {
|
switch (_object->_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return **_vi;
|
return **_vi;
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return (*_oi)->second;
|
return (*_oi)->second;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
return *_object;
|
return *_object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const JSON* JSON::const_iterator::operator->() const {
|
const JSON* JSON::const_iterator::operator->() const {
|
||||||
if (_object == nullptr) {
|
if (_object == nullptr) {
|
||||||
|
@ -1195,14 +1274,17 @@ const JSON* JSON::const_iterator::operator->() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_object->_type) {
|
switch (_object->_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return &(**_vi);
|
return &(**_vi);
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return &((*_oi)->second);
|
return &((*_oi)->second);
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
return _object;
|
return _object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string JSON::const_iterator::key() const {
|
std::string JSON::const_iterator::key() const {
|
||||||
if (_object != nullptr and _object->_type == object) {
|
if (_object != nullptr and _object->_type == object) {
|
||||||
|
@ -1218,11 +1300,14 @@ const JSON& JSON::const_iterator::value() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_object->_type) {
|
switch (_object->_type) {
|
||||||
case (array):
|
case (array): {
|
||||||
return **_vi;
|
return **_vi;
|
||||||
case (object):
|
}
|
||||||
|
case (object): {
|
||||||
return (*_oi)->second;
|
return (*_oi)->second;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
return *_object;
|
return *_object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
64
src/JSON.h
64
src/JSON.h
|
@ -5,17 +5,12 @@
|
||||||
#define __cplusplus11
|
#define __cplusplus11
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// allow us to use "nullptr" everywhere
|
// STL containers
|
||||||
#include <cstddef>
|
|
||||||
#ifndef nullptr
|
|
||||||
#define nullptr NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
// additional C++11 header
|
// additional C++11 headers
|
||||||
#ifdef __cplusplus11
|
#ifdef __cplusplus11
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
@ -27,8 +22,8 @@ class JSON {
|
||||||
class iterator;
|
class iterator;
|
||||||
class const_iterator;
|
class const_iterator;
|
||||||
|
|
||||||
private:
|
|
||||||
#ifdef __cplusplus11
|
#ifdef __cplusplus11
|
||||||
|
private:
|
||||||
/// mutex to guard payload
|
/// mutex to guard payload
|
||||||
static std::mutex _token;
|
static std::mutex _token;
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,19 +50,32 @@ class JSON {
|
||||||
|
|
||||||
/// a JSON value
|
/// a JSON value
|
||||||
union value {
|
union value {
|
||||||
|
/// array as pointer to array_t
|
||||||
array_t* array;
|
array_t* array;
|
||||||
|
/// object as pointer to object_t
|
||||||
object_t* object;
|
object_t* object;
|
||||||
|
/// string as pointer to string_t
|
||||||
string_t* string;
|
string_t* string;
|
||||||
|
/// Boolean
|
||||||
boolean_t boolean;
|
boolean_t boolean;
|
||||||
|
/// number (integer)
|
||||||
number_t number;
|
number_t number;
|
||||||
|
/// number (float)
|
||||||
number_float_t number_float;
|
number_float_t number_float;
|
||||||
|
|
||||||
|
/// default constructor
|
||||||
value() {}
|
value() {}
|
||||||
|
/// constructor for arrays
|
||||||
value(array_t* array): array(array) {}
|
value(array_t* array): array(array) {}
|
||||||
|
/// constructor for objects
|
||||||
value(object_t* object): object(object) {}
|
value(object_t* object): object(object) {}
|
||||||
|
/// constructor for strings
|
||||||
value(string_t* string): string(string) {}
|
value(string_t* string): string(string) {}
|
||||||
|
/// constructor for Booleans
|
||||||
value(boolean_t boolean) : boolean(boolean) {}
|
value(boolean_t boolean) : boolean(boolean) {}
|
||||||
|
/// constructor for numbers (integer)
|
||||||
value(number_t number) : number(number) {}
|
value(number_t number) : number(number) {}
|
||||||
|
/// constructor for numbers (float)
|
||||||
value(number_float_t number_float) : number_float(number_float) {}
|
value(number_float_t number_float) : number_float(number_float) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,15 +92,15 @@ class JSON {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// create an empty (null) object
|
/// create a null object
|
||||||
JSON();
|
JSON();
|
||||||
/// create an empty object according to given type
|
/// create an object according to given type
|
||||||
JSON(json_t);
|
JSON(json_t);
|
||||||
/// create a string object from C++ string
|
/// create a string object from a C++ string
|
||||||
JSON(const std::string&);
|
JSON(const std::string&);
|
||||||
/// create a string object from C string
|
/// create a string object from a C string
|
||||||
JSON(char*);
|
JSON(char*);
|
||||||
/// create a string object from C string
|
/// create a string object from a C string
|
||||||
JSON(const char*);
|
JSON(const char*);
|
||||||
/// create a Boolean object
|
/// create a Boolean object
|
||||||
JSON(const bool);
|
JSON(const bool);
|
||||||
|
@ -135,13 +143,16 @@ class JSON {
|
||||||
operator double() const;
|
operator double() const;
|
||||||
/// implicit conversion to Boolean (only for Booleans)
|
/// implicit conversion to Boolean (only for Booleans)
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
/// implicit conversion to JSON vector (not for objects)
|
||||||
|
operator std::vector<JSON>() const;
|
||||||
|
/// implicit conversion to JSON map (only for objects)
|
||||||
|
operator std::map<std::string, JSON>() const;
|
||||||
|
|
||||||
/// write to stream
|
/// write to stream
|
||||||
friend std::ostream& operator<<(std::ostream& o, const JSON& j) {
|
friend std::ostream& operator<<(std::ostream& o, const JSON& j) {
|
||||||
o << j.toString();
|
o << j.toString();
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// write to stream
|
/// write to stream
|
||||||
friend std::ostream& operator>>(const JSON& j, std::ostream& o) {
|
friend std::ostream& operator>>(const JSON& j, std::ostream& o) {
|
||||||
o << j.toString();
|
o << j.toString();
|
||||||
|
@ -153,7 +164,6 @@ class JSON {
|
||||||
parser(i).parse(j);
|
parser(i).parse(j);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// read from stream
|
/// read from stream
|
||||||
friend std::istream& operator<<(JSON& j, std::istream& i) {
|
friend std::istream& operator<<(JSON& j, std::istream& i) {
|
||||||
parser(i).parse(j);
|
parser(i).parse(j);
|
||||||
|
@ -211,8 +221,11 @@ class JSON {
|
||||||
|
|
||||||
/// find an element in an object (returns end() iterator otherwise)
|
/// find an element in an object (returns end() iterator otherwise)
|
||||||
iterator find(const std::string&);
|
iterator find(const std::string&);
|
||||||
|
/// find an element in an object (returns end() iterator otherwise)
|
||||||
const_iterator find(const std::string&) const;
|
const_iterator find(const std::string&) const;
|
||||||
|
/// find an element in an object (returns end() iterator otherwise)
|
||||||
iterator find(const char*);
|
iterator find(const char*);
|
||||||
|
/// find an element in an object (returns end() iterator otherwise)
|
||||||
const_iterator find(const char*) const;
|
const_iterator find(const char*) const;
|
||||||
|
|
||||||
/// direct access to the underlying payload
|
/// direct access to the underlying payload
|
||||||
|
@ -222,6 +235,8 @@ class JSON {
|
||||||
|
|
||||||
/// lexicographically compares the values
|
/// lexicographically compares the values
|
||||||
bool operator==(const JSON&) const;
|
bool operator==(const JSON&) const;
|
||||||
|
/// lexicographically compares the values
|
||||||
|
bool operator!=(const JSON&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// return the type as string
|
/// return the type as string
|
||||||
|
@ -299,26 +314,43 @@ class JSON {
|
||||||
const_iterator cend() const;
|
const_iterator cend() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// a helper class to parse a JSON object
|
||||||
class parser {
|
class parser {
|
||||||
public:
|
public:
|
||||||
|
/// a parser reading from a C string
|
||||||
parser(char*);
|
parser(char*);
|
||||||
|
/// a parser reading from a C++ string
|
||||||
parser(std::string&);
|
parser(std::string&);
|
||||||
|
/// a parser reading from an input stream
|
||||||
parser(std::istream&);
|
parser(std::istream&);
|
||||||
|
/// destructor of the parser
|
||||||
~parser();
|
~parser();
|
||||||
|
/// parse into a given JSON object
|
||||||
void parse(JSON&);
|
void parse(JSON&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// read the next character, stripping whitespace
|
||||||
bool next();
|
bool next();
|
||||||
void error(std::string = "") __attribute__((noreturn));
|
/// raise an exception with an error message
|
||||||
|
void error(std::string) __attribute__((noreturn));
|
||||||
|
/// parse a quoted string
|
||||||
std::string parseString();
|
std::string parseString();
|
||||||
|
/// parse a Boolean "true"
|
||||||
void parseTrue();
|
void parseTrue();
|
||||||
|
/// parse a Boolean "false"
|
||||||
void parseFalse();
|
void parseFalse();
|
||||||
|
/// parse a null object
|
||||||
void parseNull();
|
void parseNull();
|
||||||
|
/// a helper function to expect a certain character
|
||||||
void expect(char);
|
void expect(char);
|
||||||
|
|
||||||
|
/// the current character
|
||||||
char _current;
|
char _current;
|
||||||
|
/// a buffer of the input
|
||||||
char* _buffer;
|
char* _buffer;
|
||||||
|
/// the position inside the input buffer
|
||||||
size_t _pos;
|
size_t _pos;
|
||||||
|
/// the length of the input buffer
|
||||||
size_t _length;
|
size_t _length;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue