From 87df8bb0fe16f0a579b2b77a3fc694af12d6a6b8 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 01:13:19 -0800 Subject: [PATCH] templatize janssonxx functionality to prepare for proxy setters --- janssonxx.h | 419 +++++++++++++++++++++++++------------------------- janssonxx.tcc | 133 ++++++++++++++++ test.cc | 10 ++ 3 files changed, 350 insertions(+), 212 deletions(-) create mode 100644 janssonxx.tcc diff --git a/janssonxx.h b/janssonxx.h index b546f7e..935ac9e 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -16,252 +16,245 @@ #include namespace jansson { + // include in the jansson namespace +# include -// include in the jansson namespace -#include + class Iterator; + class Value; -class Iterator; + // base class for JSON value interface + template + class _ValueBase : public _Base { + public: + // empty constructor + _ValueBase() : _Base() {} -// represents any JSON value -class Value { -public: - // construct new Value with an undefined value - Value() : _value(0) {} + // copy constructor + _ValueBase(const _Base& base) : _Base(base) {} - // free Value resources - ~Value() { json_decref(_value); } + // create reference to value + _ValueBase(json_t* json) : _Base(json) {} - // copy an existing Value - Value(const Value& e) : _value(json_incref(e._value)) {} + // check value type + bool is_undefined() const { return _Base::as_json() == 0; } + bool is_object() const { return json_is_object(_Base::as_json()); } + bool is_array() const { return json_is_array(_Base::as_json()); } + bool is_string() const { return json_is_string(_Base::as_json()); } + bool is_integer() const { return json_is_integer(_Base::as_json()); } + bool is_real() const { return json_is_real(_Base::as_json()); } + bool is_number() const { return json_is_number(_Base::as_json()); } + bool is_true() const { return json_is_true(_Base::as_json()); } + bool is_false() const { return json_is_false(_Base::as_json()); } + bool is_boolean() const { return json_is_boolean(_Base::as_json()); } + bool is_null() const { return json_is_null(_Base::as_json()); } - // make a reference to an existing json_t value - explicit Value(json_t* value) : _value(json_incref(value)) {} + // get size of array or object + inline unsigned int size() const; - // copy an existing Value - Value& operator=(const Value& e) { - if (&e != this) { - json_decref(_value); - _value = json_incref(e._value); + // get value at array index (const version) + inline const Value at(unsigned int index) const; + + inline const Value operator[](signed int index) const; + inline const Value operator[](unsigned int index) const; + inline const Value operator[](signed short index) const; + inline const Value operator[](unsigned short index) const; + inline const Value operator[](signed long index) const; + inline const Value operator[](unsigned long index) const; + + // get value at array index (non-const version) + inline Value at(unsigned int index); + + inline Value operator[](signed int index); + inline Value operator[](unsigned int index); + inline Value operator[](signed short index); + inline Value operator[](unsigned short index); + inline Value operator[](signed long index); + inline Value operator[](unsigned long index); + + // get object property + inline const Value get(const char* key) const; + + inline const Value get(const std::string& key) const; + inline const Value operator[](const char* key) const; + inline const Value operator[](const std::string& key) const; + + // clear all array/object values + inline void clear(); + + // get value cast to specified type + inline const char* as_cstring() const; + inline std::string as_string() const; + inline int as_integer() const; + inline double as_real() const; + inline double as_number() const; + inline bool as_boolean() const; + + // set an object property (converts value to object is not one already) + inline _Base& set_key(const char* key, const Value& value); + + inline _Base& set_key(const std::string& key, const Value& value); + + // set an array index (converts value to object is not one already) + inline _Base& set_at(unsigned int index, const Value& value); + + // delete an object key + inline _Base& del_key(const char* key); + + inline _Base& del_key(const std::string& key); + + // delete an item from an array by index + inline _Base& del_at(unsigned int index); + + // insert an item into an array at a given index + inline _Base& insert_at(unsigned int index, const Value& value); + }; + + // represents any JSON value, private base + class _Value { + public: + // construct new Value with an undefined value + _Value() : _value(0) {} + + // copy constructor + _Value(const _Value& value) : _value(json_incref(value._value)) {} + + // make a reference to an existing json_t value + explicit _Value(json_t* value) : _value(json_incref(value)) {} + + // free Value resources + ~_Value() { json_decref(_value); } + + // copy an existing Value + _Value& operator=(const _Value& e) { + if (&e != this) { + json_decref(_value); + _value = json_incref(e._value); + } + return *this; } - return *this; - } - // load a file as a JSON value - static Value load_file(const char* path, json_error_t* error = 0) { - return Value::_take(json_load_file(path, error)); - } + // get the underlying json_t + json_t* as_json() const { return _value; } - // load a string as a JSON value - static Value load_string(const char* string, json_error_t* error = 0) { - return Value::_take(json_loads(string, error)); - } + protected: + // take ownership of a json_t (does not increase reference count) + static _Value _take(json_t* json) { + _Value v; + v._value = json; + return v; + } - // write the value to a file - int save_file(const char* path, int flags = 0) const { - return json_dump_file(_value, path, flags); - } + private: + // internal value pointer + json_t* _value; + }; - // write the value to a string (caller must deallocate with free()!) - char* save_string(int flags = 0) const { - return json_dumps(_value, flags); - } + // represents any JSON value + class Value : public _ValueBase<_Value> { + public: + // empty constructor + Value() : _ValueBase<_Value>() {} - // construct Value from input - static Value from(const char* value) { return Value::_take(json_string(value)); } - static Value from(const std::string& value) { return from(value.c_str()); } - static Value from(bool value) { return Value::_take(value ? json_true() : json_false()); } - static Value from(signed int value) { return Value::_take(json_integer(value)); } - static Value from(unsigned int value) { return Value::_take(json_integer(value)); } - static Value from(signed short value) { return Value::_take(json_integer(value)); } - static Value from(unsigned short value) { return Value::_take(json_integer(value)); } - static Value from(signed long value) { return Value::_take(json_integer(value)); } - static Value from(unsigned long value) { return Value::_take(json_integer(value)); } - static Value from(float value) { return Value::_take(json_real(value)); } - static Value from(double value) { return Value::_take(json_real(value)); } + // copy constructor for base + Value(const _Value& value) : _ValueBase<_Value>(value) {} + + // copy constructor for base + Value(const _ValueBase<_Value>& value) : _ValueBase<_Value>(value) {} - // create a new empty object - static Value object() { return Value::_take(json_object()); } + // copy constructor + Value(const Value& value) : _ValueBase<_Value>(value) {} - // create a new empty array - static Value array() { return Value::_take(json_array()); } + // create reference to value + explicit Value(json_t* json) : _ValueBase<_Value>(json) {} - // create a new null value - static Value null() { return Value::_take(json_null()); } + // construct Value from input + static inline Value from(const char* value) { return Value::_take(json_string(value)); } + static inline Value from(const std::string& value) { return from(value.c_str()); } + static inline Value from(bool value) { return Value::_take(value ? json_true() : json_false()); } + static inline Value from(signed int value) { return Value::_take(json_integer(value)); } + static inline Value from(unsigned int value) { return Value::_take(json_integer(value)); } + static inline Value from(signed short value) { return Value::_take(json_integer(value)); } + static inline Value from(unsigned short value) { return Value::_take(json_integer(value)); } + static inline Value from(signed long value) { return Value::_take(json_integer(value)); } + static inline Value from(unsigned long value) { return Value::_take(json_integer(value)); } + static inline Value from(float value) { return Value::_take(json_real(value)); } + static inline Value from(double value) { return Value::_take(json_real(value)); } - // get the underlying json_t - json_t* as_json() const { return _value; } + // create a new empty object + static inline Value object() { return Value::_take(json_object()); } - // check value type - bool is_undefined() const { return _value == 0; } - bool is_object() const { return json_is_object(_value); } - bool is_array() const { return json_is_array(_value); } - bool is_string() const { return json_is_string(_value); } - bool is_integer() const { return json_is_integer(_value); } - bool is_real() const { return json_is_real(_value); } - bool is_number() const { return json_is_number(_value); } - bool is_true() const { return json_is_true(_value); } - bool is_false() const { return json_is_false(_value); } - bool is_boolean() const { return json_is_boolean(_value); } - bool is_null() const { return json_is_null(_value); } + // create a new empty array + static inline Value array() { return Value::_take(json_array()); } - // get size of array or object - unsigned int size() const { - if (is_object()) - return json_object_size(_value); - else - return json_array_size(_value); - } + // create a new null value + static inline Value null() { return Value::_take(json_null()); } - // get value at array index (const version) - const Value at(unsigned int index) const { - return Value(json_array_get(_value, index)); - } + // load a file as a JSON value + static Value load_file(const char* path, json_error_t* error = 0) { + return Value::_take(json_load_file(path, error)); + } - const Value operator[](signed int index) const { return at(index); } - const Value operator[](unsigned int index) const { return at(index); } - const Value operator[](signed short index) const { return at(index); } - const Value operator[](unsigned short index) const { return at(index); } - const Value operator[](signed long index) const { return at(index); } - const Value operator[](unsigned long index) const { return at(index); } + // load a string as a JSON value + static Value load_string(const char* string, json_error_t* error = 0) { + return Value::_take(json_loads(string, error)); + } - // get value at array index (non-const version) - Value at(unsigned int index) { - return Value(json_array_get(_value, index)); - } + // write the value to a file + int save_file(const char* path, int flags = 0) const { + return json_dump_file(as_json(), path, flags); + } - Value operator[](signed int index) { return at(index); } - Value operator[](unsigned int index) { return at(index); } - Value operator[](signed short index) { return at(index); } - Value operator[](unsigned short index) { return at(index); } - Value operator[](signed long index) { return at(index); } - Value operator[](unsigned long index) { return at(index); } + // write the value to a string (caller must deallocate with free()!) + char* save_string(int flags = 0) const { + return json_dumps(as_json(), flags); + } + }; - // get object property - const Value get(const char* key) const { - return Value(json_object_get(_value, key)); - } + // iterators over a JSON object + class Iterator { + public: + // construct a new iterator for a given object + Iterator(const Value& value) : _object(value), _iter(0) { + _iter = json_object_iter(_object.as_json()); + } - const Value get(const std::string& key) const { return get(key.c_str()); } - const Value operator[](const char* key) const { return get(key); } - const Value operator[](const std::string& key) const { return get(key.c_str()); } + // increment iterator + void next() { + _iter = json_object_iter_next(_object.as_json(), _iter); + } - // clear all array/object values - void clear() { - if (is_object()) - json_object_clear(_value); - else - json_array_clear(_value); - } + Iterator& operator++() { next(); return *this; } - // get value cast to specified type - const char* as_cstring() const { return json_string_value(_value); } - std::string as_string() const { - const char* tmp = as_cstring(); - return tmp == 0 ? "" : tmp; - } - int as_integer() const { return json_integer_value(_value); } - double as_real() const { return json_real_value(_value); } - double as_number() const { return json_number_value(_value); } - bool as_boolean() const { return is_true(); } + // test if iterator is still valid + bool valid() const { return _iter != 0; } + operator bool() const { return valid(); } - // set an object property (converts value to object is not one already) - Value& set_key(const char* key, const Value& value) { - json_object_set(_value, key, value.as_json()); - return *this; - } + // get key + const char* ckey() const { + return json_object_iter_key(_iter); + } - Value& set_key(const std::string& key, const Value& value) { - return set_key(key.c_str(), value); - } + std::string key() const { return ckey(); } - // set an array index (converts value to object is not one already) - Value& set_at(unsigned int index, const Value& value) { - if (index == size()) - json_array_append(_value, value.as_json()); - else - json_array_set(_value, index, value.as_json()); - return *this; - } + // get value + const Value value() const { + return Value(json_object_iter_value(_iter)); + } - // delete an object key - Value& del_key(const char* key) { - json_object_del(_value, key); - return *this; - } + // dereference value + const Value operator*() const { return value(); } - Value& del_key(const std::string& key) { - return del_key(key.c_str()); - } + private: + // disallow copying + Iterator(const Iterator&); + Iterator& operator=(const Iterator&); - // delete an item from an array by index - Value& del_at(unsigned int index) { - json_array_remove(_value, index); - return *this; - } + // object being iterated over + Value _object; - // insert an item into an array at a given index - Value& insert_at(unsigned int index, const Value& value) { - json_array_insert(_value, index, value.as_json()); - return *this; - } - -private: - // take ownership of a json_t (does not increase reference count) - static Value _take(json_t* json) { - Value v; - v._value = json; - return v; - } - - // internal value pointer - json_t* _value; -}; - -// iterators over a JSON object -class Iterator { -public: - // construct a new iterator for a given object - Iterator(const Value& value) : _object(value), _iter(0) { - _iter = json_object_iter(_object.as_json()); - } - - // increment iterator - void next() { - _iter = json_object_iter_next(_object.as_json(), _iter); - } - - Iterator& operator++() { next(); return *this; } - - // test if iterator is still valid - bool valid() const { return _iter != 0; } - operator bool() const { return valid(); } - - // get key - const char* ckey() const { - return json_object_iter_key(_iter); - } - - std::string key() const { return ckey(); } - - // get value - const Value value() const { - return Value(json_object_iter_value(_iter)); - } - - // dereference value - const Value operator*() const { return value(); } - -private: - // disallow copying - Iterator(const Iterator&); - Iterator& operator=(const Iterator&); - - // object being iterated over - Value _object; - - // iterator value - void* _iter; -}; + // iterator value + void* _iter; + }; } // namespace jansson @@ -284,4 +277,6 @@ std::istream& operator>>(std::istream& is, jansson::Value& value) { return is; } +#include "janssonxx.tcc" + #endif diff --git a/janssonxx.tcc b/janssonxx.tcc new file mode 100644 index 0000000..2b5c8aa --- /dev/null +++ b/janssonxx.tcc @@ -0,0 +1,133 @@ +// get size of array or object +template +unsigned int jansson::_ValueBase<_Base>::size() const { + if (is_object()) + return json_object_size(_Base::as_json()); + else + return json_array_size(_Base::as_json()); +} + +// get value at array index (const version) +template +const jansson::Value jansson::_ValueBase<_Base>::at(unsigned int index) const { + return jansson::Value(json_array_get(_Base::as_json(), index)); +} + +template +const jansson::Value jansson::_ValueBase<_Base>::operator[](signed int index) const { return at(index); } +template +const jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned int index) const { return at(index); } +template +const jansson::Value jansson::_ValueBase<_Base>::operator[](signed short index) const { return at(index); } +template +const jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned short index) const { return at(index); } +template +const jansson::Value jansson::_ValueBase<_Base>::operator[](signed long index) const { return at(index); } +template +const jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned long index) const { return at(index); } + +// get value at array index (non-const version) +template +jansson::Value jansson::_ValueBase<_Base>::at(unsigned int index) { + return jansson::Value(json_array_get(_Base::as_json(), index)); +} + +template +jansson::Value jansson::_ValueBase<_Base>::operator[](signed int index) { return at(index); } +template +jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned int index) { return at(index); } +template +jansson::Value jansson::_ValueBase<_Base>::operator[](signed short index) { return at(index); } +template +jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned short index) { return at(index); } +template +jansson::Value jansson::_ValueBase<_Base>::operator[](signed long index) { return at(index); } +template +jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned long index) { return at(index); } + +// get object property +template +const jansson::Value jansson::_ValueBase<_Base>::get(const char* key) const { + return jansson::Value(json_object_get(_Base::as_json(), key)); +} + +template +const jansson::Value jansson::_ValueBase<_Base>::get(const std::string& key) const { return get(key.c_str()); } +template +const jansson::Value jansson::_ValueBase<_Base>::operator[](const char* key) const { return get(key); } +template +const jansson::Value jansson::_ValueBase<_Base>::operator[](const std::string& key) const { return get(key.c_str()); } + +// clear all array/object values +template +void jansson::_ValueBase<_Base>::clear() { + if (is_object()) + json_object_clear(_Base::as_json()); + else + json_array_clear(_Base::as_json()); +} + +// get value cast to specified type +template +const char* jansson::_ValueBase<_Base>::as_cstring() const { return json_string_value(_Base::as_json()); } +template +std::string jansson::_ValueBase<_Base>::as_string() const { + const char* tmp = as_cstring(); + return tmp == 0 ? "" : tmp; +} +template +int jansson::_ValueBase<_Base>::as_integer() const { return json_integer_value(_Base::as_json()); } +template +double jansson::_ValueBase<_Base>::as_real() const { return json_real_value(_Base::as_json()); } +template +double jansson::_ValueBase<_Base>::as_number() const { return json_number_value(_Base::as_json()); } +template +bool jansson::_ValueBase<_Base>::as_boolean() const { return is_true(); } + +// set an object property (converts value to object is not one already) +template + _Base& jansson::_ValueBase<_Base>::set_key(const char* key, const jansson::Value& value) { + json_object_set(_Base::as_json(), key, value._Base::as_json()); + return *this; +} + +template + _Base& jansson::_ValueBase<_Base>::set_key(const std::string& key, const jansson::Value& value) { + return set_key(key.c_str(), value); +} + +// set an array index (converts value to object is not one already) +template + _Base& jansson::_ValueBase<_Base>::set_at(unsigned int index, const jansson::Value& value) { + if (index == size()) + json_array_append(_Base::as_json(), value._Base::as_json()); + else + json_array_set(_Base::as_json(), index, value._Base::as_json()); + return *this; +} + +// delete an object key +template + _Base& jansson::_ValueBase<_Base>::del_key(const char* key) { + json_object_del(_Base::as_json(), key); + return *this; +} + +template + _Base& jansson::_ValueBase<_Base>::del_key(const std::string& key) { + return del_key(key.c_str()); +} + +// delete an item from an array by index +template + _Base& jansson::_ValueBase<_Base>::del_at(unsigned int index) { + json_array_remove(_Base::as_json(), index); + return *this; +} + +// insert an item into an array at a given index +template + _Base& jansson::_ValueBase<_Base>::insert_at(unsigned int index, const jansson::Value& value) { + json_array_insert(_Base::as_json(), index, value._Base::as_json()); + return *this; +} diff --git a/test.cc b/test.cc index 055d4a9..fb66f63 100644 --- a/test.cc +++ b/test.cc @@ -141,5 +141,15 @@ int main() { outstr << e12; ASSERT_EQ(instr.str(), "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); + const jansson::Value e13(e12); + ASSERT_EQ(e13["bar"].as_integer(), 3, "e13.bar has incorrect value after copy"); + + jansson::Value e14(jansson::Value::object()); + ASSERT_TRUE(e14.is_object(), "e14 is not an object after construction"); + e14.set_key("foo", jansson::Value::object()); + ASSERT_TRUE(e14["foo"].is_object(), "e14.foo is not an object after assignment"); + //e14["foo"]["bar"] = jansson::Value::from(42); + //ASSERT_EQ(e14["foo"]["bar"].as_integer(), 42, "e14.foo.bar has incorrecy value after assignment"); + return 0; }