summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qxpfunctional.h
blob: 2dd7de669d043a01786593acee73d828670c36b2 (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
// 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#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 wrappertemplate<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 constexprBoundEntityType(F *f):fun(reinterpret_cast<QFunctionPointer>(f)) {}template<typename T, if_non_function<T> =true>explicit constexprBoundEntityType(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 {returnq23::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...)constnoexcept(noex)>,qxp::function_ref<R(ArgTypes...)noexcept(noex)>>>>,#endif// Q_OS_VXWORKSstd::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 constexprfunction_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>>;returnq23::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)constnoexcept(noex){returnm_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 */
close