1 //===-- include/flang/Common/indirection.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 #ifndef FORTRAN_COMMON_INDIRECTION_H_ 10 #define FORTRAN_COMMON_INDIRECTION_H_ 11 12 // Define a smart pointer class template that is rather like 13 // non-nullable std::unique_ptr<>. Indirection<> is, like a C++ reference 14 // type, restricted to be non-null when constructed or assigned. 15 // Indirection<> optionally supports copy construction and copy assignment. 16 // 17 // To use Indirection<> with forward-referenced types, add 18 // extern template class Fortran::common::Indirection<FORWARD_TYPE>; 19 // outside any namespace in a header before use, and 20 // template class Fortran::common::Indirection<FORWARD_TYPE>; 21 // in one C++ source file later where a definition of the type is visible. 22 23 #include "idioms.h" 24 #include <memory> 25 #include <type_traits> 26 #include <utility> 27 28 namespace Fortran::common { 29 30 // The default case does not support (deep) copy construction or assignment. 31 template <typename A, bool COPY = false> class Indirection { 32 public: 33 using element_type = A; 34 Indirection() = delete; Indirection(A * && p)35 Indirection(A *&&p) : p_{p} { 36 CHECK(p_ && "assigning null pointer to Indirection"); 37 p = nullptr; 38 } Indirection(A && x)39 Indirection(A &&x) : p_{new A(std::move(x))} {} Indirection(Indirection && that)40 Indirection(Indirection &&that) : p_{that.p_} { 41 CHECK(p_ && "move construction of Indirection from null Indirection"); 42 that.p_ = nullptr; 43 } ~Indirection()44 ~Indirection() { 45 delete p_; 46 p_ = nullptr; 47 } 48 Indirection &operator=(Indirection &&that) { 49 CHECK(that.p_ && "move assignment of null Indirection to Indirection"); 50 auto tmp{p_}; 51 p_ = that.p_; 52 that.p_ = tmp; 53 return *this; 54 } 55 value()56 A &value() { return *p_; } value()57 const A &value() const { return *p_; } 58 59 bool operator==(const A &that) const { return *p_ == that; } 60 bool operator==(const Indirection &that) const { return *p_ == *that.p_; } 61 62 template <typename... ARGS> Make(ARGS &&...args)63 static common::IfNoLvalue<Indirection, ARGS...> Make(ARGS &&...args) { 64 return {new A(std::move(args)...)}; 65 } 66 67 private: 68 A *p_{nullptr}; 69 }; 70 71 // Variant with copy construction and assignment 72 template <typename A> class Indirection<A, true> { 73 public: 74 using element_type = A; 75 76 Indirection() = delete; Indirection(A * && p)77 Indirection(A *&&p) : p_{p} { 78 CHECK(p_ && "assigning null pointer to Indirection"); 79 p = nullptr; 80 } Indirection(const A & x)81 Indirection(const A &x) : p_{new A(x)} {} Indirection(A && x)82 Indirection(A &&x) : p_{new A(std::move(x))} {} Indirection(const Indirection & that)83 Indirection(const Indirection &that) { 84 CHECK(that.p_ && "copy construction of Indirection from null Indirection"); 85 p_ = new A(*that.p_); 86 } Indirection(Indirection && that)87 Indirection(Indirection &&that) : p_{that.p_} { 88 CHECK(p_ && "move construction of Indirection from null Indirection"); 89 that.p_ = nullptr; 90 } ~Indirection()91 ~Indirection() { 92 delete p_; 93 p_ = nullptr; 94 } 95 Indirection &operator=(const Indirection &that) { 96 CHECK(that.p_ && "copy assignment of Indirection from null Indirection"); 97 *p_ = *that.p_; 98 return *this; 99 } 100 Indirection &operator=(Indirection &&that) { 101 CHECK(that.p_ && "move assignment of null Indirection to Indirection"); 102 auto tmp{p_}; 103 p_ = that.p_; 104 that.p_ = tmp; 105 return *this; 106 } 107 value()108 A &value() { return *p_; } value()109 const A &value() const { return *p_; } 110 111 bool operator==(const A &that) const { return *p_ == that; } 112 bool operator==(const Indirection &that) const { return *p_ == *that.p_; } 113 114 template <typename... ARGS> Make(ARGS &&...args)115 static common::IfNoLvalue<Indirection, ARGS...> Make(ARGS &&...args) { 116 return {new A(std::move(args)...)}; 117 } 118 119 private: 120 A *p_{nullptr}; 121 }; 122 123 template <typename A> using CopyableIndirection = Indirection<A, true>; 124 125 // A variation of std::unique_ptr<> with a reified deletion routine. 126 // Used to avoid dependence cycles between shared libraries. 127 template <typename A> class ForwardOwningPointer { 128 public: ForwardOwningPointer()129 ForwardOwningPointer() {} ForwardOwningPointer(A * p,void (* del)(A *))130 ForwardOwningPointer(A *p, void (*del)(A *)) : p_{p}, deleter_{del} {} ForwardOwningPointer(ForwardOwningPointer && that)131 ForwardOwningPointer(ForwardOwningPointer &&that) 132 : p_{that.p_}, deleter_{that.deleter_} { 133 that.p_ = nullptr; 134 } 135 ForwardOwningPointer &operator=(ForwardOwningPointer &&that) { 136 p_ = that.p_; 137 that.p_ = nullptr; 138 deleter_ = that.deleter_; 139 return *this; 140 } ~ForwardOwningPointer()141 ~ForwardOwningPointer() { 142 if (p_) { 143 deleter_(p_); 144 } 145 } 146 147 A &operator*() const { return *p_; } 148 A *operator->() const { return p_; } 149 operator bool() const { return p_ != nullptr; } get()150 A *get() { return p_; } get()151 auto get() const { return reinterpret_cast<std::add_const_t<A> *>(p_); } release()152 A *release() { 153 A *result{p_}; 154 p_ = nullptr; 155 return result; 156 } 157 158 void Reset(A *p = nullptr) { 159 if (p_) { 160 deleter_(p_); 161 } 162 p_ = p; 163 } Reset(A * p,void (* del)(A *))164 void Reset(A *p, void (*del)(A *)) { 165 Reset(p); 166 deleter_ = del; 167 } 168 169 private: 170 A *p_{nullptr}; 171 void (*deleter_)(A *){nullptr}; 172 }; 173 } // namespace Fortran::common 174 #endif // FORTRAN_COMMON_INDIRECTION_H_ 175