text: //===- 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/Support/AlignOf.h"
  #include <cassert>
  #include <system_error>
  #include <type_traits>
  #include <utility>
  
  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;
  
    using wrap = ReferenceStorage<typename std::remove_reference<T>::type>;
  
  public:
    using storage_type = typename std::conditional<isRef, wrap, T>::type;
  
  private:
    using reference = typename std::remove_reference<T>::type &;
    using const_reference = const typename std::remove_reference<T>::type &;
    using pointer = typename std::remove_reference<T>::type *;
    using const_pointer = const typename std::remove_reference<T>::type *;
  
  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
  