From 2b0e3626deb33f95aeda00807278bad8c9e02b1f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 18 Oct 2020 18:11:27 +0100 Subject: No virtuals in enum and hook maps Allows static_assert tests. --- slicer/slicer/Jamfile.jam | 6 ++- slicer/slicer/enum-test.cpp | 22 ++++++++ slicer/slicer/enumMap.h | 31 +++++------- slicer/slicer/hook-test.cpp | 55 ++++++++++++++++++++ slicer/slicer/hookMap.h | 97 ++++++++++++++++++++++++++---------- slicer/slicer/modelPartsTypes.impl.h | 7 ++- 6 files changed, 172 insertions(+), 46 deletions(-) create mode 100644 slicer/slicer/enum-test.cpp create mode 100644 slicer/slicer/hook-test.cpp diff --git a/slicer/slicer/Jamfile.jam b/slicer/slicer/Jamfile.jam index f1ba4b1..38a0c66 100644 --- a/slicer/slicer/Jamfile.jam +++ b/slicer/slicer/Jamfile.jam @@ -2,9 +2,13 @@ import package ; lib stdc++fs ; +obj enum-test : enum-test.cpp ; +obj hook-test : hook-test.cpp : ..//adhocutil common ; + obj common : common.ice : tidy:none ; + lib slicer : - [ glob *.cpp ] + [ glob *.cpp : *-test.cpp ] common : ..//Ice diff --git a/slicer/slicer/enum-test.cpp b/slicer/slicer/enum-test.cpp new file mode 100644 index 0000000..166804f --- /dev/null +++ b/slicer/slicer/enum-test.cpp @@ -0,0 +1,22 @@ +#include "enumMap.h" + +enum class Es { one, two, three }; +const std::string one {"one"}, two {"two"}, three {"three"}; + +constexpr Slicer::EnumMapImpl em {{{ + {Es::one, "one", &one}, + {Es::two, "two", &two}, + {Es::three, "three", &three}, +}}}; + +static_assert(em.arr.size() == 3); +static_assert(em.arr[0].value == Es::one); +static_assert(em.arr[1].name == "two"); +static_assert(em.arr[1].nameStr == &two); +static_assert(em.arr[2].value == Es::three); + +static_assert(em.find("one")->value == Es::one); +static_assert(em.find("three")->value == Es::three); +static_assert(em.find(Es::one)->name == "one"); +static_assert(em.find(Es::three)->name == "three"); +static_assert(!em.find("four")); diff --git a/slicer/slicer/enumMap.h b/slicer/slicer/enumMap.h index 98ecd04..a7b42c2 100644 --- a/slicer/slicer/enumMap.h +++ b/slicer/slicer/enumMap.h @@ -1,6 +1,10 @@ #ifndef SLICER_ENUM_MAP_H #define SLICER_ENUM_MAP_H +#include +#include +#include + namespace Slicer { enum class EnumMapKey { Value, @@ -16,12 +20,10 @@ namespace Slicer { }; template - constexpr inline const Node * - find(const T & v) const + [[nodiscard]] constexpr inline const Node * + find(const T & v) const noexcept { - auto b = begin(); - const auto e = end(); - while (b != e) { + for (auto b = begin; b != end; b++) { if constexpr (Key == EnumMapKey::Value) { if (b->value == v) { return b; @@ -32,13 +34,12 @@ namespace Slicer { return b; } } - ++b; } return nullptr; } - virtual constexpr const Node * begin() const = 0; - virtual constexpr const Node * end() const = 0; + const Node * begin {}; + const Node * end {}; }; template class EnumMapImpl : public EnumMap { @@ -46,19 +47,11 @@ namespace Slicer { using NodeType = typename EnumMap::Node; template using Arr = std::array; - constexpr const NodeType * - begin() const override + inline constexpr EnumMapImpl(Arr a) : arr(std::move(a)) { - return arr.begin(); + EnumMap::begin = arr.begin(); + EnumMap::end = arr.end(); } - - constexpr const NodeType * - end() const override - { - return arr.end(); - } - - inline constexpr EnumMapImpl(Arr a) : arr(std::move(a)) { } const Arr arr; }; } diff --git a/slicer/slicer/hook-test.cpp b/slicer/slicer/hook-test.cpp new file mode 100644 index 0000000..11641c2 --- /dev/null +++ b/slicer/slicer/hook-test.cpp @@ -0,0 +1,55 @@ +#include "hookMap.h" +#include "modelPartsTypes.impl.h" + +#include + +struct S { + int aa; + int aA; + int Aa; + int AA; + std::string b; +}; +const std::string aa {"aa"}, aA {"aA"}, Aa {"Aa"}, AA {"AA"}, b {"b"}; + +using C = Slicer::ModelPartForComplex; +constexpr C::Hook> haa {&S::aa, "aa", "aa", &aa}; +constexpr C::Hook> haA {&S::aA, "aA", "aa", &aA}; +constexpr C::Hook> hAa {&S::Aa, "Aa", "aa", &Aa}; +constexpr C::Hook> hAA {&S::AA, "AA", "aa", &AA}; +constexpr C::Hook> hb {&S::b, "b", "b", &b}; +constexpr Slicer::HooksImpl h {{{&haa, &haA, &hAa, &hAA, &hb}}}; + +static_assert(h.arr.size() == 5); +static_assert(h.arr[0]->name == "aa"); +static_assert(h.arr[0]->nameLower == "aa"); +static_assert(h.arr[0]->nameStr == &aa); +static_assert(h.arr[1]->name == "aA"); +static_assert(h.arr[1]->nameLower == "aa"); +static_assert(h.arr[1]->nameStr == &aA); +static_assert(h.arr[4]->name == "b"); +static_assert(h.arr[4]->nameLower == "b"); +static_assert(h.arr[4]->nameStr == &b); + +constexpr auto aas = h.equal_range("aa"); +constexpr auto bbs = h.equal_range("bb"); +static_assert(aas.begin() != aas.end()); +static_assert(bbs.begin() == bbs.end()); +static_assert(aas.begin()->name == "aa"); + +constexpr auto aa0 = aas.begin(); +static_assert(aa0->name == "aa"); +constexpr auto aa1 = aa0 + 1; +static_assert(aa1 == aas.end()); +static_assert(std::distance(aas.begin(), aas.end()) == 1); +static_assert(std::distance(bbs.begin(), bbs.end()) == 0); + +constexpr auto laas = h.equal_range_lower("aa"); +constexpr auto lAAs = h.equal_range_lower("AA"); +static_assert(std::distance(laas.begin(), laas.end()) == 4); +static_assert(std::distance(lAAs.begin(), lAAs.end()) == 0); +static_assert(laas.begin()->name == "aa"); +static_assert((laas.begin() + 1)->name == "aA"); +static_assert((laas.begin() + 2)->name == "Aa"); +static_assert((laas.begin() + 3)->name == "AA"); +static_assert((laas.begin() + 4) == laas.end()); diff --git a/slicer/slicer/hookMap.h b/slicer/slicer/hookMap.h index fb75b33..5b99f96 100644 --- a/slicer/slicer/hookMap.h +++ b/slicer/slicer/hookMap.h @@ -15,43 +15,75 @@ namespace Slicer { template class iter : public std::iterator { public: - iter(const eq * const r, const HookPtr * c) : range(r), cur(c) + constexpr inline iter(const eq * const r, const HookPtr * c) : range(r), cur(c) { - operator++(); // move to first match + moveMatch(); } - HookPtr + constexpr inline HookPtr operator*() const { return *cur; } - void + constexpr inline HookPtr + operator->() const + { + return *cur; + } + + constexpr inline void operator++() { - for (; cur != range->e && (*cur)->*(range->name) != range->key; cur++) { } + if (cur++ != range->e) { + moveMatch(); + } } - bool + constexpr inline iter + operator+(std::size_t n) const + { + auto i {*this}; + while (n--) { + ++i; + } + return i; + } + + constexpr inline bool operator!=(const iter & other) const { return cur != other.cur; } + constexpr inline bool + operator==(const iter & other) const + { + return cur == other.cur; + } + private: + constexpr void + moveMatch() + { + while (cur != range->e && (*cur)->*(range->name) != range->key) { + cur++; + } + } + const eq * const range; const HookPtr * cur; }; template class eq { public: - iter + constexpr inline iter begin() const { return {this, b}; } - iter + constexpr inline iter end() const { return {this, e}; @@ -62,16 +94,40 @@ namespace Slicer { const HookPtr *b, *e; }; + template + constexpr inline eq + equal_range(K && k) const + { + return {std::move(k), &HookCommon::name, _begin, _end}; + } + + template + constexpr inline eq + equal_range_lower(K && k) const + { + return {std::move(k), &HookCommon::nameLower, _begin, _end}; + } + template inline eq - equal_range(const K & k, bool matchCase) const + equal_range_nocase(const K & k) const { - return {matchCase ? k : boost::algorithm::to_lower_copy(k), - matchCase ? &HookCommon::name : &HookCommon::nameLower, begin(), end()}; + return equal_range_lower(boost::algorithm::to_lower_copy(k)); } - virtual constexpr const HookPtr * begin() const = 0; - virtual constexpr const HookPtr * end() const = 0; + constexpr inline auto + begin() const + { + return _begin; + } + constexpr inline auto + end() const + { + return _end; + } + + const HookPtr * _begin {}; + const HookPtr * _end {}; }; template class HooksImpl : public Hooks { @@ -79,21 +135,12 @@ namespace Slicer { 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 + inline constexpr HooksImpl(Arr a) : arr(std::move(a)) { - return arr.end(); + Hooks::_begin = arr.begin(); + Hooks::_end = arr.end(); } - private: const Arr arr; }; } diff --git a/slicer/slicer/modelPartsTypes.impl.h b/slicer/slicer/modelPartsTypes.impl.h index ebfd6d9..409a4ed 100644 --- a/slicer/slicer/modelPartsTypes.impl.h +++ b/slicer/slicer/modelPartsTypes.impl.h @@ -436,7 +436,12 @@ namespace Slicer { ChildRef ModelPartForComplex::GetChildRef(const std::string & name, const HookFilter & flt, bool matchCase) { - return GetChildRefFromRange(hooks().equal_range(name, matchCase), flt); + if (matchCase) { + return GetChildRefFromRange(hooks().equal_range(name), flt); + } + else { + return GetChildRefFromRange(hooks().equal_range_nocase(name), flt); + } } template -- cgit v1.2.3