xref: /llvm-project/flang/include/flang/Common/reference.h (revision b98ad941a40c96c841bceb171725c925500fce6c)
164ab3302SCarolineConcatto //===-- include/flang/Common/reference.h ------------------------*- C++ -*-===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto // Implements a better std::reference_wrapper<> template class with
1064ab3302SCarolineConcatto // move semantics, equality testing, and member access.
1164ab3302SCarolineConcatto // Use Reference<A> in place of a real A& reference when assignability is
1264ab3302SCarolineConcatto // required; safer than a bare pointer because it's guaranteed to not be null.
1364ab3302SCarolineConcatto 
1464ab3302SCarolineConcatto #ifndef FORTRAN_COMMON_REFERENCE_H_
1564ab3302SCarolineConcatto #define FORTRAN_COMMON_REFERENCE_H_
1664ab3302SCarolineConcatto #include <type_traits>
1764ab3302SCarolineConcatto namespace Fortran::common {
1864ab3302SCarolineConcatto template <typename A> class Reference {
1964ab3302SCarolineConcatto public:
2064ab3302SCarolineConcatto   using type = A;
Reference(type & x)2164ab3302SCarolineConcatto   Reference(type &x) : p_{&x} {}
Reference(const Reference & that)2264ab3302SCarolineConcatto   Reference(const Reference &that) : p_{that.p_} {}
Reference(Reference && that)2364ab3302SCarolineConcatto   Reference(Reference &&that) : p_{that.p_} {}
2464ab3302SCarolineConcatto   Reference &operator=(const Reference &that) {
2564ab3302SCarolineConcatto     p_ = that.p_;
2664ab3302SCarolineConcatto     return *this;
2764ab3302SCarolineConcatto   }
2864ab3302SCarolineConcatto   Reference &operator=(Reference &&that) {
2964ab3302SCarolineConcatto     p_ = that.p_;
3064ab3302SCarolineConcatto     return *this;
3164ab3302SCarolineConcatto   }
3264ab3302SCarolineConcatto 
3364ab3302SCarolineConcatto   // Implicit conversions to references are supported only for
3464ab3302SCarolineConcatto   // const-qualified types in order to avoid any pernicious
3564ab3302SCarolineConcatto   // creation of a temporary copy in cases like:
3664ab3302SCarolineConcatto   //   Reference<type> ref;
3764ab3302SCarolineConcatto   //   const Type &x{ref};  // creates ref to temp copy!
38*1f879005STim Keith   operator std::conditional_t<std::is_const_v<type>, type &, void>()
39*1f879005STim Keith       const noexcept {
4064ab3302SCarolineConcatto     if constexpr (std::is_const_v<type>) {
4164ab3302SCarolineConcatto       return *p_;
4264ab3302SCarolineConcatto     }
4364ab3302SCarolineConcatto   }
4464ab3302SCarolineConcatto 
get()4564ab3302SCarolineConcatto   type &get() const noexcept { return *p_; }
4664ab3302SCarolineConcatto   type *operator->() const { return p_; }
4764ab3302SCarolineConcatto   type &operator*() const { return *p_; }
48e03b20e6Speter klausler 
49e03b20e6Speter klausler   bool operator==(std::add_const_t<A> &that) const {
50e03b20e6Speter klausler     return p_ == &that || *p_ == that;
51e03b20e6Speter klausler   }
52e03b20e6Speter klausler   bool operator!=(std::add_const_t<A> &that) const { return !(*this == that); }
53e03b20e6Speter klausler   bool operator==(const Reference &that) const {
54e03b20e6Speter klausler     return p_ == that.p_ || *this == *that.p_;
55e03b20e6Speter klausler   }
56e03b20e6Speter klausler   bool operator!=(const Reference &that) const { return !(*this == that); }
5764ab3302SCarolineConcatto 
5864ab3302SCarolineConcatto private:
5964ab3302SCarolineConcatto   type *p_; // never null
6064ab3302SCarolineConcatto };
6164ab3302SCarolineConcatto template <typename A> Reference(A &) -> Reference<A>;
62*1f879005STim Keith } // namespace Fortran::common
6364ab3302SCarolineConcatto #endif
64