lawrence_danna updated this revision to Diff 225983.
lawrence_danna added a comment.

add a comment explaining OptionalInfo


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69230/new/

https://reviews.llvm.org/D69230

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

Index: llvm/unittests/ADT/OptionalTest.cpp
===================================================================
--- llvm/unittests/ADT/OptionalTest.cpp
+++ llvm/unittests/ADT/OptionalTest.cpp
@@ -221,7 +221,7 @@
 TEST_F(OptionalTest, Emplace) {
   MultiArgConstructor::ResetCounts();
   Optional<MultiArgConstructor> A;
-  
+
   A.emplace(1, 2);
   EXPECT_TRUE(A.hasValue());
   EXPECT_EQ(1, A->x);
@@ -592,3 +592,57 @@
 }
 
 } // end anonymous namespace
+
+class NaturalNumber {
+  friend struct llvm::OptionalInfo<NaturalNumber>;
+  int value;
+  constexpr NaturalNumber() : value(-1) {}
+
+public:
+  operator int() const { return value; }
+  NaturalNumber(int x) : value(x) { assert(value >= 0); }
+};
+
+template <> struct llvm::OptionalInfo<NaturalNumber, void> {
+  static const bool has_is_valid = true;
+  static bool is_valid(const NaturalNumber &n) { return n.value >= 0; }
+  static constexpr NaturalNumber make_invalid() { return NaturalNumber(); }
+};
+
+static_assert(Optional<int>::storage_type::uses_trivial_copy,
+              "check Optional<int>");
+static_assert(Optional<NaturalNumber>::storage_type::uses_is_valid,
+              "check Optional<NaturalNumber>");
+static_assert(Optional<std::shared_ptr<int>>::storage_type::is_generic_storage,
+              "check Optional<std::shared_ptr>");
+
+TEST_F(OptionalTest, TestHasInvalid) {
+
+  constexpr Optional<NaturalNumber> none;
+
+  static_assert(sizeof(Optional<NaturalNumber>) == sizeof(int),
+                "no extra bool");
+
+  Optional<NaturalNumber> x = None;
+  EXPECT_FALSE(x.hasValue());
+  EXPECT_TRUE(x == none);
+  EXPECT_EQ(*reinterpret_cast<int *>(&x), -1);
+  x = NaturalNumber{42};
+  EXPECT_TRUE(x.hasValue());
+  EXPECT_EQ((int)x.getValue(), 42);
+  x.reset();
+  EXPECT_FALSE(x.hasValue());
+
+  x.emplace(1234);
+  EXPECT_TRUE(x.hasValue());
+  EXPECT_EQ((int)x.getValue(), 1234);
+
+  x = Optional<NaturalNumber>(4321);
+  EXPECT_TRUE(x.hasValue());
+  EXPECT_EQ((int)x.getValue(), 4321);
+
+  auto y = Optional<NaturalNumber>(0x0dedbeef);
+  x = y;
+  EXPECT_TRUE(x.hasValue());
+  EXPECT_EQ((int)x.getValue(), (int)0x0dedbeef);
+}
Index: llvm/include/llvm/ADT/Optional.h
===================================================================
--- llvm/include/llvm/ADT/Optional.h
+++ llvm/include/llvm/ADT/Optional.h
@@ -27,12 +27,33 @@
 
 class raw_ostream;
 
