summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slicer/slicer/common.ice5
-rw-r--r--slicer/slicer/modelParts.h7
-rw-r--r--slicer/slicer/modelPartsTypes.cpp16
-rw-r--r--slicer/slicer/modelPartsTypes.h16
-rw-r--r--slicer/slicer/modelPartsTypes.impl.h44
-rw-r--r--slicer/slicer/slicer.cpp8
-rw-r--r--slicer/test/Jamfile.jam5
-rw-r--r--slicer/test/initial/inherit-base.xml4
-rw-r--r--slicer/test/initial/inherit-nosuchtype.xml5
-rw-r--r--slicer/test/initial/inherit-same.xml4
-rw-r--r--slicer/test/initial/inherit-wronghier.xml5
-rw-r--r--slicer/test/serializers.cpp34
-rw-r--r--slicer/tool/parser.cpp10
13 files changed, 141 insertions, 22 deletions
diff --git a/slicer/slicer/common.ice b/slicer/slicer/common.ice
index 60a4f92..ad3ff1f 100644
--- a/slicer/slicer/common.ice
+++ b/slicer/slicer/common.ice
@@ -29,6 +29,11 @@ module Slicer {
string type;
};
["cpp:ice_print"]
+ exception IncorrectType extends DeserializerError {
+ string type;
+ string target;
+ };
+ ["cpp:ice_print"]
exception InvalidEnumerationValue extends SerializerError {
int value;
string type;
diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h
index 98de0d6..d34552e 100644
--- a/slicer/slicer/modelParts.h
+++ b/slicer/slicer/modelParts.h
@@ -77,6 +77,12 @@ namespace Slicer {
class ModelPartForRootBase;
class HookCommon;
+ struct ClassRefBase {
+ constexpr ClassRefBase() = default;
+ virtual ~ClassRefBase() = default;
+ SPECIAL_MEMBERS_DEFAULT(ClassRefBase);
+ };
+
using ModelPartParam = any_ptr<ModelPart>;
using ModelPartForRootParam = any_ptr<ModelPartForRootBase>;
using TypeId = std::optional<std::string>;
@@ -85,7 +91,6 @@ namespace Slicer {
using ModelPartHandler = std::function<void(ModelPartParam)>;
using ModelPartRootHandler = std::function<void(ModelPartForRootParam)>;
using SubPartHandler = std::function<void(ModelPartParam, const Metadata &)>;
- using ClassRef = std::function<void(void *, const ModelPartHandler &)>;
using HookFilter = std::function<bool(const HookCommon *)>;
constexpr Metadata emptyMetadata;
diff --git a/slicer/slicer/modelPartsTypes.cpp b/slicer/slicer/modelPartsTypes.cpp
index e78c6c6..ffaec04 100644
--- a/slicer/slicer/modelPartsTypes.cpp
+++ b/slicer/slicer/modelPartsTypes.cpp
@@ -27,7 +27,7 @@ namespace Ice {
}
namespace Slicer {
- using ClassRefMap = std::map<std::string, ClassRef, std::less<>>;
+ using ClassRefMap = std::map<std::string, const ClassRefBase *, std::less<>>;
using ClassNamePair = std::pair<std::string_view, std::string>;
using ClassNameMap = boost::multi_index_container<ClassNamePair,
boost::multi_index::indexed_by<
@@ -74,6 +74,12 @@ namespace Slicer {
return name;
}
+ [[noreturn]] void
+ ModelPartForComplexBase::throwIncorrectType(const std::string & name, const std::type_info & target)
+ {
+ throw IncorrectType(name, demangle(target.name()));
+ }
+
#define Roots(Type, Name, NameLen) \
template<> CONSTSTR(NameLen) Slicer::ModelPartForRoot<Type>::rootName {#Name}; \
template<> \
@@ -186,7 +192,7 @@ namespace Slicer {
void
ModelPartForComplexBase::registerClass(
- const std::string_view className, const std::optional<std::string_view> typeName, const ClassRef & cr)
+ const std::string_view className, const std::optional<std::string_view> typeName, const ClassRefBase * cr)
{
refs->emplace(className, cr);
if (typeName) {
@@ -206,11 +212,11 @@ namespace Slicer {
}
}
- void
- ModelPartForComplexBase::onSubclass(const std::string & name, void * m, const ModelPartHandler & h)
+ const ClassRefBase *
+ ModelPartForComplexBase::getSubclassRef(const std::string & name)
{
if (const auto ref = refs->find(ToModelTypeName(name)); ref != refs->end()) {
- return ref->second(m, h);
+ return ref->second;
}
throw UnknownType(name);
}
diff --git a/slicer/slicer/modelPartsTypes.h b/slicer/slicer/modelPartsTypes.h
index b30636e..f581c49 100644
--- a/slicer/slicer/modelPartsTypes.h
+++ b/slicer/slicer/modelPartsTypes.h
@@ -137,16 +137,17 @@ namespace Slicer {
static const ModelPartType type;
protected:
- void onSubclass(const std::string & name, void * m, const ModelPartHandler &);
+ const ClassRefBase * getSubclassRef(const std::string & name);
static void registerClass(
- const std::string_view className, const std::optional<std::string_view> typeName, const ClassRef &);
+ const std::string_view className, const std::optional<std::string_view> typeName, const ClassRefBase *);
static void unregisterClass(const std::string_view className, const std::optional<std::string_view> typeName);
static TypeId getTypeId(const std::string & id, const std::string_view className);
static std::string demangle(const char * mangled);
static const std::string & ToExchangeTypeName(const std::string &);
static std::string_view ToModelTypeName(const std::string &);
+ [[noreturn]] static void throwIncorrectType(const std::string & name, const std::type_info & target);
};
template<typename T> class Hooks;
@@ -196,13 +197,20 @@ namespace Slicer {
constinit static const std::string_view className;
constinit static const std::optional<const std::string_view> typeName;
- static void CreateModelPart(void *, const ModelPartHandler &);
-
private:
+ static const ClassRefBase * const classref;
static void registerClass() __attribute__((constructor(210)));
static void unregisterClass() __attribute__((destructor(210)));
};
+ template<typename T> struct ClassRef {
+ consteval ClassRef() = default;
+ virtual ~ClassRef() = default;
+ SPECIAL_MEMBERS_DEFAULT(ClassRef);
+
+ virtual void onSubClass(std::shared_ptr<T> &, const ModelPartHandler &) const = 0;
+ };
+
template<typename T> class ModelPartForStruct : public ModelPartForComplex<T>, protected ModelPartModel<T> {
public:
using element_type = T;
diff --git a/slicer/slicer/modelPartsTypes.impl.h b/slicer/slicer/modelPartsTypes.impl.h
index f3d1a42..60f221d 100644
--- a/slicer/slicer/modelPartsTypes.impl.h
+++ b/slicer/slicer/modelPartsTypes.impl.h
@@ -448,7 +448,13 @@ namespace Slicer {
ModelPartForClass<T>::OnSubclass(const ModelPartHandler & h, const std::string & name)
{
BOOST_ASSERT(this->Model);
- return ModelPartForComplexBase::onSubclass(name, this->Model, h);
+ if (const ClassRefBase * refbase = ModelPartForComplexBase::getSubclassRef(name);
+ auto ref = dynamic_cast<const ClassRef<T> *>(refbase)) [[likely]] {
+ ref->onSubClass(*this->Model, h);
+ }
+ else {
+ ModelPartForComplexBase::throwIncorrectType(name, typeid(T));
+ }
}
template<typename T>
@@ -468,18 +474,38 @@ namespace Slicer {
template<typename T>
void
- ModelPartForClass<T>::CreateModelPart(void * p, const ModelPartHandler & h)
- {
- return ::Slicer::ModelPart::CreateFor(static_cast<element_type *>(p), h);
- }
-
- template<typename T>
- void
ModelPartForClass<T>::registerClass()
{
- ModelPartForComplexBase::registerClass(className, typeName, &ModelPartForClass<T>::CreateModelPart);
+ ModelPartForComplexBase::registerClass(className, typeName, classref);
}
+ template<typename Inst, typename T> struct ClassRefImpl : public ClassRef<T> {
+ consteval ClassRefImpl() = default;
+
+ void
+ onSubClass(std::shared_ptr<T> & model, const ModelPartHandler & h) const override
+ {
+ if constexpr (std::is_same_v<T, Inst>) {
+ ModelPart::CreateFor(&model, h);
+ }
+ else {
+ auto p = std::move(std::dynamic_pointer_cast<Inst>(model));
+ ModelPart::CreateFor(&p, h);
+ model = std::move(p);
+ }
+ }
+ };
+
+ template<typename Inst, typename... Bases>
+ struct ClassRefImplImpl :
+ public ClassRefBase,
+ public ClassRefImpl<Inst, Inst>,
+ public ClassRefImpl<Inst, Bases>... {
+ consteval ClassRefImplImpl() = default;
+ ~ClassRefImplImpl() override = default;
+ SPECIAL_MEMBERS_DEFAULT(ClassRefImplImpl);
+ };
+
template<typename T>
void
ModelPartForClass<T>::unregisterClass()
diff --git a/slicer/slicer/slicer.cpp b/slicer/slicer/slicer.cpp
index ff9a948..5a253b0 100644
--- a/slicer/slicer/slicer.cpp
+++ b/slicer/slicer/slicer.cpp
@@ -13,6 +13,14 @@ namespace Slicer {
InvalidEnumerationSymbolMsg::write(s, symbol, type);
}
+ AdHocFormatter(IncorrectTypeMsg, "Type [%?] cannot be used as a [%?]");
+
+ void
+ IncorrectType::ice_print(std::ostream & s) const
+ {
+ IncorrectTypeMsg::write(s, type, target);
+ }
+
AdHocFormatter(InvalidEnumerationValueMsg, "Invalid enumeration symbol [%?] for type [%?]");
void
diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam
index 4ed71fb..20cc95e 100644
--- a/slicer/test/Jamfile.jam
+++ b/slicer/test/Jamfile.jam
@@ -1,4 +1,5 @@
import ./slicer.jam ;
+import sequence ;
lib dl ;
lib stdc++fs ;
@@ -81,7 +82,7 @@ run compilation.cpp
run serializers.cpp
helpers.cpp
- : : :
+ : -- : [ sequence.insertion-sort [ glob-tree-ex initial included expected : *.json *.xml ] ] :
<library>types
<implicit-dependency>types
<library>common
@@ -128,7 +129,7 @@ run
<use>../xml//slicer-xml
<use>../json//slicer-json
]
- : : :
+ : -- : [ sequence.insertion-sort [ glob-tree-ex initial included expected : *.json *.xml ] ] :
<library>benchmark
<library>stdc++fs
<library>common
diff --git a/slicer/test/initial/inherit-base.xml b/slicer/test/initial/inherit-base.xml
new file mode 100644
index 0000000..45456e2
--- /dev/null
+++ b/slicer/test/initial/inherit-base.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<D12 slicer-typeid="::TestModule::Base2">
+ <a>3</a>
+</D12>
diff --git a/slicer/test/initial/inherit-nosuchtype.xml b/slicer/test/initial/inherit-nosuchtype.xml
new file mode 100644
index 0000000..057bea5
--- /dev/null
+++ b/slicer/test/initial/inherit-nosuchtype.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<D12 slicer-typeid="::TestModule::NoSuchType">
+ <a>3</a>
+ <b>3</b>
+</D12>
diff --git a/slicer/test/initial/inherit-same.xml b/slicer/test/initial/inherit-same.xml
new file mode 100644
index 0000000..77a22ec
--- /dev/null
+++ b/slicer/test/initial/inherit-same.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<D1 slicer-typeid="::TestModule::D1">
+ <a>3</a>
+</D1>
diff --git a/slicer/test/initial/inherit-wronghier.xml b/slicer/test/initial/inherit-wronghier.xml
new file mode 100644
index 0000000..d1ce693
--- /dev/null
+++ b/slicer/test/initial/inherit-wronghier.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<D12 slicer-typeid="::TestModule::D3">
+ <a>3</a>
+ <b>3</b>
+</D12>
diff --git a/slicer/test/serializers.cpp b/slicer/test/serializers.cpp
index 57779be..ae9a30e 100644
--- a/slicer/test/serializers.cpp
+++ b/slicer/test/serializers.cpp
@@ -1,4 +1,5 @@
#define BOOST_TEST_MODULE execute_serializers
+#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test.hpp>
#include "classes.h"
@@ -36,7 +37,6 @@
#include <string>
#include <types.h>
#include <utility>
-#include <variant>
#include <vector>
#include <xml.h>
// IWYU pragma: no_forward_declare Slicer::InvalidEnumerationSymbol
@@ -677,3 +677,35 @@ BOOST_AUTO_TEST_CASE(sequence_element_in_same_slice_link_bug)
BOOST_CHECK_NO_THROW(
Slicer::ModelPart::Make<Slicer::ModelPartForSequence<TestModule::Dates>>(nullptr, [](auto &&) {}));
}
+
+BOOST_AUTO_TEST_CASE(typeid_specifies_same)
+{
+ std::ifstream in {rootDir / "initial/inherit-same.xml"};
+ auto d1 = Slicer::DeserializeAny<Slicer::XmlStreamDeserializer, TestModule::D1Ptr>(in);
+ BOOST_REQUIRE(d1);
+ BOOST_CHECK_EQUAL(d1->a, 3);
+ BOOST_CHECK_EQUAL(typeid(*d1).name(), typeid(TestModule::D1).name());
+}
+
+BOOST_DATA_TEST_CASE(typeid_specifies_bad,
+ boost::unit_test::data::make<std::filesystem::path>({
+ "inherit-base.xml",
+ "inherit-wronghier.xml",
+ }),
+ path)
+{
+ std::ifstream in {rootDir / "initial" / path};
+ BOOST_CHECK_THROW(std::ignore = (Slicer::DeserializeAny<Slicer::XmlStreamDeserializer, TestModule::D12Ptr>(in)),
+ Slicer::IncorrectType);
+}
+
+BOOST_DATA_TEST_CASE(typeid_specifies_no_such_type,
+ boost::unit_test::data::make<std::filesystem::path>({
+ "inherit-nosuchtype.xml",
+ }),
+ path)
+{
+ std::ifstream in {rootDir / "initial" / path};
+ BOOST_CHECK_THROW(std::ignore = (Slicer::DeserializeAny<Slicer::XmlStreamDeserializer, TestModule::D12Ptr>(in)),
+ Slicer::UnknownType);
+}
diff --git a/slicer/tool/parser.cpp b/slicer/tool/parser.cpp
index 445dda5..8a58484 100644
--- a/slicer/tool/parser.cpp
+++ b/slicer/tool/parser.cpp
@@ -415,6 +415,16 @@ namespace Slicer {
auto name = md.value("slicer:root:");
defineRoot(typeToString(decl), name ? *name : c->name(), decl);
+ fprintbf(cpp, "static constexpr ClassRefImplImpl<%s", decl->typeId());
+ for (const auto & base : decl->definition()->allBases()) {
+ if (decl != base->declaration()) {
+ fprintbf(cpp, ", %s", base->declaration()->typeId());
+ }
+ }
+ fprintbf(cpp, "> ref%d;\n", components);
+ fprintbf(cpp, "template<>\n");
+ fprintbf(cpp, "constinit const ClassRefBase * const ModelPartForClass<%s>::classref{ &ref%d };\n",
+ decl->typeId(), components);
auto typeName = md.value("slicer:typename:");
fprintbf(cpp, "template<>\n");