Revision control
++ // Copyright (C) 2022 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 QXPFUNCTIONAL_H
++ #define QXPFUNCTIONAL_H
++
++ #include <QtCore/qglobal.h>
++
++ //
++ // W A R N I N G
++ // -------------
++ //
++ // This file is not part of the Qt API. Types and functions defined in this
++ // file can reliably be replaced by their std counterparts, once available.
++ // You may use these definitions in your own code, but be aware that we
++ // will remove them once Qt depends on the C++ version that supports
++ // them in namespace std. There will be NO deprecation warning, the
++ // definitions will JUST go away.
++ //
++ // If you can't agree to these terms, don't use these definitions!
++ //
++ // We mean it.
++ //
++
++ #include <QtCore/q23functional.h>
++ #include <QtCore/q20type_traits.h>
++ #include <utility>
++
++ QT_BEGIN_NAMESPACE
++
++ namespace qxp {
++ // like P0792r9's function_ref:
++
++ // [func.wrap.ref], non-owning wrapper
++ template<class... S> class function_ref; // not defined
++
++ // template<class R, class... ArgTypes>
++ // class function_ref<R(ArgTypes...) cv noexcept(noex)>; // see below
++ //
++ // [func.wrap.ref.general]
++ // The header provides partial specializations of function_ref for each combination
++ // of the possible replacements of the placeholders cv and noex where:
++ // - cv is either const or empty.
++ // - noex is either true or false.
++
++ namespace detail {
++
++ template <typename T>
++ using if_function = std::enable_if_t<std::is_function_v<T>, bool>;
++ template <typename T>
++ using if_non_function = std::enable_if_t<!std::is_function_v<T>, bool>;
++
++ template <typename From, typename To>
++ using copy_const_t = std::conditional_t<
++ std::is_const_v<From>,
++ std::add_const_t<To>,
++ To
++ >;
++
++ template <class Const>
++ union BoundEntityType {
++ template <typename F, if_function<F> = true>
++ explicit constexpr BoundEntityType(F *f)
++ : fun(reinterpret_cast<QFunctionPointer>(f)) {}
++ template <typename T, if_non_function<T> = true>
++ explicit constexpr BoundEntityType(T *t)
++ : obj(static_cast<Const*>(t)) {}
++ Const *obj;
++ QFunctionPointer fun;
++ };
++
++ template <bool noex, class Const, class R, class... ArgTypes>
++ class function_ref_base
++ {
++ protected:
++ QT_DECLARE_RO5_SMF_AS_DEFAULTED(function_ref_base)
++
++ using BoundEntityType = detail::BoundEntityType<Const>;
++
++ template <typename... Ts>
++ using is_invocable_using = std::conditional_t<
++ noex,
++ std::is_nothrow_invocable_r<R, Ts..., ArgTypes...>,
++ std::is_invocable_r<R, Ts..., ArgTypes...>
++ >;
++
++ using ThunkPtr = R(*)(BoundEntityType, ArgTypes&&...) noexcept(noex);
++
++ BoundEntityType m_bound_entity;
++ ThunkPtr m_thunk_ptr;
++
++ public:
++ template<
++ class F,
++ std::enable_if_t<std::conjunction_v<
++ std::is_function<F>,
++ is_invocable_using<F>
++ >, bool> = true
++ >
++ Q_IMPLICIT function_ref_base(F* f) noexcept
++ : m_bound_entity(f),
++ m_thunk_ptr([](BoundEntityType ctx, ArgTypes&&... args) noexcept(noex) -> R {
++ return q23::invoke_r<R>(reinterpret_cast<F*>(ctx.fun),
++ std::forward<ArgTypes>(args)...);
++ })
++ {}
++
++ template<
++ class F,
++ std::enable_if_t<std::conjunction_v<
++ std::negation<std::is_same<q20::remove_cvref_t<F>, function_ref_base>>,
++ #ifdef Q_OS_VXWORKS
++ // The VxWorks compiler is trying to match this ctor against
++ // qxp::function_ref in lieu of using the copy-constructor, so ban
++ // matching against the equivalent qxp::function_ref here.
++ // This doesn't change anything on other platforms, so to save
++ // on compile-speed, enable it only for VxWorks:
++ std::negation<
++ std::is_same<
++ q20::remove_cvref_t<F>,
++ std::conditional_t<
++ std::is_const_v<Const>,
++ qxp::function_ref<R(ArgTypes...) const noexcept(noex)>,
++ qxp::function_ref<R(ArgTypes...) noexcept(noex)>
++ >
++ >
++ >,
++ #endif // Q_OS_VXWORKS
++ std::negation<std::is_member_pointer<std::remove_reference_t<F>>>,
++ is_invocable_using<copy_const_t<Const, std::remove_reference_t<F>>&>
++ >, bool> = true
++ >
++ Q_IMPLICIT constexpr function_ref_base(F&& f) noexcept
++ : m_bound_entity(std::addressof(f)),
++ m_thunk_ptr([](BoundEntityType ctx, ArgTypes&&... args) noexcept(noex) -> R {
++ using That = copy_const_t<Const, std::remove_reference_t<F>>;
++ return q23::invoke_r<R>(*static_cast<That*>(ctx.obj),
++ std::forward<ArgTypes>(args)...);
++ })
++ {}
++
++ protected:
++ template <
++ class T,
++ std::enable_if_t<std::negation_v<
++ std::disjunction<
++ std::is_same<T, function_ref_base>,
++ std::is_pointer<T>
++ >
++ >, bool> = true
++ >
++ function_ref_base& operator=(T) = delete;
++
++ // Invocation [func.wrap.ref.inv]
++ R operator()(ArgTypes... args) const noexcept(noex)
++ {
++ return m_thunk_ptr(m_bound_entity, std::forward<ArgTypes>(args)...);
++ }
++
++ };
++
++ } // namespace detail
++
++ #define QT_SPECIALIZE_FUNCTION_REF(cv, noex) \
++ template<class R, class... ArgTypes> \
++ class function_ref<R(ArgTypes...) cv noexcept( noex )> \
++ : private detail::function_ref_base< noex , cv void, R, ArgTypes...> \
++ { \
++ using base = detail::function_ref_base< noex , cv void, R, ArgTypes...>; \
++ \
++ public: \
++ using base::base; \
++ using base::operator(); \
++ } \
++ /* end */
++
++ QT_SPECIALIZE_FUNCTION_REF( , false);
++ QT_SPECIALIZE_FUNCTION_REF(const, false);
++ QT_SPECIALIZE_FUNCTION_REF( , true );
++ QT_SPECIALIZE_FUNCTION_REF(const, true );
++
++ #undef QT_SPECIALIZE_FUNCTION_REF
++
++ // deduction guides [func.wrap.ref.deduct]
++
++ template <
++ class F,
++ detail::if_function<F> = true
++ >
++ function_ref(F*) -> function_ref<F>;
++
++ } // namespace qxp
++
++ QT_END_NAMESPACE
++
++ #endif /* QXPFUNCTIONAL_H */