+// This template may be specialized in order to customize
+// how Optional<T> is implemented.    If you do specialize this,
+// you must do so in the same header that defines T.   Otherwise
+// there could be some translation units that see your specialized
+// OptionalInfo<T> and other translation units that do not.
+//
+// The only available customization is to set has_is_valid = true,
+// and implement is_valid() and make_invalid().
+// This will cause Optional<T> to be represented as: class { T value; }
+// None will be represented by an invalid T, as returned by
+// make_invalid().   T's representation of invalid values should
+// be private and only shared with OptionalInfo<T>
+template <typename T, typename Enable = void> struct OptionalInfo {
+  typedef T type;
+  static const bool has_is_valid = false;
+  static const bool is_trivially_copyable =
+      std::is_trivially_copyable<T>::value;
+  // static bool is_valid(const T &n) { return n.value >= 0; }
+  // static constexpr T make_invalid() { return T(); }
+};
+
 namespace optional_detail {
 
 struct in_place_t {};
 
 /// Storage for any type.
-template <typename T, bool = is_trivially_copyable<T>::value>
+template <typename T, typename Info = OptionalInfo<T>, typename Enable = void>
 class OptionalStorage {
   union {
     char empty;
@@ -41,6 +62,8 @@
   bool hasVal;
 
 public:
+  static const bool is_generic_storage = true;
+
   ~OptionalStorage() { reset(); }
 
   OptionalStorage() noexcept : empty(), hasVal(false) {}
@@ -138,7 +161,77 @@
   }
 };
 
-template <typename T> class OptionalStorage<T, true> {
+template <typename T>
+class OptionalStorage<
+    T, OptionalInfo<T>,
+    typename std::enable_if<OptionalInfo<T>::has_is_valid, void>::type> {
+
+  T value;
+  typedef OptionalInfo<T> Info;
+
+public:
+  static const bool uses_is_valid = true;
+
+  ~OptionalStorage() = default;
+
+  constexpr OptionalStorage() noexcept : value{Info::make_invalid()} {}
+
+  OptionalStorage(OptionalStorage const &other) = default;
+  OptionalStorage(OptionalStorage &&other) = default;
+
+  OptionalStorage &operator=(OptionalStorage const &other) = default;
+  OptionalStorage &operator=(OptionalStorage &&other) = default;
+
+  template <class... Args>
+  explicit OptionalStorage(in_place_t, Args &&... args)
+      : value(std::forward<Args>(args)...) {
+    assert(Info::is_valid(value));
+  }
+
+  void reset() noexcept { value = Info::make_invalid(); }
+
+  bool hasValue() const noexcept { return Info::is_valid(value); }
+
+  T &getValue() LLVM_LVALUE_FUNCTION noexcept {
+    assert(Info::is_valid(value));
+    return value;
+  }
+  T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
+    assert(Info::is_valid(value));
+    return value;
+  }
+#if LLVM_HAS_RVALUE_REFERENCE_THIS
+  T &&getValue() && noexcept {
+    assert(Info::is_valid(value));
+    return std::move(value);
+  }
+#endif
+
+  template <class... Args> void emplace(Args &&... args) {
+    value = T(std::forward<Args>(args)...);
+    assert(Info::is_valid(value));
+  }
+
+  OptionalStorage &operator=(T const &y) {
+    assert(Info::is_valid(y));
+    value = y;
+    return *this;
+  }
+
+  OptionalStorage &operator=(T &&y) {
+    assert(Info::is_valid(y));
+    value = std::move(y);
+    return *this;
+  }
+};
+
+template <typename T>
+class OptionalStorage<
+    T, OptionalInfo<T>,
+    typename std::enable_if<OptionalInfo<T>::is_trivially_copyable &&
+                                !OptionalInfo<T>::has_is_valid,
+                            void>::type> {
+
   union {
     char empty;
     T value;
@@ -146,6 +239,8 @@
   bool hasVal = false;
 
 public:
+  static const bool uses_trivial_copy = true;
+
   ~OptionalStorage() = default;
 
   OptionalStorage() noexcept : empty{} {}
@@ -213,11 +308,15 @@
 } // namespace optional_detail
 
 template <typename T> class Optional {
-  optional_detail::OptionalStorage<T> Storage;
-
 public:
   using value_type = T;
+  using info_type = OptionalInfo<T>;
+  using storage_type = optional_detail::OptionalStorage<value_type, info_type>;
+
+private:
+  storage_type Storage;
 
+public:
   constexpr Optional() {}
   constexpr Optional(NoneType) {}
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to