mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-02 00:37:09 +00:00
[Support][ErrorOr] Add optimized specialization of ErrorOr<void>.
ErrorOr<void> represents an operation that returns nothing, but can still fail. It should be used in cases where you need the aditional user data that ErrorOr provides over error_code. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@173209 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0ec35ac4fc
commit
bdd4e13118
@ -16,6 +16,7 @@
|
||||
#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"
|
||||
@ -257,6 +258,7 @@ public:
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
~ErrorOr() {
|
||||
if (!IsValid)
|
||||
@ -266,7 +268,6 @@ public:
|
||||
else
|
||||
get()->~storage_type();
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class ET>
|
||||
ET getError() const {
|
||||
@ -331,6 +332,102 @@ protected:
|
||||
bool IsValid : 1;
|
||||
};
|
||||
|
||||
// ErrorOr specialization for void.
|
||||
template <>
|
||||
class ErrorOr<void> {
|
||||
public:
|
||||
ErrorOr() : Error(nullptr, 0) {}
|
||||
|
||||
ErrorOr(llvm::error_code EC) : Error(nullptr, 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(nullptr, 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(nullptr, 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(nullptr) {
|
||||
// Get other's error.
|
||||
Error = Other.Error;
|
||||
// Tell other not to do any destruction.
|
||||
Other.Error.setPointer(nullptr);
|
||||
}
|
||||
|
||||
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() {}
|
||||
|
||||
/// \brief Return false if there is an error.
|
||||
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:
|
||||
// If the bit is 1, the error is success.
|
||||
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
|
||||
|
@ -45,6 +45,9 @@ TEST(ErrorOr, Types) {
|
||||
*a = 42;
|
||||
EXPECT_EQ(42, x);
|
||||
|
||||
EXPECT_FALSE(ErrorOr<void>(make_error_code(errc::broken_pipe)));
|
||||
EXPECT_TRUE(ErrorOr<void>(make_error_code(errc::success)));
|
||||
|
||||
#if LLVM_HAS_CXX11_STDLIB
|
||||
// Move only types.
|
||||
EXPECT_EQ(3, **t3());
|
||||
@ -71,10 +74,18 @@ ErrorOr<int> t4() {
|
||||
return InvalidArgError("adena");
|
||||
}
|
||||
|
||||
ErrorOr<void> t5() {
|
||||
return InvalidArgError("pie");
|
||||
}
|
||||
|
||||
namespace {
|
||||
TEST(ErrorOr, UserErrorData) {
|
||||
ErrorOr<int> a = t4();
|
||||
EXPECT_EQ(errc::invalid_argument, a);
|
||||
EXPECT_EQ("adena", t4().getError<InvalidArgError>().ArgName);
|
||||
|
||||
ErrorOr<void> b = t5();
|
||||
EXPECT_EQ(errc::invalid_argument, b);
|
||||
EXPECT_EQ("pie", b.getError<InvalidArgError>().ArgName);
|
||||
}
|
||||
} // end anon namespace
|
||||
|
Loading…
Reference in New Issue
Block a user