Skip to content

Commit

Permalink
folly::Try: add value_or() implementations mimicking std::optional::v…
Browse files Browse the repository at this point in the history
…alue_or API

Summary:
Add API equivalent to `std::optional::value_or`: https://en.cppreference.com/w/cpp/utility/optional/value_or

Returns the contained value if *this has a value, otherwise returns default_value.

  template< class U > constexpr T value_or( U&& default_value ) const&;

Equivalent to `bool(*this) ? **this : static_cast<T>(std::forward<U>(default_value))`

   template< class U > constexpr T value_or( U&& default_value ) &&;

Equivalent to `bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(default_value))`

Reviewed By: yfeldblum

Differential Revision: D27346319

fbshipit-source-id: 598b740cb9068cffb0cc0fbda3579e64fd125e8b
  • Loading branch information
luciang authored and facebook-github-bot committed Mar 28, 2021
1 parent d3f0a28 commit 6d8bd01
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
13 changes: 13 additions & 0 deletions folly/Try-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,19 @@ const T&& Try<T>::value() const&& {
return std::move(value_);
}

template <class T>
template <class U>
T Try<T>::value_or(U&& defaultValue) const& {
return hasValue() ? **this : static_cast<T>(static_cast<U&&>(defaultValue));
}

template <class T>
template <class U>
T Try<T>::value_or(U&& defaultValue) && {
return hasValue() ? std::move(**this)
: static_cast<T>(static_cast<U&&>(defaultValue));
}

template <class T>
void Try<T>::throwUnlessValue() const {
switch (contains_) {
Expand Down
11 changes: 11 additions & 0 deletions folly/Try.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,17 @@ class Try {
*/
const T&& value() const&&;

/*
* Returns a copy of the contained value if *this has a value,
* otherwise returns a value constructed from defaultValue.
*
* The selected constructor of the return value may throw exceptions.
*/
template <class U>
T value_or(U&& defaultValue) const&;
template <class U>
T value_or(U&& defaultValue) &&;

/*
* [Re]throw if the Try contains an exception or is empty. Otherwise do
* nothing.
Expand Down
46 changes: 46 additions & 0 deletions folly/test/TryTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ TEST(Try, emplaceWithThrowingConstructor) {

EXPECT_FALSE(t.hasValue());
EXPECT_FALSE(t.hasException());

EXPECT_THROW(t.value_or(true), MyException);
}

{
Expand All @@ -202,6 +204,8 @@ TEST(Try, emplaceWithThrowingConstructor) {
EXPECT_THROW(t.emplace(true), MyException);
EXPECT_FALSE(t.hasValue());
EXPECT_FALSE(t.hasException());

EXPECT_THROW(t.value_or(true), MyException);
}
}

Expand Down Expand Up @@ -376,6 +380,7 @@ TEST(Try, MoveDereference) {
auto t = Try<std::unique_ptr<int>>{std::move(ptr)};
auto result = *std::move(t);
EXPECT_EQ(*result, 1);
EXPECT_TRUE(t.hasValue());
}

TEST(Try, MoveConstRvalue) {
Expand Down Expand Up @@ -429,6 +434,47 @@ TEST(Try, ValueOverloads) {
}
}

TEST(Try, ValueOr) {
struct CopyableValue {
int x;
};
{
Try<CopyableValue> o{CopyableValue{42}};
CopyableValue defaultValue{17};
EXPECT_EQ(o.value_or(defaultValue).x, 42);
EXPECT_EQ(o.value_or(defaultValue).x, (*o).x);
}

{
Try<CopyableValue> empty;
EXPECT_FALSE(empty.hasValue());
CopyableValue defaultValue{17};
EXPECT_EQ(empty.value_or(defaultValue).x, defaultValue.x);
}

{
Try<std::unique_ptr<int>> o{std::make_unique<int>(42)};
std::unique_ptr<int> defaultValue = std::make_unique<int>(17);
std::unique_ptr<int> v = std::move(o).value_or(std::move(defaultValue));
ASSERT_TRUE(v);
EXPECT_EQ(*v, 42);
ASSERT_TRUE(defaultValue);
EXPECT_EQ(*defaultValue, 17);
EXPECT_TRUE(o.hasValue());
ASSERT_FALSE(*o);
}

{
Try<std::unique_ptr<int>> empty;
std::unique_ptr<int> defaultValue = std::make_unique<int>(17);
std::unique_ptr<int> v = std::move(empty).value_or(std::move(defaultValue));
ASSERT_TRUE(v);
EXPECT_EQ(*v, 17);
EXPECT_FALSE(defaultValue);
EXPECT_FALSE(empty.hasValue());
}
}

// Make sure we can copy Trys for copyable types
TEST(Try, copy) {
Try<int> t;
Expand Down

0 comments on commit 6d8bd01

Please sign in to comment.