Outline most throw expressions in Expected
authorYedidya Feldblum <yfeldblum@fb.com>
Tue, 31 Oct 2017 05:00:27 +0000 (22:00 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 31 Oct 2017 05:10:29 +0000 (22:10 -0700)
Summary:
[Folly] Outline most `throw` expressions in `Expected`.

They are definitionally cold, but in-line `throw` statements can expand code size more than is desirable.

* Inline `throw` statement: https://godbolt.org/g/LPaf7V.
* Outline `throw` statement: https://godbolt.org/g/HZBXn6.

Reviewed By: Orvid

Differential Revision: D6183613

fbshipit-source-id: 28240bb4aa40790d99da783a3c368db81fded124

folly/Expected.cpp [new file with mode: 0644]
folly/Expected.h
folly/Makefile.am

diff --git a/folly/Expected.cpp b/folly/Expected.cpp
new file mode 100644 (file)
index 0000000..7cb07e8
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/Expected.h>
+
+namespace folly {
+
+namespace expected_detail {
+
+// clang-format off
+[[noreturn]] void throwBadExpectedAccess() {
+  throw BadExpectedAccess();
+}
+// clang-format on
+
+} // namespace expected_detail
+
+} // namespace folly
index c9874eb..945797b 100644 (file)
@@ -663,6 +663,12 @@ class BadExpectedAccess : public std::logic_error {
   BadExpectedAccess() : std::logic_error("bad Expected access") {}
 };
 
+namespace expected_detail {
+
+[[noreturn]] void throwBadExpectedAccess();
+
+} // namespace expected_detail
+
 /**
  * Unexpected - a helper type used to disambiguate the construction of
  * Expected objects in the error state.
@@ -1059,7 +1065,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
   void swap(Expected& that) noexcept(
       expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>::value) {
     if (this->uninitializedByException() || that.uninitializedByException()) {
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
     using std::swap;
     if (*this) {
@@ -1199,7 +1205,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
           std::declval<const Base&>(),
           std::declval<Fns>()...)) {
     if (this->uninitializedByException()) {
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
     return expected_detail::ExpectedHelper::then_(
         base(), static_cast<Fns&&>(fns)...);
@@ -1210,7 +1216,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
       std::declval<Base&>(),
       std::declval<Fns>()...)) {
     if (this->uninitializedByException()) {
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
     return expected_detail::ExpectedHelper::then_(
         base(), static_cast<Fns&&>(fns)...);
@@ -1221,7 +1227,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
       std::declval<Base&&>(),
       std::declval<Fns>()...)) {
     if (this->uninitializedByException()) {
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
     return expected_detail::ExpectedHelper::then_(
         std::move(base()), static_cast<Fns&&>(fns)...);
@@ -1235,7 +1241,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
       std::declval<Yes>()(std::declval<const Value&>())) {
     using Ret = decltype(std::declval<Yes>()(std::declval<const Value&>()));
     if (this->uninitializedByException()) {
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
     return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
         base(), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
@@ -1246,7 +1252,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
       std::declval<Yes>()(std::declval<Value&>())) {
     using Ret = decltype(std::declval<Yes>()(std::declval<Value&>()));
     if (this->uninitializedByException()) {
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
     return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
         base(), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
@@ -1257,7 +1263,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
       std::declval<Yes>()(std::declval<Value&&>())) {
     using Ret = decltype(std::declval<Yes>()(std::declval<Value&&>()));
     if (this->uninitializedByException()) {
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
     return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
         std::move(base()), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
@@ -1269,13 +1275,13 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
       if (LIKELY(hasError())) {
         throw typename Unexpected<Error>::BadExpectedAccess(this->error_);
       }
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
   }
 
   void requireError() const {
     if (UNLIKELY(!hasError())) {
-      throw BadExpectedAccess();
+      expected_detail::throwBadExpectedAccess();
     }
   }
 
@@ -1289,12 +1295,11 @@ inline typename std::enable_if<IsEqualityComparable<Value>::value, bool>::type
 operator==(
     const Expected<Value, Error>& lhs,
     const Expected<Value, Error>& rhs) {
-  if (UNLIKELY(lhs.which_ != rhs.which_)) {
-    return UNLIKELY(lhs.uninitializedByException()) ? false
-                                                    : throw BadExpectedAccess();
-  }
   if (UNLIKELY(lhs.uninitializedByException())) {
-    throw BadExpectedAccess();
+    expected_detail::throwBadExpectedAccess();
+  }
+  if (UNLIKELY(lhs.which_ != rhs.which_)) {
+    return false;
   }
   if (UNLIKELY(lhs.hasError())) {
     return true; // All error states are considered equal
@@ -1318,7 +1323,7 @@ operator<(
     const Expected<Value, Error>& rhs) {
   if (UNLIKELY(
           lhs.uninitializedByException() || rhs.uninitializedByException())) {
-    throw BadExpectedAccess();
+    expected_detail::throwBadExpectedAccess();
   }
   if (UNLIKELY(lhs.hasError())) {
     return !rhs.hasError();
index 4873c4c..c24cd2c 100644 (file)
@@ -503,6 +503,7 @@ libfolly_la_SOURCES = \
        dynamic.cpp \
        ExceptionWrapper.cpp \
        Executor.cpp \
+       Expected.cpp \
        File.cpp \
        FileUtil.cpp \
        FingerprintTables.cpp \