From f242b1f2c9eaa238b75b4de8372e8fa890c137bf Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 17 Oct 2020 18:35:33 +0100 Subject: Custom hookmap type Removes more boost::multi_index, largely constexpr --- slicer/slicer/hookMap.h | 101 +++++++++++++++++++++++++++++++++++ slicer/slicer/modelParts.cpp | 8 ++- slicer/slicer/modelParts.h | 14 +++-- slicer/slicer/modelPartsTypes.cpp | 3 ++ slicer/slicer/modelPartsTypes.h | 8 +-- slicer/slicer/modelPartsTypes.impl.h | 68 +++++------------------ slicer/tool/parser.cpp | 59 +++++++++++--------- 7 files changed, 165 insertions(+), 96 deletions(-) create mode 100644 slicer/slicer/hookMap.h diff --git a/slicer/slicer/hookMap.h b/slicer/slicer/hookMap.h new file mode 100644 index 0000000..fb75b33 --- /dev/null +++ b/slicer/slicer/hookMap.h @@ -0,0 +1,101 @@ +#ifndef SLICER_HOOK_MAP_H +#define SLICER_HOOK_MAP_H + +#include "modelParts.h" +#include +#include + +namespace Slicer { + template class ModelPartForComplex; + template class Hooks { + public: + using HookPtr = const typename ModelPartForComplex::HookBase *; + + template class eq; + + template class iter : public std::iterator { + public: + iter(const eq * const r, const HookPtr * c) : range(r), cur(c) + { + operator++(); // move to first match + } + + HookPtr + operator*() const + { + return *cur; + } + + void + operator++() + { + for (; cur != range->e && (*cur)->*(range->name) != range->key; cur++) { } + } + + bool + operator!=(const iter & other) const + { + return cur != other.cur; + } + + private: + const eq * const range; + const HookPtr * cur; + }; + + template class eq { + public: + iter + begin() const + { + return {this, b}; + } + + iter + end() const + { + return {this, e}; + } + + K key; + std::string_view HookCommon::*name; + const HookPtr *b, *e; + }; + + template + inline eq + equal_range(const K & k, bool matchCase) const + { + return {matchCase ? k : boost::algorithm::to_lower_copy(k), + matchCase ? &HookCommon::name : &HookCommon::nameLower, begin(), end()}; + } + + virtual constexpr const HookPtr * begin() const = 0; + virtual constexpr const HookPtr * end() const = 0; + }; + + template class HooksImpl : public Hooks { + public: + using HookPtr = typename Hooks::HookPtr; + template using Arr = std::array; + + inline constexpr HooksImpl(Arr a) : arr(std::move(a)) { } + + constexpr const HookPtr * + begin() const override + { + return arr.begin(); + } + + constexpr const HookPtr * + end() const override + { + return arr.end(); + } + + private: + const Arr arr; + }; +} + +#endif diff --git a/slicer/slicer/modelParts.cpp b/slicer/slicer/modelParts.cpp index 2dd8df5..ccfd647 100644 --- a/slicer/slicer/modelParts.cpp +++ b/slicer/slicer/modelParts.cpp @@ -73,17 +73,15 @@ namespace Slicer { return shared_from_this(); } - HookCommon::HookCommon(std::string n) : name(std::move(n)) { } - bool - HookCommon::filter(const HookFilter & flt) + HookCommon::filter(const HookFilter & flt) const { return (!flt || flt(this)); } void - HookCommon::apply(const ChildHandler & ch, const ModelPartPtr & modelPart) + HookCommon::apply(const ChildHandler & ch, const ModelPartPtr & modelPart) const { - ch(this->name, modelPart, this); + ch(*this->nameStr, modelPart, this); } } diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h index a63d035..c3dd87d 100644 --- a/slicer/slicer/modelParts.h +++ b/slicer/slicer/modelParts.h @@ -69,7 +69,6 @@ namespace Slicer { using ModelPartPtr = std::shared_ptr; using ModelPartForRootPtr = std::shared_ptr; - using HookCommonPtr = std::unique_ptr; using TypeId = std::optional; using ChildHandler = std::function; using ClassRef = std::function; @@ -108,14 +107,19 @@ namespace Slicer { class DLL_PUBLIC HookCommon { public: - explicit HookCommon(std::string); + constexpr HookCommon(std::string_view n, std::string_view nl, const std::string * ns) : + name(n), nameLower(nl), nameStr(ns) + { + } - bool filter(const HookFilter & flt); - void apply(const ChildHandler & ch, const ModelPartPtr & modelPart); + bool filter(const HookFilter & flt) const; + void apply(const ChildHandler & ch, const ModelPartPtr & modelPart) const; [[nodiscard]] virtual const Metadata & GetMetadata() const = 0; - const std::string name; + std::string_view name; + std::string_view nameLower; + const std::string * nameStr; }; struct case_less { diff --git a/slicer/slicer/modelPartsTypes.cpp b/slicer/slicer/modelPartsTypes.cpp index 73e13bf..4ba7557 100644 --- a/slicer/slicer/modelPartsTypes.cpp +++ b/slicer/slicer/modelPartsTypes.cpp @@ -1,6 +1,9 @@ #include "modelPartsTypes.impl.h" #include #include +#include +#include +#include #include namespace Slicer { diff --git a/slicer/slicer/modelPartsTypes.h b/slicer/slicer/modelPartsTypes.h index 35f6cab..a95b5c5 100644 --- a/slicer/slicer/modelPartsTypes.h +++ b/slicer/slicer/modelPartsTypes.h @@ -139,10 +139,10 @@ namespace Slicer { static const std::string & ToModelTypeName(const std::string &); }; + template class Hooks; template class DLL_PUBLIC ModelPartForComplex : public ModelPartForComplexBase { public: class DLL_PRIVATE HookBase; - using HookPtr = std::unique_ptr; template class DLL_PRIVATE Hook; @@ -160,11 +160,7 @@ namespace Slicer { protected: template DLL_PRIVATE ChildRef GetChildRefFromRange(const R & range, const HookFilter & flt); - class DLL_PRIVATE Hooks; - - template static void addHook(Hooks &, const P &...); - - static const Hooks hooks; + static const Hooks & hooks(); static const Metadata metadata; }; diff --git a/slicer/slicer/modelPartsTypes.impl.h b/slicer/slicer/modelPartsTypes.impl.h index eaab54b..ebfd6d9 100644 --- a/slicer/slicer/modelPartsTypes.impl.h +++ b/slicer/slicer/modelPartsTypes.impl.h @@ -3,15 +3,11 @@ #include "common.h" #include "enumMap.h" +#include "hookMap.h" #include "modelPartsTypes.h" #include #include -#include -#include -#include -#include -#include -#include +#include #include #define CUSTOMMODELPARTFOR(Type, BaseModelPart, ModelPartType) \ @@ -404,48 +400,24 @@ namespace Slicer { } // ModelPartForComplex - template - class ModelPartForComplex::Hooks : - public boost::multi_index_container, - boost::multi_index::ordered_non_unique< - boost::multi_index::member, - std::less<>>, - boost::multi_index::ordered_non_unique< - boost::multi_index::member, - case_less>>> { - }; - template void ModelPartForComplex::OnEachChild(const ChildHandler & ch) { - for (const auto & h : hooks) { + for (const auto & h : hooks()) { h->apply(ch, h->Get(GetModel())); } } - template - auto - begin(const P & p) - { - return p.first; - } - template - auto - end(const P & p) - { - return p.second; - } template template ChildRef ModelPartForComplex::GetChildRefFromRange(const R & range, const HookFilter & flt) { - const auto itr = std::find_if(boost::begin(range), boost::end(range), [&flt](auto && h) { + const auto itr = std::find_if(range.begin(), range.end(), [&flt](auto && h) { return h->filter(flt); }); - if (itr != boost::end(range)) { + if (itr != range.end()) { const auto & h = *itr; auto model = GetModel(); return ChildRef(h->Get(model), h->GetMetadata()); @@ -457,19 +429,14 @@ namespace Slicer { ChildRef ModelPartForComplex::GetAnonChildRef(const HookFilter & flt) { - return GetChildRefFromRange(hooks.template get<0>(), flt); + return GetChildRefFromRange(hooks(), flt); } template ChildRef ModelPartForComplex::GetChildRef(const std::string & name, const HookFilter & flt, bool matchCase) { - if (matchCase) { - return GetChildRefFromRange(hooks.template get<1>().equal_range(name), flt); - } - else { - return GetChildRefFromRange(hooks.template get<2>().equal_range(name), flt); - } + return GetChildRefFromRange(hooks().equal_range(name, matchCase), flt); } template @@ -479,19 +446,9 @@ namespace Slicer { return metadata; } - template - template - void - ModelPartForComplex::addHook(Hooks & h, const P &... p) - { - h.push_back(std::make_unique(p...)); - } - template class DLL_PRIVATE ModelPartForComplex::HookBase : public HookCommon { public: - explicit HookBase(const std::string & n) : HookCommon(n) { } - SPECIAL_MEMBERS_DEFAULT(HookBase); - virtual ~HookBase() = default; + using HookCommon::HookCommon; virtual ModelPartPtr Get(T * t) const = 0; [[nodiscard]] const Metadata & @@ -505,7 +462,10 @@ namespace Slicer { template class DLL_PRIVATE ModelPartForComplex::Hook : public ModelPartForComplex::HookBase { public: - Hook(MT T::*m, const std::string & n) : HookBase(n), member(m) { } + constexpr Hook(MT T::*m, std::string_view n, std::string_view nl, const std::string * ns) : + HookBase(n, nl, ns), member(m) + { + } ModelPartPtr Get(T * t) const override @@ -522,8 +482,8 @@ namespace Slicer { template class DLL_PRIVATE ModelPartForComplex::HookMetadata : public ModelPartForComplex::template Hook { public: - HookMetadata(MT T::*member, const std::string & n, Metadata md) : - Hook(member, n), hookMetadata(std::move(md)) + HookMetadata(MT T::*member, std::string_view n, std::string_view nl, const std::string * ns, Metadata md) : + Hook(member, n, nl, ns), hookMetadata(std::move(md)) { } diff --git a/slicer/tool/parser.cpp b/slicer/tool/parser.cpp index 5951d54..39dda2d 100644 --- a/slicer/tool/parser.cpp +++ b/slicer/tool/parser.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -370,36 +371,41 @@ namespace Slicer { externType(dm->type()); } fprintbf(cpp, "using C%d = ModelPartForComplex< %s >;\n", components, it->scoped()); - fprintbf(cpp, "template<> DLL_PUBLIC\n"); - fprintbf(cpp, "const C%d::Hooks ", components); - fprintbf(cpp, "C%d::hooks ([](){\n", components); - fprintbf(cpp, "\t\tC%d::Hooks r;\n", components); + + size_t en = 0; for (const auto & dm : dataMembers) { + auto name = metaDataValue("slicer:name:", dm->getMetaData()).value_or(dm->name()); + fprintbf(cpp, "\tconst std::string hstr%d_%d { \"%s\" };\n", components, en, name); + 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()).value_or(dm->name()); - fprintbf(cpp, "\t\tC%d::addHooktype(); - if (hasMetadata(dm->getMetaData())) { - fprintbf(cpp, "HookMetadata<"); - } - else { - fprintbf(cpp, "Hook<"); - } + fprintbf(cpp, "\t%s C%d::%s<", hasMetadata(dm->getMetaData()) ? "static" : "constexpr", components, + hasMetadata(dm->getMetaData()) ? "HookMetadata" : "Hook"); fprintbf(cpp, " %s, ", Slice::typeToString(type, dm->optional())); createNewModelPartPtrFor(type, dm, getAllMetadata(dm)); - fprintbf(cpp, " > >(r, &%s, \"%s\"", dm->scoped(), name); + fprintbf(cpp, " > hook%d_%d {&%s, \"%s\", \"%s\", &hstr%d_%d", components, en, dm->scoped(), name, + boost::algorithm::to_lower_copy(name), components, en); if (hasMetadata(dm->getMetaData())) { fprintbf(cpp, ", Metadata "); copyMetadata(dm->getMetaData()); } - fprintbf(cpp, ");\n"); + fprintbf(cpp, "};\n"); + en++; } - fprintbf(cpp, "\t\treturn r;\n"); - fprintbf(cpp, "\t}());\n\n"); + + en = 0; + fprintbf( + cpp, "constexpr const HooksImpl< %s, %d > hooks%d {{{\n", it->scoped(), dataMembers.size(), components); + for (const auto & dm : dataMembers) { + fprintbf(cpp, " &hook%d_%d, // %s\n", components, en++, dm->name()); + } + fprintbf(cpp, "\t}}};\n"); + fprintbf(cpp, "\ttemplate<> const Hooks< %s > & C%d::hooks() { return hooks%d; }\n", it->scoped(), components, + components); } void @@ -513,21 +519,22 @@ namespace Slicer { iname ? *iname : "element"); fprintbf(cpp, "using C%d = ModelPartForComplex< %s::value_type >;\n", components, d->scoped()); - fprintbf(cpp, "template<> DLL_PUBLIC\n"); - fprintbf(cpp, "const C%d::Hooks ", components); - fprintbf(cpp, "C%d::hooks ([](){\n", components); - fprintbf(cpp, "\t\tC%d::Hooks r;\n", components); auto addHook = [&](const std::string & name, const char * element, const Slice::TypePtr & t) { - fprintbf(cpp, "\t\t"); - fprintbf(cpp, "C%d::addHook< C%d::Hook< const %s, ", components, components, Slice::typeToString(t)); + fprintbf(cpp, "\tconst std::string hstr%d_%d { \"%s\" };\n", components, element, name); + fprintbf(cpp, "\tconstexpr C%d::Hook< const %s, ", components, Slice::typeToString(t)); createNewModelPartPtrFor(t); - fprintbf(cpp, " > >(r, &%s::value_type::%s, \"%s\");\n", d->scoped(), element, name); + fprintbf(cpp, " > hook%d_%s {&%s::value_type::%s, \"%s\", \"%s\", &hstr%d_%s};\n", components, element, + d->scoped(), element, name, boost::algorithm::to_lower_copy(name), components, element); }; addHook(metaDataValue("slicer:key:", d->getMetaData()).value_or("key"), "first", d->keyType()); addHook(metaDataValue("slicer:value:", d->getMetaData()).value_or("value"), "second", d->valueType()); - fprintbf(cpp, "\t\treturn r;\n"); - fprintbf(cpp, "\t}());\n"); - fprintbf(cpp, "\n"); + + fprintbf(cpp, "constexpr const HooksImpl< %s::value_type, 2 > hooks%d {{{\n", d->scoped(), components); + fprintbf(cpp, " &hook%d_first,\n", components); + fprintbf(cpp, " &hook%d_second,\n", components); + fprintbf(cpp, "\t}}};\n"); + fprintbf(cpp, "\ttemplate<> const Hooks< %s::value_type > & C%d::hooks() { return hooks%d; }\n", d->scoped(), + components, components); auto name = metaDataValue("slicer:root:", d->getMetaData()); defineRoot(d->scoped(), name ? *name : d->name(), d); -- cgit v1.2.3