Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-26 09:07:59

0001 // Copyright (C) 2022 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 // Qt-Security score:significant reason:default
0004 #ifndef QXPFUNCTIONAL_H
0005 #define QXPFUNCTIONAL_H
0006 
0007 #include <QtCore/qglobal.h>
0008 
0009 //
0010 //  W A R N I N G
0011 //  -------------
0012 //
0013 // This file is not part of the Qt API. Types and functions defined in this
0014 // file can reliably be replaced by their std counterparts, once available.
0015 // You may use these definitions in your own code, but be aware that we
0016 // will remove them once Qt depends on the C++ version that supports
0017 // them in namespace std. There will be NO deprecation warning, the
0018 // definitions will JUST go away.
0019 //
0020 // If you can't agree to these terms, don't use these definitions!
0021 //
0022 // We mean it.
0023 //
0024 
0025 #include <QtCore/q23functional.h>
0026 #include <QtCore/q20type_traits.h>
0027 #include <utility>
0028 
0029 QT_BEGIN_NAMESPACE
0030 
0031 namespace qxp {
0032 // like P0792r9's function_ref:
0033 
0034 // [func.wrap.ref], non-owning wrapper
0035 template<class... S> class function_ref;              // not defined
0036 
0037 // template<class R, class... ArgTypes>
0038 // class function_ref<R(ArgTypes...) cv noexcept(noex)>; // see below
0039 //
0040 // [func.wrap.ref.general]
0041 // The header provides partial specializations of function_ref for each combination
0042 // of the possible replacements of the placeholders cv and noex where:
0043 // - cv is either const or empty.
0044 // - noex is either true or false.
0045 
0046 namespace detail {
0047 
0048 template <typename T>
0049 using if_function = std::enable_if_t<std::is_function_v<T>, bool>;
0050 template <typename T>
0051 using if_non_function = std::enable_if_t<!std::is_function_v<T>, bool>;
0052 
0053 template <typename From, typename To>
0054 using copy_const_t = std::conditional_t<
0055         std::is_const_v<From>,
0056         std::add_const_t<To>,
0057         To
0058     >;
0059 
0060 template <class Const>
0061 union BoundEntityType {
0062     template <typename F, if_function<F> = true>
0063     explicit constexpr BoundEntityType(F *f)
0064         : fun(reinterpret_cast<QFunctionPointer>(f)) {}
0065     template <typename T, if_non_function<T> = true>
0066     explicit constexpr BoundEntityType(T *t)
0067         : obj(static_cast<Const*>(t)) {}
0068     Const *obj;
0069     QFunctionPointer fun;
0070 };
0071 
0072 template <bool noex, class Const, class R, class... ArgTypes>
0073 class function_ref_base
0074 {
0075 protected:
0076     QT_DECLARE_RO5_SMF_AS_DEFAULTED(function_ref_base)
0077 
0078     using BoundEntityType = detail::BoundEntityType<Const>;
0079 
0080     template <typename... Ts>
0081     using is_invocable_using = std::conditional_t<
0082             noex,
0083             std::is_nothrow_invocable_r<R, Ts..., ArgTypes...>,
0084             std::is_invocable_r<R, Ts..., ArgTypes...>
0085         >;
0086 
0087     using ThunkPtr = R(*)(BoundEntityType, ArgTypes&&...) noexcept(noex);
0088 
0089     BoundEntityType m_bound_entity;
0090     ThunkPtr m_thunk_ptr;
0091 
0092 public:
0093     template<
0094         class F,
0095         std::enable_if_t<std::conjunction_v<
0096             std::is_function<F>,
0097             is_invocable_using<F>
0098         >, bool> = true
0099     >
0100     Q_IMPLICIT function_ref_base(F* f) noexcept
0101         : m_bound_entity(f),
0102           m_thunk_ptr([](BoundEntityType ctx, ArgTypes&&... args) noexcept(noex) -> R {
0103                 return q23::invoke_r<R>(reinterpret_cast<F*>(ctx.fun),
0104                                         std::forward<ArgTypes>(args)...);
0105             })
0106     {}
0107 
0108     template<
0109         class F,
0110         std::enable_if_t<std::conjunction_v<
0111             std::negation<std::is_same<q20::remove_cvref_t<F>, function_ref_base>>,
0112 #ifdef Q_OS_VXWORKS
0113             // The VxWorks compiler is trying to match this ctor against
0114             // qxp::function_ref in lieu of using the copy-constructor, so ban
0115             // matching against the equivalent qxp::function_ref here.
0116             // This doesn't change anything on other platforms, so to save
0117             // on compile-speed, enable it only for VxWorks:
0118             std::negation<
0119                 std::is_same<
0120                     q20::remove_cvref_t<F>,
0121                     std::conditional_t<
0122                         std::is_const_v<Const>,
0123                         qxp::function_ref<R(ArgTypes...) const noexcept(noex)>,
0124                         qxp::function_ref<R(ArgTypes...) noexcept(noex)>
0125                     >
0126                 >
0127             >,
0128 #endif // Q_OS_VXWORKS
0129             std::negation<std::is_member_pointer<std::remove_reference_t<F>>>,
0130             is_invocable_using<copy_const_t<Const, std::remove_reference_t<F>>&>
0131         >, bool> = true
0132     >
0133     Q_IMPLICIT constexpr function_ref_base(F&& f) noexcept
0134         : m_bound_entity(std::addressof(f)),
0135           m_thunk_ptr([](BoundEntityType ctx, ArgTypes&&... args) noexcept(noex) -> R {
0136                 using That = copy_const_t<Const, std::remove_reference_t<F>>;
0137                 return q23::invoke_r<R>(*static_cast<That*>(ctx.obj),
0138                                         std::forward<ArgTypes>(args)...);
0139             })
0140     {}
0141 
0142 protected:
0143     template <
0144         class T,
0145         std::enable_if_t<std::negation_v<
0146             std::disjunction<
0147                 std::is_same<T, function_ref_base>,
0148                 std::is_pointer<T>
0149             >
0150         >, bool> = true
0151     >
0152     function_ref_base& operator=(T) = delete;
0153 
0154     // Invocation [func.wrap.ref.inv]
0155     R operator()(ArgTypes... args) const noexcept(noex)
0156     {
0157         return m_thunk_ptr(m_bound_entity, std::forward<ArgTypes>(args)...);
0158     }
0159 
0160 };
0161 
0162 } // namespace detail
0163 
0164 #define QT_SPECIALIZE_FUNCTION_REF(cv, noex) \
0165     template<class R, class... ArgTypes> \
0166     class function_ref<R(ArgTypes...) cv noexcept( noex )> \
0167         : private detail::function_ref_base< noex , cv void, R, ArgTypes...> \
0168     { \
0169         using base = detail::function_ref_base< noex , cv void, R, ArgTypes...>; \
0170         \
0171     public: \
0172         using base::base; \
0173         using base::operator(); \
0174     } \
0175     /* end */
0176 
0177 QT_SPECIALIZE_FUNCTION_REF(     , false);
0178 QT_SPECIALIZE_FUNCTION_REF(const, false);
0179 QT_SPECIALIZE_FUNCTION_REF(     , true );
0180 QT_SPECIALIZE_FUNCTION_REF(const, true );
0181 
0182 #undef QT_SPECIALIZE_FUNCTION_REF
0183 
0184 // deduction guides [func.wrap.ref.deduct]
0185 
0186 template <
0187     class F,
0188     detail::if_function<F> = true
0189 >
0190 function_ref(F*) -> function_ref<F>;
0191 
0192 } // namespace qxp
0193 
0194 QT_END_NAMESPACE
0195 
0196 #endif /* QXPFUNCTIONAL_H */