From d1f71f234261b76a272e6118fa00d46b318cab71 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 19 Aug 2025 23:05:34 +0100 Subject: [PATCH] Internals: Improve V3Rtti for cppcheck (#6312) Rewrite with much less running around in the templates. Use private methods only + friend functions that do the actual type check. This avoids cppcheck warnings. --- src/V3Graph.h | 10 +--- src/V3Rtti.h | 140 +++++++++++++++++++------------------------------- 2 files changed, 56 insertions(+), 94 deletions(-) diff --git a/src/V3Graph.h b/src/V3Graph.h index 222806bb8..6a8d10b42 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -140,10 +140,7 @@ public: bool is() const { static_assert(std::is_base_of::value, "'T' must be a subtype of V3GraphEdge"); - static_assert(std::is_same::type, - VTypeListFront>::value, - "Missing VL_RTTI_IMPL(...) call in 'T'"); - return this->isInstanceOfClassWithId(T::rttiClassId()); + return V3Rtti::isInstanceOf(this); } // Return cast to subtype T and assert of that type @@ -245,10 +242,7 @@ public: bool is() const { static_assert(std::is_base_of::value, "'T' must be a subtype of V3GraphVertex"); - static_assert(std::is_same::type, - VTypeListFront>::value, - "Missing VL_RTTI_IMPL(...) call in 'T'"); - return this->isInstanceOfClassWithId(T::rttiClassId()); + return V3Rtti::isInstanceOf(this); } // Return cast to subtype T and assert of that type diff --git a/src/V3Rtti.h b/src/V3Rtti.h index 627310e02..e830d63ab 100644 --- a/src/V3Rtti.h +++ b/src/V3Rtti.h @@ -22,110 +22,78 @@ #include #include -// Holds list of types as template parameter pack. -// Useful in compile-time code generation. -template -struct VTypeList final { - template - constexpr VTypeList operator+(VTypeList) const { - return {}; - } -}; +namespace V3Rtti { -// Holds one type. -// Can be safely used as a return or argument type, and even instantiated, without triggering any -// potential limitations or effects of the held type. +// Use 'V3Rtti::isInstanceOf(objp)' to check if 'objp' is of subtype 'T' (downcasting) +template +bool isInstanceOf(SuperClass* objp) { + static_assert(std::is_base_of::value, "Impossible 'isInstanceOf'"); + static_assert(!std::is_same::value, "Useless 'isInstanceOf'"); + static_assert(std::is_same< // + typename std::remove_cv::type, // + typename SubClass::V3RttiThisClass // + >::value, + "Missing VL_RTTI_IMPL(...) in 'SubClass'"); + return objp->v3RttiIsInstanceOfImpl(SubClass::v3RttiClassId()); +} + +namespace internal { + +// Returns true iff 'id' equals the 'rttiClassId()' of either 'T', or any of its base classes template -struct VTypeWrapper final { - using type_t = T; -}; - -// Implementation details of other constructs defined in this header. -namespace V3RttiInternal { - -// Helper function for extracting first type from VTypeList. -template -static inline constexpr VTypeWrapper vlTypeListFront(VTypeList) { - return {}; +inline bool matchClassId(uintptr_t id) VL_PURE { + return id == T::v3RttiClassId() || matchClassId(id); } -// Overload for empty type list. Returns false. -inline static constexpr bool isClassIdOfOneOf(uintptr_t id, VTypeList<>) VL_PURE { return false; } - -// Returns true iff `id` has the same value as `T::rttiClassId()`, where `T` is any type held by -// `VTypeList` object passed as the second argument. -template -inline static constexpr bool isClassIdOfOneOf(uintptr_t id, VTypeList) VL_PURE { - return id == Base0::rttiClassId() || isClassIdOfOneOf(id, VTypeList{}); +// Specialization for the root class, which have 'void' for 'V3RttiBaseClass' +template <> +inline bool matchClassId(uintptr_t) VL_PURE { + return false; } -} // namespace V3RttiInternal +} // namespace internal -// Alias for the first (frontmost) type held by type list `TL`. -template -using VTypeListFront = typename decltype(::V3RttiInternal::vlTypeListFront(TL{}))::type_t; - -// `VTypeList` holding types from type lists `TL1` followed by types from type list `TL2`. -template -using VJoinedTypeLists = decltype(TL1{} + TL2{}); +} // namespace V3Rtti // Common code used by VL_RTTI_COMMON_IMPL and VL_RTTI_COMMON_IMPL_BASE. -#define V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \ -private: \ +#define V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass, OVERRIDE) \ + using V3RttiThisClass = ThisClass; \ /* A type used only for implementation of the static_assert below. */ \ struct RttiUniqueTypeForThisClass {}; \ static_assert( \ std::is_same::value, \ "'ThisClass' argument (" #ThisClass ") does not match the class name"); \ -\ -public: \ - /* Returns unique ID of the class. Useful with `isInstanceOfClassWithId()` method. */ \ - static uintptr_t rttiClassId() VL_PURE { \ - /* The only purpose of the following variable is to occupy an unique memory address. */ \ - /* This address is used as an unique class ID. */ \ - static char aStaticVariable; \ - return reinterpret_cast(&aStaticVariable); \ + /* The implementation can pick up the private members */ \ + template \ + friend bool V3Rtti::internal::matchClassId(uintptr_t id); \ + template \ + friend bool V3Rtti::isInstanceOf(U*); \ + /* Returns unique type ID of the class. */ \ + static uintptr_t v3RttiClassId() VL_PURE { \ + /* Don't complain this function is unused */ (void)&v3RttiClassId; \ + /* The address of this static variable is used as the unique class type ID. */ \ + static char s_vlrttiClassId; \ + return reinterpret_cast(&s_vlrttiClassId); \ + } \ + /* Dispatch to matchClassId with the correct sub type (this type) */ \ + virtual bool v3RttiIsInstanceOfImpl(uintptr_t id) const OVERRIDE VL_PURE { \ + return ::V3Rtti::internal::matchClassId(id); \ } -// Call this macro at the beginning of class definition if the class derives from a -// class with VL_RTTI_IMPL or VL_RTTI_IMPL_BASE calls. +// Call this macro at the beginning of class definition if the class derives +// from a class with VL_RTTI_IMPL or VL_RTTI_IMPL_BASE calls. #define VL_RTTI_IMPL(ThisClass, DirectBaseClass) \ - V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \ - static_assert( \ - std::is_same>::value, \ - "Missing VL_RTTI_IMPL(...) in the direct base class (" #DirectBaseClass ")"); \ -\ -public: \ - /* Type list containing this class and all classes from the inheritance chain. */ \ - using RttiThisAndBaseClassesList \ - = VJoinedTypeLists, \ - typename DirectBaseClass::RttiThisAndBaseClassesList>; \ -\ -protected: \ - /* Returns true iff `id` has the same value as `T::rttiClassId()`, where `T` is either this \ - * class or any class from this class' inheritance chain. */ \ - bool isInstanceOfClassWithId(uintptr_t id) const override VL_PURE { \ - return ::V3RttiInternal::isClassIdOfOneOf(id, RttiThisAndBaseClassesList{}); \ - } \ -\ -private: /* Revert to private visibility after this macro */ +private: \ + using V3RttiBaseClass = DirectBaseClass; \ + V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass, override) \ +private: -// Call this macro at the beginning of a base class to implement class type queries using -// `p->isInstanceOfClassWithId(ClassName::rttiClassId())`. +// Call this macro at the beginning of a base class to implement class type +// usable with V3Rtti::InstanceOf #define VL_RTTI_IMPL_BASE(ThisClass) \ - V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \ -public: \ - /* Type list containing this class and all classes from the inheritance chain. */ \ - using RttiThisAndBaseClassesList = VTypeList; \ -\ -protected: \ - /* Returns true iff `id` has the same value as value returned by this class' \ - `rttiClassId()` method. */ \ - virtual bool isInstanceOfClassWithId(uintptr_t id) const VL_PURE { \ - return id == rttiClassId(); \ - } \ -\ -private: /* Revert to private visibility after this macro */ +private: \ + using V3RttiBaseClass = void; \ + V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass, /* base */) \ +private: #endif // Guard