|  | //===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===// | 
|  | // | 
|  | //                             The LLVM Linker | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// | 
|  | /// \file | 
|  | /// | 
|  | /// Provides ErrorOr<T> smart pointer. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_SUPPORT_ERROROR_H | 
|  | #define LLVM_SUPPORT_ERROROR_H | 
|  |  | 
|  | #include "llvm/ADT/PointerIntPair.h" | 
|  | #include "llvm/Support/AlignOf.h" | 
|  | #include <cassert> | 
|  | #include <system_error> | 
|  | #include <type_traits> | 
|  |  | 
|  | namespace llvm { | 
|  | /// \brief Stores a reference that can be changed. | 
|  | template <typename T> | 
|  | class ReferenceStorage { | 
|  | T *Storage; | 
|  |  | 
|  | public: | 
|  | ReferenceStorage(T &Ref) : Storage(&Ref) {} | 
|  |  | 
|  | operator T &() const { return *Storage; } | 
|  | T &get() const { return *Storage; } | 
|  | }; | 
|  |  | 
|  | /// \brief Represents either an error or a value T. | 
|  | /// | 
|  | /// ErrorOr<T> is a pointer-like class that represents the result of an | 
|  | /// operation. The result is either an error, or a value of type T. This is | 
|  | /// designed to emulate the usage of returning a pointer where nullptr indicates | 
|  | /// failure. However instead of just knowing that the operation failed, we also | 
|  | /// have an error_code and optional user data that describes why it failed. | 
|  | /// | 
|  | /// It is used like the following. | 
|  | /// \code | 
|  | ///   ErrorOr<Buffer> getBuffer(); | 
|  | /// | 
|  | ///   auto buffer = getBuffer(); | 
|  | ///   if (error_code ec = buffer.getError()) | 
|  | ///     return ec; | 
|  | ///   buffer->write("adena"); | 
|  | /// \endcode | 
|  | /// | 
|  | /// | 
|  | /// Implicit conversion to bool returns true if there is a usable value. The | 
|  | /// unary * and -> operators provide pointer like access to the value. Accessing | 
|  | /// the value when there is an error has undefined behavior. | 
|  | /// | 
|  | /// When T is a reference type the behavior is slightly different. The reference | 
|  | /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and | 
|  | /// there is special handling to make operator -> work as if T was not a | 
|  | /// reference. | 
|  | /// | 
|  | /// T cannot be a rvalue reference. | 
|  | template<class T> | 
|  | class ErrorOr { | 
|  | template <class OtherT> friend class ErrorOr; | 
|  | static const bool isRef = std::is_reference<T>::value; | 
|  | typedef ReferenceStorage<typename std::remove_reference<T>::type> wrap; | 
|  |  | 
|  | public: | 
|  | typedef typename std::conditional<isRef, wrap, T>::type storage_type; | 
|  |  | 
|  | private: | 
|  | typedef typename std::remove_reference<T>::type &reference; | 
|  | typedef const typename std::remove_reference<T>::type &const_reference; | 
|  | typedef typename std::remove_reference<T>::type *pointer; | 
|  | typedef const typename std::remove_reference<T>::type *const_pointer; | 
|  |  | 
|  | public: | 
|  | template <class E> | 
|  | ErrorOr(E ErrorCode, | 
|  | typename std::enable_if<std::is_error_code_enum<E>::value || | 
|  | std::is_error_condition_enum<E>::value, | 
|  | void *>::type = nullptr) | 
|  | : HasError(true) { | 
|  | new (getErrorStorage()) std::error_code(make_error_code(ErrorCode)); | 
|  | } | 
|  |  | 
|  | ErrorOr(std::error_code EC) : HasError(true) { | 
|  | new (getErrorStorage()) std::error_code(EC); | 
|  | } | 
|  |  | 
|  | template <class OtherT> | 
|  | ErrorOr(OtherT &&Val, | 
|  | typename std::enable_if<std::is_convertible<OtherT, T>::value>::type | 
|  | * = nullptr) | 
|  | : HasError(false) { | 
|  | new (getStorage()) storage_type(std::forward<OtherT>(Val)); | 
|  | } | 
|  |  | 
|  | ErrorOr(const ErrorOr &Other) { | 
|  | copyConstruct(Other); | 
|  | } | 
|  |  | 
|  | template <class OtherT> | 
|  | ErrorOr( | 
|  | const ErrorOr<OtherT> &Other, | 
|  | typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = | 
|  | nullptr) { | 
|  | copyConstruct(Other); | 
|  | } | 
|  |  | 
|  | template <class OtherT> | 
|  | explicit ErrorOr( | 
|  | const ErrorOr<OtherT> &Other, | 
|  | typename std::enable_if< | 
|  | !std::is_convertible<OtherT, const T &>::value>::type * = nullptr) { | 
|  | copyConstruct(Other); | 
|  | } | 
|  |  | 
|  | ErrorOr(ErrorOr &&Other) { | 
|  | moveConstruct(std::move(Other)); | 
|  | } | 
|  |  | 
|  | template <class OtherT> | 
|  | ErrorOr( | 
|  | ErrorOr<OtherT> &&Other, | 
|  | typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * = | 
|  | nullptr) { | 
|  | moveConstruct(std::move(Other)); | 
|  | } | 
|  |  | 
|  | // This might eventually need SFINAE but it's more complex than is_convertible | 
|  | // & I'm too lazy to write it right now. | 
|  | template <class OtherT> | 
|  | explicit ErrorOr( | 
|  | ErrorOr<OtherT> &&Other, | 
|  | typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * = | 
|  | nullptr) { | 
|  | moveConstruct(std::move(Other)); | 
|  | } | 
|  |  | 
|  | ErrorOr &operator=(const ErrorOr &Other) { | 
|  | copyAssign(Other); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | ErrorOr &operator=(ErrorOr &&Other) { | 
|  | moveAssign(std::move(Other)); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | ~ErrorOr() { | 
|  | if (!HasError) | 
|  | getStorage()->~storage_type(); | 
|  | } | 
|  |  | 
|  | /// \brief Return false if there is an error. | 
|  | explicit operator bool() const { | 
|  | return !HasError; | 
|  | } | 
|  |  | 
|  | reference get() { return *getStorage(); } | 
|  | const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); } | 
|  |  | 
|  | std::error_code getError() const { | 
|  | return HasError ? *getErrorStorage() : std::error_code(); | 
|  | } | 
|  |  | 
|  | pointer operator ->() { | 
|  | return toPointer(getStorage()); | 
|  | } | 
|  |  | 
|  | const_pointer operator->() const { return toPointer(getStorage()); } | 
|  |  | 
|  | reference operator *() { | 
|  | return *getStorage(); | 
|  | } | 
|  |  | 
|  | const_reference operator*() const { return *getStorage(); } | 
|  |  | 
|  | private: | 
|  | template <class OtherT> | 
|  | void copyConstruct(const ErrorOr<OtherT> &Other) { | 
|  | if (!Other.HasError) { | 
|  | // Get the other value. | 
|  | HasError = false; | 
|  | new (getStorage()) storage_type(*Other.getStorage()); | 
|  | } else { | 
|  | // Get other's error. | 
|  | HasError = true; | 
|  | new (getErrorStorage()) std::error_code(Other.getError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <class T1> | 
|  | static bool compareThisIfSameType(const T1 &a, const T1 &b) { | 
|  | return &a == &b; | 
|  | } | 
|  |  | 
|  | template <class T1, class T2> | 
|  | static bool compareThisIfSameType(const T1 &a, const T2 &b) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | template <class OtherT> | 
|  | void copyAssign(const ErrorOr<OtherT> &Other) { | 
|  | if (compareThisIfSameType(*this, Other)) | 
|  | return; | 
|  |  | 
|  | this->~ErrorOr(); | 
|  | new (this) ErrorOr(Other); | 
|  | } | 
|  |  | 
|  | template <class OtherT> | 
|  | void moveConstruct(ErrorOr<OtherT> &&Other) { | 
|  | if (!Other.HasError) { | 
|  | // Get the other value. | 
|  | HasError = false; | 
|  | new (getStorage()) storage_type(std::move(*Other.getStorage())); | 
|  | } else { | 
|  | // Get other's error. | 
|  | HasError = true; | 
|  | new (getErrorStorage()) std::error_code(Other.getError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <class OtherT> | 
|  | void moveAssign(ErrorOr<OtherT> &&Other) { | 
|  | if (compareThisIfSameType(*this, Other)) | 
|  | return; | 
|  |  | 
|  | this->~ErrorOr(); | 
|  | new (this) ErrorOr(std::move(Other)); | 
|  | } | 
|  |  | 
|  | pointer toPointer(pointer Val) { | 
|  | return Val; | 
|  | } | 
|  |  | 
|  | const_pointer toPointer(const_pointer Val) const { return Val; } | 
|  |  | 
|  | pointer toPointer(wrap *Val) { | 
|  | return &Val->get(); | 
|  | } | 
|  |  | 
|  | const_pointer toPointer(const wrap *Val) const { return &Val->get(); } | 
|  |  | 
|  | storage_type *getStorage() { | 
|  | assert(!HasError && "Cannot get value when an error exists!"); | 
|  | return reinterpret_cast<storage_type*>(TStorage.buffer); | 
|  | } | 
|  |  | 
|  | const storage_type *getStorage() const { | 
|  | assert(!HasError && "Cannot get value when an error exists!"); | 
|  | return reinterpret_cast<const storage_type*>(TStorage.buffer); | 
|  | } | 
|  |  | 
|  | std::error_code *getErrorStorage() { | 
|  | assert(HasError && "Cannot get error when a value exists!"); | 
|  | return reinterpret_cast<std::error_code *>(ErrorStorage.buffer); | 
|  | } | 
|  |  | 
|  | const std::error_code *getErrorStorage() const { | 
|  | return const_cast<ErrorOr<T> *>(this)->getErrorStorage(); | 
|  | } | 
|  |  | 
|  | union { | 
|  | AlignedCharArrayUnion<storage_type> TStorage; | 
|  | AlignedCharArrayUnion<std::error_code> ErrorStorage; | 
|  | }; | 
|  | bool HasError : 1; | 
|  | }; | 
|  |  | 
|  | template <class T, class E> | 
|  | typename std::enable_if<std::is_error_code_enum<E>::value || | 
|  | std::is_error_condition_enum<E>::value, | 
|  | bool>::type | 
|  | operator==(const ErrorOr<T> &Err, E Code) { | 
|  | return Err.getError() == Code; | 
|  | } | 
|  | } // end namespace llvm | 
|  |  | 
|  | #endif // LLVM_SUPPORT_ERROROR_H |