Re-sort all of the includes with ./utils/sort_includes.py so that
[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 (getError()) error_code(make_error_code(ErrorCode));
116   }
117
118   ErrorOr(llvm::error_code EC) : HasError(true) {
119     new (getError()) error_code(EC);
120   }
121
122   ErrorOr(T Val) : HasError(false) {
123     new (get()) 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       get()->~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   operator llvm::error_code() const {
182     return HasError ? *getError() : llvm::error_code::success();
183   }
184
185   pointer operator ->() {
186     return toPointer(get());
187   }
188
189   reference operator *() {
190     return *get();
191   }
192
193 private:
194   template <class OtherT>
195   void copyConstruct(const ErrorOr<OtherT> &Other) {
196     if (!Other.HasError) {
197       // Get the other value.
198       HasError = false;
199       new (get()) storage_type(*Other.get());
200     } else {
201       // Get other's error.
202       HasError = true;
203       new (getError()) error_code(Other);
204     }
205   }
206
207   template <class T1>
208   static bool compareThisIfSameType(const T1 &a, const T1 &b) {
209     return &a == &b;
210   }
211
212   template <class T1, class T2>
213   static bool compareThisIfSameType(const T1 &a, const T2 &b) {
214     return false;
215   }
216
217   template <class OtherT>
218   void copyAssign(const ErrorOr<OtherT> &Other) {
219     if (compareThisIfSameType(*this, Other))
220       return;
221
222     this->~ErrorOr();
223     new (this) ErrorOr(Other);
224   }
225
226 #if LLVM_HAS_RVALUE_REFERENCES
227   template <class OtherT>
228   void moveConstruct(ErrorOr<OtherT> &&Other) {
229     if (!Other.HasError) {
230       // Get the other value.
231       HasError = false;
232       new (get()) storage_type(std::move(*Other.get()));
233     } else {
234       // Get other's error.
235       HasError = true;
236       new (getError()) error_code(Other);
237     }
238   }
239
240   template <class OtherT>
241   void moveAssign(ErrorOr<OtherT> &&Other) {
242     if (compareThisIfSameType(*this, Other))
243       return;
244
245     this->~ErrorOr();
246     new (this) ErrorOr(std::move(Other));
247   }
248 #endif
249
250   pointer toPointer(pointer Val) {
251     return Val;
252   }
253
254   pointer toPointer(wrap *Val) {
255     return &Val->get();
256   }
257
258   storage_type *get() {
259     assert(!HasError && "Cannot get value when an error exists!");
260     return reinterpret_cast<storage_type*>(TStorage.buffer);
261   }
262
263   const storage_type *get() const {
264     assert(!HasError && "Cannot get value when an error exists!");
265     return reinterpret_cast<const storage_type*>(TStorage.buffer);
266   }
267
268   error_code *getError() {
269     assert(HasError && "Cannot get error when a value exists!");
270     return reinterpret_cast<error_code*>(ErrorStorage.buffer);
271   }
272
273   const error_code *getError() const {
274     return const_cast<ErrorOr<T> *>(this)->getError();
275   }
276
277
278   union {
279     AlignedCharArrayUnion<storage_type> TStorage;
280     AlignedCharArrayUnion<error_code> ErrorStorage;
281   };
282   bool HasError : 1;
283 };
284
285 template<class T, class E>
286 typename enable_if_c<is_error_code_enum<E>::value ||
287                      is_error_condition_enum<E>::value, bool>::type
288 operator ==(ErrorOr<T> &Err, E Code) {
289   return error_code(Err) == Code;
290 }
291 } // end namespace llvm
292
293 #endif