[llvm-commits] [llvm] r173209 - in /llvm/trunk: include/llvm/Support/ErrorOr.h unittests/Support/ErrorOrTest.cpp

Michael J. Spencer bigcheesegs at gmail.com
Tue Jan 22 16:18:31 PST 2013


Author: mspencer
Date: Tue Jan 22 18:18:31 2013
New Revision: 173209

URL: http://llvm.org/viewvc/llvm-project?rev=173209&view=rev
Log:
[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.

Modified:
    llvm/trunk/include/llvm/Support/ErrorOr.h
    llvm/trunk/unittests/Support/ErrorOrTest.cpp

Modified: llvm/trunk/include/llvm/Support/ErrorOr.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/ErrorOr.h?rev=173209&r1=173208&r2=173209&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/ErrorOr.h (original)
+++ llvm/trunk/include/llvm/Support/ErrorOr.h Tue Jan 22 18:18:31 2013
@@ -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 @@
 
     return *this;
   }
+#endif
 
   ~ErrorOr() {
     if (!IsValid)
@@ -266,7 +268,6 @@
     else
       get()->~storage_type();
   }
-#endif
 
   template<class ET>
   ET getError() const {
@@ -331,6 +332,102 @@
   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

Modified: llvm/trunk/unittests/Support/ErrorOrTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrorOrTest.cpp?rev=173209&r1=173208&r2=173209&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/ErrorOrTest.cpp (original)
+++ llvm/trunk/unittests/Support/ErrorOrTest.cpp Tue Jan 22 18:18:31 2013
@@ -45,6 +45,9 @@
   *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 @@
   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





More information about the llvm-commits mailing list