From: Michael J. Spencer Date: Wed, 23 Jan 2013 00:18:31 +0000 (+0000) Subject: [Support][ErrorOr] Add optimized specialization of ErrorOr. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f71baa84eaca687c06dc44cc1a4349c8a344c48f;p=platform%2Fupstream%2Fllvm.git [Support][ErrorOr] Add optimized specialization of ErrorOr. ErrorOr 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. llvm-svn: 173209 --- diff --git a/llvm/include/llvm/Support/ErrorOr.h b/llvm/include/llvm/Support/ErrorOr.h index bc708a2..13705c8 100644 --- a/llvm/include/llvm/Support/ErrorOr.h +++ b/llvm/include/llvm/Support/ErrorOr.h @@ -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 ET getError() const { @@ -331,6 +332,102 @@ protected: bool IsValid : 1; }; +// ErrorOr specialization for void. +template <> +class ErrorOr { +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 + ErrorOr(UserDataT UD, typename + enable_if_c::value>::type* = 0) + : Error(nullptr, 0) { + ErrorHolderBase *E = new ErrorHolder(llvm_move(UD)); + E->Error = ErrorOrUserDataTraits::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 + ET getError() const { + assert(ErrorOrUserDataTraits::error() == *this && + "Incorrect user error data type for error!"); + if (!Error.getPointer()->HasUserData) + return ET(); + return reinterpret_cast *>( + 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 Error; +}; + template typename enable_if_c::value || is_error_condition_enum::value, bool>::type diff --git a/llvm/unittests/Support/ErrorOrTest.cpp b/llvm/unittests/Support/ErrorOrTest.cpp index b30895c..a860886 100644 --- a/llvm/unittests/Support/ErrorOrTest.cpp +++ b/llvm/unittests/Support/ErrorOrTest.cpp @@ -45,6 +45,9 @@ TEST(ErrorOr, Types) { *a = 42; EXPECT_EQ(42, x); + EXPECT_FALSE(ErrorOr(make_error_code(errc::broken_pipe))); + EXPECT_TRUE(ErrorOr(make_error_code(errc::success))); + #if LLVM_HAS_CXX11_STDLIB // Move only types. EXPECT_EQ(3, **t3()); @@ -71,10 +74,18 @@ ErrorOr t4() { return InvalidArgError("adena"); } +ErrorOr t5() { + return InvalidArgError("pie"); +} + namespace { TEST(ErrorOr, UserErrorData) { ErrorOr a = t4(); EXPECT_EQ(errc::invalid_argument, a); EXPECT_EQ("adena", t4().getError().ArgName); + + ErrorOr b = t5(); + EXPECT_EQ(errc::invalid_argument, b); + EXPECT_EQ("pie", b.getError().ArgName); } } // end anon namespace