Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:07:42

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