Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-26 08:26:31

0001 #ifndef BOOST_COMPAT_FUNCTION_REF_HPP_INCLUDED
0002 #define BOOST_COMPAT_FUNCTION_REF_HPP_INCLUDED
0003 
0004 // Copyright 2024 Christian Mazakas.
0005 // Distributed under the Boost Software License, Version 1.0.
0006 // https://www.boost.org/LICENSE_1_0.txt
0007 
0008 #include <boost/compat/invoke.hpp>
0009 #include <boost/compat/type_traits.hpp>
0010 
0011 #include <type_traits>
0012 #include <utility>
0013 
0014 #if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L
0015 #define BOOST_COMPAT_HAS_AUTO_NTTP
0016 #endif
0017 
0018 namespace boost {
0019 namespace compat {
0020 
0021 template <class... S>
0022 struct function_ref;
0023 
0024 #if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
0025 
0026 template <auto V>
0027 struct nontype_t {
0028   explicit nontype_t() = default;
0029 };
0030 
0031 #endif
0032 
0033 namespace detail {
0034 
0035 template <bool NoEx>
0036 union thunk_storage {
0037   void* pobj_;
0038   void (*pfn_)() noexcept(NoEx);
0039 };
0040 
0041 template <bool NoEx, class Fp, class R, class... Args>
0042 struct invoke_function_holder {
0043   static R invoke_function(thunk_storage<NoEx> s, Args&&... args) noexcept(NoEx) {
0044     auto f = reinterpret_cast<Fp>(s.pfn_);
0045     return compat::invoke_r<R>(f, std::forward<Args>(args)...);
0046   }
0047 };
0048 
0049 template <bool Const, bool NoEx, class F, class R, class... Args>
0050 struct invoke_object_holder {
0051   static R invoke_object(thunk_storage<NoEx> s, Args&&... args) noexcept(NoEx) {
0052     using T = remove_reference_t<F>;
0053     using cv_T = conditional_t<Const, add_const_t<T>, T>;
0054     return compat::invoke_r<R>(*static_cast<cv_T*>(s.pobj_), std::forward<Args>(args)...);
0055   }
0056 };
0057 
0058 #if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
0059 
0060 template <auto f, bool Const, bool NoEx, class R, class... Args>
0061 struct invoke_mem_fn_holder {
0062   static R invoke_mem_fn(thunk_storage<NoEx> /* s */, Args&&... args) noexcept(NoEx) {
0063     return compat::invoke_r<R>(f, std::forward<Args>(args)...);
0064   }
0065 };
0066 
0067 template <auto f, class U, bool Const, bool NoEx, class R, class... Args>
0068 struct invoke_target_mem_fn_holder {
0069   static R invoke_mem_fn(thunk_storage<NoEx> s, Args&&... args) noexcept(NoEx) {
0070     using T = remove_reference_t<U>;
0071     using cv_T = conditional_t<Const, add_const_t<T>, T>;
0072     return compat::invoke_r<R>(f, *static_cast<cv_T*>(s.pobj_), std::forward<Args>(args)...);
0073   }
0074 };
0075 
0076 template <auto f, class T, bool Const, bool NoEx, class R, class... Args>
0077 struct invoke_ptr_mem_fn_holder {
0078   static R invoke_mem_fn(thunk_storage<NoEx> s, Args&&... args) noexcept(NoEx) {
0079     using cv_T = conditional_t<Const, add_const_t<T>, T>;
0080     return compat::invoke_r<R>(f, static_cast<cv_T*>(s.pobj_), std::forward<Args>(args)...);
0081   }
0082 };
0083 
0084 #endif
0085 
0086 template <bool Const, bool NoEx, class R, class... Args>
0087 struct function_ref_base {
0088 private:
0089   thunk_storage<NoEx> thunk_ = nullptr;
0090   R (*invoke_)(thunk_storage<NoEx>, Args&&...) noexcept(NoEx) = nullptr;
0091 
0092 public:
0093   struct fp_tag {};
0094   struct obj_tag {};
0095   struct mem_fn_tag {};
0096 
0097   template <class F>
0098   function_ref_base(fp_tag, F* fn) noexcept
0099       : thunk_{}, invoke_(&invoke_function_holder<NoEx, F*, R, Args...>::invoke_function) {
0100     thunk_.pfn_ = reinterpret_cast<decltype(thunk_.pfn_)>(fn);
0101   }
0102 
0103   template <class F>
0104   function_ref_base(obj_tag, F&& fn) noexcept
0105       : thunk_{}, invoke_(&invoke_object_holder<Const, NoEx, F, R, Args...>::invoke_object) {
0106     thunk_.pobj_ = const_cast<void*>(static_cast<void const*>(std::addressof(fn)));
0107   }
0108 
0109 #if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
0110 
0111   template <auto f, class F = decltype(f)>
0112   function_ref_base(mem_fn_tag, nontype_t<f>)
0113       : thunk_{}, invoke_(&invoke_mem_fn_holder<F{f}, Const, NoEx, R, Args...>::invoke_mem_fn) {
0114     thunk_.pobj_ = nullptr;
0115   }
0116 
0117   template <auto f, class U, class F = decltype(f)>
0118   function_ref_base(mem_fn_tag, nontype_t<f>, U&& obj)
0119       : thunk_{}, invoke_(&invoke_target_mem_fn_holder<F{f}, U, Const, NoEx, R, Args...>::invoke_mem_fn) {
0120     thunk_.pobj_ = const_cast<void*>(static_cast<void const*>(std::addressof(obj)));
0121   }
0122 
0123   template <auto f, class T, class F = decltype(f)>
0124   function_ref_base(mem_fn_tag, nontype_t<f>, T* obj)
0125       : thunk_{}, invoke_(&invoke_ptr_mem_fn_holder<F{f}, T, Const, NoEx, R, Args...>::invoke_mem_fn) {
0126     thunk_.pobj_ = const_cast<void*>(static_cast<void const*>(obj));
0127   }
0128 
0129 #endif
0130 
0131   function_ref_base(const function_ref_base&) noexcept = default;
0132   function_ref_base& operator=(const function_ref_base&) noexcept = default;
0133 
0134   R operator()(Args&&... args) const noexcept(NoEx) { return this->invoke_(thunk_, std::forward<Args>(args)...); }
0135 };
0136 
0137 } // namespace detail
0138 
0139 template <class R, class... Args>
0140 struct function_ref<R(Args...)> : public detail::function_ref_base<false, false, R, Args...> {
0141 private:
0142   using base_type = detail::function_ref_base<false, false, R, Args...>;
0143   using typename base_type::fp_tag;
0144   using typename base_type::mem_fn_tag;
0145   using typename base_type::obj_tag;
0146 
0147   template <class... T>
0148   using is_invocable_using = boost::compat::is_invocable_r<R, T..., Args...>;
0149 
0150 public:
0151   template <class F, enable_if_t<std::is_function<F>::value && is_invocable_using<F>::value, int> = 0>
0152   function_ref(F* fn) noexcept : base_type(fp_tag{}, fn) {}
0153 
0154   template <class F, class T = remove_reference_t<F>,
0155             enable_if_t<!std::is_same<remove_cvref_t<F>, function_ref>::value && !std::is_member_pointer<T>::value &&
0156                             is_invocable_using<T&>::value,
0157                         int> = 0>
0158   function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
0159 
0160 #if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
0161 
0162   template <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
0163   function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
0164 
0165   template <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
0166             enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T&>::value, int> = 0>
0167   function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
0168 
0169   template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T*>::value, int> = 0>
0170   function_ref(nontype_t<f> x, T* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
0171 
0172 #endif
0173 
0174   function_ref(const function_ref&) noexcept = default;
0175   function_ref& operator=(const function_ref&) noexcept = default;
0176 
0177   template <class T, enable_if_t<!std::is_same<T, function_ref>::value && !std::is_pointer<T>::value, int> = 0>
0178   function_ref& operator=(T) = delete;
0179 };
0180 
0181 template <class R, class... Args>
0182 struct function_ref<R(Args...) const> : public detail::function_ref_base<true, false, R, Args...> {
0183 private:
0184   using base_type = detail::function_ref_base<true, false, R, Args...>;
0185   using typename base_type::fp_tag;
0186   using typename base_type::mem_fn_tag;
0187   using typename base_type::obj_tag;
0188 
0189   template <class... T>
0190   using is_invocable_using = boost::compat::is_invocable_r<R, T..., Args...>;
0191 
0192 public:
0193   template <class F, enable_if_t<std::is_function<F>::value && is_invocable_using<F>::value, int> = 0>
0194   function_ref(F* fn) noexcept : base_type(fp_tag{}, fn) {}
0195 
0196   template <class F, class T = remove_reference_t<F>,
0197             enable_if_t<!std::is_same<remove_cvref_t<F>, function_ref>::value && !std::is_member_pointer<T>::value &&
0198                             is_invocable_using<T const&>::value,
0199                         int> = 0>
0200   function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
0201 
0202 #if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
0203 
0204   template <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
0205   function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
0206 
0207   template <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
0208             enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T const&>::value, int> = 0>
0209   function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
0210 
0211   template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T const*>::value, int> = 0>
0212   function_ref(nontype_t<f> x, T const* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
0213 
0214 #endif
0215 
0216   function_ref(const function_ref&) noexcept = default;
0217   function_ref& operator=(const function_ref&) noexcept = default;
0218 
0219   template <class T, enable_if_t<!std::is_same<T, function_ref>::value && !std::is_pointer<T>::value, int> = 0>
0220   function_ref& operator=(T) = delete;
0221 };
0222 
0223 #if defined(__cpp_noexcept_function_type)
0224 
0225 template <class R, class... Args>
0226 struct function_ref<R(Args...) noexcept> : public detail::function_ref_base<false, true, R, Args...> {
0227 private:
0228   using base_type = detail::function_ref_base<false, true, R, Args...>;
0229   using typename base_type::fp_tag;
0230   using typename base_type::mem_fn_tag;
0231   using typename base_type::obj_tag;
0232 
0233   template <class... T>
0234   using is_invocable_using = boost::compat::is_nothrow_invocable_r<R, T..., Args...>;
0235 
0236 public:
0237   template <class F, enable_if_t<std::is_function<F>::value && is_invocable_using<F>::value, int> = 0>
0238   function_ref(F* fn) noexcept : base_type(fp_tag{}, fn) {}
0239 
0240   template <class F, class T = remove_reference_t<F>,
0241             enable_if_t<!std::is_same<remove_cvref_t<F>, function_ref>::value && !std::is_member_pointer<T>::value &&
0242                             is_invocable_using<T&>::value,
0243                         int> = 0>
0244   function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
0245 
0246 #if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
0247 
0248   template <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
0249   function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
0250 
0251   template <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
0252             enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T&>::value, int> = 0>
0253   function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
0254 
0255   template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T*>::value, int> = 0>
0256   function_ref(nontype_t<f> x, T* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
0257 
0258 #endif
0259 
0260   function_ref(const function_ref&) noexcept = default;
0261   function_ref& operator=(const function_ref&) noexcept = default;
0262 
0263   template <class T, enable_if_t<!std::is_same<T, function_ref>::value && !std::is_pointer<T>::value, int> = 0>
0264   function_ref& operator=(T) = delete;
0265 };
0266 
0267 template <class R, class... Args>
0268 struct function_ref<R(Args...) const noexcept> : public detail::function_ref_base<true, true, R, Args...> {
0269 private:
0270   using base_type = detail::function_ref_base<true, true, R, Args...>;
0271   using typename base_type::fp_tag;
0272   using typename base_type::mem_fn_tag;
0273   using typename base_type::obj_tag;
0274 
0275   template <class... T>
0276   using is_invocable_using = boost::compat::is_nothrow_invocable_r<R, T..., Args...>;
0277 
0278 public:
0279   template <class F, enable_if_t<std::is_function<F>::value && is_invocable_using<F>::value, int> = 0>
0280   function_ref(F* fn) noexcept : base_type(fp_tag{}, fn) {}
0281 
0282   template <class F, class T = remove_reference_t<F>,
0283             enable_if_t<!std::is_same<remove_cvref_t<F>, function_ref>::value && !std::is_member_pointer<T>::value &&
0284                             is_invocable_using<T const&>::value,
0285                         int> = 0>
0286   function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
0287 
0288 #if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
0289 
0290   template <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
0291   function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
0292 
0293   template <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
0294             enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T const&>::value, int> = 0>
0295   function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
0296 
0297   template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T const*>::value, int> = 0>
0298   function_ref(nontype_t<f> x, T const* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
0299 
0300 #endif
0301 
0302   function_ref(const function_ref&) noexcept = default;
0303   function_ref& operator=(const function_ref&) noexcept = default;
0304 
0305   template <class T, enable_if_t<!std::is_same<T, function_ref>::value && !std::is_pointer<T>::value, int> = 0>
0306   function_ref& operator=(T) = delete;
0307 };
0308 
0309 #endif
0310 
0311 } // namespace compat
0312 } // namespace boost
0313 
0314 #endif // #ifndef BOOST_COMPAT_FUNCTION_REF_HPP_INCLUDED