[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:
Michael J. Spencer 2013-01-23 00:18:31 +00:00
parent 0ec35ac4fc
commit bdd4e13118
2 changed files with 109 additions and 1 deletions

View File

@ -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

View File

@ -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