diff options
| -rw-r--r-- | slicer/slicer/modelParts.h | 86 | ||||
| -rw-r--r-- | slicer/slicer/parser.cpp | 124 | ||||
| -rw-r--r-- | slicer/slicer/parser.h | 12 | ||||
| -rw-r--r-- | slicer/test/Jamfile.jam | 1 | ||||
| -rw-r--r-- | slicer/test/do-slicer.cpp | 28 | ||||
| -rw-r--r-- | slicer/test/initial/conv-datetime.xml | 4 | ||||
| -rw-r--r-- | slicer/test/run-slicer.cpp | 45 | ||||
| -rw-r--r-- | slicer/test/types.ice | 15 | 
8 files changed, 293 insertions, 22 deletions
diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h index 6302b9f..41b0617 100644 --- a/slicer/slicer/modelParts.h +++ b/slicer/slicer/modelParts.h @@ -23,29 +23,55 @@ namespace Slicer {  			UnknownType(const std::string & n);  	}; -	class ValueTarget : public IceUtil::Shared { +	template <typename T> +	class TValueTarget {  		public: -			virtual void get(const bool &) const = 0; -			virtual void get(const Ice::Byte &) const = 0; -			virtual void get(const Ice::Short &) const = 0; -			virtual void get(const Ice::Int &) const = 0; -			virtual void get(const Ice::Long &) const = 0; -			virtual void get(const Ice::Float &) const = 0; -			virtual void get(const Ice::Double &) const = 0; -			virtual void get(const std::string &) const = 0; +			virtual void get(const T &) const = 0; +	}; +	class ValueTarget : public IceUtil::Shared, +			public TValueTarget<bool>, +			public TValueTarget<Ice::Byte>, +			public TValueTarget<Ice::Short>, +			public TValueTarget<Ice::Int>, +			public TValueTarget<Ice::Long>, +			public TValueTarget<Ice::Float>, +			public TValueTarget<Ice::Double>, +			public TValueTarget<std::string> { +		public: +			using TValueTarget<bool>::get; +			using TValueTarget<Ice::Byte>::get; +			using TValueTarget<Ice::Short>::get; +			using TValueTarget<Ice::Int>::get; +			using TValueTarget<Ice::Long>::get; +			using TValueTarget<Ice::Float>::get; +			using TValueTarget<Ice::Double>::get; +			using TValueTarget<std::string>::get;  	};  	typedef IceUtil::Handle<ValueTarget> ValueTargetPtr; -	class ValueSource : public IceUtil::Shared { +	template <typename T> +	class TValueSource { +		public: +			virtual void set(T &) const = 0; +	}; +	class ValueSource : public IceUtil::Shared, +			public TValueSource<bool>, +			public TValueSource<Ice::Byte>, +			public TValueSource<Ice::Short>, +			public TValueSource<Ice::Int>, +			public TValueSource<Ice::Long>, +			public TValueSource<Ice::Float>, +			public TValueSource<Ice::Double>, +			public TValueSource<std::string> {  		public: -			virtual void set(bool &) const = 0; -			virtual void set(Ice::Byte &) const = 0; -			virtual void set(Ice::Short &) const = 0; -			virtual void set(Ice::Int &) const = 0; -			virtual void set(Ice::Long &) const = 0; -			virtual void set(Ice::Float &) const = 0; -			virtual void set(Ice::Double &) const = 0; -			virtual void set(std::string &) const = 0; +			using TValueSource<bool>::set; +			using TValueSource<Ice::Byte>::set; +			using TValueSource<Ice::Short>::set; +			using TValueSource<Ice::Int>::set; +			using TValueSource<Ice::Long>::set; +			using TValueSource<Ice::Float>::set; +			using TValueSource<Ice::Double>::set; +			using TValueSource<std::string>::set;  	};  	typedef IceUtil::Handle<ValueSource> ValueSourcePtr; @@ -108,6 +134,30 @@ namespace Slicer {  			T & Member;  	}; +	template<typename T, typename M, T M::* MV> +	class ModelPartForConverted : public ModelPart { +		public: +			typedef T element_type; + +			ModelPartForConverted(T & h) : +				Member(h) +			{ +			} +			ModelPartForConverted(T * h) : +				Member(*h) +			{ +			} +			virtual void OnEachChild(const ChildHandler &) { } +			virtual ModelPartPtr GetChild(const std::string &) override { return NULL; } +			virtual void SetValue(ValueSourcePtr s) override; +			virtual void GetValue(ValueTargetPtr s) override; +			virtual bool HasValue() const override { return true; } +			virtual ModelPartType GetType() const { return mpt_Simple; } + +		private: +			T & Member; +	}; +  	template<typename T>  	class ModelPartForOptional : public ModelPart {  		public: diff --git a/slicer/slicer/parser.cpp b/slicer/slicer/parser.cpp index c2f2df7..6c65c1f 100644 --- a/slicer/slicer/parser.cpp +++ b/slicer/slicer/parser.cpp @@ -3,6 +3,9 @@  #include <Slice/Preprocessor.h>  #include <boost/foreach.hpp>  #include <boost/algorithm/string/predicate.hpp> +#include <boost/algorithm/string/classification.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/replace.hpp>  #include <Slice/CPlusPlusUtil.h>  #include <boost/shared_ptr.hpp>  #include <boost/filesystem/convenience.hpp> @@ -16,6 +19,62 @@ namespace Slicer {  	{  	} +	void +	Slicer::defineConversions(Slice::DataMemberPtr dm) const +	{ +		auto type = dm->type(); +		auto c = Slice::ContainedPtr::dynamicCast(dm->container()); +		auto conversions = getConversions(dm); +		BOOST_FOREACH(const auto & conversion, conversions) { +			fprintf(cpp, "%s %s(const %s &);\n", +					conversion.ExchangeType.c_str(), +					conversion.ConvertToExchangeFunc.c_str(), +					Slice::typeToString(type).c_str()); +			fprintf(cpp, "%s %s(const %s &);\n\n", +					Slice::typeToString(type).c_str(), +					conversion.ConvertToModelFunc.c_str(), +					conversion.ExchangeType.c_str()); +		} +		if (!conversions.empty()) { +			fprintf(cpp, "template<>\nvoid\n"); +			fprintf(cpp, "ModelPartForConverted< %s, %s::%s, &%s::%s::%s >::SetValue(ValueSourcePtr vsp)\n", +					Slice::typeToString(type).c_str(), +					modulePath().c_str(), c->name().c_str(), +					modulePath().c_str(), c->name().c_str(), dm->name().c_str()); +			fprintf(cpp, "{\n"); + +			BOOST_FOREACH(const auto & conversion, conversions) { +				fprintf(cpp, "\tif (auto vspt = dynamic_cast<TValueSource< %s > *>(vsp.get())) {\n", +						conversion.ExchangeType.c_str()); +				fprintf(cpp, "\t\t%s tmp;\n", +						conversion.ExchangeType.c_str()); +				fprintf(cpp, "\t\tvspt->set(tmp);\n"); +				fprintf(cpp, "\t\tMember = %s(tmp);\n", +						conversion.ConvertToModelFunc.c_str()); +				fprintf(cpp, "\t\treturn;\n"); +				fprintf(cpp, "\t}\n"); +			} +			fprintf(cpp, "}\n\n"); + +			fprintf(cpp, "template<>\nvoid\n"); +			fprintf(cpp, "ModelPartForConverted< %s, %s::%s, &%s::%s::%s >::GetValue(ValueTargetPtr vtp)\n", +					Slice::typeToString(type).c_str(), +					modulePath().c_str(), c->name().c_str(), +					modulePath().c_str(), c->name().c_str(), dm->name().c_str()); +			fprintf(cpp, "{\n"); + +			BOOST_FOREACH(const auto & conversion, conversions) { +				fprintf(cpp, "\tif (auto vtpt = dynamic_cast<TValueTarget< %s > *>(vtp.get())) {\n", +						conversion.ExchangeType.c_str()); +				fprintf(cpp, "\t\tvtpt->get(%s(Member));\n", +						conversion.ConvertToExchangeFunc.c_str()); +				fprintf(cpp, "\t\treturn;\n"); +				fprintf(cpp, "\t}\n"); +			} +			fprintf(cpp, "}\n\n"); +		} +	} +  	bool  	Slicer::visitUnitStart(const Slice::UnitPtr & u)  	{ @@ -40,6 +99,16 @@ namespace Slicer {  	{  		fprintf(cpp, "// Begin module %s\n\n", m->name().c_str());  		modules.push_back(m); +		BOOST_FOREACH(const auto & c, m->structs()) { +			BOOST_FOREACH(const auto & dm, c->dataMembers()) { +				defineConversions(dm); +			} +		} +		BOOST_FOREACH(const auto & c, m->classes()) { +			BOOST_FOREACH(const auto & dm, c->dataMembers()) { +				defineConversions(dm); +			} +		}  		return true;  	} @@ -116,6 +185,7 @@ namespace Slicer {  				t = Slice::ClassDefPtr::dynamicCast(dm->container())->declaration();  			}  			auto name = metaDataValue("slicer:name:", dm->getMetaData()); +			auto conversions = metaDataValues("slicer:conversion:", dm->getMetaData());  			fprintf(cpp, "\t\tnew ");  			auto type = dm->type();  			createNewModelPartPtrFor(t); @@ -128,13 +198,21 @@ namespace Slicer {  			if (dm->optional()) {  				fprintf(cpp, "ModelPartForOptional< ");  			} -			createNewModelPartPtrFor(type); -			fprintf(cpp, "< %s", -					Slice::typeToString(type).c_str()); +			if (!conversions.empty()) { +				fprintf(cpp, "ModelPartForConverted< %s, %s::%s, &%s::%s::%s >", +						Slice::typeToString(type).c_str(), +						modulePath().c_str(), c->name().c_str(), +						modulePath().c_str(), c->name().c_str(), dm->name().c_str()); +			} +			else { +				createNewModelPartPtrFor(type); +				fprintf(cpp, "< %s >", +						Slice::typeToString(type).c_str()); +			}  			if (dm->optional()) {  				fprintf(cpp, " > ");  			} -			fprintf(cpp, " > >(\"%s\"),\n", +			fprintf(cpp, " >(\"%s\"),\n",  					name ? name->c_str() : dm->name().c_str());  		}  	} @@ -269,6 +347,44 @@ namespace Slicer {  		return boost::optional<std::string>();  	} +	std::list<std::string> +	Slicer::metaDataValues(const std::string & prefix, const std::list<std::string> & metadata) +	{ +		std::list<std::string> mds; +		BOOST_FOREACH (const auto & md, metadata) { +			if (boost::algorithm::starts_with(md, prefix)) { +				mds.push_back(md.substr(prefix.length())); +			} +		} +		return mds; +	} + +	std::vector<std::string> +	Slicer::metaDataSplit(const std::string & metadata) +	{ +		std::vector<std::string> parts; +		boost::algorithm::split(parts, metadata, boost::algorithm::is_any_of(":"), boost::algorithm::token_compress_off);  +		return parts;	 +	} + +	std::vector<Slicer::ConversionSpec> +	Slicer::getConversions(Slice::DataMemberPtr dm) +	{ +		std::vector<ConversionSpec> rtn; +		auto conversions = metaDataValues("slicer:conversion:", dm->getMetaData()); +		BOOST_FOREACH(const auto & conversion, conversions) { +			auto split = metaDataSplit(conversion); +			if (split.size() != 3) { +				throw std::runtime_error("conversion needs 3 parts type:toModelFunc:toExchangeFunc"); +			} +			BOOST_FOREACH(auto & p, split) { +				boost::algorithm::replace_all(p, ".", "::"); +			} +			rtn.push_back(ConversionSpec({split[0], split[1], split[2]})); +		} +		return rtn; +	} +  	void  	Slicer::Apply(const boost::filesystem::path & ice, const boost::filesystem::path & cpp)  	{ diff --git a/slicer/slicer/parser.h b/slicer/slicer/parser.h index 816738d..64d961f 100644 --- a/slicer/slicer/parser.h +++ b/slicer/slicer/parser.h @@ -10,6 +10,13 @@ namespace Slicer {  	class Slicer : public Slice::ParserVisitor {  		public: +			class ConversionSpec { +				public: +					std::string ExchangeType; +					std::string ConvertToModelFunc; +					std::string ConvertToExchangeFunc; +			}; +  			Slicer(FILE * c);  			static void Apply(const boost::filesystem::path & ice, const boost::filesystem::path & cpp); @@ -38,7 +45,12 @@ namespace Slicer {  			std::string modulePath() const; +			void defineConversions(Slice::DataMemberPtr dm) const; +  			static boost::optional<std::string> metaDataValue(const std::string & prefix, const std::list<std::string> & metadata); +			static std::list<std::string> metaDataValues(const std::string & prefix, const std::list<std::string> & metadata); +			static std::vector<std::string> metaDataSplit(const std::string & metadata); +			static std::vector<ConversionSpec> getConversions(Slice::DataMemberPtr);  			FILE * cpp;  			std::vector<Slice::ModulePtr> modules; diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam index 1426704..4a149a8 100644 --- a/slicer/test/Jamfile.jam +++ b/slicer/test/Jamfile.jam @@ -34,6 +34,7 @@ unit-test do-slicer :  	common  	do-slicer.cpp  	: +	<linkflags>-rdynamic  	<library>dl  	<include>..  	<library>pthread diff --git a/slicer/test/do-slicer.cpp b/slicer/test/do-slicer.cpp index 30c5cfb..7607ff2 100644 --- a/slicer/test/do-slicer.cpp +++ b/slicer/test/do-slicer.cpp @@ -9,6 +9,34 @@  namespace fs = boost::filesystem; +namespace Slicer { +	// These are the conversion helpers defined used in types.ice, they're not called in this test, but +	// need to exist for the dynamic load to complete +	boost::posix_time::ptime +	dateTimeToPTime(const ::TestModule::DateTime &) +	{ +		throw std::runtime_error("Not implemented"); +	} + +	::TestModule::DateTime +	ptimeToDateTime(const boost::posix_time::ptime &) +	{ +		throw std::runtime_error("Not implemented"); +	} + +	std::string +	dateTimeToString(const ::TestModule::DateTime &) +	{ +		throw std::runtime_error("Not implemented"); +	} + +	::TestModule::DateTime +	stringToDateTime(const std::string &) +	{ +		throw std::runtime_error("Not implemented"); +	} +} +  int  main(int, char ** argv)  { diff --git a/slicer/test/initial/conv-datetime.xml b/slicer/test/initial/conv-datetime.xml new file mode 100644 index 0000000..b4678b4 --- /dev/null +++ b/slicer/test/initial/conv-datetime.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<DateTimeContainer> +  <dt>2014-Dec-25 12:13:14</dt> +</DateTimeContainer> diff --git a/slicer/test/run-slicer.cpp b/slicer/test/run-slicer.cpp index 0044c64..73d5be8 100644 --- a/slicer/test/run-slicer.cpp +++ b/slicer/test/run-slicer.cpp @@ -6,6 +6,7 @@  #include <json/serializer.h>  #include <boost/filesystem/convenience.hpp>  #include <boost/filesystem/operations.hpp> +#include <boost/numeric/conversion/cast.hpp>  #include <boost/format.hpp>  #include <boost/function.hpp>  #include <boost/assert.hpp> @@ -15,6 +16,49 @@  #include "helpers.h"  namespace fs = boost::filesystem; +#define SHORT(x) boost::numeric_cast< ::Ice::Short >(x) + +namespace Slicer { +	boost::posix_time::ptime +	dateTimeToPTime(const ::TestModule::DateTime &) +	{ +		throw std::runtime_error("Not implemented"); +	} + +	::TestModule::DateTime +	ptimeToDateTime(const boost::posix_time::ptime &) +	{ +		throw std::runtime_error("Not implemented"); +	} + +	std::string +	dateTimeToString(const ::TestModule::DateTime & in) +	{ +		char buf[BUFSIZ]; +		struct tm tm({ in.second, in.minute, in.hour, in.day, in.month, in.year, 0, 0, 0 +#ifdef _BSD_SOURCE +				, 0, 0 +#endif +				}); +		mktime(&tm); +		auto len = strftime(buf, BUFSIZ, "%Y-%b-%d %H:%M:%S", &tm); +		return std::string(buf, len); +	} + +	::TestModule::DateTime +	stringToDateTime(const std::string & in) +	{ +		struct tm tm; +		memset(&tm, 0, sizeof(struct tm)); +		auto end = strptime(in.c_str(), "%Y-%b-%d %H:%M:%S", &tm); +		if (!end || *end) { +			throw std::runtime_error("Invalid date string: " + in); +		} +		return ::TestModule::DateTime({ +				SHORT(tm.tm_year), SHORT(tm.tm_mon), SHORT(tm.tm_mday), +				SHORT(tm.tm_hour), SHORT(tm.tm_min), SHORT(tm.tm_sec)}); +	} +}  template<typename T, typename SerializerIn>  void @@ -200,6 +244,7 @@ main(int, char ** argv)  	verifyByFile<TestModule::Optionals, Slicer::XmlFile>(root, tmpf, "optionals-areset.xml", checkOptionals_areset);  	verifyByFile<TestModule::InheritanceCont, Slicer::XmlFile>(root, tmpf, "inherit-a.xml");  	verifyByFile<TestModule::InheritanceCont, Slicer::XmlFile>(root, tmpf, "inherit-b.xml"); +	verifyByFile<TestModule::DateTimeContainer, Slicer::XmlFile>(root, tmpf, "conv-datetime.xml");  	verifyByFile<TestModule::BuiltIns, Slicer::JsonFile>(root, tmpf, "builtins2.json", checkBuiltIns_valuesCorrect);  	verifyByFile<TestModule::Optionals, Slicer::JsonFile>(root, tmpf, "optionals-areset2.json", checkOptionals_areset); diff --git a/slicer/test/types.ice b/slicer/test/types.ice index d2fe1ab..1f484d3 100644 --- a/slicer/test/types.ice +++ b/slicer/test/types.ice @@ -1,4 +1,19 @@ +[["cpp:include:boost/date_time/posix_time/posix_time_types.hpp"]] +  module TestModule { +	struct DateTime { +		short year; +		short month; +		short day; +		short hour; +		short minute; +		short second; +	}; +	class DateTimeContainer { +		[	"slicer:conversion:boost.posix_time.ptime:ptimeToDateTime:dateTimeToPTime", +			"slicer:conversion:std.string:stringToDateTime:dateTimeToString" ] +		DateTime dt; +	};  	class BuiltIns {  		bool mbool;  		byte mbyte;  | 
