1 //===-- include/flang/Common/reference-wrapper.h ----------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // clang-format off 9 // 10 // Implementation of std::reference_wrapper borrowed from libcu++ 11 // https://github.com/NVIDIA/libcudacxx/blob/f7e6cd07ed5ba826aeac0b742feafddfedc1e400/include/cuda/std/detail/libcxx/include/__functional/reference_wrapper.h#L1 12 // with modifications. 13 // 14 // The original source code is distributed under the Apache License v2.0 15 // with LLVM Exceptions. 16 // 17 // TODO: using libcu++ is the best option for CUDA, but there is a couple 18 // of issues: 19 // * The include paths need to be set up such that all STD header files 20 // are taken from libcu++. 21 // * cuda:: namespace need to be forced for all std:: references. 22 // 23 // clang-format on 24 25 #ifndef FORTRAN_COMMON_REFERENCE_WRAPPER_H 26 #define FORTRAN_COMMON_REFERENCE_WRAPPER_H 27 28 #include "flang/Common/api-attrs.h" 29 #include <functional> 30 #include <type_traits> 31 32 #if !defined(STD_REFERENCE_WRAPPER_UNSUPPORTED) && \ 33 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__) 34 #define STD_REFERENCE_WRAPPER_UNSUPPORTED 1 35 #endif 36 37 namespace Fortran::common { 38 39 template <class _Tp> 40 using __remove_cvref_t = std::remove_cv_t<std::remove_reference_t<_Tp>>; 41 template <class _Tp, class _Up> 42 struct __is_same_uncvref 43 : std::is_same<__remove_cvref_t<_Tp>, __remove_cvref_t<_Up>> {}; 44 45 #if STD_REFERENCE_WRAPPER_UNSUPPORTED 46 template <class _Tp> class reference_wrapper { 47 public: 48 // types 49 typedef _Tp type; 50 51 private: 52 type *__f_; 53 54 static RT_API_ATTRS void __fun(_Tp &); 55 static void __fun(_Tp &&) = delete; 56 57 public: 58 template <class _Up, 59 class = 60 std::enable_if_t<!__is_same_uncvref<_Up, reference_wrapper>::value, 61 decltype(__fun(std::declval<_Up>()))>> reference_wrapper(_Up && __u)62 constexpr RT_API_ATTRS reference_wrapper(_Up &&__u) { 63 type &__f = static_cast<_Up &&>(__u); 64 __f_ = std::addressof(__f); 65 } 66 67 // access 68 constexpr RT_API_ATTRS operator type &() const { return *__f_; } get()69 constexpr RT_API_ATTRS type &get() const { return *__f_; } 70 71 // invoke 72 template <class... _ArgTypes> 73 constexpr RT_API_ATTRS typename std::invoke_result_t<type &, _ArgTypes...> operator()74 operator()(_ArgTypes &&...__args) const { 75 return std::invoke(get(), std::forward<_ArgTypes>(__args)...); 76 } 77 }; 78 79 template <class _Tp> reference_wrapper(_Tp &) -> reference_wrapper<_Tp>; 80 81 template <class _Tp> ref(_Tp & __t)82inline constexpr RT_API_ATTRS reference_wrapper<_Tp> ref(_Tp &__t) { 83 return reference_wrapper<_Tp>(__t); 84 } 85 86 template <class _Tp> ref(reference_wrapper<_Tp> __t)87inline constexpr RT_API_ATTRS reference_wrapper<_Tp> ref( 88 reference_wrapper<_Tp> __t) { 89 return __t; 90 } 91 92 template <class _Tp> cref(const _Tp & __t)93inline constexpr RT_API_ATTRS reference_wrapper<const _Tp> cref( 94 const _Tp &__t) { 95 return reference_wrapper<const _Tp>(__t); 96 } 97 98 template <class _Tp> cref(reference_wrapper<_Tp> __t)99inline constexpr RT_API_ATTRS reference_wrapper<const _Tp> cref( 100 reference_wrapper<_Tp> __t) { 101 return __t; 102 } 103 104 template <class _Tp> void ref(const _Tp &&) = delete; 105 template <class _Tp> void cref(const _Tp &&) = delete; 106 #else // !STD_REFERENCE_WRAPPER_UNSUPPORTED 107 using std::cref; 108 using std::ref; 109 using std::reference_wrapper; 110 #endif // !STD_REFERENCE_WRAPPER_UNSUPPORTED 111 112 } // namespace Fortran::common 113 114 #endif // FORTRAN_COMMON_REFERENCE_WRAPPER_H 115