diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h index 9570cfe4624d2..b222339fd309b 100644 --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -91,16 +91,29 @@ class OptionalStorage { } } + constexpr bool has_value() const noexcept { return hasVal; } constexpr bool hasValue() const noexcept { return hasVal; } + T &value() &noexcept { + assert(hasVal); + return val; + } T &getValue() &noexcept { assert(hasVal); return val; } + constexpr T const &value() const &noexcept { + assert(hasVal); + return val; + } constexpr T const &getValue() const &noexcept { assert(hasVal); return val; } + T &&value() &&noexcept { + assert(hasVal); + return std::move(val); + } T &&getValue() &&noexcept { assert(hasVal); return std::move(val); @@ -189,16 +202,29 @@ template class OptionalStorage { } } + constexpr bool has_value() const noexcept { return hasVal; } constexpr bool hasValue() const noexcept { return hasVal; } + T &value() &noexcept { + assert(hasVal); + return val; + } T &getValue() &noexcept { assert(hasVal); return val; } + constexpr T const &value() const &noexcept { + assert(hasVal); + return val; + } constexpr T const &getValue() const &noexcept { assert(hasVal); return val; } + T &&value() &&noexcept { + assert(hasVal); + return std::move(val); + } T &&getValue() &&noexcept { assert(hasVal); return std::move(val); @@ -276,16 +302,22 @@ template class Optional { constexpr const T *getPointer() const { return &Storage.getValue(); } T *getPointer() { return &Storage.getValue(); } + constexpr const T &value() const & { return Storage.getValue(); } constexpr const T &getValue() const & { return Storage.getValue(); } + T &value() & { return Storage.getValue(); } T &getValue() & { return Storage.getValue(); } constexpr explicit operator bool() const { return hasValue(); } + constexpr bool has_value() const { return Storage.hasValue(); } constexpr bool hasValue() const { return Storage.hasValue(); } constexpr const T *operator->() const { return getPointer(); } T *operator->() { return getPointer(); } constexpr const T &operator*() const & { return getValue(); } T &operator*() & { return getValue(); } + template constexpr T value_or(U &&value) const & { + return hasValue() ? getValue() : std::forward(value); + } template constexpr T getValueOr(U &&value) const & { return hasValue() ? getValue() : std::forward(value); } @@ -298,9 +330,13 @@ template class Optional { return None; } + T &&value() && { return std::move(Storage.getValue()); } T &&getValue() && { return std::move(Storage.getValue()); } T &&operator*() && { return std::move(Storage.getValue()); } + template T value_or(U &&value) && { + return hasValue() ? std::move(getValue()) : std::forward(value); + } template T getValueOr(U &&value) && { return hasValue() ? std::move(getValue()) : std::forward(value); } diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp index 06283f477e556..f88437f0ab294 100644 --- a/llvm/unittests/ADT/OptionalTest.cpp +++ b/llvm/unittests/ADT/OptionalTest.cpp @@ -27,10 +27,14 @@ static_assert(std::is_trivially_copyable>>::value, void OptionalWorksInConstexpr() { constexpr auto x1 = Optional(); constexpr Optional x2{}; + static_assert(!x1.has_value() && !x2.has_value(), + "Default construction and hasValue() are contexpr"); static_assert(!x1.hasValue() && !x2.hasValue(), "Default construction and hasValue() are contexpr"); constexpr auto y1 = Optional(3); constexpr Optional y2{3}; + static_assert(y1.value() == y2.value() && y1.value() == 3, + "Construction with value and getValue() are constexpr"); static_assert(y1.getValue() == y2.getValue() && y1.getValue() == 3, "Construction with value and getValue() are constexpr"); static_assert(Optional{3} >= 2 && Optional{1} < Optional{2}, @@ -205,9 +209,11 @@ TEST(OptionalTest, InPlaceConstructionNonDefaultConstructibleTest) { TEST(OptionalTest, GetValueOr) { Optional A; + EXPECT_EQ(42, A.value_or(42)); EXPECT_EQ(42, A.getValueOr(42)); A = 5; + EXPECT_EQ(5, A.value_or(42)); EXPECT_EQ(5, A.getValueOr(42)); } @@ -245,12 +251,14 @@ TEST(OptionalTest, Emplace) { Optional A; A.emplace(1, 2); + EXPECT_TRUE(A.has_value()); EXPECT_TRUE(A.hasValue()); EXPECT_EQ(1, A->x); EXPECT_EQ(2, A->y); EXPECT_EQ(0u, MultiArgConstructor::Destructions); A.emplace(5, false); + EXPECT_TRUE(A.has_value()); EXPECT_TRUE(A.hasValue()); EXPECT_EQ(5, A->x); EXPECT_EQ(-5, A->y); @@ -261,10 +269,12 @@ TEST(OptionalTest, InPlaceConstructionMultiArgConstructorTest) { MultiArgConstructor::ResetCounts(); { Optional A{in_place, 1, 2}; + EXPECT_TRUE(A.has_value()); EXPECT_TRUE(A.hasValue()); EXPECT_EQ(1, A->x); EXPECT_EQ(2, A->y); Optional B{in_place, 5, false}; + EXPECT_TRUE(B.has_value()); EXPECT_TRUE(B.hasValue()); EXPECT_EQ(5, B->x); EXPECT_EQ(-5, B->y); @@ -578,6 +588,23 @@ TEST(OptionalTest, DeletedCopyStringMap) { Optional TestInstantiation; } +TEST(OptionalTest, MoveValueOr) { + Optional A; + + MoveOnly::ResetCounts(); + EXPECT_EQ(42, std::move(A).value_or(MoveOnly(42)).val); + EXPECT_EQ(1u, MoveOnly::MoveConstructions); + EXPECT_EQ(0u, MoveOnly::MoveAssignments); + EXPECT_EQ(2u, MoveOnly::Destructions); + + A = MoveOnly(5); + MoveOnly::ResetCounts(); + EXPECT_EQ(5, std::move(A).value_or(MoveOnly(42)).val); + EXPECT_EQ(1u, MoveOnly::MoveConstructions); + EXPECT_EQ(0u, MoveOnly::MoveAssignments); + EXPECT_EQ(2u, MoveOnly::Destructions); +} + TEST(OptionalTest, MoveGetValueOr) { Optional A;