diff --git a/src/JSON.cc b/src/JSON.cc index a9b9a4e5..1d1567e7 100644 --- a/src/JSON.cc +++ b/src/JSON.cc @@ -34,32 +34,32 @@ std::mutex JSON::_token; * CONSTRUCTORS AND DESTRUCTOR * *******************************/ -JSON::JSON() : _type(null), _payload(nullptr) {} +JSON::JSON() : _type(null) {} JSON::JSON(json_t type) : _type(type) { switch (_type) { case (array): { - _payload = new array_t(); + _value.array = new array_t(); break; } case (object): { - _payload = new object_t(); + _value.object = new object_t(); break; } case (string): { - _payload = new std::string(); + _value.string = new string_t(); break; } case (boolean): { - _payload = new bool(); + _value.boolean = new boolean_t(); break; } case (number): { - _payload = new int(0); + _value.number = new number_t(); break; } case (number_float): { - _payload = new double(0.0); + _value.number_float = new number_float_t(); break; } case (null): { @@ -68,44 +68,44 @@ JSON::JSON(json_t type) : _type(type) { } } -JSON::JSON(const std::string& s) : _type(string), _payload(new std::string(s)) {} -JSON::JSON(const char* s) : _type(string), _payload(new std::string(s)) {} -JSON::JSON(char* s) : _type(string), _payload(new std::string(s)) {} -JSON::JSON(const bool b) : _type(boolean), _payload(new bool(b)) {} -JSON::JSON(const int i) : _type(number), _payload(new int(i)) {} -JSON::JSON(const double f) : _type(number_float), _payload(new double(f)) {} -JSON::JSON(array_t a) : _type(array), _payload(new array_t(a)) {} -JSON::JSON(object_t o) : _type(object), _payload(new object_t(o)) {} +JSON::JSON(const std::string& s) : _type(string), _value(new string_t(s)) {} +JSON::JSON(const char* s) : _type(string), _value(new string_t(s)) {} +JSON::JSON(char* s) : _type(string), _value(new string_t(s)) {} +JSON::JSON(const bool b) : _type(boolean), _value(new boolean_t(b)) {} +JSON::JSON(const int i) : _type(number), _value(new number_t(i)) {} +JSON::JSON(const double f) : _type(number_float), _value(new number_float_t(f)) {} +JSON::JSON(array_t a) : _type(array), _value(new array_t(a)) {} +JSON::JSON(object_t o) : _type(object), _value(new object_t(o)) {} #ifdef __cplusplus11 -JSON::JSON(array_init_t a) : _type(array), _payload(new array_t(a)) {} +JSON::JSON(array_init_t a) : _type(array), _value(new array_t(a)) {} #endif /// copy constructor JSON::JSON(const JSON& o) : _type(o._type) { switch (_type) { case (array): { - _payload = new array_t(*static_cast(o._payload)); + _value.array = new array_t(*o._value.array); break; } case (object): { - _payload = new object_t(*static_cast(o._payload)); + _value.object = new object_t(*o._value.object); break; } case (string): { - _payload = new std::string(*static_cast(o._payload)); + _value.string = new string_t(*o._value.string); break; } case (boolean): { - _payload = new bool(*static_cast(o._payload)); + _value.boolean = new boolean_t(*o._value.boolean); break; } case (number): { - _payload = new int(*static_cast(o._payload)); + _value.number = new number_t(*o._value.number); break; } case (number_float): { - _payload = new double(*static_cast(o._payload)); + _value.number_float = new number_float_t(*o._value.number_float); break; } case (null): { @@ -116,14 +116,14 @@ JSON::JSON(const JSON& o) : _type(o._type) { #ifdef __cplusplus11 /// move constructor -JSON::JSON(JSON&& o) : _type(std::move(o._type)), _payload(std::move(o._payload)) {} +JSON::JSON(JSON&& o) : _type(std::move(o._type)), _value(std::move(o._value)) {} #endif /// copy assignment #ifdef __cplusplus11 JSON& JSON::operator=(JSON o) { std::swap(_type, o._type); - std::swap(_payload, o._payload); + std::swap(_value, o._value); return *this; } #else @@ -135,27 +135,27 @@ JSON& JSON::operator=(const JSON& o) { switch (_type) { case (array): { - delete static_cast(_payload); + delete _value.array; break; } case (object): { - delete static_cast(_payload); + delete _value.object; break; } case (string): { - delete static_cast(_payload); + delete _value.string; break; } case (boolean): { - delete static_cast(_payload); + delete _value.boolean; break; } case (number): { - delete static_cast(_payload); + delete _value.number; break; } case (number_float): { - delete static_cast(_payload); + delete _value.number_float; break; } case (null): { @@ -166,27 +166,27 @@ JSON& JSON::operator=(const JSON& o) { _type = o._type; switch (_type) { case (array): { - _payload = new array_t(*static_cast(o._payload)); + _value.array = new array_t(*o._value.array); break; } case (object): { - _payload = new object_t(*static_cast(o._payload)); + _value.object = new object_t(*o._value.object); break; } case (string): { - _payload = new std::string(*static_cast(o._payload)); + _value.string = new string_t(*o._value.string); break; } case (boolean): { - _payload = new bool(*static_cast(o._payload)); + _value.boolean = new boolean_t(*o._value.boolean); break; } case (number): { - _payload = new int(*static_cast(o._payload)); + _value.number = new number_t(*o._value.number); break; } case (number_float): { - _payload = new double(*static_cast(o._payload)); + _value.number_float = new number_float_t(*o._value.number_float); break; } case (null): { @@ -202,27 +202,27 @@ JSON& JSON::operator=(const JSON& o) { JSON::~JSON() { switch (_type) { case (array): { - delete static_cast(_payload); + delete _value.array; break; } case (object): { - delete static_cast(_payload); + delete _value.object; break; } case (string): { - delete static_cast(_payload); + delete _value.string; break; } case (boolean): { - delete static_cast(_payload); + delete _value.boolean; break; } case (number): { - delete static_cast(_payload); + delete _value.number; break; } case (number_float): { - delete static_cast(_payload); + delete _value.number_float; break; } case (null): { @@ -239,7 +239,7 @@ JSON::~JSON() { JSON::operator const std::string() const { switch (_type) { case (string): - return *static_cast(_payload); + return *_value.string; default: throw std::runtime_error("cannot cast " + _typename() + " to JSON string"); } @@ -249,9 +249,9 @@ JSON::operator const std::string() const { JSON::operator int() const { switch (_type) { case (number): - return *static_cast(_payload); + return *_value.number; case (number_float): - return static_cast(*static_cast(_payload)); + return static_cast(*_value.number_float); default: throw std::runtime_error("cannot cast " + _typename() + " to JSON number"); } @@ -260,9 +260,9 @@ JSON::operator int() const { JSON::operator double() const { switch (_type) { case (number): - return static_cast(*static_cast(_payload)); + return static_cast(*_value.number); case (number_float): - return *static_cast(_payload); + return *_value.number_float; default: throw std::runtime_error("cannot cast " + _typename() + " to JSON number"); } @@ -271,7 +271,7 @@ JSON::operator double() const { JSON::operator bool() const { switch (_type) { case (boolean): - return *static_cast(_payload); + return *_value.boolean; default: throw std::runtime_error("cannot cast " + _typename() + " to JSON Boolean"); } @@ -284,27 +284,26 @@ const std::string JSON::toString() const { } case (string): { - return std::string("\"") + *static_cast(_payload) + "\""; + return std::string("\"") + *_value.string + "\""; } case (boolean): { - return *static_cast(_payload) ? "true" : "false"; + return *_value.boolean ? "true" : "false"; } case (number): { - return to_string(*static_cast(_payload)); + return to_string(*_value.number); } case (number_float): { - return to_string(*static_cast(_payload)); + return to_string(*_value.number_float); } case (array): { std::string result; - const array_t* array = static_cast(_payload); - for (array_t::const_iterator i = array->begin(); i != array->end(); ++i) { - if (i != array->begin()) { + for (array_t::const_iterator i = _value.array->begin(); i != _value.array->end(); ++i) { + if (i != _value.array->begin()) { result += ", "; } result += (*i).toString(); @@ -316,9 +315,8 @@ const std::string JSON::toString() const { case (object): { std::string result; - const object_t* object = static_cast(_payload); - for (object_t::const_iterator i = object->begin(); i != object->end(); ++i) { - if (i != object->begin()) { + for (object_t::const_iterator i = _value.object->begin(); i != _value.object->end(); ++i) { + if (i != _value.object->begin()) { result += ", "; } result += "\"" + i->first + "\": " + (i->second).toString(); @@ -375,10 +373,10 @@ void JSON::push_back(const JSON& o) { if (_type == null) { _type = array; - _payload = new array_t; + _value.array = new array_t; } - static_cast(_payload)->push_back(o); + _value.array->push_back(o); } void JSON::push_back(const std::string& s) { @@ -411,13 +409,11 @@ JSON& JSON::operator[](int index) { throw std::runtime_error("cannot add entry with index " + to_string(index) + " to " + _typename()); } - array_t* array = static_cast(_payload); - - if (index >= (int)array->size()) { + if (index >= (int)_value.array->size()) { throw std::runtime_error("cannot access element at index " + to_string(index)); } - return array->at(index); + return _value.array->at(index); } /// operator to get an element in an object @@ -426,13 +422,11 @@ const JSON& JSON::operator[](const int index) const { throw std::runtime_error("cannot get entry with index " + to_string(index) + " from " + _typename()); } - array_t* array = static_cast(_payload); - - if (index >= (int)array->size()) { + if (index >= (int)_value.array->size()) { throw std::runtime_error("cannot access element at index " + to_string(index)); } - return array->at(index); + return _value.array->at(index); } /// operator to set an element in an object @@ -443,19 +437,18 @@ JSON& JSON::operator[](const std::string& key) { if (_type == null) { _type = object; - _payload = new object_t; + _value.object = new object_t; } if (_type != object) { throw std::runtime_error("cannot add entry with key " + std::string(key) + " to " + _typename()); } - object_t* object = static_cast(_payload); - if (object->find(key) == object->end()) { - (*object)[key] = JSON(); + if (_value.object->find(key) == _value.object->end()) { + (*_value.object)[key] = JSON(); } - return (*object)[key]; + return (*_value.object)[key]; } /// operator to set an element in an object @@ -466,19 +459,18 @@ JSON& JSON::operator[](const char* key) { if (_type == null) { _type = object; - _payload = new object_t; + _value.object = new object_t; } if (_type != object) { throw std::runtime_error("cannot add entry with key " + std::string(key) + " to " + _typename()); } - object_t* object = static_cast(_payload); - if (object->find(key) == object->end()) { - (*object)[key] = JSON(); + if (_value.object->find(key) == _value.object->end()) { + (*_value.object)[key] = JSON(); } - return (*object)[key]; + return (*_value.object)[key]; } /// operator to get an element in an object @@ -487,11 +479,10 @@ const JSON& JSON::operator[](const std::string& key) const { throw std::runtime_error("cannot get entry with key " + std::string(key) + " from " + _typename()); } - const object_t* object = static_cast(_payload); - if (object->find(key) == object->end()) { + if (_value.object->find(key) == _value.object->end()) { throw std::runtime_error("key " + key + " not found"); } else { - return object->find(key)->second; + return _value.object->find(key)->second; } } @@ -499,9 +490,9 @@ const JSON& JSON::operator[](const std::string& key) const { size_t JSON::size() const { switch (_type) { case (array): - return static_cast(_payload)->size(); + return _value.array->size(); case (object): - return static_cast(_payload)->size(); + return _value.object->size(); case (null): return 0; case (string): @@ -519,9 +510,9 @@ size_t JSON::size() const { bool JSON::empty() const { switch (_type) { case (array): - return static_cast(_payload)->empty(); + return _value.array->empty(); case (object): - return static_cast(_payload)->empty(); + return _value.object->empty(); case (null): return true; case (string): @@ -552,9 +543,8 @@ JSON::iterator JSON::find(const char* key) { if (_type != object) { return end(); } else { - object_t* o = static_cast(_payload); - const object_t::iterator i = o->find(key); - if (i != o->end()) { + const object_t::iterator i = _value.object->find(key); + if (i != _value.object->end()) { JSON::iterator result; result._object = this; result._oi = new object_t::iterator(i); @@ -569,9 +559,8 @@ JSON::const_iterator JSON::find(const char* key) const { if (_type != object) { return end(); } else { - object_t* o = static_cast(_payload); - const object_t::const_iterator i = o->find(key); - if (i != o->end()) { + const object_t::const_iterator i = _value.object->find(key); + if (i != _value.object->end()) { JSON::const_iterator result; result._object = this; result._oi = new object_t::const_iterator(i); @@ -583,13 +572,13 @@ JSON::const_iterator JSON::find(const char* key) const { } /// direct access to the underlying payload -void* JSON::data() { - return _payload; +JSON::value JSON::data() { + return _value; } /// direct access to the underlying payload -const void* JSON::data() const { - return _payload; +const JSON::value JSON::data() const { + return _value; } /// lexicographically compares the values @@ -597,16 +586,12 @@ bool JSON::operator==(const JSON& o) const { switch (_type) { case (array): { if (o._type == array) { - array_t* a = static_cast(_payload); - array_t* b = static_cast(o._payload); - return *a == *b; + return *_value.array == *o._value.array; } } case (object): { if (o._type == object) { - object_t* a = static_cast(_payload); - object_t* b = static_cast(o._payload); - return *a == *b; + return *_value.object == *o._value.object; } } case (null): { @@ -616,29 +601,25 @@ bool JSON::operator==(const JSON& o) const { } case (string): { if (o._type == string) { - const std::string a = *this; - const std::string b = o; - return a == b; + return *_value.string == *o._value.string; } } case (boolean): { if (o._type == boolean) { - bool a = *this; - bool b = o; - return a == b; + return *_value.boolean == *o._value.boolean; } } case (number): { if (o._type == number or o._type == number_float) { - int a = *this; - int b = o; + number_t a = *this; + number_t b = o; return a == b; } } case (number_float): { if (o._type == number or o._type == number_float) { - double a = *this; - double b = o; + number_float_t a = *this; + number_float_t b = o; return a == b; } } @@ -793,7 +774,7 @@ void JSON::parser::parseNull() { _pos += 3; - // read next character (optional?) + // read next character next(); } @@ -817,7 +798,7 @@ void JSON::parser::parse(JSON& result) { case ('{'): { // explicitly set result to object to cope with {} result._type = object; - result._payload = new object_t; + result._value.object = new object_t; next(); @@ -844,7 +825,7 @@ void JSON::parser::parse(JSON& result) { case ('['): { // explicitly set result to array to cope with [] result._type = array; - result._payload = new array_t; + result._value.array = new array_t; next(); @@ -866,21 +847,21 @@ void JSON::parser::parse(JSON& result) { case ('\"'): { result._type = string; - result._payload = new std::string(parseString()); + result._value.string = new string_t(parseString()); break; } case ('t'): { parseTrue(); result._type = boolean; - result._payload = new bool(true); + result._value.boolean = new boolean_t(true); break; } case ('f'): { parseFalse(); result._type = boolean; - result._payload = new bool(false); + result._value.boolean = new boolean_t(false); break; } @@ -902,11 +883,11 @@ void JSON::parser::parse(JSON& result) { if (tmp.find(".") == std::string::npos) { // integer (we use atof, because it can cope with e) result._type = number; - result._payload = new int(std::atof(tmp.c_str())); + result._value.number = new number_t(std::atof(tmp.c_str())); } else { // float result._type = number_float; - result._payload = new double(std::atof(tmp.c_str())); + result._value.number_float = new number_float_t(std::atof(tmp.c_str())); } break; } else { @@ -933,11 +914,11 @@ JSON::iterator::iterator(JSON* j) : _object(j), _vi(nullptr), _oi(nullptr) { if (_object != nullptr) switch (_object->_type) { case (array): { - _vi = new array_t::iterator(static_cast(_object->_payload)->begin()); + _vi = new array_t::iterator(_object->_value.array->begin()); break; } case (object): { - _oi = new object_t::iterator(static_cast(_object->_payload)->begin()); + _oi = new object_t::iterator(_object->_value.object->begin()); break; } default: @@ -1001,13 +982,13 @@ JSON::iterator& JSON::iterator::operator++() { switch (_object->_type) { case (array): { - if (++(*_vi) == static_cast(_object->_payload)->end()) { + if (++(*_vi) == _object->_value.array->end()) { _object = nullptr; } break; } case (object): { - if (++(*_oi) == static_cast(_object->_payload)->end()) { + if (++(*_oi) == _object->_value.object->end()) { _object = nullptr; } break; @@ -1095,11 +1076,11 @@ JSON::const_iterator::const_iterator(const JSON* j) : _object(j), _vi(nullptr), if (_object != nullptr) switch (_object->_type) { case (array): { - _vi = new array_t::const_iterator(static_cast(_object->_payload)->begin()); + _vi = new array_t::const_iterator(_object->_value.array->begin()); break; } case (object): { - _oi = new object_t::const_iterator(static_cast(_object->_payload)->begin()); + _oi = new object_t::const_iterator(_object->_value.object->begin()); break; } default: @@ -1179,13 +1160,13 @@ JSON::const_iterator& JSON::const_iterator::operator++() { switch (_object->_type) { case (array): { - if (++(*_vi) == static_cast(_object->_payload)->end()) { + if (++(*_vi) == _object->_value.array->end()) { _object = nullptr; } break; } case (object): { - if (++(*_oi) == static_cast(_object->_payload)->end()) { + if (++(*_oi) == _object->_value.object->end()) { _object = nullptr; } break; diff --git a/src/JSON.h b/src/JSON.h index f2750ebd..1d78a8ca 100644 --- a/src/JSON.h +++ b/src/JSON.h @@ -39,18 +39,44 @@ class JSON { array, object, null, string, boolean, number, number_float } json_t; - private: - /// the type of this object - json_t _type; - - /// the payload - void* _payload; - public: /// a type for an object typedef std::map object_t; /// a type for an array typedef std::vector array_t; + /// a type for a string + typedef std::string string_t; + /// a type for a Boolean + typedef bool boolean_t; + /// a type for an integer number + typedef int number_t; + /// a type for a floating point number + typedef double number_float_t; + + /// a JSON value + union value { + array_t* array; + object_t* object; + string_t* string; + boolean_t* boolean; + number_t* number; + number_float_t* number_float; + + value() {} + value(array_t* array): array(array) {} + value(object_t* object): object(object) {} + value(string_t* string): string(string) {} + value(boolean_t* boolean) : boolean(boolean) {} + value(number_t* number) : number(number) {} + value(number_float_t* number_float) : number_float(number_float) {} + }; + + private: + /// the type of this object + json_t _type; + + /// the payload + value _value; #ifdef __cplusplus11 /// a type for array initialization @@ -190,9 +216,9 @@ class JSON { const_iterator find(const char*) const; /// direct access to the underlying payload - void* data(); + value data(); /// direct access to the underlying payload - const void* data() const; + const value data() const; /// lexicographically compares the values bool operator==(const JSON&) const; diff --git a/test/JSON_test.cc b/test/JSON_test.cc index e43595cb..10e668d9 100644 --- a/test/JSON_test.cc +++ b/test/JSON_test.cc @@ -145,7 +145,7 @@ void test_string() { { // get payload - std::string* s1 = static_cast(a.data()); + std::string* s1 = a.data().string; std::string s2 = a; assert(*s1 == s2); } @@ -271,7 +271,7 @@ void test_array() { { // get payload - std::vector* array = static_cast*>(a.data()); + std::vector* array = a.data().array; assert(array->size() == a.size()); assert(array->empty() == a.empty()); }