Revision control
++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #ifndef QNATIVEINTERFACE_H
++ #define QNATIVEINTERFACE_H
++
++ #include <QtCore/qglobal.h>
++
++ QT_BEGIN_NAMESPACE
++
++ // We declare a virtual non-inline function in the form
++ // of the destructor, making it the key function. This
++ // ensures that the typeinfo of the class is exported.
++ // By being protected, we also ensure that pointers to
++ // the interface can't be deleted.
++ #define QT_DECLARE_NATIVE_INTERFACE_3(NativeInterface, Revision, BaseType) \
++ protected: \
++ virtual ~NativeInterface(); \
++ \
++ struct TypeInfo { \
++ using baseType = BaseType; \
++ static constexpr char const *name = QT_STRINGIFY(NativeInterface); \
++ static constexpr int revision = Revision; \
++ }; \
++ \
++ template <typename, typename> \
++ friend struct QNativeInterface::Private::has_type_info; \
++ \
++ template <typename> \
++ friend bool constexpr QNativeInterface::Private::hasTypeInfo(); \
++ \
++ template <typename> \
++ friend struct QNativeInterface::Private::TypeInfo; \
++ public: \
++ NativeInterface() = default; \
++ Q_DISABLE_COPY_MOVE(NativeInterface)
++
++ // Revisioned interfaces only make sense when exposed through a base
++ // type via QT_DECLARE_NATIVE_INTERFACE_ACCESSOR, as the revision
++ // checks happen at that level (and not for normal dynamic_casts).
++ #define QT_DECLARE_NATIVE_INTERFACE_2(NativeInterface, Revision) \
++ static_assert(false, "Must provide a base type when specifying revision");
++
++ #define QT_DECLARE_NATIVE_INTERFACE_1(NativeInterface) \
++ QT_DECLARE_NATIVE_INTERFACE_3(NativeInterface, 0, void)
++
++ #define QT_DECLARE_NATIVE_INTERFACE(...) \
++ QT_OVERLOADED_MACRO(QT_DECLARE_NATIVE_INTERFACE, __VA_ARGS__)
++
++ namespace QNativeInterface::Private {
++
++ // Basic type-trait to verify that a given native interface has
++ // all the required type information for us to evaluate it.
++ template <typename NativeInterface, typename = void>
++ struct has_type_info : std::false_type {};
++
++ // The type-trait is friended by TypeInfo, so that we can
++ // evaluate TypeInfo in the template arguments.
++ template <typename NativeInterface>
++ struct has_type_info<NativeInterface, std::void_t<
++ typename NativeInterface::TypeInfo,
++ typename NativeInterface::TypeInfo::baseType,
++ decltype(&NativeInterface::TypeInfo::name),
++ decltype(&NativeInterface::TypeInfo::revision)
++ >> : std::true_type {};
++
++ // We need to wrap the instantiation of has_type_info in a
++ // function friended by TypeInfo, otherwise MSVC will not
++ // let us evaluate TypeInfo in the template arguments.
++ template <typename NativeInterface>
++ bool constexpr hasTypeInfo()
++ {
++ return has_type_info<NativeInterface>::value;
++ }
++
++ template <typename NativeInterface>
++ struct TypeInfo
++ {
++ // To ensure SFINAE works for hasTypeInfo we can't use it in a constexpr
++ // variable that also includes an expression that relies on the type
++ // info. This helper variable is okey, as it it self contained.
++ static constexpr bool haveTypeInfo = hasTypeInfo<NativeInterface>();
++
++ // We can then use the helper variable in a constexpr condition in a
++ // function, which does not break SFINAE if haveTypeInfo is false.
++ template <typename BaseType>
++ static constexpr bool isCompatibleHelper()
++ {
++ if constexpr (haveTypeInfo)
++ return std::is_base_of<typename NativeInterface::TypeInfo::baseType, BaseType>::value;
++ else
++ return false;
++ }
++
++ // MSVC however doesn't like constexpr functions in enable_if_t conditions,
++ // so we need to wrap it yet again in a constexpr variable. This is fine,
++ // as all the SFINAE magic has been resolved at this point.
++ template <typename BaseType>
++ static constexpr bool isCompatibleWith = isCompatibleHelper<BaseType>();
++
++ // The revision and name accessors are not used in enable_if_t conditions,
++ // so we can leave them as constexpr functions. As this class template is
++ // friended by TypeInfo we can access the protected members of TypeInfo.
++ static constexpr int revision()
++ {
++ if constexpr (haveTypeInfo)
++ return NativeInterface::TypeInfo::revision;
++ else
++ return 0;
++ }
++
++ static constexpr char const *name()
++ {
++ if constexpr (haveTypeInfo)
++ return NativeInterface::TypeInfo::name;
++ else
++ return nullptr;
++ }
++ };
++
++ // Wrapper type to make the error message in case
++ // of incompatible interface types read better.
++ template <typename I>
++ struct NativeInterface : TypeInfo<I> {};
++ } // QNativeInterface::Private
++
++ // Declares an accessor for the native interface
++ #ifdef Q_QDOC
++ #define QT_DECLARE_NATIVE_INTERFACE_ACCESSOR(T) \
++ template <typename QNativeInterface> \
++ QNativeInterface *nativeInterface() const;
++ #else
++ #define QT_DECLARE_NATIVE_INTERFACE_ACCESSOR(T) \
++ template <typename NativeInterface, typename TypeInfo = QNativeInterface::Private::NativeInterface<NativeInterface>, \
++ typename BaseType = T, std::enable_if_t<TypeInfo::template isCompatibleWith<T>, bool> = true> \
++ NativeInterface *nativeInterface() const \
++ { \
++ return static_cast<NativeInterface*>(resolveInterface( \
++ TypeInfo::name(), TypeInfo::revision())); \
++ } \
++ protected: \
++ void *resolveInterface(const char *name, int revision) const; \
++ public:
++ #endif
++
++ QT_END_NAMESPACE
++
++ #endif // QNATIVEINTERFACE_H