xref: /llvm-project/flang/include/flang/Common/indirection.h (revision 4ad7279392653c0bcf564799ffb3f7e20ed4ef00)
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