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