diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2013-01-23 00:18:31 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2013-01-23 00:18:31 +0000 |
commit | bdd4e1311830bea92c8b8c09f0644cba15421241 (patch) | |
tree | fa243ee56abe28a8ff8802924fdd0bf83b05dff9 | |
parent | 0ec35ac4fcd5c83e2ec35d04fc20db9eb387d289 (diff) | |
download | external_llvm-bdd4e1311830bea92c8b8c09f0644cba15421241.zip external_llvm-bdd4e1311830bea92c8b8c09f0644cba15421241.tar.gz external_llvm-bdd4e1311830bea92c8b8c09f0644cba15421241.tar.bz2 |
[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
-rw-r--r-- | include/llvm/Support/ErrorOr.h | 99 | ||||
-rw-r--r-- | unittests/Support/ErrorOrTest.cpp | 11 |
2 files changed, 109 insertions, 1 deletions
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<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 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<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 |