diff options
| author | Dan Goodliffe <dan@randomdan.homeip.net> | 2018-04-02 12:18:29 +0100 | 
|---|---|---|
| committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2018-04-02 12:18:36 +0100 | 
| commit | df567eff902ed3c550dbdabff6e4c69d858ccbe1 (patch) | |
| tree | 341a2691d7d24226099aa65ae29dc53145980fdc | |
| parent | Add some nice cxxflags (diff) | |
| download | libjsonpp-df567eff902ed3c550dbdabff6e4c69d858ccbe1.tar.bz2 libjsonpp-df567eff902ed3c550dbdabff6e4c69d858ccbe1.tar.xz libjsonpp-df567eff902ed3c550dbdabff6e4c69d858ccbe1.zip | |
Refactor
Refactor to reduce constant creation of new serializer object.
Use standard C++ stream control for formatting.
| -rw-r--r-- | libjsonpp/jsonpp.h | 9 | ||||
| -rw-r--r-- | libjsonpp/serialize.cpp | 230 | ||||
| -rw-r--r-- | libjsonpp/testParse.cpp | 2 | ||||
| -rw-r--r-- | libjsonpp/testSerialise.cpp | 15 | 
4 files changed, 120 insertions, 136 deletions
| diff --git a/libjsonpp/jsonpp.h b/libjsonpp/jsonpp.h index 45c7415..df628ae 100644 --- a/libjsonpp/jsonpp.h +++ b/libjsonpp/jsonpp.h @@ -32,21 +32,12 @@ namespace json {  			Value(const X & x) : VT(x) { }  	}; -	Object parseObject(Glib::ustring::const_iterator &); -	Object parseObject(const Glib::ustring &);  	Value parseValue(std::istream &);  	Value parseValue(std::istream &, const std::string & encoding);  	Value parseValue(const Glib::ustring & s);  	Value parseValue(Glib::ustring::const_iterator & s); -	void serializeObject(const Object &, std::ostream & s, const std::string & encoding);  	void serializeValue(const Value &, std::ostream & s, const std::string & encoding); -	void serializeArray(const Array &, std::ostream & s, const std::string & encoding); -	void serializeString(const String &, std::ostream & s, const std::string & encoding); -	void serializeNumber(const Number &, std::ostream & s, const std::string & encoding); -	void serializeBoolean(const Boolean &, std::ostream & s, const std::string & encoding); -	void serializeNull(const Null &, std::ostream & s, const std::string & encoding); -	Glib::ustring serializeObject(const Object &, const std::string & encoding);  }  #pragma GCC visibility pop diff --git a/libjsonpp/serialize.cpp b/libjsonpp/serialize.cpp index 97cf7ba..7c5cd06 100644 --- a/libjsonpp/serialize.cpp +++ b/libjsonpp/serialize.cpp @@ -1,149 +1,127 @@  #include "jsonpp.h"  #include <glibmm/convert.h>  #include <ios> +#include <iomanip>  namespace json { +	const std::string null("null"); +	const std::string utf8("utf-8"); +  	class JsonSerialize : public boost::static_visitor<> {  		public:  			JsonSerialize(std::ostream & out, const std::string & encoding) : -				o(out), +				s(out),  				e(encoding) { +					s << std::boolalpha // for Boolean +						<< std::defaultfloat // for Number +						<< std::setfill('0') // for String \uNNNN +						; +				} +			void operator()(const Value & v) const { +				boost::apply_visitor(*this, v);  			} -			void operator()(const String & s) const { -				serializeString(s, o, e); -			} -			void operator()(const Number & s) const { -				serializeNumber(s, o, e); -			} -			void operator()(const Array & s) const { -				serializeArray(s, o, e); +			void operator()(const std::string & str) const { +				(*this)(str, e);  			} -			void operator()(const Object & s) const { -				serializeObject(s, o, e); +			void operator()(const String & str) const { +				(*this)(str, e);  			} -			void operator()(const Null & s) const { -				serializeNull(s, o, e); +			void operator()(const String & str, const std::string & enc) const { +				if (!enc.empty()) { +					serializeString(Glib::convert(str, enc, utf8)); +				} +				else { +					serializeString(str); +				}  			} -			void operator()(const Boolean & s) const { -				serializeBoolean(s, o, e); +			void serializeString(const String & str) const { +				s << '"'; +				for (auto i = str.begin(); i != str.end(); ) { +					const auto start = i; +					while (i != str.end() && *i >= 32 && *i != '/' && *i != '"' && *i != '\\') { +						i++; +					} +					if (start == str.begin() && i == str.end()) { +						s << str.raw(); +						break; +					} +					else if (start != i) { +						s << Glib::ustring(start, i).raw(); +					} +					while (i != str.end() && (*i < 32 || *i == '/' || *i == '"' || *i == '\\')) { +						const gunichar & c = *i; +						switch (c) { +							case '\f': +								s << "\\f"; +								break; +							case '\t': +								s << "\\t"; +								break; +							case '\n': +								s << "\\n"; +								break; +							case '\b': +								s << "\\b"; +								break; +							case '\r': +								s << "\\r"; +								break; +							case '/': +								s << "\\/"; +								break; +							case '\\': +								s << "\\\\"; +								break; +							case '"': +								s << "\\\""; +								break; +							default: +								s << "\\u" << std::setw(4) << std::hex << c << std::setw(1); +								break; +						} +						i++; +					} +				} +				s << '"';  			} -		private: -			std::ostream & o; -			std::string e; -	}; - -	void serializeObject(const Object & o, std::ostream & s, const std::string & renc) { -		std::string enc(renc == "utf-8" ? std::string() : renc); -		s << std::boolalpha; -		s << std::fixed; -		s << '{'; -		for (const Object::value_type & v : o) { -			if (&v != &*o.begin()) { -				s << ','; +			void operator()(const Number & n) const { +				s << std::dec << n;  			} -			serializeString(v.first, s, enc); -			s << ':'; -			serializeValue(*v.second, s, enc); -		} -		s << '}'; -	} - -	void serializeValue(const Value & v, std::ostream & s, const std::string & enc) { -		boost::apply_visitor(JsonSerialize(s, enc), v); -	} - -	void serializeArray(const Array & a, std::ostream & s, const std::string & enc) { -		s << '['; -		for (const Array::value_type & v : a) { -			if (&v != &*a.begin()) { -				s << ','; +			void operator()(const Array & a) const { +				s << '['; +				for (const Array::value_type & v : a) { +					if (&v != &*a.begin()) { +						s << ','; +					} +					(*this)(*v); +				} +				s << ']';  			} -			serializeValue(*v, s, enc); -		} -		s << ']'; -	} - -	void serializeString(const String & str, std::ostream & s) { -		s << '"'; -		for (auto i = str.begin(); i != str.end(); ) { -			auto start = i; -			while (i != str.end() && *i >= 32 && *i != '/' && *i != '"' && *i != '\\') { -				i++; +			void operator()(const Object & o) const { +				s << '{'; +				for (const Object::value_type & v : o) { +					if (&v != &*o.begin()) { +						s << ','; +					} +					(*this)(v.first); +					s << ':'; +					(*this)(*v.second); +				} +				s << '}';  			} -			if (start == str.begin() && i == str.end()) { -				s << str.raw(); -				break; +			void operator()(const Null &) const { +				s << null;  			} -			else if (start != i) { -				s << Glib::ustring(start, i).raw(); +			void operator()(const Boolean & b) const { +				s << b;  			} -			while (i != str.end() && (*i < 32 || *i == '/' || *i == '"' || *i == '\\')) { -				gunichar c = *i; -				switch (c) { -					case '\f': -						s << "\\f"; -						break; -					case '\t': -						s << "\\t"; -						break; -					case '\n': -						s << "\\n"; -						break; -					case '\b': -						s << "\\b"; -						break; -					case '\r': -						s << "\\r"; -						break; -					case '/': -						s << "\\/"; -						break; -					case '\\': -						s << "\\\\"; -						break; -					case '"': -						s << "\\\""; -						break; -					default: -						char buf[7]; -						snprintf(buf, sizeof(buf), "\\u%04x", c); -						s << buf; -						break; -				} -				i++; -			} -		} -		s << '"'; -	} - -	void serializeString(const String & str, std::ostream & o, const std::string & encoding) { -		if (!encoding.empty()) { -			std::stringstream s; -			serializeString(str, s); -			o << Glib::convert(s.str(), encoding, "utf-8"); -		} -		else { -			serializeString(str, o); -		} -	} - -	void serializeNumber(const Number & n, std::ostream & s, const std::string & ) { -		s.unsetf(std::ios::fixed); -		s << n; -	} - -	void serializeBoolean(const Boolean & b, std::ostream & s, const std::string & ) { -		s << (b ? "true" : "false"); -	} - -	void serializeNull(const Null &, std::ostream & s, const std::string & ) { -		s << "null"; -	} +		private: +			std::ostream & s; +			const std::string & e; +	}; -	Glib::ustring serializeObject(const Object & o, const std::string & enc) { -		std::stringstream out; -		serializeObject(o, out, enc); -		return out.str(); +	void serializeValue(const Value & v, std::ostream & s, const std::string & enc) { +		JsonSerialize(s, enc)(v);  	}  } diff --git a/libjsonpp/testParse.cpp b/libjsonpp/testParse.cpp index 77fe975..30cf85e 100644 --- a/libjsonpp/testParse.cpp +++ b/libjsonpp/testParse.cpp @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE( parse_string_simple )  BOOST_AUTO_TEST_CASE( parse_object_withStringContainingQuote )  {  	const Glib::ustring val(" { \"key1\": \"value1\", \"key2\": \"value\\\"2\\\"\", \"key3\": 3 } "); -	auto obj = json::parseObject(val); +	auto obj = boost::get<json::Object>(json::parseValue(val));  	BOOST_REQUIRE_EQUAL(3, obj.size());  	BOOST_REQUIRE_EQUAL("value1", boost::get<json::String>(*obj["key1"]));  	BOOST_REQUIRE_EQUAL("value\"2\"", boost::get<json::String>(*obj["key2"])); diff --git a/libjsonpp/testSerialise.cpp b/libjsonpp/testSerialise.cpp index fb90930..e1d7af2 100644 --- a/libjsonpp/testSerialise.cpp +++ b/libjsonpp/testSerialise.cpp @@ -81,6 +81,21 @@ BOOST_AUTO_TEST_CASE( serialise_whitespace )  	BOOST_REQUIRE_EQUAL("\"\\r\\n\\t\"", writeString(Glib::ustring("\r\n\t")));  } +BOOST_AUTO_TEST_CASE( serialise_control ) +{ +	BOOST_REQUIRE_EQUAL("\"\\b\\f\"", writeString(Glib::ustring("\b\f"))); +} + +BOOST_AUTO_TEST_CASE( serialise_slashes ) +{ +	BOOST_REQUIRE_EQUAL("\"\\\\\\/\"", writeString(Glib::ustring("\\/"))); +} + +BOOST_AUTO_TEST_CASE( serialise_other ) +{ +	BOOST_REQUIRE_EQUAL("\"\\u000b\\u0007\"", writeString(Glib::ustring("\v\a"))); +} +  BOOST_AUTO_TEST_CASE( serialise_quotes )  {  	BOOST_REQUIRE_EQUAL("\"string with \\\" in\"", writeString(Glib::ustring("string with \" in"))); | 
