From fe8a20a09f732f6bc2ff38a97ea528b11eeeac57 Mon Sep 17 00:00:00 2001 From: randomdan Date: Fri, 4 Jul 2014 10:26:58 +0000 Subject: Adds core support for model part approximate type (complex, simple, sequence, etc) Adds support for JSON --- slicer/Jamfile.jam | 2 + slicer/json/Jamfile.jam | 23 +++ slicer/json/serializer.cpp | 252 +++++++++++++++++++++++++++++ slicer/json/serializer.h | 25 +++ slicer/slicer/modelParts.h | 23 +++ slicer/test/Jamfile.jam | 1 + slicer/test/initial/builtins2.json | 1 + slicer/test/initial/optionals-areset2.json | 1 + slicer/test/run-slicer.cpp | 15 +- 9 files changed, 339 insertions(+), 4 deletions(-) create mode 100644 slicer/json/Jamfile.jam create mode 100644 slicer/json/serializer.cpp create mode 100644 slicer/json/serializer.h create mode 100644 slicer/test/initial/builtins2.json create mode 100644 slicer/test/initial/optionals-areset2.json 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 : . : tool//slicer : slicer//slicer : [ glob slicer/*.h ] ; package.install install-xml : . : : xml//slicer-xml : [ glob xml/*.h ] ; +package.install install-json : . : : 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 : : : : + "`pkg-config --cflags glibmm-2.4`" + "`pkg-config --libs glibmm-2.4`" + ; + +lib jsonpp : : : : + "`pkg-config --cflags glibmm-2.4`" + ; + +lib boost_system ; +lib boost_filesystem ; +lib IceUtil ; + +lib slicer-json : + [ glob *.cpp ] + : + .. + boost_system + boost_filesystem + IceUtil + jsonpp + 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 +#include +#include +#include +#include +#include + +namespace Slicer { + class JsonValueSource : public ValueSource { + public: + JsonValueSource(const json::Value & s) : + value(s) + { + } + + void set(bool & v) const override + { + v = boost::get(value); + } + + void set(Ice::Byte & v) const override + { + v = boost::numeric_cast(boost::get(value)); + } + + void set(Ice::Short & v) const override + { + v = boost::numeric_cast(boost::get(value)); + } + + void set(Ice::Int & v) const override + { + v = boost::numeric_cast(boost::get(value)); + } + + void set(Ice::Long & v) const override + { + v = boost::numeric_cast(boost::get(value)); + } + + void set(Ice::Float & v) const override + { + v = boost::numeric_cast(boost::get(value)); + } + + void set(Ice::Double & v) const override + { + v = boost::numeric_cast(boost::get(value)); + } + + void set(std::string & v) const override + { + v = boost::get(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(value); + } + + virtual void set(const Ice::Short & value) const + { + target = boost::numeric_cast(value); + } + + virtual void get(const Ice::Int & value) const + { + target = boost::numeric_cast(value); + } + + virtual void get(const Ice::Long & value) const + { + target = boost::numeric_cast(value); + } + + virtual void get(const Ice::Float & value) const + { + target = boost::numeric_cast(value); + } + + virtual void get(const Ice::Double & value) const + { + target = boost::numeric_cast(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 + 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(*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(*n).insert({name, json::ValuePtr(new json::Value())}); + return; + case mpt_Simple: + mp->GetValue(new JsonValueTarget(*boost::get(*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(*nn).insert({"slicer-typeid", json::ValuePtr(new json::Value(*typeId))}); + mp = mp->GetSubclassModelPart(*typeId); + } + mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, boost::get(*n).insert({name, nn}).first->second.get(), _1, _2)); + break; + } + case mpt_Sequence: + case mpt_Dictionary: + mp->OnEachChild(boost::bind(&Json::ModelTreeIterateSeq, boost::get(*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(*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 + +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 ClassRef; typedef std::map 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 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 : IceUtil ../slicer//slicer ../xml//slicer-xml + ../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 #include #include +#include #include #include #include @@ -12,21 +13,25 @@ namespace fs = boost::filesystem; -template +template void verify(const fs::path & root, const fs::path & tmp, const fs::path & infile, const boost::function & 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 p = Slicer::Deserialize(input); + IceInternal::Handle p = Slicer::Deserialize(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(p, output); + fprintf(stderr, "%s : Serialize -> %s\n", input.string().c_str(), outputJson.string().c_str()); + Slicer::Serialize(p, outputJson); + fprintf(stderr, "%s : Serialize -> %s\n", input.string().c_str(), outputXml.string().c_str()); + Slicer::Serialize(p, outputXml); if (check) { fprintf(stderr, "%s : Check2\n", input.string().c_str()); check(*p); @@ -108,6 +113,8 @@ main(int, char ** argv) verify(root, tmp, "optionals-areset.xml", checkOptionals_areset); verify(root, tmp, "inherit-a.xml"); verify(root, tmp, "inherit-b.xml"); + verify(root, tmp, "builtins2.json", checkBuiltIns_valuesCorrect); + verify(root, tmp, "optionals-areset2.json", checkOptionals_areset); return 0; } -- cgit v1.2.3