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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits