Use getError and remove the error_code operator.
[oota-llvm.git] / include / llvm / Support / ErrorOr.h
1 //===- llvm/Support/ErrorOr.h - Error Smart Pointer -----------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 ///
12 /// Provides ErrorOr<T> smart pointer.
13 ///
14 //===----------------------------------------------------------------------===//
15
16 #ifndef LLVM_SUPPORT_ERROR_OR_H
17 #define LLVM_SUPPORT_ERROR_OR_H
18
19 #include "llvm/ADT/PointerIntPair.h"
20 #include "llvm/Support/AlignOf.h"
21 #include "llvm/Support/system_error.h"
22 #include "llvm/Support/type_traits.h"
23 #include <cassert>
24 #if LLVM_HAS_CXX11_TYPETRAITS
25 #include <type_traits>
26 #endif
27
28 namespace llvm {
29 #if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES
30 template<class T, class V>
31 typename std::enable_if< std::is_constructible<T, V>::value
32                        , typename std::remove_reference<V>::type>::type &&
33  moveIfMoveConstructible(V &Val) {
34   return std::move(Val);
35 }
36
37 template<class T, class V>
38 typename std::enable_if< !std::is_constructible<T, V>::value
39                        , typename std::remove_reference<V>::type>::type &
40 moveIfMoveConstructible(V &Val) {
41   return Val;
42 }
43 #else
44 template<class T, class V>
45 V &moveIfMoveConstructible(V &Val) {
46   return Val;
47 }
48 #endif
49
50 /// \brief Stores a reference that can be changed.
51 template <typename T>
52 class ReferenceStorage {
53   T *Storage;
54
55 public:
56   ReferenceStorage(T &Ref) : Storage(&Ref) {}
57
58   operator T &() const { return *Storage; }
59   T &get() const { return *Storage; }
60 };
61
62 /// \brief Represents either an error or a value T.
63 ///
64 /// ErrorOr<T> is a pointer-like class that represents the result of an
65 /// operation. The result is either an error, or a value of type T. This is
66 /// designed to emulate the usage of returning a pointer where nullptr indicates
67 /// failure. However instead of just knowing that the operation failed, we also
68 /// have an error_code and optional user data that describes why it failed.
69 ///
70 /// It is used like the following.
71 /// \code
72 ///   ErrorOr<Buffer> getBuffer();
73 ///   void handleError(error_code ec);
74 ///
75 ///   auto buffer = getBuffer();
76 ///   if (!buffer)
77 ///     handleError(buffer);
78 ///   buffer->write("adena");
79 /// \endcode
80 ///
81 ///
82 /// An implicit conversion to bool provides a way to check if there was an
83 /// error. The unary * and -> operators provide pointer like access to the
84 /// value. Accessing the value when there is an error has undefined behavior.
85 ///
86 /// When T is a reference type the behaivor is slightly different. The reference
87 /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
88 /// there is special handling to make operator -> work as if T was not a
89 /// reference.
90 ///
91 /// T cannot be a rvalue reference.
92 template<class T>
93 class ErrorOr {
94   template <class OtherT> friend class ErrorOr;
95   static const bool isRef = is_reference<T>::value;
96   typedef ReferenceStorage<typename remove_reference<T>::type> wrap;
97
98 public:
99   typedef typename
100     conditional< isRef
101                , wrap
102                , T
103                >::type storage_type;
104
105 private:
106   typedef typename remove_reference<T>::type &reference;
107   typedef typename remove_reference<T>::type *pointer;
108
109 public:
110   template <class E>
111   ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value ||
112                                             is_error_condition_enum<E>::value,
113                                             void *>::type = 0)
114       : HasError(true) {
115     new (getErrorStorage()) error_code(make_error_code(ErrorCode));
116   }
117
118   ErrorOr(llvm::error_code EC) : HasError(true) {
119     new (getErrorStorage()) error_code(EC);
120   }
121
122   ErrorOr(T Val) : HasError(false) {
123     new (getStorage()) storage_type(moveIfMoveConstructible<storage_type>(Val));
124   }
125
126   ErrorOr(const ErrorOr &Other) {
127     copyConstruct(Other);
128   }
129
130   template <class OtherT>
131   ErrorOr(const ErrorOr<OtherT> &Other) {
132     copyConstruct(Other);
133   }
134
135   ErrorOr &operator =(const ErrorOr &Other) {
136     copyAssign(Other);
137     return *this;
138   }
139
140   template <class OtherT>
141   ErrorOr &operator =(const ErrorOr<OtherT> &Other) {
142     copyAssign(Other);
143     return *this;
144   }
145
146 #if LLVM_HAS_RVALUE_REFERENCES
147   ErrorOr(ErrorOr &&Other) {
148     moveConstruct(std::move(Other));
149   }
150
151   template <class OtherT>
152   ErrorOr(ErrorOr<OtherT> &&Other) {
153     moveConstruct(std::move(Other));
154   }
155
156   ErrorOr &operator =(ErrorOr &&Other) {
157     moveAssign(std::move(Other));
158     return *this;
159   }
160
161   template <class OtherT>
162   ErrorOr &operator =(ErrorOr<OtherT> &&Other) {
163     moveAssign(std::move(Other));
164     return *this;
165   }
166 #endif
167
168   ~ErrorOr() {
169     if (!HasError)
170       getStorage()->~storage_type();
171   }
172
173   typedef void (*unspecified_bool_type)();
174   static void unspecified_bool_true() {}
175
176   /// \brief Return false if there is an error.
177   operator unspecified_bool_type() const {
178     return HasError ? 0 : unspecified_bool_true;
179   }
180
181   T &get() { return *getStorage(); }
182   const T &get() const { return const_cast<ErrorOr<T> >(this)->get(); }
183
184   error_code getError() const {
185     return HasError ? *getErrorStorage() : error_code::success();
186   }
187
188   pointer operator ->() {
189     return toPointer(getStorage());
190   }
191
192   reference operator *() {
193     return *getStorage();
194   }
195
196 private:
197   template <class OtherT>
198   void copyConstruct(const ErrorOr<OtherT> &Other) {
199     if (!Other.HasError) {
200       // Get the other value.
201       HasError = false;
202       new (getStorage()) storage_type(*Other.getStorage());
203     } else {
204       // Get other's error.
205       HasError = true;
206       new (getErrorStorage()) error_code(Other);
207     }
208   }
209
210   template <class T1>
211   static bool compareThisIfSameType(const T1 &a, const T1 &b) {
212     return &a == &b;
213   }
214
215   template <class T1, class T2>
216   static bool compareThisIfSameType(const T1 &a, const T2 &b) {
217     return false;
218   }
219
220   template <class OtherT>
221   void copyAssign(const ErrorOr<OtherT> &Other) {
222     if (compareThisIfSameType(*this, Other))
223       return;
224
225     this->~ErrorOr();
226     new (this) ErrorOr(Other);
227   }
228
229 #if LLVM_HAS_RVALUE_REFERENCES
230   template <class OtherT>
231   void moveConstruct(ErrorOr<OtherT> &&Other) {
232     if (!Other.HasError) {
233       // Get the other value.
234       HasError = false;
235       new (getStorage()) storage_type(std::move(*Other.getStorage()));
236     } else {
237       // Get other's error.
238       HasError = true;
239       new (getErrorStorage()) error_code(Other.getError());
240     }
241   }
242
243   template <class OtherT>
244   void moveAssign(ErrorOr<OtherT> &&Other) {
245     if (compareThisIfSameType(*this, Other))
246       return;
247
248     this->~ErrorOr();
249     new (this) ErrorOr(std::move(Other));
250   }
251 #endif
252
253   pointer toPointer(pointer Val) {
254     return Val;
255   }
256
257   pointer toPointer(wrap *Val) {
258     return &Val->get();
259   }
260
261   storage_type *getStorage() {
262     assert(!HasError && "Cannot get value when an error exists!");
263     return reinterpret_cast<storage_type*>(TStorage.buffer);
264   }
265
266   const storage_type *getStorage() const {
267     assert(!HasError && "Cannot get value when an error exists!");
268     return reinterpret_cast<const storage_type*>(TStorage.buffer);
269   }
270
271   error_code *getErrorStorage() {
272     assert(HasError && "Cannot get error when a value exists!");
273     return reinterpret_cast<error_code*>(ErrorStorage.buffer);
274   }
275
276   const error_code *getErrorStorage() const {
277     return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
278   }
279
280
281   union {
282     AlignedCharArrayUnion<storage_type> TStorage;
283     AlignedCharArrayUnion<error_code> ErrorStorage;
284   };
285   bool HasError : 1;
286 };
287
288 template<class T, class E>
289 typename enable_if_c<is_error_code_enum<E>::value ||
290                      is_error_condition_enum<E>::value, bool>::type
291 operator ==(ErrorOr<T> &Err, E Code) {
292   return error_code(Err) == Code;
293 }
294 } // end namespace llvm
295
296 #endif