Commit e3d0887c authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Outline most throw expressions in Expected

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
parent 598926c4
/*
* 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
...@@ -663,6 +663,12 @@ class BadExpectedAccess : public std::logic_error { ...@@ -663,6 +663,12 @@ class BadExpectedAccess : public std::logic_error {
BadExpectedAccess() : std::logic_error("bad Expected access") {} 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 * Unexpected - a helper type used to disambiguate the construction of
* Expected objects in the error state. * Expected objects in the error state.
...@@ -1059,7 +1065,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1059,7 +1065,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
void swap(Expected& that) noexcept( void swap(Expected& that) noexcept(
expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>::value) { expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>::value) {
if (this->uninitializedByException() || that.uninitializedByException()) { if (this->uninitializedByException() || that.uninitializedByException()) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
using std::swap; using std::swap;
if (*this) { if (*this) {
...@@ -1199,7 +1205,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1199,7 +1205,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
std::declval<const Base&>(), std::declval<const Base&>(),
std::declval<Fns>()...)) { std::declval<Fns>()...)) {
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
return expected_detail::ExpectedHelper::then_( return expected_detail::ExpectedHelper::then_(
base(), static_cast<Fns&&>(fns)...); base(), static_cast<Fns&&>(fns)...);
...@@ -1210,7 +1216,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1210,7 +1216,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
std::declval<Base&>(), std::declval<Base&>(),
std::declval<Fns>()...)) { std::declval<Fns>()...)) {
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
return expected_detail::ExpectedHelper::then_( return expected_detail::ExpectedHelper::then_(
base(), static_cast<Fns&&>(fns)...); base(), static_cast<Fns&&>(fns)...);
...@@ -1221,7 +1227,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1221,7 +1227,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
std::declval<Base&&>(), std::declval<Base&&>(),
std::declval<Fns>()...)) { std::declval<Fns>()...)) {
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
return expected_detail::ExpectedHelper::then_( return expected_detail::ExpectedHelper::then_(
std::move(base()), static_cast<Fns&&>(fns)...); std::move(base()), static_cast<Fns&&>(fns)...);
...@@ -1235,7 +1241,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1235,7 +1241,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
std::declval<Yes>()(std::declval<const Value&>())) { std::declval<Yes>()(std::declval<const Value&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<const Value&>())); using Ret = decltype(std::declval<Yes>()(std::declval<const Value&>()));
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
base(), static_cast<Yes&&>(yes), static_cast<No&&>(no))); base(), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
...@@ -1246,7 +1252,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1246,7 +1252,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
std::declval<Yes>()(std::declval<Value&>())) { std::declval<Yes>()(std::declval<Value&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<Value&>())); using Ret = decltype(std::declval<Yes>()(std::declval<Value&>()));
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
base(), static_cast<Yes&&>(yes), static_cast<No&&>(no))); base(), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
...@@ -1257,7 +1263,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1257,7 +1263,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
std::declval<Yes>()(std::declval<Value&&>())) { std::declval<Yes>()(std::declval<Value&&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<Value&&>())); using Ret = decltype(std::declval<Yes>()(std::declval<Value&&>()));
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
std::move(base()), static_cast<Yes&&>(yes), static_cast<No&&>(no))); std::move(base()), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
...@@ -1269,13 +1275,13 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1269,13 +1275,13 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
if (LIKELY(hasError())) { if (LIKELY(hasError())) {
throw typename Unexpected<Error>::BadExpectedAccess(this->error_); throw typename Unexpected<Error>::BadExpectedAccess(this->error_);
} }
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
} }
void requireError() const { void requireError() const {
if (UNLIKELY(!hasError())) { if (UNLIKELY(!hasError())) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
} }
...@@ -1289,12 +1295,11 @@ inline typename std::enable_if<IsEqualityComparable<Value>::value, bool>::type ...@@ -1289,12 +1295,11 @@ inline typename std::enable_if<IsEqualityComparable<Value>::value, bool>::type
operator==( operator==(
const Expected<Value, Error>& lhs, const Expected<Value, Error>& lhs,
const Expected<Value, Error>& rhs) { const Expected<Value, Error>& rhs) {
if (UNLIKELY(lhs.which_ != rhs.which_)) {
return UNLIKELY(lhs.uninitializedByException()) ? false
: throw BadExpectedAccess();
}
if (UNLIKELY(lhs.uninitializedByException())) { if (UNLIKELY(lhs.uninitializedByException())) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
}
if (UNLIKELY(lhs.which_ != rhs.which_)) {
return false;
} }
if (UNLIKELY(lhs.hasError())) { if (UNLIKELY(lhs.hasError())) {
return true; // All error states are considered equal return true; // All error states are considered equal
...@@ -1318,7 +1323,7 @@ operator<( ...@@ -1318,7 +1323,7 @@ operator<(
const Expected<Value, Error>& rhs) { const Expected<Value, Error>& rhs) {
if (UNLIKELY( if (UNLIKELY(
lhs.uninitializedByException() || rhs.uninitializedByException())) { lhs.uninitializedByException() || rhs.uninitializedByException())) {
throw BadExpectedAccess(); expected_detail::throwBadExpectedAccess();
} }
if (UNLIKELY(lhs.hasError())) { if (UNLIKELY(lhs.hasError())) {
return !rhs.hasError(); return !rhs.hasError();
......
...@@ -503,6 +503,7 @@ libfolly_la_SOURCES = \ ...@@ -503,6 +503,7 @@ libfolly_la_SOURCES = \
dynamic.cpp \ dynamic.cpp \
ExceptionWrapper.cpp \ ExceptionWrapper.cpp \
Executor.cpp \ Executor.cpp \
Expected.cpp \
File.cpp \ File.cpp \
FileUtil.cpp \ FileUtil.cpp \
FingerprintTables.cpp \ FingerprintTables.cpp \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment