#ifndef LLVM_SUPPORT_ERROR_OR_H
#define LLVM_SUPPORT_ERROR_OR_H
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/system_error.h"
#include "llvm/Support/type_traits.h"
#include <cassert>
#if LLVM_HAS_CXX11_TYPETRAITS
#include <type_traits>
#endif
namespace llvm {
struct ErrorHolderBase {
error_code Error;
uint16_t RefCount;
bool HasUserData;
ErrorHolderBase() : RefCount(1) {}
void aquire() {
++RefCount;
}
void release() {
if (--RefCount == 0)
delete this;
}
protected:
virtual ~ErrorHolderBase() {}
};
template<class T>
struct ErrorHolder : ErrorHolderBase {
#if LLVM_HAS_RVALUE_REFERENCES
ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {}
#else
ErrorHolder(T &UD) : UserData(UD) {}
#endif
T UserData;
};
template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {};
#if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES
template<class T, class V>
typename std::enable_if< std::is_constructible<T, V>::value
, typename std::remove_reference<V>::type>::type &&
moveIfMoveConstructible(V &Val) {
return std::move(Val);
}
template<class T, class V>
typename std::enable_if< !std::is_constructible<T, V>::value
, typename std::remove_reference<V>::type>::type &
moveIfMoveConstructible(V &Val) {
return Val;
}
#else
template<class T, class V>
V &moveIfMoveConstructible(V &Val) {
return Val;
}
#endif
template <typename T>
class ReferenceStorage {
T *Storage;
public:
ReferenceStorage(T &Ref) : Storage(&Ref) {}
operator T &() const { return *Storage; }
T &get() const { return *Storage; }
};
template<class T>
class ErrorOr {
static const bool isRef = is_reference<T>::value;
typedef ReferenceStorage<typename remove_reference<T>::type> wrap;
public:
typedef typename
conditional< isRef
, wrap
, T
>::type storage_type;
private:
typedef typename remove_reference<T>::type &reference;
typedef typename remove_reference<T>::type *pointer;
public:
ErrorOr() : IsValid(false) {}
ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
Error = new ErrorHolderBase;
Error->Error = EC;
Error->HasUserData = false;
}
template<class UserDataT>
ErrorOr(UserDataT UD, typename
enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0)
: HasError(true), IsValid(true) {
Error = new ErrorHolder<UserDataT>(llvm_move(UD));
Error->Error = ErrorOrUserDataTraits<UserDataT>::error();
Error->HasUserData = true;
}
ErrorOr(T Val) : HasError(false), IsValid(true) {
new (get()) storage_type(moveIfMoveConstructible<storage_type>(Val));
}
ErrorOr(const ErrorOr &Other) : IsValid(false) {
if (!Other.IsValid)
return;
if (!Other.HasError) {
new (get()) storage_type(*Other.get());
HasError = false;
} else {
Error = Other.Error;
HasError = true;
Error->aquire();
}
IsValid = true;
}
ErrorOr &operator =(const ErrorOr &Other) {
if (this == &Other)
return *this;
this->~ErrorOr();
new (this) ErrorOr(Other);
return *this;
}
#if LLVM_HAS_RVALUE_REFERENCES
ErrorOr(ErrorOr &&Other) : IsValid(false) {
if (!Other.IsValid)
return;
if (!Other.HasError) {
IsValid = true;
new (get()) storage_type(std::move(*Other.get()));
HasError = false;
Other.IsValid = false;
} else {
Error = Other.Error;
HasError = true;
Other.IsValid = false;
}
IsValid = true;
}
ErrorOr &operator =(ErrorOr &&Other) {
if (this == &Other)
return *this;
this->~ErrorOr();
new (this) ErrorOr(std::move(Other));
return *this;
}
#endif
~ErrorOr() {
if (!IsValid)
return;
if (HasError)
Error->release();
else
get()->~storage_type();
}
template<class ET>
ET getError() const {
assert(IsValid && "Cannot get the error of a default constructed ErrorOr!");
assert(HasError && "Cannot get an error if none exists!");
assert(ErrorOrUserDataTraits<ET>::error() == Error->Error &&
"Incorrect user error data type for error!");
if (!Error->HasUserData)
return ET();
return reinterpret_cast<const ErrorHolder<ET>*>(Error)->UserData;
}
typedef void (*unspecified_bool_type)();
static void unspecified_bool_true() {}
operator unspecified_bool_type() const {
assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
return HasError ? 0 : unspecified_bool_true;
}
operator llvm::error_code() const {
assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
return HasError ? Error->Error : llvm::error_code::success();
}
pointer operator ->() {
return toPointer(get());
}
reference operator *() {
return *get();
}
private:
pointer toPointer(pointer Val) {
return Val;
}
pointer toPointer(wrap *Val) {
return &Val->get();
}
protected:
storage_type *get() {
assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
assert(!HasError && "Cannot get value when an error exists!");
return reinterpret_cast<storage_type*>(TStorage.buffer);
}
const storage_type *get() const {
assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
assert(!HasError && "Cannot get value when an error exists!");
return reinterpret_cast<const storage_type*>(TStorage.buffer);
}
union {
AlignedCharArrayUnion<storage_type> TStorage;
ErrorHolderBase *Error;
};
bool HasError : 1;
bool IsValid : 1;
};
template <>
class ErrorOr<void> {
public:
ErrorOr() : Error(0, 0) {}
ErrorOr(llvm::error_code EC) : Error(0, 0) {
if (EC == errc::success) {
Error.setInt(1);
return;
}
ErrorHolderBase *E = new ErrorHolderBase;
E->Error = EC;
E->HasUserData = false;
Error.setPointer(E);
}
template<class UserDataT>
ErrorOr(UserDataT UD, typename
enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0)
: Error(0, 0) {
ErrorHolderBase *E = new ErrorHolder<UserDataT>(llvm_move(UD));
E->Error = ErrorOrUserDataTraits<UserDataT>::error();
E->HasUserData = true;
Error.setPointer(E);
}
ErrorOr(const ErrorOr &Other) : Error(0, 0) {
Error = Other.Error;
if (Other.Error.getPointer()->Error) {
Error.getPointer()->aquire();
}
}
ErrorOr &operator =(const ErrorOr &Other) {
if (this == &Other)
return *this;
this->~ErrorOr();
new (this) ErrorOr(Other);
return *this;
}
#if LLVM_HAS_RVALUE_REFERENCES
ErrorOr(ErrorOr &&Other) : Error(0) {
Error = Other.Error;
Other.Error.setPointer(0);
}
ErrorOr &operator =(ErrorOr &&Other) {
if (this == &Other)
return *this;
this->~ErrorOr();
new (this) ErrorOr(std::move(Other));
return *this;
}
#endif
~ErrorOr() {
if (Error.getPointer())
Error.getPointer()->release();
}
template<class ET>
ET getError() const {
assert(ErrorOrUserDataTraits<ET>::error() == *this &&
"Incorrect user error data type for error!");
if (!Error.getPointer()->HasUserData)
return ET();
return reinterpret_cast<const ErrorHolder<ET> *>(
Error.getPointer())->UserData;
}
typedef void (*unspecified_bool_type)();
static void unspecified_bool_true() {}
operator unspecified_bool_type() const {
return Error.getInt() ? unspecified_bool_true : 0;
}
operator llvm::error_code() const {
return Error.getInt() ? make_error_code(errc::success)
: Error.getPointer()->Error;
}
private:
llvm::PointerIntPair<ErrorHolderBase *, 1> Error;
};
template<class T, class E>
typename enable_if_c<is_error_code_enum<E>::value ||
is_error_condition_enum<E>::value, bool>::type
operator ==(ErrorOr<T> &Err, E Code) {
return error_code(Err) == Code;
}
}
#endif