[Support] Port ErrorOr<T> from lld to C++03.
[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/Support/AlignOf.h"
20 #include "llvm/Support/system_error.h"
21 #include "llvm/Support/type_traits.h"
22
23 #include <cassert>
24 #if LLVM_HAS_CXX11_TYPETRAITS
25 #include <type_traits>
26 #endif
27
28 namespace llvm {
29 struct ErrorHolderBase {
30   error_code Error;
31   uint16_t RefCount;
32   bool HasUserData;
33
34   ErrorHolderBase() : RefCount(1) {}
35
36   void aquire() {
37     ++RefCount;
38   }
39
40   void release() {
41     if (--RefCount == 0)
42       delete this;
43   }
44
45 protected:
46   virtual ~ErrorHolderBase() {}
47 };
48
49 template<class T>
50 struct ErrorHolder : ErrorHolderBase {
51 #if LLVM_HAS_RVALUE_REFERENCES
52   ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {}
53 #else
54   ErrorHolder(T &UD) : UserData(UD) {}
55 #endif
56   T UserData;
57 };
58
59 template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {};
60
61 #if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES
62 template<class T, class V>
63 typename std::enable_if< std::is_constructible<T, V>::value
64                        , typename std::remove_reference<V>::type>::type &&
65  moveIfMoveConstructible(V &Val) {
66   return std::move(Val);
67 }
68
69 template<class T, class V>
70 typename std::enable_if< !std::is_constructible<T, V>::value
71                        , typename std::remove_reference<V>::type>::type &
72 moveIfMoveConstructible(V &Val) {
73   return Val;
74 }
75 #else
76 template<class T, class V>
77 V &moveIfMoveConstructible(V &Val) {
78   return Val;
79 }
80 #endif
81
82 /// \brief Stores a reference that can be changed.
83 template <typename T>
84 class ReferenceStorage {
85   T *Storage;
86
87 public:
88   ReferenceStorage(T &Ref) : Storage(&Ref) {}
89
90   operator T &() const { return *Storage; }
91   T &get() const { return *Storage; }
92 };
93
94 /// \brief Represents either an error or a value T.
95 ///
96 /// ErrorOr<T> is a pointer-like class that represents the result of an
97 /// operation. The result is either an error, or a value of type T. This is
98 /// designed to emulate the usage of returning a pointer where nullptr indicates
99 /// failure. However instead of just knowing that the operation failed, we also
100 /// have an error_code and optional user data that describes why it failed.
101 ///
102 /// It is used like the following.
103 /// \code
104 ///   ErrorOr<Buffer> getBuffer();
105 ///   void handleError(error_code ec);
106 ///
107 ///   auto buffer = getBuffer();
108 ///   if (!buffer)
109 ///     handleError(buffer);
110 ///   buffer->write("adena");
111 /// \endcode
112 ///
113 /// ErrorOr<T> also supports user defined data for specific error_codes. To use
114 /// this feature you must first add a template specialization of
115 /// ErrorOrUserDataTraits derived from std::true_type for your type in the lld
116 /// namespace. This specialization must have a static error_code error()
117 /// function that returns the error_code this data is used with.
118 ///
119 /// getError<UserData>() may be called to get either the stored user data, or
120 /// a default constructed UserData if none was stored.
121 ///
122 /// Example:
123 /// \code
124 ///   struct InvalidArgError {
125 ///     InvalidArgError() {}
126 ///     InvalidArgError(std::string S) : ArgName(S) {}
127 ///     std::string ArgName;
128 ///   };
129 ///
130 ///   namespace llvm {
131 ///   template<>
132 ///   struct ErrorOrUserDataTraits<InvalidArgError> : std::true_type {
133 ///     static error_code error() {
134 ///       return make_error_code(errc::invalid_argument);
135 ///     }
136 ///   };
137 ///   } // end namespace llvm
138 ///
139 ///   using namespace llvm;
140 ///
141 ///   ErrorOr<int> foo() {
142 ///     return InvalidArgError("adena");
143 ///   }
144 ///
145 ///   int main() {
146 ///     auto a = foo();
147 ///     if (!a && error_code(a) == errc::invalid_argument)
148 ///       llvm::errs() << a.getError<InvalidArgError>().ArgName << "\n";
149 ///   }
150 /// \endcode
151 ///
152 /// An implicit conversion to bool provides a way to check if there was an
153 /// error. The unary * and -> operators provide pointer like access to the
154 /// value. Accessing the value when there is an error has undefined behavior.
155 ///
156 /// When T is a reference type the behaivor is slightly different. The reference
157 /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
158 /// there is special handling to make operator -> work as if T was not a
159 /// reference.
160 ///
161 /// T cannot be a rvalue reference.
162 template<class T>
163 class ErrorOr {
164   static const bool isRef = is_reference<T>::value;
165   typedef ReferenceStorage<typename remove_reference<T>::type> wrap;
166
167 public:
168   typedef typename
169     conditional< isRef
170                , wrap
171                , T
172                >::type storage_type;
173
174 private:
175   typedef T &reference;
176   typedef typename remove_reference<T>::type *pointer;
177
178 public:
179   ErrorOr() : IsValid(false) {}
180
181   ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
182     Error = new ErrorHolderBase;
183     Error->Error = EC;
184     Error->HasUserData = false;
185   }
186
187   template<class UserDataT>
188   ErrorOr(UserDataT UD, typename
189           enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0)
190     : HasError(true), IsValid(true) {
191     Error = new ErrorHolder<UserDataT>(llvm_move(UD));
192     Error->Error = ErrorOrUserDataTraits<UserDataT>::error();
193     Error->HasUserData = true;
194   }
195
196   ErrorOr(T Val) : HasError(false), IsValid(true) {
197     new (get()) storage_type(moveIfMoveConstructible<storage_type>(Val));
198   }
199
200   ErrorOr(const ErrorOr &Other) : IsValid(false) {
201     // Construct an invalid ErrorOr if other is invalid.
202     if (!Other.IsValid)
203       return;
204     if (!Other.HasError) {
205       // Get the other value.
206       new (get()) storage_type(*Other.get());
207       HasError = false;
208     } else {
209       // Get other's error.
210       Error = Other.Error;
211       HasError = true;
212       Error->aquire();
213     }
214
215     IsValid = true;
216   }
217
218   ErrorOr &operator =(const ErrorOr &Other) {
219     if (this == &Other)
220       return *this;
221
222     this->~ErrorOr();
223     new (this) ErrorOr(Other);
224
225     return *this;
226   }
227
228 #if LLVM_HAS_RVALUE_REFERENCES
229   ErrorOr(ErrorOr &&Other) : IsValid(false) {
230     // Construct an invalid ErrorOr if other is invalid.
231     if (!Other.IsValid)
232       return;
233     if (!Other.HasError) {
234       // Get the other value.
235       IsValid = true;
236       new (get()) storage_type(std::move(*Other.get()));
237       HasError = false;
238       // Tell other not to do any destruction.
239       Other.IsValid = false;
240     } else {
241       // Get other's error.
242       Error = Other.Error;
243       HasError = true;
244       // Tell other not to do any destruction.
245       Other.IsValid = false;
246     }
247
248     IsValid = true;
249   }
250
251   ErrorOr &operator =(ErrorOr &&Other) {
252     if (this == &Other)
253       return *this;
254
255     this->~ErrorOr();
256     new (this) ErrorOr(std::move(Other));
257
258     return *this;
259   }
260
261   ~ErrorOr() {
262     if (!IsValid)
263       return;
264     if (HasError)
265       Error->release();
266     else
267       get()->~storage_type();
268   }
269 #endif
270
271   template<class ET>
272   ET getError() const {
273     assert(IsValid && "Cannot get the error of a default constructed ErrorOr!");
274     assert(HasError && "Cannot get an error if none exists!");
275     assert(ErrorOrUserDataTraits<ET>::error() == Error->Error &&
276            "Incorrect user error data type for error!");
277     if (!Error->HasUserData)
278       return ET();
279     return reinterpret_cast<const ErrorHolder<ET>*>(Error)->UserData;
280   }
281
282   typedef void (*unspecified_bool_type)();
283   static void unspecified_bool_true() {}
284
285   /// \brief Return false if there is an error.
286   operator unspecified_bool_type() const {
287     assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
288     return HasError ? 0 : unspecified_bool_true;
289   }
290
291   operator llvm::error_code() const {
292     assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
293     return HasError ? Error->Error : llvm::error_code::success();
294   }
295
296   pointer operator ->() {
297     return toPointer(get());
298   }
299
300   reference operator *() {
301     return *get();
302   }
303
304 private:
305   pointer toPointer(pointer Val) {
306     return Val;
307   }
308
309   pointer toPointer(wrap *Val) {
310     return &Val->get();
311   }
312
313 protected:
314   storage_type *get() {
315     assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
316     assert(!HasError && "Cannot get value when an error exists!");
317     return reinterpret_cast<storage_type*>(TStorage.buffer);
318   }
319
320   const storage_type *get() const {
321     assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
322     assert(!HasError && "Cannot get value when an error exists!");
323     return reinterpret_cast<const storage_type*>(TStorage.buffer);
324   }
325
326   union {
327     AlignedCharArrayUnion<storage_type> TStorage;
328     ErrorHolderBase *Error;
329   };
330   bool HasError : 1;
331   bool IsValid : 1;
332 };
333
334 template<class T, class E>
335 typename enable_if_c<is_error_code_enum<E>::value ||
336                      is_error_condition_enum<E>::value, bool>::type
337 operator ==(ErrorOr<T> &Err, E Code) {
338   return error_code(Err) == Code;
339 }
340 } // end namespace llvm
341
342 #endif