summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2023-09-21 20:08:21 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2023-09-21 20:08:21 +0100
commit972b93f95b5cfdc68e914bea4bcf9dbb037ae23c (patch)
tree08a93926b0d3a1a47770457808bc201f0a82dcbb
parentApply same length check to built-in strings (diff)
downloadslicer-972b93f95b5cfdc68e914bea4bcf9dbb037ae23c.tar.bz2
slicer-972b93f95b5cfdc68e914bea4bcf9dbb037ae23c.tar.xz
slicer-972b93f95b5cfdc68e914bea4bcf9dbb037ae23c.zip
Remove void * in class hierarchy handling
Replaces the map of typename to function pointer taking void * (which pointed to the std::shared_ptr<T> and cast that to a shared_ptr<I>, thus invoking undefined behaviour) with a map to a small class hierarchy which represents that matching the model class and applying dynamic casts to properly convert as required.
-rw-r--r--slicer/slicer/modelParts.h7
-rw-r--r--slicer/slicer/modelPartsTypes.cpp10
-rw-r--r--slicer/slicer/modelPartsTypes.h15
-rw-r--r--slicer/slicer/modelPartsTypes.impl.h43
-rw-r--r--slicer/tool/parser.cpp10
5 files changed, 66 insertions, 19 deletions
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..c57d987 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<
@@ -186,7 +186,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 +206,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..6b6f852 100644
--- a/slicer/slicer/modelPartsTypes.h
+++ b/slicer/slicer/modelPartsTypes.h
@@ -137,10 +137,10 @@ 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);
@@ -196,13 +196,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..3d1d2be 100644
--- a/slicer/slicer/modelPartsTypes.impl.h
+++ b/slicer/slicer/modelPartsTypes.impl.h
@@ -448,7 +448,12 @@ namespace Slicer {
ModelPartForClass<T>::OnSubclass(const ModelPartHandler & h, const std::string & name)
{
BOOST_ASSERT(this->Model);
- return ModelPartForComplexBase::onSubclass(name, this->Model, h);
+ const ClassRefBase * refbase = ModelPartForComplexBase::getSubclassRef(name);
+ BOOST_ASSERT(refbase);
+ BOOST_ASSERT(dynamic_cast<const ClassRef<T> *>(refbase));
+ if (auto ref = dynamic_cast<const ClassRef<T> *>(refbase)) {
+ ref->onSubClass(*this->Model, h);
+ }
}
template<typename T>
@@ -468,18 +473,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/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");