From 1e3b41e8ea82b83d7072a6e08a8dcb4a3c134a98 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 01:10:09 -0800 Subject: [PATCH 01/38] initial commit of janssonxx.h --- janssonxx.h | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 janssonxx.h diff --git a/janssonxx.h b/janssonxx.h new file mode 100644 index 0000000..873c4a9 --- /dev/null +++ b/janssonxx.h @@ -0,0 +1,207 @@ +#if !defined(JANSSONXX_H) +#define JANSSONXX_H 1 + +#include +#include + +namespace jansson { + +class Iterator; + +// represents any JSON value +class Value { +public: + // construct new Value with an undefined value + Value() : _value(0) {} + + // free Value resources + ~Value() { json_decref(_value); } + + // copy an existing Value + Value(const Value& e) : _value(json_incref(e._value)) {} + + // make a reference to an existing json_t value + explicit Value(json_t* value) : _value(json_incref(value)) {} + + // copy an existing Value + Value& operator=(const Value& e) { + json_decref(_value); + _value = json_incref(e._value); + return *this; + } + + // take ownership of a json_t (does not increase reference count) + Value& take_ownership(json_t* value) { + json_decref(_value); + _value = value; + return *this; + } + + // load a file as a JSON value + static Value load_file(const char* path, json_error_t* error = 0) { + return Value().take_ownership(json_load_file(path, error)); + } + + // load a string as a JSON value + static Value load_string(const char* string, json_error_t* error = 0) { + return Value().take_ownership(json_loads(string, error)); + } + + // get the underlying json_t + json_t* as_json_t() const { return _value; } + + // check Value 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); } + + // get size of array or object + unsigned int size() const { + if (is_object()) + return json_object_size(_value); + else if (is_array()) + return json_array_size(_value); + else + return 0; + } + + // get value at array index + const Value at(unsigned int index) const { + if (is_array()) + return Value(json_array_get(_value, index)); + else + return Value(); + } + + 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); } + + // get object property + const Value get(const char* key) const { + if (is_object()) + return Value(json_object_get(_value, key)); + else + return Value(); + } + + 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()); } + + // clear all array/object values + void clear() { + if (is_object()) + json_object_clear(_value); + else if (is_array()) + json_array_clear(_value); + } + + // get value cast to specified type + const char* as_cstring() const { return json_string_value(_value); } + std::string as_string() const { return as_cstring(); } + 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(); } + + // assign new string value + Value& operator=(const char* value) { + json_decref(_value); + _value = json_string(value); + return *this; + } + + // assign new integer value + Value& operator=(int value) { + json_decref(_value); + _value = json_integer(value); + return *this; + } + + // assign new real/double/number value + Value& operator=(double value) { + json_decref(_value); + _value = json_real(value); + return *this; + } + + // assign new boolean value + Value& operator=(bool value) { + json_decref(_value); + _value = value ? json_true() : json_false(); + return *this; + } + +private: + // 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_t()); + } + + // increment iterator + void next() { + if (_iter != 0) + _iter = json_object_iter_next(_object.as_json_t(), _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 { + if (_iter != 0) + return json_object_iter_key(_iter); + else + return ""; + } + + std::string key() const { return ckey(); } + + // get value + const Value value() const { + if (_iter != 0) + return Value(json_object_iter_value(_iter)); + else + return Value(); + } + + // 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; +}; + +} // namespace jansson + +#endif From 39601c183a79686b7940dd7927e416268d2e8770 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 01:10:20 -0800 Subject: [PATCH 02/38] add tests --- Makefile | 13 ++++++++ test.cc | 66 +++++++++++++++++++++++++++++++++++++++++ test.json | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 Makefile create mode 100644 test.cc create mode 100644 test.json diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..21f68e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +JANSSON_CFLAGS := $(shell pkg-config --cflags jansson) +JANSSON_LIBS := $(shell pkg-config --libs jansson) + +all: test + +test-bin: test.cc janssonxx.h Makefile + $(CXX) -o $@ -g -O0 -Wall $(JANSSON_CFLAGS) $< $(JANSSON_LIBS) + +test: test-bin + ./test-bin + +clean: + rm -f test-bin diff --git a/test.cc b/test.cc new file mode 100644 index 0000000..7b44bb0 --- /dev/null +++ b/test.cc @@ -0,0 +1,66 @@ +#include +#include + +#include "janssonxx.h" + +using namespace std; + +#define ASSERT_OP(lhs, rhs, op, m) \ + do { \ + if(!((lhs) op (rhs))) { \ + std::cerr << std::boolalpha; \ + std::cerr << __FILE__ << '[' << __LINE__ << "]: ERROR: " << (m) << std::endl; \ + std::cerr << "\ttest: " << #lhs << ' ' << #op << ' ' << #rhs << std::endl; \ + std::cerr << "\tresult: " << (lhs) << ' ' << #op << ' ' << (rhs) << std::endl; \ + return 1; \ + } \ + } while(0) +#define ASSERT_EQ(lhs, rhs, m) ASSERT_OP(lhs, rhs, ==, m) +#define ASSERT_NE(lhs, rhs, m) ASSERT_OP(lhs, rhs, !=, m) +#define ASSERT_TRUE(p, m) ASSERT_OP(p, true, ==, m) +#define ASSERT_FALSE(p, m) ASSERT_OP(p, true, !=, m) + +int main() { + jansson::Value e1(jansson::Value::load_file("test.json")); + jansson::Value e2(e1); + jansson::Value e3; + jansson::Value e4(jansson::Value::load_string("{\"foo\": true, \"bar\": \"test\"}")); + + ASSERT_TRUE(e1.is_object(), "e1 is not an object"); + ASSERT_TRUE(e2.is_object(), "e2 is not an object"); + ASSERT_TRUE(e3.is_undefined(), "e3 has a defined value"); + ASSERT_TRUE(e4.is_object(), "e4 is not an object"); + + ASSERT_EQ(e1.size(), 1, "e1 has too many properties"); + ASSERT_EQ(e2.size(), 1, "e2 has too many properties"); + ASSERT_EQ(e4.size(), 2, "e4 does not have 2 elements"); + + ASSERT_TRUE(e1.get("web-app").is_object(), "e1[0].web-app is not an object"); + ASSERT_EQ(e1.get("web-app").get("servlet").at(0).get("servlet-class").as_string(), "org.cofax.cds.CDSServlet", "property has incorrect value"); + ASSERT_EQ(e1["web-app"]["servlet"][0]["servlet-class"].as_string(), "org.cofax.cds.CDSServlet", "property has incorrect value"); + + ASSERT_EQ(e4["foo"].as_boolean(), true, "property has incorrect value"); + + jansson::Iterator i(e1.get("web-app")); + ASSERT_EQ(i.key(), "taglib", "first iterator result has incorrect key"); + i.next(); + ASSERT_EQ(i.key(), "servlet", "first iterator result has incorrect key"); + i.next(); + ASSERT_EQ(i.key(), "servlet-mapping", "first iterator result has incorrect key"); + i.next(); + ASSERT_FALSE(i.valid(), "iterator has more values than expected"); + + e3 = 12.34; + ASSERT_TRUE(e3.is_number(), "e3 is not a number after assignment"); + ASSERT_EQ(e3.as_real(), 12.34, "e3 has incorrect value after assignment"); + + e3 = true; + ASSERT_TRUE(e3.is_boolean(), "e3 is not a boolean after assignment"); + ASSERT_EQ(e3.as_boolean(), true, "e3 has incorrect value after assignment"); + + e3 = "foobar"; + ASSERT_TRUE(e3.is_string(), "e3 is not a string after assignment"); + ASSERT_EQ(e3.as_string(), "foobar", "e3 has incorrect value after assignment"); + + return 0; +} diff --git a/test.json b/test.json new file mode 100644 index 0000000..9eea6ad --- /dev/null +++ b/test.json @@ -0,0 +1,88 @@ +{"web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500}}, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2"}}, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet"}, + + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet"}, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true}}], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*"}, + + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} From 6818c117ee1e2cfe304f15497e754823f15c29d9 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 01:10:38 -0800 Subject: [PATCH 03/38] ignore test-bin output file --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5880b2a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +test-bin From bd091278595b76cb2a72c977b8e6526a764d85b0 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 01:26:47 -0800 Subject: [PATCH 04/38] cleaner assignment behavior --- janssonxx.h | 78 +++++++++++++++++++++++++++++++++++++---------------- test.cc | 11 +++++--- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 873c4a9..6e81241 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -47,10 +47,26 @@ public: return Value().take_ownership(json_loads(string, error)); } + // construct Value from input + static Value from(const char* value) { return Value().take_ownership(json_string(value)); } + static Value from(const std::string& value) { return from(value.c_str()); } + static Value from(bool value) { return Value().take_ownership(value ? json_true() : json_false()); } + static Value from(int value) { return Value().take_ownership(json_integer(value)); } + static Value from(double value) { return Value().take_ownership(json_real(value)); } + + // create a new empty object + static Value object() { return Value().take_ownership(json_object()); } + + // create a new empty array + static Value array() { return Value().take_ownership(json_array()); } + + // create a new null value + static Value null() { return Value().take_ownership(json_null()); } + // get the underlying json_t json_t* as_json_t() const { return _value; } - // check Value value type + // 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); } @@ -73,7 +89,7 @@ public: return 0; } - // get value at array index + // get value at array index (const version) const Value at(unsigned int index) const { if (is_array()) return Value(json_array_get(_value, index)); @@ -88,6 +104,21 @@ public: const Value operator[](signed long index) const { return at(index); } const Value operator[](unsigned long index) const { return at(index); } + // get value at array index (non-const version) + Value at(unsigned int index) { + if (is_array()) + return Value(json_array_get(_value, index)); + else + return Value(); + } + + 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); } + // get object property const Value get(const char* key) const { if (is_object()) @@ -116,33 +147,34 @@ public: double as_number() const { return json_number_value(_value); } bool as_boolean() const { return is_true(); } - // assign new string value - Value& operator=(const char* value) { - json_decref(_value); - _value = json_string(value); + // set an object property (converts value to object is not one already) + Value& set(const char* key, const Value& value) { + if (!is_object()) { + json_decref(_value); + _value = json_object(); + } + + json_object_set(_value, key, value.as_json_t()); + return *this; } - // assign new integer value - Value& operator=(int value) { - json_decref(_value); - _value = json_integer(value); + // set an array index (converts value to object is not one already) + Value& set(unsigned int index, const Value& value) { + if (!is_array()) { + json_decref(_value); + _value = json_array(); + } + + if (index == size()) + json_array_append(_value, value.as_json_t()); + else + json_array_set(_value, index, value.as_json_t()); + return *this; } - // assign new real/double/number value - Value& operator=(double value) { - json_decref(_value); - _value = json_real(value); - return *this; - } - - // assign new boolean value - Value& operator=(bool value) { - json_decref(_value); - _value = value ? json_true() : json_false(); - return *this; - } + Value& set(int index, const Value& value) { return set(static_cast(index), value); } private: // internal value pointer diff --git a/test.cc b/test.cc index 7b44bb0..165589f 100644 --- a/test.cc +++ b/test.cc @@ -50,17 +50,22 @@ int main() { i.next(); ASSERT_FALSE(i.valid(), "iterator has more values than expected"); - e3 = 12.34; + e3 = jansson::Value::from(12.34); ASSERT_TRUE(e3.is_number(), "e3 is not a number after assignment"); ASSERT_EQ(e3.as_real(), 12.34, "e3 has incorrect value after assignment"); - e3 = true; + e3 = jansson::Value::from(true); ASSERT_TRUE(e3.is_boolean(), "e3 is not a boolean after assignment"); ASSERT_EQ(e3.as_boolean(), true, "e3 has incorrect value after assignment"); - e3 = "foobar"; + e3 = jansson::Value::from("foobar"); ASSERT_TRUE(e3.is_string(), "e3 is not a string after assignment"); ASSERT_EQ(e3.as_string(), "foobar", "e3 has incorrect value after assignment"); + e3.set(0, jansson::Value::from("foobar")); + ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); + ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of elements after assignment"); + ASSERT_EQ(e3[0].as_string(), "foobar", "e3[0] has incorrect value after assignment"); + return 0; } From cd18aa97f079df52edae73a7a84cf6bf5e5ea901 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 01:29:44 -0800 Subject: [PATCH 05/38] added README --- README | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..e74b78f --- /dev/null +++ b/README @@ -0,0 +1,28 @@ +janssonxx is a simple C++ wrapper around the Jansson library. + +It does not purport to be as flexible or efficient as what a competent +developer can achieve using the Jansson C API, but it does offer a +safe and easy to use API that should cover most users' needs. + +janssonxx is developed by Sean Middleditch and +is released under the MIT/X license, same as Jansson: + +Copyright (c) 2010 Sean Middleditch + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From 5a20e2695bd3fefff62dd74bf5b77b89816a02d2 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 01:31:08 -0800 Subject: [PATCH 06/38] add link to Jansson web to README --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index e74b78f..fc5648d 100644 --- a/README +++ b/README @@ -1,5 +1,7 @@ janssonxx is a simple C++ wrapper around the Jansson library. + http://digip.org/jansson/ + It does not purport to be as flexible or efficient as what a competent developer can achieve using the Jansson C API, but it does offer a safe and easy to use API that should cover most users' needs. From c994eddec418b4200b04e7f30287b15159e9eb9d Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 01:34:58 -0800 Subject: [PATCH 07/38] expand array assignment tests --- test.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test.cc b/test.cc index 165589f..9b0eb2c 100644 --- a/test.cc +++ b/test.cc @@ -67,5 +67,19 @@ int main() { ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of elements after assignment"); ASSERT_EQ(e3[0].as_string(), "foobar", "e3[0] has incorrect value after assignment"); + e3.set(1, jansson::Value::from("foobar")); + ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); + ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); + ASSERT_EQ(e3[1].as_string(), "foobar", "e3[0] has incorrect value after assignment"); + + e3.set(0, jansson::Value::from("barfoo")); + ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); + ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); + ASSERT_EQ(e3[0].as_string(), "barfoo", "e3[0] has incorrect value after assignment"); + + e3.set(100, jansson::Value::null()); + ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); + ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); + return 0; } From f743c4ee7f199ce2b0efeb99f56c91426e0f5263 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 01:41:17 -0800 Subject: [PATCH 08/38] test object property assignment and clear --- test.cc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test.cc b/test.cc index 9b0eb2c..531db58 100644 --- a/test.cc +++ b/test.cc @@ -62,6 +62,12 @@ int main() { ASSERT_TRUE(e3.is_string(), "e3 is not a string after assignment"); ASSERT_EQ(e3.as_string(), "foobar", "e3 has incorrect value after assignment"); + e3 = jansson::Value::object(); + ASSERT_TRUE(e3.is_object(), "e3 is not an object after assignment"); + + e3 = jansson::Value::null(); + ASSERT_TRUE(e3.is_null(), "e3 is not null after assignment"); + e3.set(0, jansson::Value::from("foobar")); ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of elements after assignment"); @@ -81,5 +87,26 @@ int main() { ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); + e3.clear(); + ASSERT_EQ(e3.size(), 0, "e3 has incorrect number of elements after clear"); + + e3.set("foo", jansson::Value::from("test")); + ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); + ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of properties after assignment"); + ASSERT_EQ(e3["foo"].as_string(), "test", "e3.foo has incorrect value after assignment"); + + e3.set("foo", jansson::Value::from("again")); + ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); + ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of properties after assignment"); + ASSERT_EQ(e3["foo"].as_string(), "again", "e3.foo has incorrect value after assignment"); + + e3.set("bar", jansson::Value::from("test")); + ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); + ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of properties after assignment"); + ASSERT_EQ(e3["bar"].as_string(), "test", "e3.foo has incorrect value after assignment"); + + e3.clear(); + ASSERT_EQ(e3.size(), 0, "e3 has incorrect number of properties after clear"); + return 0; } From 36085ab49af15a6df9aabbae4b027ca54f380bff Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 04:13:26 -0800 Subject: [PATCH 09/38] include jansson.h inside the jansson namespace --- janssonxx.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/janssonxx.h b/janssonxx.h index 6e81241..9085652 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -2,10 +2,12 @@ #define JANSSONXX_H 1 #include -#include namespace jansson { +// include in the jansson namespace +#include + class Iterator; // represents any JSON value From 7ef3202f835835aa5d3f18c662ae09c2f6d5f603 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 04:20:17 -0800 Subject: [PATCH 10/38] added save_file and save_string methods --- janssonxx.h | 10 ++++++++++ test.cc | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/janssonxx.h b/janssonxx.h index 9085652..46e53e8 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -49,6 +49,16 @@ public: return Value().take_ownership(json_loads(string, error)); } + // write the value to a file + int save_file(const char* path, int flags = JSON_INDENT(2)) const { + return json_dump_file(_value, path, flags); + } + + // write the value to a string (caller must deallocate with free()!) + char* save_string(int flags = JSON_INDENT(2)) const { + return json_dumps(_value, flags); + } + // construct Value from input static Value from(const char* value) { return Value().take_ownership(json_string(value)); } static Value from(const std::string& value) { return from(value.c_str()); } diff --git a/test.cc b/test.cc index 531db58..daacbea 100644 --- a/test.cc +++ b/test.cc @@ -1,5 +1,6 @@ #include #include +#include #include "janssonxx.h" @@ -108,5 +109,13 @@ int main() { e3.clear(); ASSERT_EQ(e3.size(), 0, "e3 has incorrect number of properties after clear"); + e3 = jansson::Value::object(); + e3.set("foo", jansson::Value::from("test")); + e3.set("bar", jansson::Value::from(3)); + char* out_cstr = e3.save_string(0); + string out(out_cstr); + free(out_cstr); + ASSERT_EQ(out, "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); + return 0; } From d77c2e3fb0bee8bdb0c5210930845082a2064513 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 04:26:30 -0800 Subject: [PATCH 11/38] cleanup the take_ownership function a bit --- janssonxx.h | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 46e53e8..6f83ef1 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -27,26 +27,21 @@ public: // copy an existing Value Value& operator=(const Value& e) { - json_decref(_value); - _value = json_incref(e._value); - return *this; - } - - // take ownership of a json_t (does not increase reference count) - Value& take_ownership(json_t* value) { - json_decref(_value); - _value = value; + if (&e != this) { + json_decref(_value); + _value = json_incref(e._value); + } return *this; } // load a file as a JSON value static Value load_file(const char* path, json_error_t* error = 0) { - return Value().take_ownership(json_load_file(path, error)); + return Value::_take(json_load_file(path, error)); } // load a string as a JSON value static Value load_string(const char* string, json_error_t* error = 0) { - return Value().take_ownership(json_loads(string, error)); + return Value::_take(json_loads(string, error)); } // write the value to a file @@ -60,20 +55,20 @@ public: } // construct Value from input - static Value from(const char* value) { return Value().take_ownership(json_string(value)); } + 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_ownership(value ? json_true() : json_false()); } - static Value from(int value) { return Value().take_ownership(json_integer(value)); } - static Value from(double value) { return Value().take_ownership(json_real(value)); } + static Value from(bool value) { return Value::_take(value ? json_true() : json_false()); } + static Value from(int value) { return Value::_take(json_integer(value)); } + static Value from(double value) { return Value::_take(json_real(value)); } // create a new empty object - static Value object() { return Value().take_ownership(json_object()); } + static Value object() { return Value::_take(json_object()); } // create a new empty array - static Value array() { return Value().take_ownership(json_array()); } + static Value array() { return Value::_take(json_array()); } // create a new null value - static Value null() { return Value().take_ownership(json_null()); } + static Value null() { return Value::_take(json_null()); } // get the underlying json_t json_t* as_json_t() const { return _value; } @@ -189,6 +184,13 @@ public: Value& set(int index, const Value& value) { return set(static_cast(index), value); } 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; }; From 8d5d2a93d589271aea335d0c3af0d25e6125fc7c Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 04:30:02 -0800 Subject: [PATCH 12/38] remove some unnecessary checks --- janssonxx.h | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 6f83ef1..cfc1058 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -90,18 +90,13 @@ public: unsigned int size() const { if (is_object()) return json_object_size(_value); - else if (is_array()) - return json_array_size(_value); else - return 0; + return json_array_size(_value); } // get value at array index (const version) const Value at(unsigned int index) const { - if (is_array()) - return Value(json_array_get(_value, index)); - else - return Value(); + return Value(json_array_get(_value, index)); } const Value operator[](signed int index) const { return at(index); } @@ -113,10 +108,7 @@ public: // get value at array index (non-const version) Value at(unsigned int index) { - if (is_array()) - return Value(json_array_get(_value, index)); - else - return Value(); + return Value(json_array_get(_value, index)); } Value operator[](signed int index) { return at(index); } @@ -128,10 +120,7 @@ public: // get object property const Value get(const char* key) const { - if (is_object()) - return Value(json_object_get(_value, key)); - else - return Value(); + return Value(json_object_get(_value, key)); } const Value get(const std::string& key) const { return get(key.c_str()); } @@ -142,7 +131,7 @@ public: void clear() { if (is_object()) json_object_clear(_value); - else if (is_array()) + else json_array_clear(_value); } @@ -205,8 +194,7 @@ public: // increment iterator void next() { - if (_iter != 0) - _iter = json_object_iter_next(_object.as_json_t(), _iter); + _iter = json_object_iter_next(_object.as_json_t(), _iter); } Iterator& operator++() { next(); return *this; } @@ -217,20 +205,14 @@ public: // get key const char* ckey() const { - if (_iter != 0) - return json_object_iter_key(_iter); - else - return ""; + return json_object_iter_key(_iter); } std::string key() const { return ckey(); } // get value const Value value() const { - if (_iter != 0) - return Value(json_object_iter_value(_iter)); - else - return Value(); + return Value(json_object_iter_value(_iter)); } // dereference value From b98e9d180cdbe0d6f890ecaae3a6d3dcaf1f4926 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 15:14:57 -0800 Subject: [PATCH 13/38] rename the set() methods --- janssonxx.h | 12 +++++++++--- test.cc | 18 +++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index cfc1058..b60e8cf 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -144,7 +144,7 @@ public: bool as_boolean() const { return is_true(); } // set an object property (converts value to object is not one already) - Value& set(const char* key, const Value& value) { + Value& set_key(const char* key, const Value& value) { if (!is_object()) { json_decref(_value); _value = json_object(); @@ -155,8 +155,12 @@ public: return *this; } + Value& set_key(const std::string& key, const Value& value) { + return set_key(key.c_str(), value); + } + // set an array index (converts value to object is not one already) - Value& set(unsigned int index, const Value& value) { + Value& set_at(unsigned int index, const Value& value) { if (!is_array()) { json_decref(_value); _value = json_array(); @@ -170,7 +174,9 @@ public: return *this; } - Value& set(int index, const Value& value) { return set(static_cast(index), value); } + Value& set_at(int index, const Value& value) { + return set_at(static_cast(index), value); + } private: // take ownership of a json_t (does not increase reference count) diff --git a/test.cc b/test.cc index daacbea..66ce7bb 100644 --- a/test.cc +++ b/test.cc @@ -69,39 +69,39 @@ int main() { e3 = jansson::Value::null(); ASSERT_TRUE(e3.is_null(), "e3 is not null after assignment"); - e3.set(0, jansson::Value::from("foobar")); + e3.set_at(0, jansson::Value::from("foobar")); ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of elements after assignment"); ASSERT_EQ(e3[0].as_string(), "foobar", "e3[0] has incorrect value after assignment"); - e3.set(1, jansson::Value::from("foobar")); + e3.set_at(1, jansson::Value::from("foobar")); ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); ASSERT_EQ(e3[1].as_string(), "foobar", "e3[0] has incorrect value after assignment"); - e3.set(0, jansson::Value::from("barfoo")); + e3.set_at(0, jansson::Value::from("barfoo")); ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); ASSERT_EQ(e3[0].as_string(), "barfoo", "e3[0] has incorrect value after assignment"); - e3.set(100, jansson::Value::null()); + e3.set_at(100, jansson::Value::null()); ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); e3.clear(); ASSERT_EQ(e3.size(), 0, "e3 has incorrect number of elements after clear"); - e3.set("foo", jansson::Value::from("test")); + e3.set_key("foo", jansson::Value::from("test")); ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of properties after assignment"); ASSERT_EQ(e3["foo"].as_string(), "test", "e3.foo has incorrect value after assignment"); - e3.set("foo", jansson::Value::from("again")); + e3.set_key("foo", jansson::Value::from("again")); ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of properties after assignment"); ASSERT_EQ(e3["foo"].as_string(), "again", "e3.foo has incorrect value after assignment"); - e3.set("bar", jansson::Value::from("test")); + e3.set_key("bar", jansson::Value::from("test")); ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of properties after assignment"); ASSERT_EQ(e3["bar"].as_string(), "test", "e3.foo has incorrect value after assignment"); @@ -110,8 +110,8 @@ int main() { ASSERT_EQ(e3.size(), 0, "e3 has incorrect number of properties after clear"); e3 = jansson::Value::object(); - e3.set("foo", jansson::Value::from("test")); - e3.set("bar", jansson::Value::from(3)); + e3.set_key("foo", jansson::Value::from("test")); + e3.set_key("bar", jansson::Value::from(3)); char* out_cstr = e3.save_string(0); string out(out_cstr); free(out_cstr); From f79a81dad96a6f3a57c5d5b0bbb65aa0494975a6 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 15:29:45 -0800 Subject: [PATCH 14/38] add (ugly) stream support --- janssonxx.h | 21 +++++++++++++++++++++ test.cc | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/janssonxx.h b/janssonxx.h index b60e8cf..49975bf 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -2,6 +2,10 @@ #define JANSSONXX_H 1 #include +#include +#include +#include +#include namespace jansson { @@ -238,4 +242,21 @@ private: } // namespace jansson +// stream JSON value out +std::ostream& operator<<(std::ostream& os, const jansson::Value& value) { + char* tmp = value.save_string(); + os << tmp; + free(tmp); + return os; +} + +// read JSON value +std::istream& operator>>(std::istream& is, jansson::Value& value) { + std::stringstream tmp; + while (is) + tmp << static_cast(is.get()); + value = jansson::Value::load_string(tmp.str().c_str()); + return is; +} + #endif diff --git a/test.cc b/test.cc index 66ce7bb..28a83c8 100644 --- a/test.cc +++ b/test.cc @@ -117,5 +117,16 @@ int main() { free(out_cstr); ASSERT_EQ(out, "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); + std::istringstream instr(out); + instr >> e3; + ASSERT_TRUE(e3.is_object(), "e3 is not an object after stream read"); + ASSERT_EQ(e3.size(), 2, "e3 has wrong size after stream read"); + ASSERT_EQ(e3.get("bar").as_integer(), 3, "e3.bar has incorrect value after stream read"); + ASSERT_EQ(e3.get("foo").as_string(), "test", "ee3.test has incorrect value after stream read"); + + std::ostringstream outstr; + outstr << e3; + ASSERT_EQ(instr.str(), "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); + return 0; } From 8d3a9e347cc05a05ae1909a7156cf0b96c440106 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 15:33:36 -0800 Subject: [PATCH 15/38] rename as_json_t to as_json --- janssonxx.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 49975bf..1df424d 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -75,7 +75,7 @@ public: static Value null() { return Value::_take(json_null()); } // get the underlying json_t - json_t* as_json_t() const { return _value; } + json_t* as_json() const { return _value; } // check value type bool is_undefined() const { return _value == 0; } @@ -154,7 +154,7 @@ public: _value = json_object(); } - json_object_set(_value, key, value.as_json_t()); + json_object_set(_value, key, value.as_json()); return *this; } @@ -171,9 +171,9 @@ public: } if (index == size()) - json_array_append(_value, value.as_json_t()); + json_array_append(_value, value.as_json()); else - json_array_set(_value, index, value.as_json_t()); + json_array_set(_value, index, value.as_json()); return *this; } @@ -199,12 +199,12 @@ 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_t()); + _iter = json_object_iter(_object.as_json()); } // increment iterator void next() { - _iter = json_object_iter_next(_object.as_json_t(), _iter); + _iter = json_object_iter_next(_object.as_json(), _iter); } Iterator& operator++() { next(); return *this; } From 7d09af38c1c993bf2c08a9c776a58df9b0ce2efe Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 15:38:47 -0800 Subject: [PATCH 16/38] remove auto type conversion on array/object assignment --- janssonxx.h | 12 ------------ test.cc | 8 ++++++-- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 1df424d..0fad7dd 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -149,13 +149,7 @@ public: // set an object property (converts value to object is not one already) Value& set_key(const char* key, const Value& value) { - if (!is_object()) { - json_decref(_value); - _value = json_object(); - } - json_object_set(_value, key, value.as_json()); - return *this; } @@ -165,16 +159,10 @@ public: // set an array index (converts value to object is not one already) Value& set_at(unsigned int index, const Value& value) { - if (!is_array()) { - json_decref(_value); - _value = json_array(); - } - if (index == size()) json_array_append(_value, value.as_json()); else json_array_set(_value, index, value.as_json()); - return *this; } diff --git a/test.cc b/test.cc index 28a83c8..c6e5362 100644 --- a/test.cc +++ b/test.cc @@ -69,8 +69,10 @@ int main() { e3 = jansson::Value::null(); ASSERT_TRUE(e3.is_null(), "e3 is not null after assignment"); - e3.set_at(0, jansson::Value::from("foobar")); + e3 = jansson::Value::array(); ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); + + e3.set_at(0, jansson::Value::from("foobar")); ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of elements after assignment"); ASSERT_EQ(e3[0].as_string(), "foobar", "e3[0] has incorrect value after assignment"); @@ -91,8 +93,10 @@ int main() { e3.clear(); ASSERT_EQ(e3.size(), 0, "e3 has incorrect number of elements after clear"); - e3.set_key("foo", jansson::Value::from("test")); + e3 = jansson::Value::object(); ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); + + e3.set_key("foo", jansson::Value::from("test")); ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of properties after assignment"); ASSERT_EQ(e3["foo"].as_string(), "test", "e3.foo has incorrect value after assignment"); From 7ba18d3f0a7c4ab83b28c6b98f21acee41616ed2 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 16:03:27 -0800 Subject: [PATCH 17/38] use different temporaries in tests instead of reusing e3 --- test.cc | 112 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/test.cc b/test.cc index c6e5362..ce9d761 100644 --- a/test.cc +++ b/test.cc @@ -51,85 +51,85 @@ int main() { i.next(); ASSERT_FALSE(i.valid(), "iterator has more values than expected"); - e3 = jansson::Value::from(12.34); - ASSERT_TRUE(e3.is_number(), "e3 is not a number after assignment"); - ASSERT_EQ(e3.as_real(), 12.34, "e3 has incorrect value after assignment"); + jansson::Value e5(jansson::Value::from(12.34)); + ASSERT_TRUE(e5.is_number(), "e5 is not a number after assignment"); + ASSERT_EQ(e5.as_real(), 12.34, "e5 has incorrect value after assignment"); - e3 = jansson::Value::from(true); - ASSERT_TRUE(e3.is_boolean(), "e3 is not a boolean after assignment"); - ASSERT_EQ(e3.as_boolean(), true, "e3 has incorrect value after assignment"); + jansson::Value e6(jansson::Value::from(true)); + ASSERT_TRUE(e6.is_boolean(), "e6 is not a boolean after assignment"); + ASSERT_EQ(e6.as_boolean(), true, "e6 has incorrect value after assignment"); - e3 = jansson::Value::from("foobar"); - ASSERT_TRUE(e3.is_string(), "e3 is not a string after assignment"); - ASSERT_EQ(e3.as_string(), "foobar", "e3 has incorrect value after assignment"); + jansson::Value e7(jansson::Value::from("foobar")); + ASSERT_TRUE(e7.is_string(), "e7 is not a string after assignment"); + ASSERT_EQ(e7.as_string(), "foobar", "e7 has incorrect value after assignment"); - e3 = jansson::Value::object(); - ASSERT_TRUE(e3.is_object(), "e3 is not an object after assignment"); + jansson::Value e8(jansson::Value::object()); + ASSERT_TRUE(e8.is_object(), "e8 is not an object after assignment"); - e3 = jansson::Value::null(); - ASSERT_TRUE(e3.is_null(), "e3 is not null after assignment"); + jansson::Value e9(jansson::Value::null()); + ASSERT_TRUE(e9.is_null(), "e9 is not null after assignment"); - e3 = jansson::Value::array(); - ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); + jansson::Value e10(jansson::Value::array()); + ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); - e3.set_at(0, jansson::Value::from("foobar")); - ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of elements after assignment"); - ASSERT_EQ(e3[0].as_string(), "foobar", "e3[0] has incorrect value after assignment"); + e10.set_at(0, jansson::Value::from("foobar")); + ASSERT_EQ(e10.size(), 1, "e10 has incorrect number of elements after assignment"); + ASSERT_EQ(e10[0].as_string(), "foobar", "e10[0] has incorrect value after assignment"); - e3.set_at(1, jansson::Value::from("foobar")); - ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); - ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); - ASSERT_EQ(e3[1].as_string(), "foobar", "e3[0] has incorrect value after assignment"); + e10.set_at(1, jansson::Value::from("foobar")); + ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); + ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); + ASSERT_EQ(e10[1].as_string(), "foobar", "e10[0] has incorrect value after assignment"); - e3.set_at(0, jansson::Value::from("barfoo")); - ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); - ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); - ASSERT_EQ(e3[0].as_string(), "barfoo", "e3[0] has incorrect value after assignment"); + e10.set_at(0, jansson::Value::from("barfoo")); + ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); + ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); + ASSERT_EQ(e10[0].as_string(), "barfoo", "e10[0] has incorrect value after assignment"); - e3.set_at(100, jansson::Value::null()); - ASSERT_TRUE(e3.is_array(), "e3 is not an array after index assignment"); - ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of elements after assignment"); + e10.set_at(100, jansson::Value::null()); + ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); + ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); - e3.clear(); - ASSERT_EQ(e3.size(), 0, "e3 has incorrect number of elements after clear"); + e10.clear(); + ASSERT_EQ(e10.size(), 0, "e10 has incorrect number of elements after clear"); - e3 = jansson::Value::object(); - ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); + jansson::Value e11(jansson::Value::object()); + ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); - e3.set_key("foo", jansson::Value::from("test")); - ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of properties after assignment"); - ASSERT_EQ(e3["foo"].as_string(), "test", "e3.foo has incorrect value after assignment"); + e11.set_key("foo", jansson::Value::from("test")); + ASSERT_EQ(e11.size(), 1, "e11 has incorrect number of properties after assignment"); + ASSERT_EQ(e11["foo"].as_string(), "test", "e11.foo has incorrect value after assignment"); - e3.set_key("foo", jansson::Value::from("again")); - ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); - ASSERT_EQ(e3.size(), 1, "e3 has incorrect number of properties after assignment"); - ASSERT_EQ(e3["foo"].as_string(), "again", "e3.foo has incorrect value after assignment"); + e11.set_key("foo", jansson::Value::from("again")); + ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); + ASSERT_EQ(e11.size(), 1, "e11 has incorrect number of properties after assignment"); + ASSERT_EQ(e11["foo"].as_string(), "again", "e11.foo has incorrect value after assignment"); - e3.set_key("bar", jansson::Value::from("test")); - ASSERT_TRUE(e3.is_object(), "e3 is not an object after property assignment"); - ASSERT_EQ(e3.size(), 2, "e3 has incorrect number of properties after assignment"); - ASSERT_EQ(e3["bar"].as_string(), "test", "e3.foo has incorrect value after assignment"); + e11.set_key("bar", jansson::Value::from("test")); + ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); + ASSERT_EQ(e11.size(), 2, "e11 has incorrect number of properties after assignment"); + ASSERT_EQ(e11["bar"].as_string(), "test", "e11.foo has incorrect value after assignment"); - e3.clear(); - ASSERT_EQ(e3.size(), 0, "e3 has incorrect number of properties after clear"); + e11.clear(); + ASSERT_EQ(e11.size(), 0, "e11 has incorrect number of properties after clear"); - e3 = jansson::Value::object(); - e3.set_key("foo", jansson::Value::from("test")); - e3.set_key("bar", jansson::Value::from(3)); - char* out_cstr = e3.save_string(0); + jansson::Value e12(jansson::Value::object()); + e12.set_key("foo", jansson::Value::from("test")); + e12.set_key("bar", jansson::Value::from(3)); + char* out_cstr = e12.save_string(0); string out(out_cstr); free(out_cstr); ASSERT_EQ(out, "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); std::istringstream instr(out); - instr >> e3; - ASSERT_TRUE(e3.is_object(), "e3 is not an object after stream read"); - ASSERT_EQ(e3.size(), 2, "e3 has wrong size after stream read"); - ASSERT_EQ(e3.get("bar").as_integer(), 3, "e3.bar has incorrect value after stream read"); - ASSERT_EQ(e3.get("foo").as_string(), "test", "ee3.test has incorrect value after stream read"); + instr >> e12; + ASSERT_TRUE(e12.is_object(), "e12 is not an object after stream read"); + ASSERT_EQ(e12.size(), 2, "e12 has wrong size after stream read"); + ASSERT_EQ(e12.get("bar").as_integer(), 3, "e12.bar has incorrect value after stream read"); + ASSERT_EQ(e12.get("foo").as_string(), "test", "ee12.test has incorrect value after stream read"); std::ostringstream outstr; - outstr << e3; + outstr << e12; ASSERT_EQ(instr.str(), "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); return 0; From 492d95329aceab9a404d082562c24fa946196904 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 16:07:57 -0800 Subject: [PATCH 18/38] add proper attribution to janssonxx.h --- janssonxx.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/janssonxx.h b/janssonxx.h index 0fad7dd..6039646 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -1,3 +1,11 @@ +// janssonxx - C++ wrapper for jansson +// +// author: Sean Middleditch +// +// janssonxx is free software; you can redistribute it and/or modify +// it under the terms of the MIT license. See LICENSE for details. + + #if !defined(JANSSONXX_H) #define JANSSONXX_H 1 From 17805e582951a2101452ddb6d3d211f82720d439 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Tue, 12 Jan 2010 16:17:11 -0800 Subject: [PATCH 19/38] insert and remove methods --- janssonxx.h | 29 ++++++++++++++++++++++++++--- test.cc | 9 +++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 6039646..0871c52 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -70,7 +70,12 @@ public: 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(int value) { return Value::_take(json_integer(value)); } + 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(double value) { return Value::_take(json_real(value)); } // create a new empty object @@ -174,8 +179,26 @@ public: return *this; } - Value& set_at(int index, const Value& value) { - return set_at(static_cast(index), value); + // delete an object key + Value& del_key(const char* key) { + json_object_del(_value, key); + return *this; + } + + Value& del_key(const std::string& key) { + return del_key(key.c_str()); + } + + // delete an item from an array by index + Value& del_at(unsigned int index) { + json_array_remove(_value, index); + return *this; + } + + // 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: diff --git a/test.cc b/test.cc index ce9d761..055d4a9 100644 --- a/test.cc +++ b/test.cc @@ -90,6 +90,15 @@ int main() { ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); + e10.insert_at(1, jansson::Value::from("new")); + ASSERT_EQ(e10.size(), 3, "e10 has incorrect size after insert"); + ASSERT_EQ(e10[1].as_string(), "new", "e10[1] has incorrect value after insert"); + ASSERT_EQ(e10[2].as_string(), "foobar", "e10[2] has incorrect value after insert"); + + e10.del_at(0); + ASSERT_EQ(e10.size(), 2, "e10 has incorrect size after delete"); + ASSERT_EQ(e10[1].as_string(), "foobar", "e10[1] has incorrect value after delete"); + e10.clear(); ASSERT_EQ(e10.size(), 0, "e10 has incorrect number of elements after clear"); From 01759517aa8172270725cdac22384239ceabee14 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Wed, 13 Jan 2010 18:32:44 -0800 Subject: [PATCH 20/38] add Value::from(float) --- janssonxx.h | 1 + 1 file changed, 1 insertion(+) diff --git a/janssonxx.h b/janssonxx.h index 0871c52..e09010d 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -76,6 +76,7 @@ public: 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)); } // create a new empty object From 5a0efe6536faf22bdbab90b130fb8965631a519d Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Wed, 13 Jan 2010 18:33:19 -0800 Subject: [PATCH 21/38] add a safeguard against NULL return output stream --- janssonxx.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index e09010d..57e2aed 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -265,8 +265,10 @@ private: // stream JSON value out std::ostream& operator<<(std::ostream& os, const jansson::Value& value) { char* tmp = value.save_string(); - os << tmp; - free(tmp); + if (tmp != 0) { + os << tmp; + free(tmp); + } return os; } From 63f762bc4847147bb9c18ed9ef41911daa444823 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Wed, 13 Jan 2010 18:34:17 -0800 Subject: [PATCH 22/38] save flags default to 0 --- janssonxx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 57e2aed..6703f95 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -57,12 +57,12 @@ public: } // write the value to a file - int save_file(const char* path, int flags = JSON_INDENT(2)) const { + int save_file(const char* path, int flags = 0) const { return json_dump_file(_value, path, flags); } // write the value to a string (caller must deallocate with free()!) - char* save_string(int flags = JSON_INDENT(2)) const { + char* save_string(int flags = 0) const { return json_dumps(_value, flags); } From 69437a7183c4d7105fc5e85021642ab9a04eaf6b Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Wed, 13 Jan 2010 18:35:07 -0800 Subject: [PATCH 23/38] dont attempt to create a std::string from NULL in as_string() --- janssonxx.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/janssonxx.h b/janssonxx.h index 6703f95..b546f7e 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -155,7 +155,10 @@ public: // get value cast to specified type const char* as_cstring() const { return json_string_value(_value); } - std::string as_string() const { return as_cstring(); } + 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); } From 87df8bb0fe16f0a579b2b77a3fc694af12d6a6b8 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 01:13:19 -0800 Subject: [PATCH 24/38] 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; } From 1bc0225441d17011de0681004265e9edec1a8eab Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 01:24:27 -0800 Subject: [PATCH 25/38] add array element proxy support --- janssonxx.h | 41 ++++++++++++++++++++++++++++++++++------- janssonxx.tcc | 22 ++++++++++++++-------- test.cc | 8 +++++++- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 935ac9e..193a354 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -21,6 +21,7 @@ namespace jansson { class Iterator; class Value; + class _ArrayProxy; // base class for JSON value interface template @@ -35,6 +36,9 @@ namespace jansson { // create reference to value _ValueBase(json_t* json) : _Base(json) {} + // assignment operator + _ValueBase& operator=(const Value& value) { _Base::operator=(value); return *this; } + // check value type bool is_undefined() const { return _Base::as_json() == 0; } bool is_object() const { return json_is_object(_Base::as_json()); } @@ -62,14 +66,14 @@ namespace jansson { inline const Value operator[](unsigned long index) const; // get value at array index (non-const version) - inline Value at(unsigned int index); + inline _ValueBase<_ArrayProxy> 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); + inline _ValueBase<_ArrayProxy> operator[](signed int index); + inline _ValueBase<_ArrayProxy> operator[](unsigned int index); + inline _ValueBase<_ArrayProxy> operator[](signed short index); + inline _ValueBase<_ArrayProxy> operator[](unsigned short index); + inline _ValueBase<_ArrayProxy> operator[](signed long index); + inline _ValueBase<_ArrayProxy> operator[](unsigned long index); // get object property inline const Value get(const char* key) const; @@ -149,6 +153,29 @@ namespace jansson { json_t* _value; }; + // proxies an array element + class _ArrayProxy { + public: + // construct new Value with an undefined value + _ArrayProxy() : _array(0), _index(0) {} + + // constructor + _ArrayProxy(json_t* array, unsigned int index) : _array(array), _index(index) {} + + // assign to the proxied element + inline _ArrayProxy& operator=(const Value& value); + + // get the proxied element + json_t* as_json() const { return json_array_get(_array, _index); } + + private: + // array object we wrap + json_t* _array; + + // index of property + unsigned int _index; + }; + // represents any JSON value class Value : public _ValueBase<_Value> { public: diff --git a/janssonxx.tcc b/janssonxx.tcc index 2b5c8aa..c4b1efa 100644 --- a/janssonxx.tcc +++ b/janssonxx.tcc @@ -28,22 +28,22 @@ const jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned long 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)); +jansson::_ValueBase jansson::_ValueBase<_Base>::at(unsigned int index) { + return _ArrayProxy(_Base::as_json(), index); } template -jansson::Value jansson::_ValueBase<_Base>::operator[](signed int index) { return at(index); } +jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](signed int index) { return at(index); } template -jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned int index) { return at(index); } +jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](unsigned int index) { return at(index); } template -jansson::Value jansson::_ValueBase<_Base>::operator[](signed short index) { return at(index); } +jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](signed short index) { return at(index); } template -jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned short index) { return at(index); } +jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](unsigned short index) { return at(index); } template -jansson::Value jansson::_ValueBase<_Base>::operator[](signed long index) { return at(index); } +jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](signed long index) { return at(index); } template -jansson::Value jansson::_ValueBase<_Base>::operator[](unsigned long index) { return at(index); } +jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](unsigned long index) { return at(index); } // get object property template @@ -131,3 +131,9 @@ template json_array_insert(_Base::as_json(), index, value._Base::as_json()); return *this; } + +// assign value to proxied array element +jansson::_ArrayProxy& jansson::_ArrayProxy::operator=(const Value& value) { + json_array_set(_array, _index, value.as_json()); + return *this; +} diff --git a/test.cc b/test.cc index fb66f63..bff3cef 100644 --- a/test.cc +++ b/test.cc @@ -149,7 +149,13 @@ int main() { 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"); + //ASSERT_EQ(e14["foo"]["bar"].as_integer(), 42, "e14.foo.bar has incorrect value after assignment"); + jansson::Value e15(jansson::Value::array()); + ASSERT_TRUE(e15.is_array(), "e15 is not an array after construction"); + e15.set_at(0, jansson::Value::from(42)); + ASSERT_EQ(e15[0].as_integer(), 42, "e15[0] has incorrect value after assignment"); + e15[0] = jansson::Value::from("foo"); + ASSERT_EQ(e15[0].as_string(), "foo", "e15[0] has incorrecy value after assignment"); return 0; } From f0be52f9f83909de249544d3d1c12bd3ccec057a Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 01:31:37 -0800 Subject: [PATCH 26/38] add object property proxy support --- janssonxx.h | 38 ++++++++++++++++++++++++++++++++++---- janssonxx.tcc | 21 ++++++++++++++++++++- test.cc | 4 ++-- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 193a354..2193ff1 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -22,6 +22,7 @@ namespace jansson { class Iterator; class Value; class _ArrayProxy; + class _ObjectProxy; // base class for JSON value interface template @@ -75,13 +76,20 @@ namespace jansson { inline _ValueBase<_ArrayProxy> operator[](signed long index); inline _ValueBase<_ArrayProxy> operator[](unsigned long index); - // get object property + // get object property (const version) 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; + // get object property (non-const version) + inline _ValueBase<_ObjectProxy> get(const char* key); + + inline _ValueBase<_ObjectProxy> get(const std::string& key); + inline _ValueBase<_ObjectProxy> operator[](const char* key); + inline _ValueBase<_ObjectProxy> operator[](const std::string& key); + // clear all array/object values inline void clear(); @@ -156,9 +164,6 @@ namespace jansson { // proxies an array element class _ArrayProxy { public: - // construct new Value with an undefined value - _ArrayProxy() : _array(0), _index(0) {} - // constructor _ArrayProxy(json_t* array, unsigned int index) : _array(array), _index(index) {} @@ -176,6 +181,26 @@ namespace jansson { unsigned int _index; }; + // proxies an object property + class _ObjectProxy { + public: + // constructor + _ObjectProxy(json_t* array, const char* key) : _object(array), _key(key) {} + + // assign to the proxied element + inline _ObjectProxy& operator=(const Value& value); + + // get the proxied element + json_t* as_json() const { return json_object_get(_object, _key); } + + private: + // array object we wrap + json_t* _object; + + // key of property + const char* _key; + }; + // represents any JSON value class Value : public _ValueBase<_Value> { public: @@ -245,6 +270,11 @@ namespace jansson { _iter = json_object_iter(_object.as_json()); } + // construct a new iterator for a given object + Iterator(const _ValueBase<_ObjectProxy>& value) : _object(value.as_json()), _iter(0) { + _iter = json_object_iter(_object.as_json()); + } + // increment iterator void next() { _iter = json_object_iter_next(_object.as_json(), _iter); diff --git a/janssonxx.tcc b/janssonxx.tcc index c4b1efa..27ed239 100644 --- a/janssonxx.tcc +++ b/janssonxx.tcc @@ -45,7 +45,7 @@ jansson::_ValueBase jansson::_ValueBase<_Base>::operator[] template jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](unsigned long index) { return at(index); } -// get object property +// get object property (const version) template const jansson::Value jansson::_ValueBase<_Base>::get(const char* key) const { return jansson::Value(json_object_get(_Base::as_json(), key)); @@ -58,6 +58,19 @@ const jansson::Value jansson::_ValueBase<_Base>::operator[](const char* key) con template const jansson::Value jansson::_ValueBase<_Base>::operator[](const std::string& key) const { return get(key.c_str()); } +// get object property (non-const version) +template +jansson::_ValueBase jansson::_ValueBase<_Base>::get(const char* key) { + return _ObjectProxy(_Base::as_json(), key); +} + +template +jansson::_ValueBase jansson::_ValueBase<_Base>::get(const std::string& key) { return get(key.c_str()); } +template +jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](const char* key) { return get(key); } +template +jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](const std::string& key) { return get(key.c_str()); } + // clear all array/object values template void jansson::_ValueBase<_Base>::clear() { @@ -137,3 +150,9 @@ jansson::_ArrayProxy& jansson::_ArrayProxy::operator=(const Value& value) { json_array_set(_array, _index, value.as_json()); return *this; } + +// assign value to proxied object property +jansson::_ObjectProxy& jansson::_ObjectProxy::operator=(const Value& value) { + json_object_set(_object, _key, value.as_json()); + return *this; +} diff --git a/test.cc b/test.cc index bff3cef..092679d 100644 --- a/test.cc +++ b/test.cc @@ -148,8 +148,8 @@ int main() { 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 incorrect value after assignment"); + e14["foo"]["bar"] = jansson::Value::from(42); + ASSERT_EQ(e14["foo"]["bar"].as_integer(), 42, "e14.foo.bar has incorrect value after assignment"); jansson::Value e15(jansson::Value::array()); ASSERT_TRUE(e15.is_array(), "e15 is not an array after construction"); From 49a64a6edf712d196f6c3b68f8c239436777870c Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 01:36:13 -0800 Subject: [PATCH 27/38] rename and move the _* private classes to _private namespace --- janssonxx.h | 292 +++++++++++++++++++++++++------------------------- janssonxx.tcc | 82 +++++++------- 2 files changed, 189 insertions(+), 185 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 2193ff1..c8a70ab 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -21,203 +21,207 @@ namespace jansson { class Iterator; class Value; - class _ArrayProxy; - class _ObjectProxy; - // base class for JSON value interface - template - class _ValueBase : public _Base { - public: - // empty constructor - _ValueBase() : _Base() {} + namespace _private { + class ArrayProxy; + class ObjectProxy; - // copy constructor - _ValueBase(const _Base& base) : _Base(base) {} + // base class for JSON value interface + template + class ValueBase : public _Base { + public: + // empty constructor + ValueBase() : _Base() {} - // create reference to value - _ValueBase(json_t* json) : _Base(json) {} + // copy constructor + ValueBase(const _Base& base) : _Base(base) {} - // assignment operator - _ValueBase& operator=(const Value& value) { _Base::operator=(value); return *this; } + // create reference to value + ValueBase(json_t* json) : _Base(json) {} - // 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()); } + // assignment operator + ValueBase& operator=(const Value& value) { _Base::operator=(value); return *this; } - // get size of array or object - inline unsigned int size() const; + // 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()); } - // get value at array index (const version) - inline const Value at(unsigned int index) const; + // get size of array or object + inline unsigned int size() 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 (const version) + inline const Value at(unsigned int index) const; - // get value at array index (non-const version) - inline _ValueBase<_ArrayProxy> at(unsigned int index); + 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; - inline _ValueBase<_ArrayProxy> operator[](signed int index); - inline _ValueBase<_ArrayProxy> operator[](unsigned int index); - inline _ValueBase<_ArrayProxy> operator[](signed short index); - inline _ValueBase<_ArrayProxy> operator[](unsigned short index); - inline _ValueBase<_ArrayProxy> operator[](signed long index); - inline _ValueBase<_ArrayProxy> operator[](unsigned long index); + // get value at array index (non-const version) + inline ValueBase at(unsigned int index); - // get object property (const version) - inline const Value get(const char* key) const; + inline ValueBase operator[](signed int index); + inline ValueBase operator[](unsigned int index); + inline ValueBase operator[](signed short index); + inline ValueBase operator[](unsigned short index); + inline ValueBase operator[](signed long index); + inline ValueBase operator[](unsigned long index); - 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; + // get object property (const version) + inline const Value get(const char* key) const; - // get object property (non-const version) - inline _ValueBase<_ObjectProxy> get(const char* key); + 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; - inline _ValueBase<_ObjectProxy> get(const std::string& key); - inline _ValueBase<_ObjectProxy> operator[](const char* key); - inline _ValueBase<_ObjectProxy> operator[](const std::string& key); + // get object property (non-const version) + inline ValueBase get(const char* key); - // clear all array/object values - inline void clear(); + inline ValueBase get(const std::string& key); + inline ValueBase operator[](const char* key); + inline ValueBase operator[](const std::string& key); - // 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; + // clear all array/object values + inline void clear(); - // set an object property (converts value to object is not one already) - inline _Base& set_key(const char* key, const Value& value); + // 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; - inline _Base& set_key(const std::string& key, const Value& value); + // set an object property (converts value to object is not one already) + inline _Base& set_key(const char* 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); + inline _Base& set_key(const std::string& key, const Value& value); - // delete an object key - inline _Base& del_key(const char* key); + // set an array index (converts value to object is not one already) + inline _Base& set_at(unsigned int index, const Value& value); - inline _Base& del_key(const std::string& key); + // delete an object key + inline _Base& del_key(const char* key); - // delete an item from an array by index - inline _Base& del_at(unsigned int index); + inline _Base& del_key(const std::string& key); - // insert an item into an array at a given index - inline _Base& insert_at(unsigned int index, const Value& value); - }; + // delete an item from an array by index + inline _Base& del_at(unsigned int index); - // represents any JSON value, private base - class _Value { - public: - // construct new Value with an undefined value - _Value() : _value(0) {} + // insert an item into an array at a given index + inline _Base& insert_at(unsigned int index, const Value& value); + }; - // copy constructor - _Value(const _Value& value) : _value(json_incref(value._value)) {} + // represents any JSON value, private base + class Basic { + public: + // construct new Value with an undefined value + Basic() : _value(0) {} - // make a reference to an existing json_t value - explicit _Value(json_t* value) : _value(json_incref(value)) {} + // copy constructor + Basic(const Basic& value) : _value(json_incref(value._value)) {} - // free Value resources - ~_Value() { json_decref(_value); } + // make a reference to an existing json_t value + explicit Basic(json_t* value) : _value(json_incref(value)) {} - // copy an existing Value - _Value& operator=(const _Value& e) { - if (&e != this) { - json_decref(_value); - _value = json_incref(e._value); + // free Value resources + ~Basic() { json_decref(_value); } + + // copy an existing Value + Basic& operator=(const Basic& e) { + if (&e != this) { + json_decref(_value); + _value = json_incref(e._value); + } + return *this; } - return *this; - } - // get the underlying json_t - json_t* as_json() const { return _value; } + // get the underlying json_t + json_t* as_json() const { return _value; } - 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; - } + protected: + // take ownership of a json_t (does not increase reference count) + static Basic _take(json_t* json) { + Basic v; + v._value = json; + return v; + } - private: - // internal value pointer - json_t* _value; - }; + private: + // internal value pointer + json_t* _value; + }; - // proxies an array element - class _ArrayProxy { - public: - // constructor - _ArrayProxy(json_t* array, unsigned int index) : _array(array), _index(index) {} + // proxies an array element + class ArrayProxy { + public: + // constructor + ArrayProxy(json_t* array, unsigned int index) : _array(array), _index(index) {} - // assign to the proxied element - inline _ArrayProxy& operator=(const Value& value); + // assign to the proxied element + inline ArrayProxy& operator=(const Value& value); - // get the proxied element - json_t* as_json() const { return json_array_get(_array, _index); } + // get the proxied element + json_t* as_json() const { return json_array_get(_array, _index); } - private: - // array object we wrap - json_t* _array; + private: + // array object we wrap + json_t* _array; - // index of property - unsigned int _index; - }; + // index of property + unsigned int _index; + }; - // proxies an object property - class _ObjectProxy { - public: - // constructor - _ObjectProxy(json_t* array, const char* key) : _object(array), _key(key) {} + // proxies an object property + class ObjectProxy { + public: + // constructor + ObjectProxy(json_t* array, const char* key) : _object(array), _key(key) {} - // assign to the proxied element - inline _ObjectProxy& operator=(const Value& value); + // assign to the proxied element + inline ObjectProxy& operator=(const Value& value); - // get the proxied element - json_t* as_json() const { return json_object_get(_object, _key); } + // get the proxied element + json_t* as_json() const { return json_object_get(_object, _key); } - private: - // array object we wrap - json_t* _object; + private: + // array object we wrap + json_t* _object; - // key of property - const char* _key; - }; + // key of property + const char* _key; + }; + + } // namespace jansson::_private // represents any JSON value - class Value : public _ValueBase<_Value> { + class Value : public _private::ValueBase<_private::Basic> { public: // empty constructor - Value() : _ValueBase<_Value>() {} + Value() : _private::ValueBase<_private::Basic>() {} // copy constructor for base - Value(const _Value& value) : _ValueBase<_Value>(value) {} + Value(const _private::Basic& value) : _private::ValueBase<_private::Basic>(value) {} // copy constructor for base - Value(const _ValueBase<_Value>& value) : _ValueBase<_Value>(value) {} + Value(const _private::ValueBase<_private::Basic>& value) : _private::ValueBase<_private::Basic>(value) {} // copy constructor - Value(const Value& value) : _ValueBase<_Value>(value) {} + Value(const Value& value) : _private::ValueBase<_private::Basic>(value) {} // create reference to value - explicit Value(json_t* json) : _ValueBase<_Value>(json) {} + explicit Value(json_t* json) : _private::ValueBase<_private::Basic>(json) {} // construct Value from input static inline Value from(const char* value) { return Value::_take(json_string(value)); } @@ -271,7 +275,7 @@ namespace jansson { } // construct a new iterator for a given object - Iterator(const _ValueBase<_ObjectProxy>& value) : _object(value.as_json()), _iter(0) { + Iterator(const _private::ValueBase<_private::ObjectProxy>& value) : _object(value.as_json()), _iter(0) { _iter = json_object_iter(_object.as_json()); } diff --git a/janssonxx.tcc b/janssonxx.tcc index 27ed239..0bc505b 100644 --- a/janssonxx.tcc +++ b/janssonxx.tcc @@ -1,6 +1,6 @@ // get size of array or object template -unsigned int jansson::_ValueBase<_Base>::size() const { +unsigned int jansson::_private::ValueBase<_Base>::size() const { if (is_object()) return json_object_size(_Base::as_json()); else @@ -9,71 +9,71 @@ unsigned int jansson::_ValueBase<_Base>::size() const { // get value at array index (const version) template -const jansson::Value jansson::_ValueBase<_Base>::at(unsigned int index) const { +const jansson::Value jansson::_private::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); } +const jansson::Value jansson::_private::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); } +const jansson::Value jansson::_private::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); } +const jansson::Value jansson::_private::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); } +const jansson::Value jansson::_private::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); } +const jansson::Value jansson::_private::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); } +const jansson::Value jansson::_private::ValueBase<_Base>::operator[](unsigned long index) const { return at(index); } // get value at array index (non-const version) template -jansson::_ValueBase jansson::_ValueBase<_Base>::at(unsigned int index) { - return _ArrayProxy(_Base::as_json(), index); +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::at(unsigned int index) { + return ArrayProxy(_Base::as_json(), index); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](signed int index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed int index) { return at(index); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](unsigned int index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned int index) { return at(index); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](signed short index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed short index) { return at(index); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](unsigned short index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned short index) { return at(index); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](signed long index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed long index) { return at(index); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](unsigned long index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned long index) { return at(index); } // get object property (const version) template -const jansson::Value jansson::_ValueBase<_Base>::get(const char* key) const { +const jansson::Value jansson::_private::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()); } +const jansson::Value jansson::_private::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); } +const jansson::Value jansson::_private::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()); } +const jansson::Value jansson::_private::ValueBase<_Base>::operator[](const std::string& key) const { return get(key.c_str()); } // get object property (non-const version) template -jansson::_ValueBase jansson::_ValueBase<_Base>::get(const char* key) { - return _ObjectProxy(_Base::as_json(), key); +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::get(const char* key) { + return ObjectProxy(_Base::as_json(), key); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::get(const std::string& key) { return get(key.c_str()); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::get(const std::string& key) { return get(key.c_str()); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](const char* key) { return get(key); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](const char* key) { return get(key); } template -jansson::_ValueBase jansson::_ValueBase<_Base>::operator[](const std::string& key) { return get(key.c_str()); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](const std::string& key) { return get(key.c_str()); } // clear all array/object values template -void jansson::_ValueBase<_Base>::clear() { +void jansson::_private::ValueBase<_Base>::clear() { if (is_object()) json_object_clear(_Base::as_json()); else @@ -82,36 +82,36 @@ void jansson::_ValueBase<_Base>::clear() { // get value cast to specified type template -const char* jansson::_ValueBase<_Base>::as_cstring() const { return json_string_value(_Base::as_json()); } +const char* jansson::_private::ValueBase<_Base>::as_cstring() const { return json_string_value(_Base::as_json()); } template -std::string jansson::_ValueBase<_Base>::as_string() const { +std::string jansson::_private::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()); } +int jansson::_private::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()); } +double jansson::_private::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()); } +double jansson::_private::ValueBase<_Base>::as_number() const { return json_number_value(_Base::as_json()); } template -bool jansson::_ValueBase<_Base>::as_boolean() const { return is_true(); } +bool jansson::_private::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) { + _Base& jansson::_private::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) { + _Base& jansson::_private::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) { + _Base& jansson::_private::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 @@ -121,38 +121,38 @@ template // delete an object key template - _Base& jansson::_ValueBase<_Base>::del_key(const char* key) { + _Base& jansson::_private::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) { + _Base& jansson::_private::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) { + _Base& jansson::_private::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) { + _Base& jansson::_private::ValueBase<_Base>::insert_at(unsigned int index, const jansson::Value& value) { json_array_insert(_Base::as_json(), index, value._Base::as_json()); return *this; } // assign value to proxied array element -jansson::_ArrayProxy& jansson::_ArrayProxy::operator=(const Value& value) { +jansson::_private::ArrayProxy& jansson::_private::ArrayProxy::operator=(const Value& value) { json_array_set(_array, _index, value.as_json()); return *this; } // assign value to proxied object property -jansson::_ObjectProxy& jansson::_ObjectProxy::operator=(const Value& value) { +jansson::_private::ObjectProxy& jansson::_private::ObjectProxy::operator=(const Value& value) { json_object_set(_object, _key, value.as_json()); return *this; } From 2dc2b6bab7176f5e49597fc97aaf6788d5f53b01 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 01:40:16 -0800 Subject: [PATCH 28/38] rename ArrayProxy to ElementProxy and ObjectProxy to PropertyProxy --- janssonxx.h | 40 ++++++++++++++++++++-------------------- janssonxx.tcc | 30 +++++++++++++++--------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index c8a70ab..bac4317 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -23,8 +23,8 @@ namespace jansson { class Value; namespace _private { - class ArrayProxy; - class ObjectProxy; + class ElementProxy; + class PropertyProxy; // base class for JSON value interface template @@ -69,14 +69,14 @@ namespace jansson { inline const Value operator[](unsigned long index) const; // get value at array index (non-const version) - inline ValueBase at(unsigned int index); + inline ValueBase at(unsigned int index); - inline ValueBase operator[](signed int index); - inline ValueBase operator[](unsigned int index); - inline ValueBase operator[](signed short index); - inline ValueBase operator[](unsigned short index); - inline ValueBase operator[](signed long index); - inline ValueBase operator[](unsigned long index); + inline ValueBase operator[](signed int index); + inline ValueBase operator[](unsigned int index); + inline ValueBase operator[](signed short index); + inline ValueBase operator[](unsigned short index); + inline ValueBase operator[](signed long index); + inline ValueBase operator[](unsigned long index); // get object property (const version) inline const Value get(const char* key) const; @@ -86,11 +86,11 @@ namespace jansson { inline const Value operator[](const std::string& key) const; // get object property (non-const version) - inline ValueBase get(const char* key); + inline ValueBase get(const char* key); - inline ValueBase get(const std::string& key); - inline ValueBase operator[](const char* key); - inline ValueBase operator[](const std::string& key); + inline ValueBase get(const std::string& key); + inline ValueBase operator[](const char* key); + inline ValueBase operator[](const std::string& key); // clear all array/object values inline void clear(); @@ -164,13 +164,13 @@ namespace jansson { }; // proxies an array element - class ArrayProxy { + class ElementProxy { public: // constructor - ArrayProxy(json_t* array, unsigned int index) : _array(array), _index(index) {} + ElementProxy(json_t* array, unsigned int index) : _array(array), _index(index) {} // assign to the proxied element - inline ArrayProxy& operator=(const Value& value); + inline ElementProxy& operator=(const Value& value); // get the proxied element json_t* as_json() const { return json_array_get(_array, _index); } @@ -184,13 +184,13 @@ namespace jansson { }; // proxies an object property - class ObjectProxy { + class PropertyProxy { public: // constructor - ObjectProxy(json_t* array, const char* key) : _object(array), _key(key) {} + PropertyProxy(json_t* array, const char* key) : _object(array), _key(key) {} // assign to the proxied element - inline ObjectProxy& operator=(const Value& value); + inline PropertyProxy& operator=(const Value& value); // get the proxied element json_t* as_json() const { return json_object_get(_object, _key); } @@ -275,7 +275,7 @@ namespace jansson { } // construct a new iterator for a given object - Iterator(const _private::ValueBase<_private::ObjectProxy>& value) : _object(value.as_json()), _iter(0) { + Iterator(const _private::ValueBase<_private::PropertyProxy>& value) : _object(value.as_json()), _iter(0) { _iter = json_object_iter(_object.as_json()); } diff --git a/janssonxx.tcc b/janssonxx.tcc index 0bc505b..2ba753e 100644 --- a/janssonxx.tcc +++ b/janssonxx.tcc @@ -28,22 +28,22 @@ const jansson::Value jansson::_private::ValueBase<_Base>::operator[](unsigned lo // get value at array index (non-const version) template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::at(unsigned int index) { - return ArrayProxy(_Base::as_json(), index); +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::at(unsigned int index) { + return ElementProxy(_Base::as_json(), index); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed int index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed int index) { return at(index); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned int index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned int index) { return at(index); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed short index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed short index) { return at(index); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned short index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned short index) { return at(index); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed long index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed long index) { return at(index); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned long index) { return at(index); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned long index) { return at(index); } // get object property (const version) template @@ -60,16 +60,16 @@ const jansson::Value jansson::_private::ValueBase<_Base>::operator[](const std:: // get object property (non-const version) template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::get(const char* key) { - return ObjectProxy(_Base::as_json(), key); +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::get(const char* key) { + return PropertyProxy(_Base::as_json(), key); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::get(const std::string& key) { return get(key.c_str()); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::get(const std::string& key) { return get(key.c_str()); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](const char* key) { return get(key); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](const char* key) { return get(key); } template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](const std::string& key) { return get(key.c_str()); } +jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](const std::string& key) { return get(key.c_str()); } // clear all array/object values template @@ -146,13 +146,13 @@ template } // assign value to proxied array element -jansson::_private::ArrayProxy& jansson::_private::ArrayProxy::operator=(const Value& value) { +jansson::_private::ElementProxy& jansson::_private::ElementProxy::operator=(const Value& value) { json_array_set(_array, _index, value.as_json()); return *this; } // assign value to proxied object property -jansson::_private::ObjectProxy& jansson::_private::ObjectProxy::operator=(const Value& value) { +jansson::_private::PropertyProxy& jansson::_private::PropertyProxy::operator=(const Value& value) { json_object_set(_object, _key, value.as_json()); return *this; } From cc06bc334a39d78d5bd580438f3a92863a2b78df Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 20:15:33 -0800 Subject: [PATCH 29/38] cleanup code --- Makefile | 2 +- janssonxx.h | 151 +++++-------- janssonxx.tcc | 608 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 510 insertions(+), 251 deletions(-) diff --git a/Makefile b/Makefile index 21f68e6..9352227 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ JANSSON_LIBS := $(shell pkg-config --libs jansson) all: test -test-bin: test.cc janssonxx.h Makefile +test-bin: test.cc janssonxx.h janssonxx.tcc Makefile $(CXX) -o $@ -g -O0 -Wall $(JANSSON_CFLAGS) $< $(JANSSON_LIBS) test: test-bin diff --git a/janssonxx.h b/janssonxx.h index bac4317..f040ec2 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -16,12 +16,13 @@ #include namespace jansson { - // include in the jansson namespace -# include + // include Jansson C library in the jansson namespace + #include class Iterator; class Value; + // implementation details; do not use directly namespace _private { class ElementProxy; class PropertyProxy; @@ -40,20 +41,20 @@ namespace jansson { ValueBase(json_t* json) : _Base(json) {} // assignment operator - ValueBase& operator=(const Value& value) { _Base::operator=(value); return *this; } + inline ValueBase& operator=(const Value& 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()); } + inline bool is_undefined() const; + inline bool is_object() const; + inline bool is_array() const; + inline bool is_string() const; + inline bool is_integer() const; + inline bool is_real() const; + inline bool is_number() const; + inline bool is_true() const; + inline bool is_false() const; + inline bool is_boolean() const; + inline bool is_null() const; // get size of array or object inline unsigned int size() const; @@ -121,6 +122,12 @@ namespace jansson { // insert an item into an array at a given index inline _Base& insert_at(unsigned int index, const Value& value); + + // write the value to a file + inline int save_file(const char* path, int flags = 0) const; + + // write the value to a string (caller must deallocate with free()!) + inline char* save_string(int flags = 0) const; }; // represents any JSON value, private base @@ -136,27 +143,17 @@ namespace jansson { explicit Basic(json_t* value) : _value(json_incref(value)) {} // free Value resources - ~Basic() { json_decref(_value); } + inline ~Basic(); // copy an existing Value - Basic& operator=(const Basic& e) { - if (&e != this) { - json_decref(_value); - _value = json_incref(e._value); - } - return *this; - } + inline Basic& operator=(const Basic& e); // get the underlying json_t - json_t* as_json() const { return _value; } + inline json_t* as_json() const; protected: // take ownership of a json_t (does not increase reference count) - static Basic _take(json_t* json) { - Basic v; - v._value = json; - return v; - } + static inline Basic _take(json_t* json); private: // internal value pointer @@ -173,7 +170,7 @@ namespace jansson { inline ElementProxy& operator=(const Value& value); // get the proxied element - json_t* as_json() const { return json_array_get(_array, _index); } + inline json_t* as_json() const; private: // array object we wrap @@ -193,7 +190,7 @@ namespace jansson { inline PropertyProxy& operator=(const Value& value); // get the proxied element - json_t* as_json() const { return json_object_get(_object, _key); } + inline json_t* as_json() const; private: // array object we wrap @@ -224,86 +221,63 @@ namespace jansson { explicit Value(json_t* json) : _private::ValueBase<_private::Basic>(json) {} // 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)); } + static inline Value from(const char* value); + static inline Value from(const std::string& value); + static inline Value from(bool value); + static inline Value from(signed int value); + static inline Value from(unsigned int value); + static inline Value from(signed short value); + static inline Value from(unsigned short value); + static inline Value from(signed long value); + static inline Value from(unsigned long value); + static inline Value from(float value); + static inline Value from(double value); // create a new empty object - static inline Value object() { return Value::_take(json_object()); } + static inline Value object(); // create a new empty array - static inline Value array() { return Value::_take(json_array()); } + static inline Value array(); // create a new null value - static inline Value null() { return Value::_take(json_null()); } + static inline Value null(); // 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)); - } + static inline Value load_file(const char* path, json_error_t* error = 0); // 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)); - } - - // write the value to a file - int save_file(const char* path, int flags = 0) const { - return json_dump_file(as_json(), path, flags); - } - - // write the value to a string (caller must deallocate with free()!) - char* save_string(int flags = 0) const { - return json_dumps(as_json(), flags); - } + static inline Value load_string(const char* string, json_error_t* error = 0); }; // 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()); - } + inline Iterator(const Value& value); // construct a new iterator for a given object - Iterator(const _private::ValueBase<_private::PropertyProxy>& value) : _object(value.as_json()), _iter(0) { - _iter = json_object_iter(_object.as_json()); - } + inline Iterator(const _private::ValueBase<_private::PropertyProxy>& value); // increment iterator - void next() { - _iter = json_object_iter_next(_object.as_json(), _iter); - } + inline void next(); - Iterator& operator++() { next(); return *this; } + inline Iterator& operator++(); // test if iterator is still valid - bool valid() const { return _iter != 0; } - operator bool() const { return valid(); } + inline bool valid() const; + + inline operator bool() const; // get key - const char* ckey() const { - return json_object_iter_key(_iter); - } + inline const char* ckey() const; - std::string key() const { return ckey(); } + inline std::string key() const; // get value - const Value value() const { - return Value(json_object_iter_value(_iter)); - } + inline const Value value() const; // dereference value - const Value operator*() const { return value(); } + inline const Value operator*() const; private: // disallow copying @@ -320,23 +294,10 @@ namespace jansson { } // namespace jansson // stream JSON value out -std::ostream& operator<<(std::ostream& os, const jansson::Value& value) { - char* tmp = value.save_string(); - if (tmp != 0) { - os << tmp; - free(tmp); - } - return os; -} +inline std::ostream& operator<<(std::ostream& os, const jansson::Value& value); // read JSON value -std::istream& operator>>(std::istream& is, jansson::Value& value) { - std::stringstream tmp; - while (is) - tmp << static_cast(is.get()); - value = jansson::Value::load_string(tmp.str().c_str()); - return is; -} +inline std::istream& operator>>(std::istream& is, jansson::Value& value); #include "janssonxx.tcc" diff --git a/janssonxx.tcc b/janssonxx.tcc index 2ba753e..cdbadd8 100644 --- a/janssonxx.tcc +++ b/janssonxx.tcc @@ -1,158 +1,456 @@ -// get size of array or object -template -unsigned int jansson::_private::ValueBase<_Base>::size() const { - if (is_object()) - return json_object_size(_Base::as_json()); - else - return json_array_size(_Base::as_json()); +namespace jansson { + namespace _private { + // assignment operator + template + ValueBase<_Base>& ValueBase<_Base>::operator=(const Value& value) { + _Base::operator=(value); + return *this; + } + + // check value type + template + bool ValueBase<_Base>::is_undefined() const { + return _Base::as_json() == 0; + } + + template + bool ValueBase<_Base>::is_object() const { + return json_is_object(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_array() const { + return json_is_array(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_string() const { + return json_is_string(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_integer() const { + return json_is_integer(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_real() const { + return json_is_real(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_number() const { + return json_is_number(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_true() const { + return json_is_true(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_false() const { + return json_is_false(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_boolean() const { + return json_is_boolean(_Base::as_json()); + } + + template + bool ValueBase<_Base>::is_null() const { + return json_is_null(_Base::as_json()); + } + + // get size of array or object + template + unsigned int 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 Value ValueBase<_Base>::at(unsigned int index) const { + return Value(json_array_get(_Base::as_json(), index)); + } + + template + const Value ValueBase<_Base>::operator[](signed int index) const { return at(index); } + template + const Value ValueBase<_Base>::operator[](unsigned int index) const { return at(index); } + template + const Value ValueBase<_Base>::operator[](signed short index) const { return at(index); } + template + const Value ValueBase<_Base>::operator[](unsigned short index) const { return at(index); } + template + const Value ValueBase<_Base>::operator[](signed long index) const { return at(index); } + template + const Value ValueBase<_Base>::operator[](unsigned long index) const { return at(index); } + + // get value at array index (non-const version) + template + ValueBase ValueBase<_Base>::at(unsigned int index) { + return ElementProxy(_Base::as_json(), index); + } + + template + ValueBase ValueBase<_Base>::operator[](signed int index) { + return at(index); + } + + template + ValueBase ValueBase<_Base>::operator[](unsigned int index) { + return at(index); + } + + template + ValueBase ValueBase<_Base>::operator[](signed short index) { + return at(index); + } + + template + ValueBase ValueBase<_Base>::operator[](unsigned short index) { + return at(index); + } + + template + ValueBase ValueBase<_Base>::operator[](signed long index) { + return at(index); + } + + template + ValueBase ValueBase<_Base>::operator[](unsigned long index) { + return at(index); + } + + // get object property (const version) + template + const Value ValueBase<_Base>::get(const char* key) const { + return Value(json_object_get(_Base::as_json(), key)); + } + + template + const Value ValueBase<_Base>::get(const std::string& key) const { + return get(key.c_str()); + } + + template + const Value ValueBase<_Base>::operator[](const char* key) const { + return get(key); + } + + template + const Value ValueBase<_Base>::operator[](const std::string& key) const { + return get(key.c_str()); + } + + // get object property (non-const version) + template + ValueBase ValueBase<_Base>::get(const char* key) { + return PropertyProxy(_Base::as_json(), key); + } + + template + ValueBase ValueBase<_Base>::get(const std::string& key) { + return get(key.c_str()); + } + + template + ValueBase ValueBase<_Base>::operator[](const char* key) { + return get(key); + } + + template + ValueBase ValueBase<_Base>::operator[](const std::string& key) { + return get(key.c_str()); + } + + // clear all array/object values + template + void 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* ValueBase<_Base>::as_cstring() const { + return json_string_value(_Base::as_json()); + } + + template + std::string ValueBase<_Base>::as_string() const { + const char* tmp = as_cstring(); + return tmp == 0 ? "" : tmp; + } + + template + int ValueBase<_Base>::as_integer() const { + return json_integer_value(_Base::as_json()); + } + + template + double ValueBase<_Base>::as_real() const { + return json_real_value(_Base::as_json()); + } + + template + double ValueBase<_Base>::as_number() const { + return json_number_value(_Base::as_json()); + } + + template + bool ValueBase<_Base>::as_boolean() const { + return is_true(); + } + + // set an object property (converts value to object is not one already) + template + _Base& ValueBase<_Base>::set_key(const char* key, const Value& value) { + json_object_set(_Base::as_json(), key, value._Base::as_json()); + return *this; + } + + template + _Base& ValueBase<_Base>::set_key(const std::string& key, const Value& value) { + return set_key(key.c_str(), value); + } + + // set an array index (converts value to object is not one already) + template + _Base& ValueBase<_Base>::set_at(unsigned int index, const 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& ValueBase<_Base>::del_key(const char* key) { + json_object_del(_Base::as_json(), key); + return *this; + } + + template + _Base& ValueBase<_Base>::del_key(const std::string& key) { + return del_key(key.c_str()); + } + + // delete an item from an array by index + template + _Base& 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& ValueBase<_Base>::insert_at(unsigned int index, const Value& value) { + json_array_insert(_Base::as_json(), index, value._Base::as_json()); + return *this; + } + + // write the value to a file + template + int ValueBase<_Base>::save_file(const char* path, int flags) const { + return json_dump_file(_Base::as_json(), path, flags); + } + + // write the value to a string (caller must deallocate with free()!) + template + char* ValueBase<_Base>::save_string(int flags) const { + return json_dumps(_Base::as_json(), flags); + } + + Basic::~Basic() { + json_decref(_value); + } + + // copy an existing Value + Basic& Basic::operator=(const Basic& e) { + if (&e != this) { + json_decref(_value); + _value = json_incref(e._value); + } + return *this; + } + + // get the underlying json_t + json_t* Basic::as_json() const { + return _value; + } + + // take ownership of a json_t (does not increase reference count) + Basic Basic::_take(json_t* json) { + Basic v; + v._value = json; + return v; + } + + // assign value to proxied array element + ElementProxy& ElementProxy::operator=(const Value& value) { + json_array_set(_array, _index, value.as_json()); + return *this; + } + + // get the proxied element + json_t* ElementProxy::as_json() const { + return json_array_get(_array, _index); + } + + // assign value to proxied object property + PropertyProxy& PropertyProxy::operator=(const Value& value) { + json_object_set(_object, _key, value.as_json()); + return *this; + } + + json_t* PropertyProxy::as_json() const { + return json_object_get(_object, _key); + } + + } // namespace jansson::_private + + // construct Value from input + Value Value::from(const char* value) { + return Value::_take(json_string(value)); + } + + Value Value::from(const std::string& value) { + return Value::from(value.c_str()); + } + + Value Value::from(bool value) { + return Value::_take(value ? json_true() : json_false()); + } + + Value Value::from(signed int value) { + return Value::_take(json_integer(value)); + } + + Value Value::from(unsigned int value) { + return Value::_take(json_integer(value)); + } + + Value Value::from(signed short value) { + return Value::_take(json_integer(value)); + } + + Value Value::from(unsigned short value) { + return Value::_take(json_integer(value)); + } + + Value Value::from(signed long value) { + return Value::_take(json_integer(value)); + } + + Value Value::from(unsigned long value) { + return Value::_take(json_integer(value)); + } + + Value Value::from(float value) { + return Value::_take(json_real(value)); + } + + Value Value::from(double value) { + return Value::_take(json_real(value)); + } + + // create a new empty object + Value Value::object() { + return Value::_take(json_object()); + } + + // create a new empty array + Value Value::array() { + return Value::_take(json_array()); + } + + // create a new null value + Value Value::null() { + return Value::_take(json_null()); + } + + // load a file as a JSON value + Value Value::load_file(const char* path, json_error_t* error) { + return Value::_take(json_load_file(path, error)); + } + + // load a string as a JSON value + Value Value::load_string(const char* string, json_error_t* error) { + return Value::_take(json_loads(string, error)); + } + + // construct a new iterator for a given object + Iterator::Iterator(const Value& value) : _object(value), _iter(0) { + _iter = json_object_iter(_object.as_json()); + } + + // construct a new iterator for a given object + Iterator::Iterator(const _private::ValueBase<_private::PropertyProxy>& value) : + _object(value.as_json()), _iter(0) { + _iter = json_object_iter(_object.as_json()); + } + + // increment iterator + void Iterator::next() { + _iter = json_object_iter_next(_object.as_json(), _iter); + } + + Iterator& Iterator::operator++() { next(); return *this; } + + // test if iterator is still valid + bool Iterator::valid() const { + return _iter != 0; + } + + Iterator::operator bool() const { + return valid(); + } + + // get key + const char* Iterator::ckey() const { + return json_object_iter_key(_iter); + } + + std::string Iterator::key() const { + return ckey(); + } + + // get value + const Value Iterator::value() const { + return Value(json_object_iter_value(_iter)); + } + + // dereference value + const Value Iterator::operator*() const { + return value(); + } + +} // namespace jansson + +// stream JSON value out +std::ostream& operator<<(std::ostream& os, const jansson::Value& value) { + char* tmp = value.save_string(); + if (tmp != 0) { + os << tmp; + free(tmp); + } + return os; } -// get value at array index (const version) -template -const jansson::Value jansson::_private::ValueBase<_Base>::at(unsigned int index) const { - return jansson::Value(json_array_get(_Base::as_json(), index)); -} - -template -const jansson::Value jansson::_private::ValueBase<_Base>::operator[](signed int index) const { return at(index); } -template -const jansson::Value jansson::_private::ValueBase<_Base>::operator[](unsigned int index) const { return at(index); } -template -const jansson::Value jansson::_private::ValueBase<_Base>::operator[](signed short index) const { return at(index); } -template -const jansson::Value jansson::_private::ValueBase<_Base>::operator[](unsigned short index) const { return at(index); } -template -const jansson::Value jansson::_private::ValueBase<_Base>::operator[](signed long index) const { return at(index); } -template -const jansson::Value jansson::_private::ValueBase<_Base>::operator[](unsigned long index) const { return at(index); } - -// get value at array index (non-const version) -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::at(unsigned int index) { - return ElementProxy(_Base::as_json(), index); -} - -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed int index) { return at(index); } -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned int index) { return at(index); } -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed short index) { return at(index); } -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned short index) { return at(index); } -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](signed long index) { return at(index); } -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](unsigned long index) { return at(index); } - -// get object property (const version) -template -const jansson::Value jansson::_private::ValueBase<_Base>::get(const char* key) const { - return jansson::Value(json_object_get(_Base::as_json(), key)); -} - -template -const jansson::Value jansson::_private::ValueBase<_Base>::get(const std::string& key) const { return get(key.c_str()); } -template -const jansson::Value jansson::_private::ValueBase<_Base>::operator[](const char* key) const { return get(key); } -template -const jansson::Value jansson::_private::ValueBase<_Base>::operator[](const std::string& key) const { return get(key.c_str()); } - -// get object property (non-const version) -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::get(const char* key) { - return PropertyProxy(_Base::as_json(), key); -} - -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::get(const std::string& key) { return get(key.c_str()); } -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](const char* key) { return get(key); } -template -jansson::_private::ValueBase jansson::_private::ValueBase<_Base>::operator[](const std::string& key) { return get(key.c_str()); } - -// clear all array/object values -template -void jansson::_private::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::_private::ValueBase<_Base>::as_cstring() const { return json_string_value(_Base::as_json()); } -template -std::string jansson::_private::ValueBase<_Base>::as_string() const { - const char* tmp = as_cstring(); - return tmp == 0 ? "" : tmp; -} -template -int jansson::_private::ValueBase<_Base>::as_integer() const { return json_integer_value(_Base::as_json()); } -template -double jansson::_private::ValueBase<_Base>::as_real() const { return json_real_value(_Base::as_json()); } -template -double jansson::_private::ValueBase<_Base>::as_number() const { return json_number_value(_Base::as_json()); } -template -bool jansson::_private::ValueBase<_Base>::as_boolean() const { return is_true(); } - -// set an object property (converts value to object is not one already) -template - _Base& jansson::_private::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::_private::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::_private::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::_private::ValueBase<_Base>::del_key(const char* key) { - json_object_del(_Base::as_json(), key); - return *this; -} - -template - _Base& jansson::_private::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::_private::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::_private::ValueBase<_Base>::insert_at(unsigned int index, const jansson::Value& value) { - json_array_insert(_Base::as_json(), index, value._Base::as_json()); - return *this; -} - -// assign value to proxied array element -jansson::_private::ElementProxy& jansson::_private::ElementProxy::operator=(const Value& value) { - json_array_set(_array, _index, value.as_json()); - return *this; -} - -// assign value to proxied object property -jansson::_private::PropertyProxy& jansson::_private::PropertyProxy::operator=(const Value& value) { - json_object_set(_object, _key, value.as_json()); - return *this; +// read JSON value +std::istream& operator>>(std::istream& is, jansson::Value& value) { + std::stringstream tmp; + while (is) + tmp << static_cast(is.get()); + value = jansson::Value::load_string(tmp.str().c_str()); + return is; } From f88a5a0e6b1ee3284238cb4ea3af73c0be501fcb Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 20:17:48 -0800 Subject: [PATCH 30/38] added a couple minor comments --- janssonxx.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/janssonxx.h b/janssonxx.h index f040ec2..15f34f7 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -299,6 +299,7 @@ inline std::ostream& operator<<(std::ostream& os, const jansson::Value& value); // read JSON value inline std::istream& operator>>(std::istream& is, jansson::Value& value); +// include implementation code #include "janssonxx.tcc" -#endif +#endif // defined(JANSSONXX_H) From df35adc43856cfef48abd3af93cf4275e7866899 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 20:21:52 -0800 Subject: [PATCH 31/38] add comments noting inefficiency of stream ops --- janssonxx.h | 4 ++-- janssonxx.tcc | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/janssonxx.h b/janssonxx.h index 15f34f7..260450f 100644 --- a/janssonxx.h +++ b/janssonxx.h @@ -293,10 +293,10 @@ namespace jansson { } // namespace jansson -// stream JSON value out +// stream JSON value out -- inefficient and not recommended for production use inline std::ostream& operator<<(std::ostream& os, const jansson::Value& value); -// read JSON value +// read JSON value -- inefficient and not recommended for production use inline std::istream& operator>>(std::istream& is, jansson::Value& value); // include implementation code diff --git a/janssonxx.tcc b/janssonxx.tcc index cdbadd8..74e4be5 100644 --- a/janssonxx.tcc +++ b/janssonxx.tcc @@ -438,8 +438,10 @@ namespace jansson { // stream JSON value out std::ostream& operator<<(std::ostream& os, const jansson::Value& value) { + // get the temporary serialize string char* tmp = value.save_string(); if (tmp != 0) { + // stream temp string out and release it os << tmp; free(tmp); } @@ -448,9 +450,11 @@ std::ostream& operator<<(std::ostream& os, const jansson::Value& value) { // read JSON value std::istream& operator>>(std::istream& is, jansson::Value& value) { + // buffer the remaining bytes into a single string for Jansson std::stringstream tmp; while (is) tmp << static_cast(is.get()); + // parse the buffered string value = jansson::Value::load_string(tmp.str().c_str()); return is; } From dd36e4e838b6d7eb9c0951f92d81118289a0a0db Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sat, 16 Jan 2010 20:27:13 -0800 Subject: [PATCH 32/38] rename files to match upstream's preferences --- Makefile | 2 +- janssonxx.tcc => jansson-impl.hpp | 11 +++++++++++ janssonxx.h => jansson.hpp | 11 ++++++----- test.cc => test.cpp | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) rename janssonxx.tcc => jansson-impl.hpp (97%) rename janssonxx.h => jansson.hpp (98%) rename test.cc => test.cpp (99%) diff --git a/Makefile b/Makefile index 9352227..7eb4984 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ JANSSON_LIBS := $(shell pkg-config --libs jansson) all: test -test-bin: test.cc janssonxx.h janssonxx.tcc Makefile +test-bin: test.cpp jansson.hpp jansson-impl.hpp Makefile $(CXX) -o $@ -g -O0 -Wall $(JANSSON_CFLAGS) $< $(JANSSON_LIBS) test: test-bin diff --git a/janssonxx.tcc b/jansson-impl.hpp similarity index 97% rename from janssonxx.tcc rename to jansson-impl.hpp index 74e4be5..b275eb1 100644 --- a/janssonxx.tcc +++ b/jansson-impl.hpp @@ -1,3 +1,14 @@ +// janssonxx - C++ wrapper for jansson, implementation file +// +// author: Sean Middleditch +// +// janssonxx is free software; you can redistribute it and/or modify +// it under the terms of the MIT license. See LICENSE for details. + +#if !defined(IN_JANSSON_HPP) +# error "jansson-impl.hpp may only by included from jansson.hpp" +#endif + namespace jansson { namespace _private { // assignment operator diff --git a/janssonxx.h b/jansson.hpp similarity index 98% rename from janssonxx.h rename to jansson.hpp index 260450f..40fb19b 100644 --- a/janssonxx.h +++ b/jansson.hpp @@ -5,9 +5,8 @@ // janssonxx is free software; you can redistribute it and/or modify // it under the terms of the MIT license. See LICENSE for details. - -#if !defined(JANSSONXX_H) -#define JANSSONXX_H 1 +#if !defined(JANSSON_HPP) +#define JANSSON_HPP 1 #include #include @@ -300,6 +299,8 @@ inline std::ostream& operator<<(std::ostream& os, const jansson::Value& value); inline std::istream& operator>>(std::istream& is, jansson::Value& value); // include implementation code -#include "janssonxx.tcc" +#define IN_JANSSON_HPP 1 +#include "jansson-impl.hpp" +#undef IN_JANSSON_HPP -#endif // defined(JANSSONXX_H) +#endif // defined(JANSSON_HPP) diff --git a/test.cc b/test.cpp similarity index 99% rename from test.cc rename to test.cpp index 092679d..40a6a07 100644 --- a/test.cc +++ b/test.cpp @@ -2,7 +2,7 @@ #include #include -#include "janssonxx.h" +#include "jansson.hpp" using namespace std; From 95bf762eebf3f3c2ed2d690eaf30e6c3885143d4 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Mon, 18 Jan 2010 18:37:13 -0800 Subject: [PATCH 33/38] rename jansson namespace to json --- jansson-impl.hpp | 12 +++++----- jansson.hpp | 12 +++++----- test.cpp | 60 ++++++++++++++++++++++++------------------------ 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/jansson-impl.hpp b/jansson-impl.hpp index b275eb1..6c2e134 100644 --- a/jansson-impl.hpp +++ b/jansson-impl.hpp @@ -9,7 +9,7 @@ # error "jansson-impl.hpp may only by included from jansson.hpp" #endif -namespace jansson { +namespace json { namespace _private { // assignment operator template @@ -327,7 +327,7 @@ namespace jansson { return json_object_get(_object, _key); } - } // namespace jansson::_private + } // namespace json::_private // construct Value from input Value Value::from(const char* value) { @@ -445,10 +445,10 @@ namespace jansson { return value(); } -} // namespace jansson +} // namespace json // stream JSON value out -std::ostream& operator<<(std::ostream& os, const jansson::Value& value) { +std::ostream& operator<<(std::ostream& os, const json::Value& value) { // get the temporary serialize string char* tmp = value.save_string(); if (tmp != 0) { @@ -460,12 +460,12 @@ std::ostream& operator<<(std::ostream& os, const jansson::Value& value) { } // read JSON value -std::istream& operator>>(std::istream& is, jansson::Value& value) { +std::istream& operator>>(std::istream& is, json::Value& value) { // buffer the remaining bytes into a single string for Jansson std::stringstream tmp; while (is) tmp << static_cast(is.get()); // parse the buffered string - value = jansson::Value::load_string(tmp.str().c_str()); + value = json::Value::load_string(tmp.str().c_str()); return is; } diff --git a/jansson.hpp b/jansson.hpp index 40fb19b..9df3961 100644 --- a/jansson.hpp +++ b/jansson.hpp @@ -14,8 +14,8 @@ #include #include -namespace jansson { - // include Jansson C library in the jansson namespace +namespace json { + // include Jansson C library into the json namespace #include class Iterator; @@ -199,7 +199,7 @@ namespace jansson { const char* _key; }; - } // namespace jansson::_private + } // namespace json::_private // represents any JSON value class Value : public _private::ValueBase<_private::Basic> { @@ -290,13 +290,13 @@ namespace jansson { void* _iter; }; -} // namespace jansson +} // namespace json // stream JSON value out -- inefficient and not recommended for production use -inline std::ostream& operator<<(std::ostream& os, const jansson::Value& value); +inline std::ostream& operator<<(std::ostream& os, const json::Value& value); // read JSON value -- inefficient and not recommended for production use -inline std::istream& operator>>(std::istream& is, jansson::Value& value); +inline std::istream& operator>>(std::istream& is, json::Value& value); // include implementation code #define IN_JANSSON_HPP 1 diff --git a/test.cpp b/test.cpp index 40a6a07..cc10689 100644 --- a/test.cpp +++ b/test.cpp @@ -22,10 +22,10 @@ using namespace std; #define ASSERT_FALSE(p, m) ASSERT_OP(p, true, !=, m) int main() { - jansson::Value e1(jansson::Value::load_file("test.json")); - jansson::Value e2(e1); - jansson::Value e3; - jansson::Value e4(jansson::Value::load_string("{\"foo\": true, \"bar\": \"test\"}")); + json::Value e1(json::Value::load_file("test.json")); + json::Value e2(e1); + json::Value e3; + json::Value e4(json::Value::load_string("{\"foo\": true, \"bar\": \"test\"}")); ASSERT_TRUE(e1.is_object(), "e1 is not an object"); ASSERT_TRUE(e2.is_object(), "e2 is not an object"); @@ -42,7 +42,7 @@ int main() { ASSERT_EQ(e4["foo"].as_boolean(), true, "property has incorrect value"); - jansson::Iterator i(e1.get("web-app")); + json::Iterator i(e1.get("web-app")); ASSERT_EQ(i.key(), "taglib", "first iterator result has incorrect key"); i.next(); ASSERT_EQ(i.key(), "servlet", "first iterator result has incorrect key"); @@ -51,46 +51,46 @@ int main() { i.next(); ASSERT_FALSE(i.valid(), "iterator has more values than expected"); - jansson::Value e5(jansson::Value::from(12.34)); + json::Value e5(json::Value::from(12.34)); ASSERT_TRUE(e5.is_number(), "e5 is not a number after assignment"); ASSERT_EQ(e5.as_real(), 12.34, "e5 has incorrect value after assignment"); - jansson::Value e6(jansson::Value::from(true)); + json::Value e6(json::Value::from(true)); ASSERT_TRUE(e6.is_boolean(), "e6 is not a boolean after assignment"); ASSERT_EQ(e6.as_boolean(), true, "e6 has incorrect value after assignment"); - jansson::Value e7(jansson::Value::from("foobar")); + json::Value e7(json::Value::from("foobar")); ASSERT_TRUE(e7.is_string(), "e7 is not a string after assignment"); ASSERT_EQ(e7.as_string(), "foobar", "e7 has incorrect value after assignment"); - jansson::Value e8(jansson::Value::object()); + json::Value e8(json::Value::object()); ASSERT_TRUE(e8.is_object(), "e8 is not an object after assignment"); - jansson::Value e9(jansson::Value::null()); + json::Value e9(json::Value::null()); ASSERT_TRUE(e9.is_null(), "e9 is not null after assignment"); - jansson::Value e10(jansson::Value::array()); + json::Value e10(json::Value::array()); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); - e10.set_at(0, jansson::Value::from("foobar")); + e10.set_at(0, json::Value::from("foobar")); ASSERT_EQ(e10.size(), 1, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[0].as_string(), "foobar", "e10[0] has incorrect value after assignment"); - e10.set_at(1, jansson::Value::from("foobar")); + e10.set_at(1, json::Value::from("foobar")); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[1].as_string(), "foobar", "e10[0] has incorrect value after assignment"); - e10.set_at(0, jansson::Value::from("barfoo")); + e10.set_at(0, json::Value::from("barfoo")); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[0].as_string(), "barfoo", "e10[0] has incorrect value after assignment"); - e10.set_at(100, jansson::Value::null()); + e10.set_at(100, json::Value::null()); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); - e10.insert_at(1, jansson::Value::from("new")); + e10.insert_at(1, json::Value::from("new")); ASSERT_EQ(e10.size(), 3, "e10 has incorrect size after insert"); ASSERT_EQ(e10[1].as_string(), "new", "e10[1] has incorrect value after insert"); ASSERT_EQ(e10[2].as_string(), "foobar", "e10[2] has incorrect value after insert"); @@ -102,19 +102,19 @@ int main() { e10.clear(); ASSERT_EQ(e10.size(), 0, "e10 has incorrect number of elements after clear"); - jansson::Value e11(jansson::Value::object()); + json::Value e11(json::Value::object()); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); - e11.set_key("foo", jansson::Value::from("test")); + e11.set_key("foo", json::Value::from("test")); ASSERT_EQ(e11.size(), 1, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["foo"].as_string(), "test", "e11.foo has incorrect value after assignment"); - e11.set_key("foo", jansson::Value::from("again")); + e11.set_key("foo", json::Value::from("again")); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); ASSERT_EQ(e11.size(), 1, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["foo"].as_string(), "again", "e11.foo has incorrect value after assignment"); - e11.set_key("bar", jansson::Value::from("test")); + e11.set_key("bar", json::Value::from("test")); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); ASSERT_EQ(e11.size(), 2, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["bar"].as_string(), "test", "e11.foo has incorrect value after assignment"); @@ -122,9 +122,9 @@ int main() { e11.clear(); ASSERT_EQ(e11.size(), 0, "e11 has incorrect number of properties after clear"); - jansson::Value e12(jansson::Value::object()); - e12.set_key("foo", jansson::Value::from("test")); - e12.set_key("bar", jansson::Value::from(3)); + json::Value e12(json::Value::object()); + e12.set_key("foo", json::Value::from("test")); + e12.set_key("bar", json::Value::from(3)); char* out_cstr = e12.save_string(0); string out(out_cstr); free(out_cstr); @@ -141,21 +141,21 @@ int main() { outstr << e12; ASSERT_EQ(instr.str(), "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); - const jansson::Value e13(e12); + const json::Value e13(e12); ASSERT_EQ(e13["bar"].as_integer(), 3, "e13.bar has incorrect value after copy"); - jansson::Value e14(jansson::Value::object()); + json::Value e14(json::Value::object()); ASSERT_TRUE(e14.is_object(), "e14 is not an object after construction"); - e14.set_key("foo", jansson::Value::object()); + e14.set_key("foo", json::Value::object()); ASSERT_TRUE(e14["foo"].is_object(), "e14.foo is not an object after assignment"); - e14["foo"]["bar"] = jansson::Value::from(42); + e14["foo"]["bar"] = json::Value::from(42); ASSERT_EQ(e14["foo"]["bar"].as_integer(), 42, "e14.foo.bar has incorrect value after assignment"); - jansson::Value e15(jansson::Value::array()); + json::Value e15(json::Value::array()); ASSERT_TRUE(e15.is_array(), "e15 is not an array after construction"); - e15.set_at(0, jansson::Value::from(42)); + e15.set_at(0, json::Value::from(42)); ASSERT_EQ(e15[0].as_integer(), 42, "e15[0] has incorrect value after assignment"); - e15[0] = jansson::Value::from("foo"); + e15[0] = json::Value::from("foo"); ASSERT_EQ(e15[0].as_string(), "foo", "e15[0] has incorrecy value after assignment"); return 0; } From ef6c35ae1baa9bab3333636088c4b132b3aeeec5 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Mon, 18 Jan 2010 18:50:13 -0800 Subject: [PATCH 34/38] move static functions out of Value, add test driver to ensure linking works properly --- Makefile | 4 +- driver.cpp | 7 +++ jansson-impl.hpp | 144 +++++++++++++++++++++++------------------------ jansson.hpp | 59 ++++++++++--------- test.cpp | 58 +++++++++---------- 5 files changed, 138 insertions(+), 134 deletions(-) create mode 100644 driver.cpp diff --git a/Makefile b/Makefile index 7eb4984..7d4931c 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ JANSSON_LIBS := $(shell pkg-config --libs jansson) all: test -test-bin: test.cpp jansson.hpp jansson-impl.hpp Makefile - $(CXX) -o $@ -g -O0 -Wall $(JANSSON_CFLAGS) $< $(JANSSON_LIBS) +test-bin: driver.cpp test.cpp jansson.hpp jansson-impl.hpp Makefile + $(CXX) -o $@ -g -O0 -Wall $(JANSSON_CFLAGS) driver.cpp test.cpp $(JANSSON_LIBS) test: test-bin ./test-bin diff --git a/driver.cpp b/driver.cpp new file mode 100644 index 0000000..f42831e --- /dev/null +++ b/driver.cpp @@ -0,0 +1,7 @@ +#include "jansson.hpp" + +extern int json_cpp_tests(); + +int main() { + return json_cpp_tests(); +} diff --git a/jansson-impl.hpp b/jansson-impl.hpp index 6c2e134..6242ed9 100644 --- a/jansson-impl.hpp +++ b/jansson-impl.hpp @@ -300,7 +300,7 @@ namespace json { } // take ownership of a json_t (does not increase reference count) - Basic Basic::_take(json_t* json) { + Basic Basic::take_ownership(json_t* json) { Basic v; v._value = json; return v; @@ -328,76 +328,6 @@ namespace json { } } // namespace json::_private - - // construct Value from input - Value Value::from(const char* value) { - return Value::_take(json_string(value)); - } - - Value Value::from(const std::string& value) { - return Value::from(value.c_str()); - } - - Value Value::from(bool value) { - return Value::_take(value ? json_true() : json_false()); - } - - Value Value::from(signed int value) { - return Value::_take(json_integer(value)); - } - - Value Value::from(unsigned int value) { - return Value::_take(json_integer(value)); - } - - Value Value::from(signed short value) { - return Value::_take(json_integer(value)); - } - - Value Value::from(unsigned short value) { - return Value::_take(json_integer(value)); - } - - Value Value::from(signed long value) { - return Value::_take(json_integer(value)); - } - - Value Value::from(unsigned long value) { - return Value::_take(json_integer(value)); - } - - Value Value::from(float value) { - return Value::_take(json_real(value)); - } - - Value Value::from(double value) { - return Value::_take(json_real(value)); - } - - // create a new empty object - Value Value::object() { - return Value::_take(json_object()); - } - - // create a new empty array - Value Value::array() { - return Value::_take(json_array()); - } - - // create a new null value - Value Value::null() { - return Value::_take(json_null()); - } - - // load a file as a JSON value - Value Value::load_file(const char* path, json_error_t* error) { - return Value::_take(json_load_file(path, error)); - } - - // load a string as a JSON value - Value Value::load_string(const char* string, json_error_t* error) { - return Value::_take(json_loads(string, error)); - } // construct a new iterator for a given object Iterator::Iterator(const Value& value) : _object(value), _iter(0) { @@ -445,6 +375,76 @@ namespace json { return value(); } + // construct Value from input + Value from(const char* value) { + return Value::take_ownership(json_string(value)); + } + + Value from(const std::string& value) { + return from(value.c_str()); + } + + Value from(bool value) { + return Value::take_ownership(value ? json_true() : json_false()); + } + + Value from(signed int value) { + return Value::take_ownership(json_integer(value)); + } + + Value from(unsigned int value) { + return Value::take_ownership(json_integer(value)); + } + + Value from(signed short value) { + return Value::take_ownership(json_integer(value)); + } + + Value from(unsigned short value) { + return Value::take_ownership(json_integer(value)); + } + + Value from(signed long value) { + return Value::take_ownership(json_integer(value)); + } + + Value from(unsigned long value) { + return Value::take_ownership(json_integer(value)); + } + + Value from(float value) { + return Value::take_ownership(json_real(value)); + } + + Value from(double value) { + return Value::take_ownership(json_real(value)); + } + + // create a new empty object + Value object() { + return Value::take_ownership(json_object()); + } + + // create a new empty array + Value array() { + return Value::take_ownership(json_array()); + } + + // create a new null value + Value null() { + return Value::take_ownership(json_null()); + } + + // load a file as a JSON value + Value load_file(const char* path, json_error_t* error) { + return Value::take_ownership(json_load_file(path, error)); + } + + // load a string as a JSON value + Value load_string(const char* string, json_error_t* error) { + return Value::take_ownership(json_loads(string, error)); + } + } // namespace json // stream JSON value out @@ -466,6 +466,6 @@ std::istream& operator>>(std::istream& is, json::Value& value) { while (is) tmp << static_cast(is.get()); // parse the buffered string - value = json::Value::load_string(tmp.str().c_str()); + value = json::load_string(tmp.str().c_str()); return is; } diff --git a/jansson.hpp b/jansson.hpp index 9df3961..fc81d98 100644 --- a/jansson.hpp +++ b/jansson.hpp @@ -150,9 +150,8 @@ namespace json { // get the underlying json_t inline json_t* as_json() const; - protected: // take ownership of a json_t (does not increase reference count) - static inline Basic _take(json_t* json); + static inline Basic take_ownership(json_t* json); private: // internal value pointer @@ -218,34 +217,6 @@ namespace json { // create reference to value explicit Value(json_t* json) : _private::ValueBase<_private::Basic>(json) {} - - // construct Value from input - static inline Value from(const char* value); - static inline Value from(const std::string& value); - static inline Value from(bool value); - static inline Value from(signed int value); - static inline Value from(unsigned int value); - static inline Value from(signed short value); - static inline Value from(unsigned short value); - static inline Value from(signed long value); - static inline Value from(unsigned long value); - static inline Value from(float value); - static inline Value from(double value); - - // create a new empty object - static inline Value object(); - - // create a new empty array - static inline Value array(); - - // create a new null value - static inline Value null(); - - // load a file as a JSON value - static inline Value load_file(const char* path, json_error_t* error = 0); - - // load a string as a JSON value - static inline Value load_string(const char* string, json_error_t* error = 0); }; // iterators over a JSON object @@ -290,6 +261,34 @@ namespace json { void* _iter; }; + // construct Value from input + inline Value from(const char* value); + inline Value from(const std::string& value); + inline Value from(bool value); + inline Value from(signed int value); + inline Value from(unsigned int value); + inline Value from(signed short value); + inline Value from(unsigned short value); + inline Value from(signed long value); + inline Value from(unsigned long value); + inline Value from(float value); + inline Value from(double value); + + // create a new empty object + inline Value object(); + + // create a new empty array + inline Value array(); + + // create a new null value + inline Value null(); + + // load a file as a JSON value + inline Value load_file(const char* path, json_error_t* error = 0); + + // load a string as a JSON value + inline Value load_string(const char* string, json_error_t* error = 0); + } // namespace json // stream JSON value out -- inefficient and not recommended for production use diff --git a/test.cpp b/test.cpp index cc10689..cfadd1c 100644 --- a/test.cpp +++ b/test.cpp @@ -4,8 +4,6 @@ #include "jansson.hpp" -using namespace std; - #define ASSERT_OP(lhs, rhs, op, m) \ do { \ if(!((lhs) op (rhs))) { \ @@ -21,11 +19,11 @@ using namespace std; #define ASSERT_TRUE(p, m) ASSERT_OP(p, true, ==, m) #define ASSERT_FALSE(p, m) ASSERT_OP(p, true, !=, m) -int main() { - json::Value e1(json::Value::load_file("test.json")); +int json_cpp_tests() { + json::Value e1(json::load_file("test.json")); json::Value e2(e1); json::Value e3; - json::Value e4(json::Value::load_string("{\"foo\": true, \"bar\": \"test\"}")); + json::Value e4(json::load_string("{\"foo\": true, \"bar\": \"test\"}")); ASSERT_TRUE(e1.is_object(), "e1 is not an object"); ASSERT_TRUE(e2.is_object(), "e2 is not an object"); @@ -51,46 +49,46 @@ int main() { i.next(); ASSERT_FALSE(i.valid(), "iterator has more values than expected"); - json::Value e5(json::Value::from(12.34)); + json::Value e5(json::from(12.34)); ASSERT_TRUE(e5.is_number(), "e5 is not a number after assignment"); ASSERT_EQ(e5.as_real(), 12.34, "e5 has incorrect value after assignment"); - json::Value e6(json::Value::from(true)); + json::Value e6(json::from(true)); ASSERT_TRUE(e6.is_boolean(), "e6 is not a boolean after assignment"); ASSERT_EQ(e6.as_boolean(), true, "e6 has incorrect value after assignment"); - json::Value e7(json::Value::from("foobar")); + json::Value e7(json::from("foobar")); ASSERT_TRUE(e7.is_string(), "e7 is not a string after assignment"); ASSERT_EQ(e7.as_string(), "foobar", "e7 has incorrect value after assignment"); - json::Value e8(json::Value::object()); + json::Value e8(json::object()); ASSERT_TRUE(e8.is_object(), "e8 is not an object after assignment"); - json::Value e9(json::Value::null()); + json::Value e9(json::null()); ASSERT_TRUE(e9.is_null(), "e9 is not null after assignment"); - json::Value e10(json::Value::array()); + json::Value e10(json::array()); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); - e10.set_at(0, json::Value::from("foobar")); + e10.set_at(0, json::from("foobar")); ASSERT_EQ(e10.size(), 1, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[0].as_string(), "foobar", "e10[0] has incorrect value after assignment"); - e10.set_at(1, json::Value::from("foobar")); + e10.set_at(1, json::from("foobar")); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[1].as_string(), "foobar", "e10[0] has incorrect value after assignment"); - e10.set_at(0, json::Value::from("barfoo")); + e10.set_at(0, json::from("barfoo")); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[0].as_string(), "barfoo", "e10[0] has incorrect value after assignment"); - e10.set_at(100, json::Value::null()); + e10.set_at(100, json::null()); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); - e10.insert_at(1, json::Value::from("new")); + e10.insert_at(1, json::from("new")); ASSERT_EQ(e10.size(), 3, "e10 has incorrect size after insert"); ASSERT_EQ(e10[1].as_string(), "new", "e10[1] has incorrect value after insert"); ASSERT_EQ(e10[2].as_string(), "foobar", "e10[2] has incorrect value after insert"); @@ -102,19 +100,19 @@ int main() { e10.clear(); ASSERT_EQ(e10.size(), 0, "e10 has incorrect number of elements after clear"); - json::Value e11(json::Value::object()); + json::Value e11(json::object()); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); - e11.set_key("foo", json::Value::from("test")); + e11.set_key("foo", json::from("test")); ASSERT_EQ(e11.size(), 1, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["foo"].as_string(), "test", "e11.foo has incorrect value after assignment"); - e11.set_key("foo", json::Value::from("again")); + e11.set_key("foo", json::from("again")); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); ASSERT_EQ(e11.size(), 1, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["foo"].as_string(), "again", "e11.foo has incorrect value after assignment"); - e11.set_key("bar", json::Value::from("test")); + e11.set_key("bar", json::from("test")); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); ASSERT_EQ(e11.size(), 2, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["bar"].as_string(), "test", "e11.foo has incorrect value after assignment"); @@ -122,11 +120,11 @@ int main() { e11.clear(); ASSERT_EQ(e11.size(), 0, "e11 has incorrect number of properties after clear"); - json::Value e12(json::Value::object()); - e12.set_key("foo", json::Value::from("test")); - e12.set_key("bar", json::Value::from(3)); + json::Value e12(json::object()); + e12.set_key("foo", json::from("test")); + e12.set_key("bar", json::from(3)); char* out_cstr = e12.save_string(0); - string out(out_cstr); + std::string out(out_cstr); free(out_cstr); ASSERT_EQ(out, "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); @@ -144,18 +142,18 @@ int main() { const json::Value e13(e12); ASSERT_EQ(e13["bar"].as_integer(), 3, "e13.bar has incorrect value after copy"); - json::Value e14(json::Value::object()); + json::Value e14(json::object()); ASSERT_TRUE(e14.is_object(), "e14 is not an object after construction"); - e14.set_key("foo", json::Value::object()); + e14.set_key("foo", json::object()); ASSERT_TRUE(e14["foo"].is_object(), "e14.foo is not an object after assignment"); - e14["foo"]["bar"] = json::Value::from(42); + e14["foo"]["bar"] = json::from(42); ASSERT_EQ(e14["foo"]["bar"].as_integer(), 42, "e14.foo.bar has incorrect value after assignment"); - json::Value e15(json::Value::array()); + json::Value e15(json::array()); ASSERT_TRUE(e15.is_array(), "e15 is not an array after construction"); - e15.set_at(0, json::Value::from(42)); + e15.set_at(0, json::from(42)); ASSERT_EQ(e15[0].as_integer(), 42, "e15[0] has incorrect value after assignment"); - e15[0] = json::Value::from("foo"); + e15[0] = json::from("foo"); ASSERT_EQ(e15[0].as_string(), "foo", "e15[0] has incorrecy value after assignment"); return 0; } From e0806677296e1d223adb02f0cbf0a03837bf893b Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Mon, 18 Jan 2010 19:24:25 -0800 Subject: [PATCH 35/38] replace json::from() with explicit Value() constructors --- jansson-impl.hpp | 90 ++++++++++++++++++++++++------------------------ jansson.hpp | 30 ++++++++-------- test.cpp | 30 ++++++++-------- 3 files changed, 75 insertions(+), 75 deletions(-) diff --git a/jansson-impl.hpp b/jansson-impl.hpp index 6242ed9..89242fa 100644 --- a/jansson-impl.hpp +++ b/jansson-impl.hpp @@ -328,6 +328,51 @@ namespace json { } } // namespace json::_private + + // construct Value::Value input + Value::Value(const char* value) { + _value = json_string(value); + } + + Value::Value(const std::string& value) { + _value = json_string(value.c_str()); + } + + Value::Value(bool value) { + _value = value ? json_true() : json_false(); + } + + Value::Value(signed int value) { + _value = json_integer(value); + } + + Value::Value(unsigned int value) { + _value = json_integer(value); + } + + Value::Value(signed short value) { + _value = json_integer(value); + } + + Value::Value(unsigned short value) { + _value = json_integer(value); + } + + Value::Value(signed long value) { + _value = json_integer(value); + } + + Value::Value(unsigned long value) { + _value = json_integer(value); + } + + Value::Value(float value) { + _value = json_real(value); + } + + Value::Value(double value) { + _value = json_real(value); + } // construct a new iterator for a given object Iterator::Iterator(const Value& value) : _object(value), _iter(0) { @@ -375,51 +420,6 @@ namespace json { return value(); } - // construct Value from input - Value from(const char* value) { - return Value::take_ownership(json_string(value)); - } - - Value from(const std::string& value) { - return from(value.c_str()); - } - - Value from(bool value) { - return Value::take_ownership(value ? json_true() : json_false()); - } - - Value from(signed int value) { - return Value::take_ownership(json_integer(value)); - } - - Value from(unsigned int value) { - return Value::take_ownership(json_integer(value)); - } - - Value from(signed short value) { - return Value::take_ownership(json_integer(value)); - } - - Value from(unsigned short value) { - return Value::take_ownership(json_integer(value)); - } - - Value from(signed long value) { - return Value::take_ownership(json_integer(value)); - } - - Value from(unsigned long value) { - return Value::take_ownership(json_integer(value)); - } - - Value from(float value) { - return Value::take_ownership(json_real(value)); - } - - Value from(double value) { - return Value::take_ownership(json_real(value)); - } - // create a new empty object Value object() { return Value::take_ownership(json_object()); diff --git a/jansson.hpp b/jansson.hpp index fc81d98..d3d11b3 100644 --- a/jansson.hpp +++ b/jansson.hpp @@ -151,9 +151,9 @@ namespace json { inline json_t* as_json() const; // take ownership of a json_t (does not increase reference count) - static inline Basic take_ownership(json_t* json); + inline static Basic take_ownership(json_t* json); - private: + protected: // internal value pointer json_t* _value; }; @@ -203,6 +203,19 @@ namespace json { // represents any JSON value class Value : public _private::ValueBase<_private::Basic> { public: + // construct Value from input + explicit inline Value(const char* value); + explicit inline Value(const std::string& value); + explicit inline Value(bool value); + explicit inline Value(signed int value); + explicit inline Value(unsigned int value); + explicit inline Value(signed short value); + explicit inline Value(unsigned short value); + explicit inline Value(signed long value); + explicit inline Value(unsigned long value); + explicit inline Value(float value); + explicit inline Value(double value); + // empty constructor Value() : _private::ValueBase<_private::Basic>() {} @@ -261,19 +274,6 @@ namespace json { void* _iter; }; - // construct Value from input - inline Value from(const char* value); - inline Value from(const std::string& value); - inline Value from(bool value); - inline Value from(signed int value); - inline Value from(unsigned int value); - inline Value from(signed short value); - inline Value from(unsigned short value); - inline Value from(signed long value); - inline Value from(unsigned long value); - inline Value from(float value); - inline Value from(double value); - // create a new empty object inline Value object(); diff --git a/test.cpp b/test.cpp index cfadd1c..d69c344 100644 --- a/test.cpp +++ b/test.cpp @@ -49,15 +49,15 @@ int json_cpp_tests() { i.next(); ASSERT_FALSE(i.valid(), "iterator has more values than expected"); - json::Value e5(json::from(12.34)); + json::Value e5(json::Value(12.34)); ASSERT_TRUE(e5.is_number(), "e5 is not a number after assignment"); ASSERT_EQ(e5.as_real(), 12.34, "e5 has incorrect value after assignment"); - json::Value e6(json::from(true)); + json::Value e6(json::Value(true)); ASSERT_TRUE(e6.is_boolean(), "e6 is not a boolean after assignment"); ASSERT_EQ(e6.as_boolean(), true, "e6 has incorrect value after assignment"); - json::Value e7(json::from("foobar")); + json::Value e7(json::Value("foobar")); ASSERT_TRUE(e7.is_string(), "e7 is not a string after assignment"); ASSERT_EQ(e7.as_string(), "foobar", "e7 has incorrect value after assignment"); @@ -70,16 +70,16 @@ int json_cpp_tests() { json::Value e10(json::array()); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); - e10.set_at(0, json::from("foobar")); + e10.set_at(0, json::Value("foobar")); ASSERT_EQ(e10.size(), 1, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[0].as_string(), "foobar", "e10[0] has incorrect value after assignment"); - e10.set_at(1, json::from("foobar")); + e10.set_at(1, json::Value("foobar")); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[1].as_string(), "foobar", "e10[0] has incorrect value after assignment"); - e10.set_at(0, json::from("barfoo")); + e10.set_at(0, json::Value("barfoo")); ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); ASSERT_EQ(e10[0].as_string(), "barfoo", "e10[0] has incorrect value after assignment"); @@ -88,7 +88,7 @@ int json_cpp_tests() { ASSERT_TRUE(e10.is_array(), "e10 is not an array after index assignment"); ASSERT_EQ(e10.size(), 2, "e10 has incorrect number of elements after assignment"); - e10.insert_at(1, json::from("new")); + e10.insert_at(1, json::Value("new")); ASSERT_EQ(e10.size(), 3, "e10 has incorrect size after insert"); ASSERT_EQ(e10[1].as_string(), "new", "e10[1] has incorrect value after insert"); ASSERT_EQ(e10[2].as_string(), "foobar", "e10[2] has incorrect value after insert"); @@ -103,16 +103,16 @@ int json_cpp_tests() { json::Value e11(json::object()); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); - e11.set_key("foo", json::from("test")); + e11.set_key("foo", json::Value("test")); ASSERT_EQ(e11.size(), 1, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["foo"].as_string(), "test", "e11.foo has incorrect value after assignment"); - e11.set_key("foo", json::from("again")); + e11.set_key("foo", json::Value("again")); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); ASSERT_EQ(e11.size(), 1, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["foo"].as_string(), "again", "e11.foo has incorrect value after assignment"); - e11.set_key("bar", json::from("test")); + e11.set_key("bar", json::Value("test")); ASSERT_TRUE(e11.is_object(), "e11 is not an object after property assignment"); ASSERT_EQ(e11.size(), 2, "e11 has incorrect number of properties after assignment"); ASSERT_EQ(e11["bar"].as_string(), "test", "e11.foo has incorrect value after assignment"); @@ -121,8 +121,8 @@ int json_cpp_tests() { ASSERT_EQ(e11.size(), 0, "e11 has incorrect number of properties after clear"); json::Value e12(json::object()); - e12.set_key("foo", json::from("test")); - e12.set_key("bar", json::from(3)); + e12.set_key("foo", json::Value("test")); + e12.set_key("bar", json::Value(3)); char* out_cstr = e12.save_string(0); std::string out(out_cstr); free(out_cstr); @@ -146,14 +146,14 @@ int json_cpp_tests() { ASSERT_TRUE(e14.is_object(), "e14 is not an object after construction"); e14.set_key("foo", json::object()); ASSERT_TRUE(e14["foo"].is_object(), "e14.foo is not an object after assignment"); - e14["foo"]["bar"] = json::from(42); + e14["foo"]["bar"] = json::Value(42); ASSERT_EQ(e14["foo"]["bar"].as_integer(), 42, "e14.foo.bar has incorrect value after assignment"); json::Value e15(json::array()); ASSERT_TRUE(e15.is_array(), "e15 is not an array after construction"); - e15.set_at(0, json::from(42)); + e15.set_at(0, json::Value(42)); ASSERT_EQ(e15[0].as_integer(), 42, "e15[0] has incorrect value after assignment"); - e15[0] = json::from("foo"); + e15[0] = json::Value("foo"); ASSERT_EQ(e15[0].as_string(), "foo", "e15[0] has incorrecy value after assignment"); return 0; } From c9b33e33867ca101b50d54f36057463ca353ec29 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Mon, 18 Jan 2010 21:36:02 -0800 Subject: [PATCH 36/38] integrate jansson.hpp into build and test suite --- configure.ac | 1 + src/Makefile.am | 2 +- test/.gitignore | 1 + test/suites/api/Makefile.am | 4 +++- test/suites/api/test_cpp.cpp | 8 ++++---- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index d28a5e4..43ce1d0 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,7 @@ AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC +AC_PROG_CXX AC_PROG_LIBTOOL # Checks for libraries. diff --git a/src/Makefile.am b/src/Makefile.am index 87123a0..d5c20e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -include_HEADERS = jansson.h +include_HEADERS = jansson.h jansson.hpp jansson-impl.hpp lib_LTLIBRARIES = libjansson.la libjansson_la_SOURCES = \ diff --git a/test/.gitignore b/test/.gitignore index a960c50..065b4ea 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -7,3 +7,4 @@ suites/api/test_load suites/api/test_number suites/api/test_object suites/api/test_simple +suites/api/test_cpp diff --git a/test/suites/api/Makefile.am b/test/suites/api/Makefile.am index 772f75a..35f1ee0 100644 --- a/test/suites/api/Makefile.am +++ b/test/suites/api/Makefile.am @@ -5,7 +5,8 @@ check_PROGRAMS = \ test_load \ test_simple \ test_number \ - test_object + test_object \ + test_cpp test_array_SOURCES = test_array.c util.h test_copy_SOURCES = test_copy.c util.h @@ -13,6 +14,7 @@ test_load_SOURCES = test_load.c util.h test_simple_SOURCES = test_simple.c util.h test_number_SOURCES = test_number.c util.h test_object_SOURCES = test_object.c util.h +test_cpp_SOURCES = test_cpp.cpp AM_CPPFLAGS = -I$(top_srcdir)/src AM_CFLAGS = -Wall -Werror diff --git a/test/suites/api/test_cpp.cpp b/test/suites/api/test_cpp.cpp index d69c344..edcac77 100644 --- a/test/suites/api/test_cpp.cpp +++ b/test/suites/api/test_cpp.cpp @@ -19,8 +19,8 @@ #define ASSERT_TRUE(p, m) ASSERT_OP(p, true, ==, m) #define ASSERT_FALSE(p, m) ASSERT_OP(p, true, !=, m) -int json_cpp_tests() { - json::Value e1(json::load_file("test.json")); +int main() { + json::Value e1(json::load_file("suites/api/test.json")); json::Value e2(e1); json::Value e3; json::Value e4(json::load_string("{\"foo\": true, \"bar\": \"test\"}")); @@ -126,7 +126,7 @@ int json_cpp_tests() { char* out_cstr = e12.save_string(0); std::string out(out_cstr); free(out_cstr); - ASSERT_EQ(out, "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); + ASSERT_EQ(out, "{\"bar\": 3, \"foo\": \"test\"}", "object did not serialize as expected"); std::istringstream instr(out); instr >> e12; @@ -137,7 +137,7 @@ int json_cpp_tests() { std::ostringstream outstr; outstr << e12; - ASSERT_EQ(instr.str(), "{\"bar\": 3,\"foo\": \"test\"}\n", "object did not serialize as expected"); + ASSERT_EQ(instr.str(), "{\"bar\": 3, \"foo\": \"test\"}", "object did not serialize as expected"); const json::Value e13(e12); ASSERT_EQ(e13["bar"].as_integer(), 3, "e13.bar has incorrect value after copy"); From 56687e9b56e92ea44e3a9c5e90434833edadea36 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Mon, 18 Jan 2010 21:55:25 -0800 Subject: [PATCH 37/38] add meaningful copyright to jansson.hpp --- src/jansson.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/jansson.hpp b/src/jansson.hpp index d3d11b3..1bd18b1 100644 --- a/src/jansson.hpp +++ b/src/jansson.hpp @@ -1,8 +1,6 @@ -// janssonxx - C++ wrapper for jansson +// Copyright (c) 2010 Sean Middleditch // -// author: Sean Middleditch -// -// janssonxx is free software; you can redistribute it and/or modify +// Jansson is free software; you can redistribute it and/or modify // it under the terms of the MIT license. See LICENSE for details. #if !defined(JANSSON_HPP) From 38950b081cae9b231b5474d4cb861f8fa2b1d099 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Mon, 18 Jan 2010 21:55:41 -0800 Subject: [PATCH 38/38] add meaningful copyright to jansson-impl.hpp too --- src/jansson-impl.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/jansson-impl.hpp b/src/jansson-impl.hpp index 89242fa..dbf94df 100644 --- a/src/jansson-impl.hpp +++ b/src/jansson-impl.hpp @@ -1,8 +1,6 @@ -// janssonxx - C++ wrapper for jansson, implementation file +// Copyright (c) 2010 Sean Middleditch // -// author: Sean Middleditch -// -// janssonxx is free software; you can redistribute it and/or modify +// Jansson is free software; you can redistribute it and/or modify // it under the terms of the MIT license. See LICENSE for details. #if !defined(IN_JANSSON_HPP)