diff options
| author | randomdan <randomdan@localhost> | 2014-07-04 10:26:58 +0000 | 
|---|---|---|
| committer | randomdan <randomdan@localhost> | 2014-07-04 10:26:58 +0000 | 
| commit | b473f8427f78d57504df4d312b1b0e042f10be2d (patch) | |
| tree | 5e3d92a9151ee7a56c3a353430d1a7c61c696444 | |
| parent | Fix handling of Byte data type (treat as integer) (diff) | |
| download | slicer-b473f8427f78d57504df4d312b1b0e042f10be2d.tar.bz2 slicer-b473f8427f78d57504df4d312b1b0e042f10be2d.tar.xz slicer-b473f8427f78d57504df4d312b1b0e042f10be2d.zip | |
Adds core support for model part approximate type (complex, simple, sequence, etc)
Adds support for JSON
| -rw-r--r-- | slicer/Jamfile.jam | 2 | ||||
| -rw-r--r-- | slicer/json/Jamfile.jam | 23 | ||||
| -rw-r--r-- | slicer/json/serializer.cpp | 252 | ||||
| -rw-r--r-- | slicer/json/serializer.h | 25 | ||||
| -rw-r--r-- | slicer/slicer/modelParts.h | 23 | ||||
| -rw-r--r-- | slicer/test/Jamfile.jam | 1 | ||||
| -rw-r--r-- | slicer/test/initial/builtins2.json | 1 | ||||
| -rw-r--r-- | slicer/test/initial/optionals-areset2.json | 1 | ||||
| -rw-r--r-- | slicer/test/run-slicer.cpp | 15 | 
9 files changed, 339 insertions, 4 deletions
| diff --git a/slicer/Jamfile.jam b/slicer/Jamfile.jam index b6de7a4..04fc453 100644 --- a/slicer/Jamfile.jam +++ b/slicer/Jamfile.jam @@ -3,7 +3,9 @@ import package ;  build-project tool ;  build-project slicer ;  build-project xml ; +build-project json ;  build-project test ;  package.install install : <install-source-root>. : tool//slicer : slicer//slicer : [ glob slicer/*.h ] ;  package.install install-xml : <install-source-root>. : : xml//slicer-xml : [ glob xml/*.h ] ; +package.install install-json : <install-source-root>. : : json//slicer-json : [ glob json/*.h ] ; diff --git a/slicer/json/Jamfile.jam b/slicer/json/Jamfile.jam new file mode 100644 index 0000000..27022ee --- /dev/null +++ b/slicer/json/Jamfile.jam @@ -0,0 +1,23 @@ +alias glibmm : : : : +	<cflags>"`pkg-config --cflags glibmm-2.4`" +	<linkflags>"`pkg-config --libs glibmm-2.4`" +	; + +lib jsonpp : : : : +	<cflags>"`pkg-config --cflags glibmm-2.4`" +	; +	 +lib boost_system ; +lib boost_filesystem ; +lib IceUtil ; + +lib slicer-json : +	[ glob *.cpp ] +	: +	<include>.. +	<library>boost_system +	<library>boost_filesystem +	<library>IceUtil +	<library>jsonpp +	<library>glibmm +	; diff --git a/slicer/json/serializer.cpp b/slicer/json/serializer.cpp new file mode 100644 index 0000000..e9cd58c --- /dev/null +++ b/slicer/json/serializer.cpp @@ -0,0 +1,252 @@ +#include "serializer.h" +#include <jsonpp.h> +#include <boost/lexical_cast.hpp> +#include <boost/bind.hpp> +#include <stdexcept> +#include <fstream> +#include <glibmm/ustring.h> + +namespace Slicer { +	class JsonValueSource : public ValueSource { +		public: +			JsonValueSource(const json::Value & s) : +				value(s) +			{ +			} + +			void set(bool & v) const override +			{ +				v = boost::get<bool>(value); +			} + +			void set(Ice::Byte & v) const override +			{ +				v = boost::numeric_cast<Ice::Byte>(boost::get<json::Number>(value)); +			} + +			void set(Ice::Short & v) const override +			{ +				v = boost::numeric_cast<Ice::Short>(boost::get<json::Number>(value)); +			} + +			void set(Ice::Int & v) const override +			{ +				v = boost::numeric_cast<Ice::Int>(boost::get<json::Number>(value)); +			} + +			void set(Ice::Long & v) const override +			{ +				v = boost::numeric_cast<Ice::Long>(boost::get<json::Number>(value)); +			} + +			void set(Ice::Float & v) const override +			{ +				v = boost::numeric_cast<Ice::Float>(boost::get<json::Number>(value)); +			} + +			void set(Ice::Double & v) const override +			{ +				v = boost::numeric_cast<Ice::Double>(boost::get<json::Number>(value)); +			} + +			void set(std::string & v) const override +			{ +				v = boost::get<json::String>(value); +			} + +		protected: +			const json::Value & value; +	}; + +	class JsonValueTarget : public ValueTarget { +		public: +			JsonValueTarget(json::Value & t) : +				target(t) +			{ +				target = json::Null(); +			} + +			virtual void get(const bool & value) const +			{ +				target = value; +			} + +			virtual void get(const Ice::Byte & value) const +			{ +				target = boost::numeric_cast<json::Number>(value); +			} + +			virtual void set(const Ice::Short & value) const +			{ +				target = boost::numeric_cast<json::Number>(value); +			} + +			virtual void get(const Ice::Int & value) const +			{ +				target = boost::numeric_cast<json::Number>(value); +			} + +			virtual void get(const Ice::Long & value) const +			{ +				target = boost::numeric_cast<json::Number>(value); +			} + +			virtual void get(const Ice::Float & value) const +			{ +				target = boost::numeric_cast<json::Number>(value); +			} + +			virtual void get(const Ice::Double & value) const +			{ +				target = boost::numeric_cast<json::Number>(value); +			} + +			virtual void get(const std::string & value) const +			{ +				target = value; +			} + +		private: +			json::Value & target; +	}; + +	class DocumentTreeIterate : public boost::static_visitor<> { +		public: +			DocumentTreeIterate(ModelPartPtr mp) : modelPart(mp) +			{ +			} +			template<typename SimpleT> +			void operator()(const SimpleT & v) const +			{ +				modelPart->Create(); +				modelPart->SetValue(new JsonValueSource(v)); +				modelPart->Complete(); +			} +			void operator()(const json::Null &) const +			{ +				modelPart->Complete(); +			} +			void operator()(const json::Object & o) const +			{ +				modelPart->Create(); +				BOOST_FOREACH(const auto & element, o) { +					auto emp = modelPart->GetChild(element.first); +					if (emp) { +						emp->Create(); +						boost::apply_visitor(DocumentTreeIterate(emp), *element.second); +				emp->Complete(); +					} +				} +				modelPart->Complete(); +			} +			void operator()(const json::Array & a) const +			{ +				modelPart->Create(); +				BOOST_FOREACH(const auto & element, a) { +					auto emp = modelPart->GetChild(std::string()); +					if (emp) { +						emp->Create(); +						boost::apply_visitor(DocumentTreeIterate(emp), *element); +				emp->Complete(); +					} +				} +				modelPart->Complete(); +			} +		private: +			ModelPartPtr modelPart; +	}; + +	void +	Json::ModelTreeIterateSeq(json::Value * n, ModelPartPtr mp) +	{ +		auto & arr = boost::get<json::Array &>(*n); +		arr.push_back(json::ValuePtr(new json::Value())); +		ModelTreeIterateRoot(arr.back().get(), mp); +	} + +	void +	Json::ModelTreeIterate(json::Value * n, const std::string & name, ModelPartPtr mp) +	{ +		if (name.empty() || !n) { +			return; +		} +		if (mp) { +			switch (mp->GetType()) { +				case mpt_Null: +					boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value())}); +					return; +				case mpt_Simple: +					mp->GetValue(new JsonValueTarget(*boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value())}).first->second)); +					break; +				case mpt_Complex: +					{ +						auto nn = json::ValuePtr(new json::Value(json::Object())); +						if (auto typeId = mp->GetTypeId()) { +							boost::get<json::Object>(*nn).insert({"slicer-typeid", json::ValuePtr(new json::Value(*typeId))}); +							mp = mp->GetSubclassModelPart(*typeId); +						} +						mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, boost::get<json::Object>(*n).insert({name, nn}).first->second.get(), _1, _2)); +						break; +					} +				case mpt_Sequence: +				case mpt_Dictionary: +					mp->OnEachChild(boost::bind(&Json::ModelTreeIterateSeq, boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value(json::Array()))}).first->second.get(), _2)); +					break; +			} +		} +	} + +	void +	Json::ModelTreeIterateRoot(json::Value * n, ModelPartPtr mp) +	{ +		if (mp) { +			switch (mp->GetType()) { +				case mpt_Null: +					*n = json::Null(); +					return; +				case mpt_Simple: +					mp->GetValue(new JsonValueTarget(*n)); +					break; +				case mpt_Complex: +					*n = json::Object(); +					if (auto typeId = mp->GetTypeId()) { +						boost::get<json::Object>(*n).insert({"slicer-typeid", json::ValuePtr(new json::Value(*typeId))}); +						mp = mp->GetSubclassModelPart(*typeId); +					} +					mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, n, _1, _2)); +					break; +				case mpt_Sequence: +					*n = json::Array(); +					mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, n, _1, _2)); +					break; +				case mpt_Dictionary: +					*n = json::Array(); +					mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, n, _1, _2)); +					break; +			} +		} +	} + +	void +	Json::Deserialize(const boost::filesystem::path & path, ModelPartPtr modelRoot) +	{ +		std::ifstream inFile(path.string()); +		std::stringstream buffer; +		buffer << inFile.rdbuf(); +		Glib::ustring doc(buffer.str()); +		Glib::ustring::const_iterator itr = doc.begin(); +		json::Value obj = json::parseValue(itr); +		boost::apply_visitor(DocumentTreeIterate(modelRoot->GetChild(std::string())), obj); +	} + +	void +	Json::Serialize(const boost::filesystem::path & path, ModelPartPtr modelRoot) +	{ +		json::Value doc; +		modelRoot->OnEachChild(boost::bind(&Json::ModelTreeIterateRoot, &doc, _2)); +		std::ofstream outFile(path.string()); +		json::serializeValue(doc, outFile, "utf-8"); +	} +} + + diff --git a/slicer/json/serializer.h b/slicer/json/serializer.h new file mode 100644 index 0000000..0d70f21 --- /dev/null +++ b/slicer/json/serializer.h @@ -0,0 +1,25 @@ +#ifndef SLICER_JSON_H +#define SLICER_JSON_H + +#include <slicer/serializer.h> + +namespace json { +	class Value; +} + +namespace Slicer { +	class Json : public Serializer { +		public: +			virtual void Deserialize(const boost::filesystem::path &, ModelPartPtr) override; +			virtual void Serialize(const boost::filesystem::path &, ModelPartPtr) override; + +		protected: +			static void ModelTreeIterate(json::Value *, const std::string &, ModelPartPtr mp); +			static void ModelTreeIterateSeq(json::Value *, ModelPartPtr mp); +			static void ModelTreeIterateRoot(json::Value *, ModelPartPtr mp); +	}; +} + +#endif + + diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h index 28ab86d..ca1573a 100644 --- a/slicer/slicer/modelParts.h +++ b/slicer/slicer/modelParts.h @@ -60,6 +60,13 @@ namespace Slicer {  	typedef boost::function<ModelPartPtr(void *)> ClassRef;  	typedef std::map<std::string, ClassRef> ClassRefMap;  	ClassRefMap * & classRefMap(); +	enum ModelPartType { +		mpt_Null, +		mpt_Simple, +		mpt_Complex, +		mpt_Sequence, +		mpt_Dictionary, +	};  	class ModelPart : public IceUtil::Shared {  		public: @@ -69,6 +76,7 @@ namespace Slicer {  			virtual ModelPartPtr GetChild(const std::string & memberName) = 0;  			virtual ModelPartPtr GetSubclassModelPart(const std::string &);  			virtual TypeId GetTypeId() const; +			virtual ModelPartType GetType() const = 0;  			virtual void Create();  			virtual void Complete();  			virtual void SetValue(ValueSourcePtr); @@ -94,6 +102,7 @@ namespace Slicer {  			virtual void SetValue(ValueSourcePtr s) override { s->set(Member); }  			virtual void GetValue(ValueTargetPtr s) override { s->get(Member); }  			virtual bool HasValue() const override { return true; } +			virtual ModelPartType GetType() const { return mpt_Simple; }  		private:  			T & Member; @@ -160,6 +169,14 @@ namespace Slicer {  			virtual bool HasValue() const override { return OptionalMember; } +			virtual ModelPartType GetType() const +			{ +				if (HasValue()) { +					return modelPart->GetType(); +				} +				return mpt_Null; +			} +  		private:  			IceUtil::Optional< typename T::element_type > & OptionalMember;  			ModelPartPtr modelPart; @@ -217,6 +234,8 @@ namespace Slicer {  				return NULL;  			} +			virtual ModelPartType GetType() const { return mpt_Complex; } +  			virtual T * GetModel() = 0;  			typedef std::vector<HookPtr> Hooks; @@ -359,6 +378,8 @@ namespace Slicer {  			virtual bool HasValue() const override { return true; } +			virtual ModelPartType GetType() const { return mpt_Sequence; } +  		private:  			ModelPartPtr elementModelPart(typename T::value_type &) const; @@ -435,6 +456,8 @@ namespace Slicer {  			virtual bool HasValue() const override { return true; } +			virtual ModelPartType GetType() const { return mpt_Dictionary; } +  		private:  			T & dictionary;  			static std::string pairName; diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam index ebc6c25..1426704 100644 --- a/slicer/test/Jamfile.jam +++ b/slicer/test/Jamfile.jam @@ -57,4 +57,5 @@ unit-test run-slicer :  	<library>IceUtil  	<library>../slicer//slicer  	<library>../xml//slicer-xml +	<library>../json//slicer-json  ; diff --git a/slicer/test/initial/builtins2.json b/slicer/test/initial/builtins2.json new file mode 100644 index 0000000..ed9ee11 --- /dev/null +++ b/slicer/test/initial/builtins2.json @@ -0,0 +1 @@ +{"mbool":true,"mbyte":4.000000,"mdouble":3.062500,"mfloat":3.125000,"mint":80.000000,"mlong":800.000000,"mshort":40.000000,"mstring":"Sample text"} diff --git a/slicer/test/initial/optionals-areset2.json b/slicer/test/initial/optionals-areset2.json new file mode 100644 index 0000000..33bf12a --- /dev/null +++ b/slicer/test/initial/optionals-areset2.json @@ -0,0 +1 @@ +{"optClass":{"a":1.000000,"b":2.000000},"optDict":[{"key":10.000000,"value":{"a":11.000000,"b":12.000000}},{"key":13.000000,"value":{"a":14.000000,"b":15.000000}}],"optSeq":[{"a":3.000000,"b":4.000000},{"a":5.000000,"b":6.000000}],"optSimple":4.000000,"optStruct":{"a":1.000000,"b":2.000000}}
\ No newline at end of file diff --git a/slicer/test/run-slicer.cpp b/slicer/test/run-slicer.cpp index c6a1ed2..955b735 100644 --- a/slicer/test/run-slicer.cpp +++ b/slicer/test/run-slicer.cpp @@ -1,6 +1,7 @@  #include <slicer/parser.h>  #include <slicer/slicer.h>  #include <xml/serializer.h> +#include <json/serializer.h>  #include <boost/filesystem/convenience.hpp>  #include <boost/filesystem/operations.hpp>  #include <boost/format.hpp> @@ -12,21 +13,25 @@  namespace fs = boost::filesystem; -template<typename T, typename Serializer> +template<typename T, typename SerializerIn>  void  verify(const fs::path & root, const fs::path & tmp, const fs::path & infile, const boost::function<void(const T &)> & check = NULL)  {  	const fs::path input = root / "initial" / infile;  	const fs::path output = tmp / infile; +	const fs::path outputJson = tmp / fs::change_extension(infile, "json"); +	const fs::path outputXml = tmp / fs::change_extension(infile, "xml");  	fprintf(stderr, "%s : Deserialize\n", input.string().c_str()); -	IceInternal::Handle<T> p = Slicer::Deserialize<Serializer, T>(input); +	IceInternal::Handle<T> p = Slicer::Deserialize<SerializerIn, T>(input);  	if (check) {  		fprintf(stderr, "%s : Check1\n", input.string().c_str());  		check(*p);  	} -	fprintf(stderr, "%s : Serialize -> %s\n", input.string().c_str(), output.string().c_str()); -	Slicer::Serialize<Serializer>(p, output); +	fprintf(stderr, "%s : Serialize -> %s\n", input.string().c_str(), outputJson.string().c_str()); +	Slicer::Serialize<Slicer::Json>(p, outputJson); +	fprintf(stderr, "%s : Serialize -> %s\n", input.string().c_str(), outputXml.string().c_str()); +	Slicer::Serialize<Slicer::Xml>(p, outputXml);  	if (check) {  		fprintf(stderr, "%s : Check2\n", input.string().c_str());  		check(*p); @@ -108,6 +113,8 @@ main(int, char ** argv)  	verify<TestModule::Optionals, Slicer::Xml>(root, tmp, "optionals-areset.xml", checkOptionals_areset);  	verify<TestModule::InheritanceCont, Slicer::Xml>(root, tmp, "inherit-a.xml");  	verify<TestModule::InheritanceCont, Slicer::Xml>(root, tmp, "inherit-b.xml"); +	verify<TestModule::BuiltIns, Slicer::Json>(root, tmp, "builtins2.json", checkBuiltIns_valuesCorrect); +	verify<TestModule::Optionals, Slicer::Json>(root, tmp, "optionals-areset2.json", checkOptionals_areset);  	return 0;  } | 
