Introduce llvm::sys::path::home_directory.
[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 ///
74 ///   auto buffer = getBuffer();
75 ///   if (error_code ec = buffer.getError())
76 ///     return ec;
77 ///   buffer->write("adena");
78 /// \endcode
79 ///
80 ///
81 /// An implicit conversion to bool provides a way to check if there was an
82 /// error. The unary * and -> operators provide pointer like access to the
83 /// value. Accessing the value when there is an error has undefined behavior.
84 ///
85 /// When T is a reference type the behaivor is slightly different. The reference
86 /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
87 /// there is special handling to make operator -> work as if T was not a
88 /// reference.
89 ///
90 /// T cannot be a rvalue reference.
91 template<class T>
92 class ErrorOr {
93   template <class OtherT> friend class ErrorOr;
94   static const bool isRef = is_reference<T>::value;
95   typedef ReferenceStorage<typename remove_reference<T>::type> wrap;
96
97 public:
98   typedef typename
99     conditional< isRef
100                , wrap
101                , T
102                >::type storage_type;
103
104 private:
105   typedef typename remove_reference<T>::type &reference;
106   typedef typename remove_reference<T>::type *pointer;
107
108 public:
109   template <class E>
110   ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value ||
111                                             is_error_condition_enum<E>::value,
112                                             void *>::type = 0)
113       : HasError(true) {
114     new (getErrorStorage()) error_code(make_error_code(ErrorCode));
115   }
116
117   ErrorOr(llvm::error_code EC) : HasError(true) {
118     new (getErrorStorage()) error_code(EC);
119   }
120
121   ErrorOr(T Val) : HasError(false) {
122     new (getStorage()) storage_type(moveIfMoveConstructible<storage_type>(Val));
123   }
124
125   ErrorOr(const ErrorOr &Other) {
126     copyConstruct(Other);
127   }
128
129   template <class OtherT>
130   ErrorOr(const ErrorOr<OtherT> &Other) {
131     copyConstruct(Other);
132   }
133
134   ErrorOr &operator =(const ErrorOr &Other) {
135     copyAssign(Other);
136     return *this;
137   }
138
139   template <class OtherT>
140   ErrorOr &operator =(const ErrorOr<OtherT> &Other) {
141     copyAssign(Other);
142     return *this;
143   }
144
145 #if LLVM_HAS_RVALUE_REFERENCES
146   ErrorOr(ErrorOr &&Other) {
147     moveConstruct(std::move(Other));
148   }
149
150   template <class OtherT>
151   ErrorOr(ErrorOr<OtherT> &&Other) {
152     moveConstruct(std::move(Other));
153   }
154
155   ErrorOr &operator =(ErrorOr &&Other) {
156     moveAssign(std::move(Other));
157     return *this;
158   }
159
160   template <class OtherT>
161   ErrorOr &operator =(ErrorOr<OtherT> &&Other) {
162     moveAssign(std::move(Other));
163     return *this;
164   }
165 #endif
166
167   ~ErrorOr() {
168     if (!HasError)
169       getStorage()->~storage_type();
170   }
171
172   /// \brief Return false if there is an error.
173   LLVM_EXPLICIT operator bool() const {
174     return !HasError;
175   }
176
177   reference get() { return *getStorage(); }
178   const reference get() const { return const_cast<ErrorOr<T> >(this)->get(); }
179
180   error_code getError() const {
181     return HasError ? *getErrorStorage() : error_code::success();
182   }
183
184   pointer operator ->() {
185     return toPointer(getStorage());
186   }
187
188   reference operator *() {
189     return *getStorage();
190   }
191
192 private:
193   template <class OtherT>
194   void copyConstruct(const ErrorOr<OtherT> &Other) {
195     if (!Other.HasError) {
196       // Get the other value.
197       HasError = false;
198       new (getStorage()) storage_type(*Other.getStorage());
199     } else {
200       // Get other's error.
201       HasError = true;
202       new (getErrorStorage()) error_code(Other.getError());
203     }
204   }
205
206   template <class T1>
207   static bool compareThisIfSameType(const T1 &a, const T1 &b) {
208     return &a == &b;
209   }
210
211   template <class T1, class T2>
212   static bool compareThisIfSameType(const T1 &a, const T2 &b) {
213     return false;
214   }
215
216   template <class OtherT>
217   void copyAssign(const ErrorOr<OtherT> &Other) {
218     if (compareThisIfSameType(*this, Other))
219       return;
220
221     this->~ErrorOr();
222     new (this) ErrorOr(Other);
223   }
224
225 #if LLVM_HAS_RVALUE_REFERENCES
226   template <class OtherT>
227   void moveConstruct(ErrorOr<OtherT> &&Other) {
228     if (!Other.HasError) {
229       // Get the other value.
230       HasError = false;
231       new (getStorage()) storage_type(std::move(*Other.getStorage()));
232     } else {
233       // Get other's error.
234       HasError = true;
235       new (getErrorStorage()) error_code(Other.getError());
236     }
237   }
238
239   template <class OtherT>
240   void moveAssign(ErrorOr<OtherT> &&Other) {
241     if (compareThisIfSameType(*this, Other))
242       return;
243
244     this->~ErrorOr();
245     new (this) ErrorOr(std::move(Other));
246   }
247 #endif
248
249   pointer toPointer(pointer Val) {
250     return Val;
251   }
252
253   pointer toPointer(wrap *Val) {
254     return &Val->get();
255   }
256
257   storage_type *getStorage() {
258     assert(!HasError && "Cannot get value when an error exists!");
259     return reinterpret_cast<storage_type*>(TStorage.buffer);
260   }
261
262   const storage_type *getStorage() const {
263     assert(!HasError && "Cannot get value when an error exists!");
264     return reinterpret_cast<const storage_type*>(TStorage.buffer);
265   }
266
267   error_code *getErrorStorage() {
268     assert(HasError && "Cannot get error when a value exists!");
269     return reinterpret_cast<error_code*>(ErrorStorage.buffer);
270   }
271
272   const error_code *getErrorStorage() const {
273     return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
274   }
275
276
277   union {
278     AlignedCharArrayUnion<storage_type> TStorage;
279     AlignedCharArrayUnion<error_code> ErrorStorage;
280   };
281   bool HasError : 1;
282 };
283
284 template<class T, class E>
285 typename enable_if_c<is_error_code_enum<E>::value ||
286                      is_error_condition_enum<E>::value, bool>::type
287 operator ==(ErrorOr<T> &Err, E Code) {
288   return error_code(Err) == Code;
289 }
290 } // end namespace llvm
291
292 #endif