[llvm] 3c49576 - [ADT] Add has_value, value, value_or to llvm::Optional

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 18 21:21:39 PDT 2022


Author: Kazu Hirata
Date: 2022-06-18T21:21:33-07:00
New Revision: 3c49576417bab1b07764aa0b22664cbc8d3c3f53

URL: https://github.com/llvm/llvm-project/commit/3c49576417bab1b07764aa0b22664cbc8d3c3f53
DIFF: https://github.com/llvm/llvm-project/commit/3c49576417bab1b07764aa0b22664cbc8d3c3f53.diff

LOG: [ADT] Add has_value, value, value_or to llvm::Optional

This patch adds has_value, value, value_or to llvm::Optional so that
llvm::Optional looks more like std::optional.

I will keep the existing functions while migrating their callers and
then remove them later.

Differential Revision: https://reviews.llvm.org/D128131

Added: 
    

Modified: 
    llvm/include/llvm/ADT/Optional.h
    llvm/unittests/ADT/OptionalTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h
index 9570cfe4624d..b222339fd309 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 <typename T> class OptionalStorage<T, true> {
     }
   }
 
+  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 <typename T> 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 <typename U> constexpr T value_or(U &&value) const & {
+    return hasValue() ? getValue() : std::forward<U>(value);
+  }
   template <typename U> constexpr T getValueOr(U &&value) const & {
     return hasValue() ? getValue() : std::forward<U>(value);
   }
@@ -298,9 +330,13 @@ template <typename T> 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 <typename U> T value_or(U &&value) && {
+    return hasValue() ? std::move(getValue()) : std::forward<U>(value);
+  }
   template <typename U> T getValueOr(U &&value) && {
     return hasValue() ? std::move(getValue()) : std::forward<U>(value);
   }

diff  --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp
index 06283f477e55..f88437f0ab29 100644
--- a/llvm/unittests/ADT/OptionalTest.cpp
+++ b/llvm/unittests/ADT/OptionalTest.cpp
@@ -27,10 +27,14 @@ static_assert(std::is_trivially_copyable<Optional<std::array<int, 3>>>::value,
 void OptionalWorksInConstexpr() {
   constexpr auto x1 = Optional<int>();
   constexpr Optional<int> 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<int>(3);
   constexpr Optional<int> 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<int>{3} >= 2 && Optional<int>{1} < Optional<int>{2},
@@ -205,9 +209,11 @@ TEST(OptionalTest, InPlaceConstructionNonDefaultConstructibleTest) {
 
 TEST(OptionalTest, GetValueOr) {
   Optional<int> 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<MultiArgConstructor> 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<MultiArgConstructor> 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<MultiArgConstructor> 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<NoCopyStringMap> TestInstantiation;
 }
 
+TEST(OptionalTest, MoveValueOr) {
+  Optional<MoveOnly> 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<MoveOnly> A;
 


        


More information about the llvm-commits mailing list