xref: /llvm-project/flang/include/flang/Common/reference-wrapper.h (revision 8ebf741136c66f51053315bf4f0ef828c6f66094)
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)82 inline 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)87 inline 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)93 inline 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)99 inline 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