diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-09-21 20:08:21 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-09-21 20:08:21 +0100 |
commit | 972b93f95b5cfdc68e914bea4bcf9dbb037ae23c (patch) | |
tree | 08a93926b0d3a1a47770457808bc201f0a82dcbb | |
parent | Apply same length check to built-in strings (diff) | |
download | slicer-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.h | 7 | ||||
-rw-r--r-- | slicer/slicer/modelPartsTypes.cpp | 10 | ||||
-rw-r--r-- | slicer/slicer/modelPartsTypes.h | 15 | ||||
-rw-r--r-- | slicer/slicer/modelPartsTypes.impl.h | 43 | ||||
-rw-r--r-- | slicer/tool/parser.cpp | 10 |
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"); |