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