summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2014-07-04 10:26:58 +0000
committerrandomdan <randomdan@localhost>2014-07-04 10:26:58 +0000
commitb473f8427f78d57504df4d312b1b0e042f10be2d (patch)
tree5e3d92a9151ee7a56c3a353430d1a7c61c696444
parentFix handling of Byte data type (treat as integer) (diff)
downloadslicer-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.jam2
-rw-r--r--slicer/json/Jamfile.jam23
-rw-r--r--slicer/json/serializer.cpp252
-rw-r--r--slicer/json/serializer.h25
-rw-r--r--slicer/slicer/modelParts.h23
-rw-r--r--slicer/test/Jamfile.jam1
-rw-r--r--slicer/test/initial/builtins2.json1
-rw-r--r--slicer/test/initial/optionals-areset2.json1
-rw-r--r--slicer/test/run-slicer.cpp15
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;
}