xref: /llvm-project/flang/include/flang/Common/reference.h (revision b98ad941a40c96c841bceb171725c925500fce6c)
1 //===-- include/flang/Common/reference.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 
9 // Implements a better std::reference_wrapper<> template class with
10 // move semantics, equality testing, and member access.
11 // Use Reference<A> in place of a real A& reference when assignability is
12 // required; safer than a bare pointer because it's guaranteed to not be null.
13 
14 #ifndef FORTRAN_COMMON_REFERENCE_H_
15 #define FORTRAN_COMMON_REFERENCE_H_
16 #include <type_traits>
17 namespace Fortran::common {
18 template <typename A> class Reference {
19 public:
20   using type = A;
Reference(type & x)21   Reference(type &x) : p_{&x} {}
Reference(const Reference & that)22   Reference(const Reference &that) : p_{that.p_} {}
Reference(Reference && that)23   Reference(Reference &&that) : p_{that.p_} {}
24   Reference &operator=(const Reference &that) {
25     p_ = that.p_;
26     return *this;
27   }
28   Reference &operator=(Reference &&that) {
29     p_ = that.p_;
30     return *this;
31   }
32 
33   // Implicit conversions to references are supported only for
34   // const-qualified types in order to avoid any pernicious
35   // creation of a temporary copy in cases like:
36   //   Reference<type> ref;
37   //   const Type &x{ref};  // creates ref to temp copy!
38   operator std::conditional_t<std::is_const_v<type>, type &, void>()
39       const noexcept {
40     if constexpr (std::is_const_v<type>) {
41       return *p_;
42     }
43   }
44 
get()45   type &get() const noexcept { return *p_; }
46   type *operator->() const { return p_; }
47   type &operator*() const { return *p_; }
48 
49   bool operator==(std::add_const_t<A> &that) const {
50     return p_ == &that || *p_ == that;
51   }
52   bool operator!=(std::add_const_t<A> &that) const { return !(*this == that); }
53   bool operator==(const Reference &that) const {
54     return p_ == that.p_ || *this == *that.p_;
55   }
56   bool operator!=(const Reference &that) const { return !(*this == that); }
57 
58 private:
59   type *p_; // never null
60 };
61 template <typename A> Reference(A &) -> Reference<A>;
62 } // namespace Fortran::common
63 #endif
64