From bdd4e1311830bea92c8b8c09f0644cba15421241 Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Wed, 23 Jan 2013 00:18:31 +0000 Subject: [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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@173209 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Support/ErrorOr.h | 99 ++++++++++++++++++++++++++++++++++++++- unittests/Support/ErrorOrTest.cpp | 11 +++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/include/llvm/Support/ErrorOr.h b/include/llvm/Support/ErrorOr.h index bc708a2..13705c8 100644 --- a/include/llvm/Support/ErrorOr.h +++ b/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/unittests/Support/ErrorOrTest.cpp b/unittests/Support/ErrorOrTest.cpp index b30895c..a860886 100644 --- a/unittests/Support/ErrorOrTest.cpp +++ b/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 -- cgit v1.1