FLANG

indirection.h
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;
35 Indirection(A *&&p) : p_{p} {
36 CHECK(p_ && "assigning null pointer to Indirection");
37 p = nullptr;
38 }
39 Indirection(A &&x) : p_{new A(std::move(x))} {}
40 Indirection(Indirection &&that) : p_{that.p_} {
41 CHECK(p_ && "move construction of Indirection from null Indirection");
42 that.p_ = nullptr;
43 }
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
56 A &value() { return *p_; }
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>
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;
77 Indirection(A *&&p) : p_{p} {
78 CHECK(p_ && "assigning null pointer to Indirection");
79 p = nullptr;
80 }
81 Indirection(const A &x) : p_{new A(x)} {}
82 Indirection(A &&x) : p_{new A(std::move(x))} {}
83 Indirection(const Indirection &that) {
84 CHECK(that.p_ && "copy construction of Indirection from null Indirection");
85 p_ = new A(*that.p_);
86 }
87 Indirection(Indirection &&that) : p_{that.p_} {
88 CHECK(p_ && "move construction of Indirection from null Indirection");
89 that.p_ = nullptr;
90 }
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
108 A &value() { return *p_; }
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>
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:
129 ForwardOwningPointer() {}
130 ForwardOwningPointer(A *p, void (*del)(A *)) : p_{p}, deleter_{del} {}
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 }
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; }
150 A *get() { return p_; }
151 A *release() {
152 A *result{p_};
153 p_ = nullptr;
154 return result;
155 }
156
157 void Reset(A *p, void (*del)(A *)) {
158 if (p_) {
159 deleter_(p_);
160 }
161 p_ = p;
162 deleter_ = del;
163 }
164
165 private:
166 A *p_{nullptr};
167 void (*deleter_)(A *){nullptr};
168 };
169 } // namespace Fortran::common
170 #endif // FORTRAN_COMMON_INDIRECTION_H_
Fortran::common::ForwardOwningPointer
Definition: indirection.h:127
Fortran::common::Indirection
Definition: indirection.h:31
Fortran::common::Indirection< A, true >
Definition: indirection.h:72