summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2014-06-26 13:20:58 +0000
committerrandomdan <randomdan@localhost>2014-06-26 13:20:58 +0000
commit9b0fb1a52dd7b8db1dab98cebf7b928e4d921111 (patch)
tree346f7c2dfe4530f86b44d304a5b620ce3a4dce06
parentMove the name into the hook (diff)
downloadslicer-9b0fb1a52dd7b8db1dab98cebf7b928e4d921111.tar.bz2
slicer-9b0fb1a52dd7b8db1dab98cebf7b928e4d921111.tar.xz
slicer-9b0fb1a52dd7b8db1dab98cebf7b928e4d921111.zip
Adds support for classes with inheritance
Adds more unit tests and verifies written XML is the same as the initial
-rw-r--r--slicer/slicer/modelParts.cpp31
-rw-r--r--slicer/slicer/modelParts.h34
-rw-r--r--slicer/slicer/parser.cpp137
-rw-r--r--slicer/slicer/parser.h5
-rw-r--r--slicer/test/Jamfile.jam1
-rw-r--r--slicer/test/initial/builtins.xml8
-rw-r--r--slicer/test/initial/optionals-areset.xml42
-rw-r--r--slicer/test/initial/optionals-notset.xml5
-rw-r--r--slicer/test/run-slicer.cpp6
-rw-r--r--slicer/test/types.ice19
-rw-r--r--slicer/xml/serializer.cpp9
11 files changed, 202 insertions, 95 deletions
diff --git a/slicer/slicer/modelParts.cpp b/slicer/slicer/modelParts.cpp
index 9d33d51..4c05513 100644
--- a/slicer/slicer/modelParts.cpp
+++ b/slicer/slicer/modelParts.cpp
@@ -1,14 +1,45 @@
#include "modelParts.h"
namespace Slicer {
+ IncorrectElementName::IncorrectElementName(const std::string & n) :
+ std::invalid_argument(n)
+ {
+ }
+
+ UnknownType::UnknownType(const std::string & n) :
+ std::invalid_argument(n)
+ {
+ }
+
+ ClassRefMap * &
+ classRefMap()
+ {
+ static ClassRefMap * refs = new ClassRefMap();
+ return refs;
+ }
+
void
ModelPart::Create()
{
}
+
void
ModelPart::Complete()
{
}
+
+ ModelPartPtr
+ ModelPart::GetSubclassModelPart(const std::string &)
+ {
+ return this;
+ }
+
+ TypeId
+ ModelPart::GetTypeId() const
+ {
+ return TypeId();
+ }
+
void
ModelPart::SetValue(ValueSourcePtr)
{
diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h
index 9c2bf45..28ab86d 100644
--- a/slicer/slicer/modelParts.h
+++ b/slicer/slicer/modelParts.h
@@ -15,8 +15,12 @@
namespace Slicer {
class IncorrectElementName : public std::invalid_argument {
public:
- IncorrectElementName() :
- std::invalid_argument("") { }
+ IncorrectElementName(const std::string & n);
+ };
+
+ class UnknownType : public std::invalid_argument {
+ public:
+ UnknownType(const std::string & n);
};
class ValueTarget : public IceUtil::Shared {
@@ -49,15 +53,22 @@ namespace Slicer {
typedef IceUtil::Handle<ModelPart> ModelPartPtr;
typedef std::map<std::string, ModelPartPtr> ModelParts;
+ typedef IceUtil::Optional<std::string> TypeId;
typedef boost::function<void(const std::string &, ModelPartPtr)> ChildHandler;
+ typedef boost::function<ModelPartPtr(void *)> ClassRef;
+ typedef std::map<std::string, ClassRef> ClassRefMap;
+ ClassRefMap * & classRefMap();
+
class ModelPart : public IceUtil::Shared {
public:
virtual ~ModelPart() = default;
virtual void OnEachChild(const ChildHandler &) = 0;
- virtual ModelPartPtr GetChild(const std::string &) = 0;
+ virtual ModelPartPtr GetChild(const std::string & memberName) = 0;
+ virtual ModelPartPtr GetSubclassModelPart(const std::string &);
+ virtual TypeId GetTypeId() const;
virtual void Create();
virtual void Complete();
virtual void SetValue(ValueSourcePtr);
@@ -165,7 +176,7 @@ namespace Slicer {
};
typedef IceUtil::Handle<HookBase> HookPtr;
- template <typename MT, MT T::*M, typename MP>
+ template <typename MT, typename CT, MT CT::*M, typename MP>
class Hook : public HookBase {
public:
Hook(const std::string & n) :
@@ -239,8 +250,19 @@ namespace Slicer {
return ModelObject.get();
}
+ virtual ModelPartPtr GetSubclassModelPart(const std::string & name) override
+ {
+ auto ref = classRefMap()->find(name);
+ if (ref == classRefMap()->end()) {
+ throw UnknownType(name);
+ }
+ return ref->second(&this->ModelObject);
+ }
+
virtual bool HasValue() const override { return ModelObject; }
+ virtual TypeId GetTypeId() const override;
+
private:
T & ModelObject;
};
@@ -288,7 +310,7 @@ namespace Slicer {
virtual ModelPartPtr GetChild(const std::string & name) override
{
if (!name.empty() && name != rootName) {
- throw IncorrectElementName();
+ throw IncorrectElementName(rootName);
}
ModelPartForClass<T>::Create();
return new ModelPartForClass<T>(ModelObject);
@@ -406,7 +428,7 @@ namespace Slicer {
ModelPartPtr GetChild(const std::string & name) override
{
if (!name.empty() && name != pairName) {
- throw IncorrectElementName();
+ throw IncorrectElementName(pairName);
}
return new ModelPartForDictionaryElementInserter<T>(dictionary);
}
diff --git a/slicer/slicer/parser.cpp b/slicer/slicer/parser.cpp
index c874f57..8e2bfa9 100644
--- a/slicer/slicer/parser.cpp
+++ b/slicer/slicer/parser.cpp
@@ -11,7 +11,8 @@ namespace fs = boost::filesystem;
namespace Slicer {
Slicer::Slicer(FILE * c) :
- cpp(c)
+ cpp(c),
+ classNo(0)
{
}
@@ -47,47 +48,43 @@ namespace Slicer {
{
if (c->hasMetaData("slicer:ignore")) { return false; }
+ auto decl = c->declaration();
fprintf(cpp, "// Class %s\n", c->name().c_str());
fprintf(cpp, "template<>\n");
fprintf(cpp, "ModelPartForComplex< %s::%s >::Hooks ",
modulePath().c_str(), c->name().c_str());
fprintf(cpp, "ModelPartForComplex< %s::%s >::hooks {\n",
modulePath().c_str(), c->name().c_str());
- BOOST_FOREACH (const auto & dm, c->allDataMembers()) {
- auto name = metaDataValue("slicer:name:", dm->getMetaData());
- fprintf(cpp, "\t\t{ ");
- auto type = dm->type();
- fprintf(cpp, "new ModelPartForClass< %s::%sPtr >::Hook< ",
- modulePath().c_str(), c->name().c_str());
- if (dm->optional()) {
- fprintf(cpp, "::IceUtil::Optional< %s >",
- Slice::typeToString(type).c_str());
- }
- else {
- fprintf(cpp, "%s",
- Slice::typeToString(type).c_str());
- }
- fprintf(cpp, ", &%s::%s::%s, ",
- modulePath().c_str(), c->name().c_str(), dm->name().c_str());
- if (dm->optional()) {
- fprintf(cpp, "ModelPartForOptional< ");
- }
- createNewModelPartPtrFor(type);
- fprintf(cpp, "< %s",
- Slice::typeToString(type).c_str());
- if (dm->optional()) {
- fprintf(cpp, " > ");
- }
- fprintf(cpp, " > >(\"%s\") },\n",
- name ? name->c_str() : dm->name().c_str());
- }
- fprintf(cpp, "\t};\n");
+ visitComplexDataMembers(decl, c->allDataMembers());
+ fprintf(cpp, "\t};\n\n");
fprintf(cpp, "template<>\n");
auto name = metaDataValue("slicer:root:", c->getMetaData());
- fprintf(cpp, "std::string ModelPartForClassRoot< %s::%sPtr >::rootName(\"%s\");\n\n",
- modulePath().c_str(), c->name().c_str(),
+ fprintf(cpp, "std::string ModelPartForClassRoot< %s >::rootName(\"%s\");\n\n",
+ typeToString(decl).c_str(),
name ? name->c_str() : c->name().c_str());
+
+ fprintf(cpp, "static void registerClass_%u() __attribute__ ((constructor(210)));\n", classNo);
+ fprintf(cpp, "static void registerClass_%u()\n{\n", classNo);
+ fprintf(cpp, "\tSlicer::classRefMap()->insert({ \"%s::%s\", [](void * p){ return new ModelPartForClass< %s >(*static_cast< %s *>(p)); } });\n",
+ modulePath().c_str(), c->name().c_str(),
+ typeToString(decl).c_str(),
+ typeToString(decl).c_str());
+ fprintf(cpp, "}\n\n");
+ fprintf(cpp, "static void unregisterClass_%u() __attribute__ ((destructor(210)));\n", classNo);
+ fprintf(cpp, "static void unregisterClass_%u()\n{\n", classNo);
+ fprintf(cpp, "\tSlicer::classRefMap()->erase(\"%s::%s\");\n",
+ modulePath().c_str(), c->name().c_str());
+ fprintf(cpp, "}\n\n");
+
+ fprintf(cpp, "template<>\nTypeId\nModelPartForClass< %s >::GetTypeId() const\n{\n",
+ typeToString(decl).c_str());
+ fprintf(cpp, "\tauto id = ModelObject->ice_id();\n");
+ fprintf(cpp, "\treturn (id == \"%s::%s\") ? TypeId() : id;\n}\n\n",
+ modulePath().c_str(), c->name().c_str());
+
+ classNo += 1;
+
return true;
}
@@ -102,22 +99,43 @@ namespace Slicer {
modulePath().c_str(), c->name().c_str());
fprintf(cpp, "ModelPartForComplex< %s::%s >::hooks {\n",
modulePath().c_str(), c->name().c_str());
- BOOST_FOREACH (const auto & dm, c->dataMembers()) {
+ visitComplexDataMembers(c, c->dataMembers());
+ fprintf(cpp, "\t};\n\n");
+
+ return true;
+ }
+
+ void
+ Slicer::visitComplexDataMembers(Slice::TypePtr it, const Slice::DataMemberList & dataMembers) const
+ {
+ BOOST_FOREACH (const auto & dm, dataMembers) {
+ auto c = Slice::ContainedPtr::dynamicCast(dm->container());
+ auto t = Slice::TypePtr::dynamicCast(dm->container());
+ if (!t) {
+ t = Slice::ClassDefPtr::dynamicCast(dm->container())->declaration();
+ }
auto name = metaDataValue("slicer:name:", dm->getMetaData());
- fprintf(cpp, "\t\t{ ");
+ fprintf(cpp, "\t\tnew ");
auto type = dm->type();
- fprintf(cpp, "new ModelPartForStruct< %s::%s >::Hook< %s, &%s::%s::%s, ",
- modulePath().c_str(), c->name().c_str(),
- Slice::typeToString(type).c_str(),
- modulePath().c_str(), c->name().c_str(), dm->name().c_str());
+ createNewModelPartPtrFor(t);
+ fprintf(cpp, "< %s >::Hook< %s",
+ typeToString(it).c_str(),
+ Slice::typeToString(type, dm->optional()).c_str());
+ fprintf(cpp, ", %s::%s, &%s::%s::%s, ",
+ modulePath().c_str(), c->name().c_str(),
+ modulePath().c_str(), c->name().c_str(), dm->name().c_str());
+ if (dm->optional()) {
+ fprintf(cpp, "ModelPartForOptional< ");
+ }
createNewModelPartPtrFor(type);
- fprintf(cpp, "< %s > >(\"%s\") },\n",
- Slice::typeToString(type).c_str(),
+ fprintf(cpp, "< %s",
+ Slice::typeToString(type).c_str());
+ if (dm->optional()) {
+ fprintf(cpp, " > ");
+ }
+ fprintf(cpp, " > >(\"%s\"),\n",
name ? name->c_str() : dm->name().c_str());
}
- fprintf(cpp, "\t};\n\n");
-
- return true;
}
void
@@ -137,13 +155,11 @@ namespace Slicer {
else {
fprintf(cpp, "\t(void)name;\n");
}
- fprintf(cpp, "\tsequence.push_back(%s());\n",
- Slice::typeToString(s->type()).c_str());
+ fprintf(cpp, "\tsequence.push_back(typename element_type::value_type());\n");
fprintf(cpp, "\treturn new ");
auto etype = s->type();
createNewModelPartPtrFor(etype);
- fprintf(cpp, "< %s >(sequence.back());\n}\n\n",
- Slice::typeToString(etype).c_str());
+ fprintf(cpp, "<typename element_type::value_type>(sequence.back());\n}\n\n");
fprintf(cpp, "template<>\n");
fprintf(cpp, "ModelPartPtr\n");
fprintf(cpp, "ModelPartForSequence< %s::%s >::elementModelPart(typename %s::%s::value_type & e) const {\n",
@@ -151,8 +167,7 @@ namespace Slicer {
modulePath().c_str(), s->name().c_str());
fprintf(cpp, "\treturn new ");
createNewModelPartPtrFor(etype);
- fprintf(cpp, "< %s >(e);\n}\n\n",
- Slice::typeToString(etype).c_str());
+ fprintf(cpp, "<typename element_type::value_type>(e);\n}\n\n");
fprintf(cpp, "template<>\n");
auto ename = metaDataValue("slicer:element:", s->getMetaData());
fprintf(cpp, "std::string ModelPartForSequence< %s::%s >::elementName(\"%s\");\n\n",
@@ -179,23 +194,25 @@ namespace Slicer {
modulePath().c_str(), d->name().c_str());
auto kname = metaDataValue("slicer:key:", d->getMetaData());
auto vname = metaDataValue("slicer:value:", d->getMetaData());
- fprintf(cpp, "\t\t{ ");
+ fprintf(cpp, "\t\t");
auto ktype = d->keyType();
- fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, &ModelPartForDictionaryElement< %s::%s >::key, ",
+ fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, ModelPartForDictionaryElement< %s::%s >, &ModelPartForDictionaryElement< %s::%s >::key, ",
modulePath().c_str(), d->name().c_str(),
Slice::typeToString(ktype).c_str(),
+ modulePath().c_str(), d->name().c_str(),
modulePath().c_str(), d->name().c_str());
createNewModelPartPtrFor(ktype);
- fprintf(cpp, "< %s > >(\"%s\") },\n\t\t{ ",
+ fprintf(cpp, "< %s > >(\"%s\"),\n\t\t",
Slice::typeToString(ktype).c_str(),
kname ? kname->c_str() : "key");
auto vtype = d->valueType();
- fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, &ModelPartForDictionaryElement< %s::%s >::value, ",
+ fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, ModelPartForDictionaryElement< %s::%s >, &ModelPartForDictionaryElement< %s::%s >::value, ",
modulePath().c_str(), d->name().c_str(),
Slice::typeToString(vtype).c_str(),
+ modulePath().c_str(), d->name().c_str(),
modulePath().c_str(), d->name().c_str());
createNewModelPartPtrFor(vtype);
- fprintf(cpp, "< %s > >(\"%s\") },\n",
+ fprintf(cpp, "< %s > >(\"%s\"),\n",
Slice::typeToString(vtype).c_str(),
vname ? vname->c_str() : "value");
fprintf(cpp, "\t};\n");
@@ -213,24 +230,24 @@ namespace Slicer {
Slicer::createNewModelPartPtrFor(const Slice::TypePtr & type) const
{
if (auto builtin = Slice::BuiltinPtr::dynamicCast(type)) {
- fprintf(cpp, "ModelPartForSimple ");
+ fprintf(cpp, "ModelPartForSimple");
}
else if (auto complexClass = Slice::ClassDeclPtr::dynamicCast(type)) {
- fprintf(cpp, "ModelPartForClass ");
+ fprintf(cpp, "ModelPartForClass");
}
else if (auto complexStruct = Slice::StructPtr::dynamicCast(type)) {
- fprintf(cpp, "ModelPartForStruct ");
+ fprintf(cpp, "ModelPartForStruct");
}
else if (auto sequence = Slice::SequencePtr::dynamicCast(type)) {
- fprintf(cpp, "ModelPartForSequence ");
+ fprintf(cpp, "ModelPartForSequence");
}
else if (auto dictionary = Slice::DictionaryPtr::dynamicCast(type)) {
- fprintf(cpp, "ModelPartForDictionary ");
+ fprintf(cpp, "ModelPartForDictionary");
}
}
std::string
- Slicer::modulePath()
+ Slicer::modulePath() const
{
std::string path;
BOOST_FOREACH (const auto & m, modules) {
diff --git a/slicer/slicer/parser.h b/slicer/slicer/parser.h
index 90aa05a..816738d 100644
--- a/slicer/slicer/parser.h
+++ b/slicer/slicer/parser.h
@@ -34,12 +34,15 @@ namespace Slicer {
private:
void createNewModelPartPtrFor(const Slice::TypePtr & type) const;
- std::string modulePath();
+ void visitComplexDataMembers(Slice::TypePtr t, const Slice::DataMemberList &) const;
+
+ std::string modulePath() const;
static boost::optional<std::string> metaDataValue(const std::string & prefix, const std::list<std::string> & metadata);
FILE * cpp;
std::vector<Slice::ModulePtr> modules;
+ unsigned int classNo;
};
}
diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam
index 88c981f..ebc6c25 100644
--- a/slicer/test/Jamfile.jam
+++ b/slicer/test/Jamfile.jam
@@ -26,6 +26,7 @@ lib common :
: :
<library>boost_filesystem
<library>boost_system
+ <include>../../libmisc
;
unit-test do-slicer :
diff --git a/slicer/test/initial/builtins.xml b/slicer/test/initial/builtins.xml
index 650d187..d77126e 100644
--- a/slicer/test/initial/builtins.xml
+++ b/slicer/test/initial/builtins.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<BuiltIns>
<mbool>true</mbool>
<mbyte>4</mbyte>
- <mdouble>3.14159265359</mdouble>
- <mfloat>3.14</mfloat>
+ <mshort>40</mshort>
<mint>80</mint>
<mlong>800</mlong>
- <mshort>40</mshort>
+ <mfloat>3.125</mfloat>
+ <mdouble>3.0625</mdouble>
<mstring>Sample text</mstring>
</BuiltIns>
diff --git a/slicer/test/initial/optionals-areset.xml b/slicer/test/initial/optionals-areset.xml
index e4cdf42..aa2a97a 100644
--- a/slicer/test/initial/optionals-areset.xml
+++ b/slicer/test/initial/optionals-areset.xml
@@ -1,14 +1,14 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<Optionals>
<optSimple>4</optSimple>
- <optClass>
- <a>1</a>
- <b>2</b>
- </optClass>
<optStruct>
<a>1</a>
<b>2</b>
</optStruct>
+ <optClass>
+ <a>1</a>
+ <b>2</b>
+ </optClass>
<optSeq>
<element>
<a>3</a>
@@ -19,20 +19,20 @@
<b>6</b>
</element>
</optSeq>
- <optDict>
- <element>
- <key>10</key>
- <value>
- <a>11</a>
- <b>12</b>
- </value>
- </element>
- <element>
- <key>13</key>
- <value>
- <a>14</a>
- <b>15</b>
- </value>
- </element>
- </optDict>
+ <optDict>
+ <element>
+ <key>10</key>
+ <value>
+ <a>11</a>
+ <b>12</b>
+ </value>
+ </element>
+ <element>
+ <key>13</key>
+ <value>
+ <a>14</a>
+ <b>15</b>
+ </value>
+ </element>
+ </optDict>
</Optionals>
diff --git a/slicer/test/initial/optionals-notset.xml b/slicer/test/initial/optionals-notset.xml
index 8fbb701..8c679d1 100644
--- a/slicer/test/initial/optionals-notset.xml
+++ b/slicer/test/initial/optionals-notset.xml
@@ -1,3 +1,2 @@
-<?xml version="1.0"?>
-<Optionals>
-</Optionals>
+<?xml version="1.0" encoding="UTF-8"?>
+<Optionals/>
diff --git a/slicer/test/run-slicer.cpp b/slicer/test/run-slicer.cpp
index 897d9ee..35db875 100644
--- a/slicer/test/run-slicer.cpp
+++ b/slicer/test/run-slicer.cpp
@@ -7,6 +7,8 @@
#include <boost/function.hpp>
#include <boost/assert.hpp>
#include <types.h>
+#include <misc.h>
+#include "helpers.h"
namespace fs = boost::filesystem;
@@ -26,6 +28,8 @@ verify(const fs::path & root, const fs::path & tmp, const fs::path & infile, con
fprintf(stderr, "%s : Check2\n", input.string().c_str());
if (check) check(*p);
fprintf(stderr, "%s : OK\n", input.string().c_str());
+
+ system(stringbf("diff -w %s %s", input, output));
}
void
@@ -85,6 +89,8 @@ main(int, char ** argv)
verify<TestModule::BuiltIns, Slicer::Xml>(root, tmp, "builtins.xml");
verify<TestModule::Optionals, Slicer::Xml>(root, tmp, "optionals-notset.xml", checkOptionals_notset);
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");
return 0;
}
diff --git a/slicer/test/types.ice b/slicer/test/types.ice
index 46f834f..bdcd4be 100644
--- a/slicer/test/types.ice
+++ b/slicer/test/types.ice
@@ -38,4 +38,23 @@ module TestModule {
StructType str;
int simp;
};
+ class Base {
+ int a;
+ };
+ class D1 extends Base {
+ int b;
+ };
+ class D2 extends Base {
+ int c;
+ };
+ class D3 extends D2 {
+ int d;
+ };
+ sequence<Base> BaseSeq;
+ dictionary<int, Base> BaseMap;
+ class InheritanceCont {
+ Base b;
+ BaseSeq bs;
+ BaseMap bm;
+ };
};
diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp
index 1ff6058..b08e274 100644
--- a/slicer/xml/serializer.cpp
+++ b/slicer/xml/serializer.cpp
@@ -167,6 +167,10 @@ namespace Slicer {
if (auto element = dynamic_cast<const xmlpp::Element *>(node)) {
auto smp = mp->GetChild(element->get_name());
if (smp) {
+ auto typeAttr = element->get_attribute("slicer-typeid");
+ if (typeAttr) {
+ smp = smp->GetSubclassModelPart(typeAttr->get_value());
+ }
smp->Create();
auto attrs(element->get_attributes());
if (!attrs.empty()) {
@@ -208,6 +212,11 @@ namespace Slicer {
}
else if (mp) {
auto element = n->add_child(name);
+ auto typeId = mp->GetTypeId();
+ if (typeId) {
+ element->set_attribute("slicer-typeid", *typeId);
+ mp = mp->GetSubclassModelPart(*typeId);
+ }
mp->GetValue(new XmlContentValueTarget(element));
mp->OnEachChild(boost::bind(&Xml::ModelTreeIterate, element, _1, _2));
}