summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lloyd Pique <lpique@google.com> 2024-10-02 13:44:41 -0700
committer Lloyd Pique <lpique@google.com> 2024-10-03 12:13:23 -0700
commit6aa3b8931d7ffc8306b22358bb0dd4b2dc646b49 (patch)
tree48ae34d5846997541a6d36fa140ac7941f6c4226
parent6d17c9b341b564f1e9e95dc477fb1681d6b3bb44 (diff)
FTL: Allow implicit conversions with NonNull<T>
C++ allows certain implicit conversions for pointers, such as the implicit conversion of "T*" to "const T*". NonNull did not allow them, but that is easily corrected. Bug: 185536303 Flag: EXEMPT Relaxes a compile-time constraint Test: atest ftl_test Change-Id: I0c14805c8fdcca979c67d2c86d57e5e678aa1b32
-rw-r--r--include/ftl/non_null.h9
-rw-r--r--libs/ftl/non_null_test.cpp35
2 files changed, 44 insertions, 0 deletions
diff --git a/include/ftl/non_null.h b/include/ftl/non_null.h
index 4a5d8bffd0..e68428810b 100644
--- a/include/ftl/non_null.h
+++ b/include/ftl/non_null.h
@@ -68,6 +68,15 @@ class NonNull final {
constexpr NonNull(const NonNull&) = default;
constexpr NonNull& operator=(const NonNull&) = default;
+ template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, Pointer>>>
+ constexpr NonNull(const NonNull<U>& other) : pointer_(other.get()) {}
+
+ template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, Pointer>>>
+ constexpr NonNull& operator=(const NonNull<U>& other) {
+ pointer_ = other.get();
+ return *this;
+ }
+
[[nodiscard]] constexpr const Pointer& get() const { return pointer_; }
[[nodiscard]] constexpr explicit operator const Pointer&() const { return get(); }
diff --git a/libs/ftl/non_null_test.cpp b/libs/ftl/non_null_test.cpp
index 367b398915..457237c35e 100644
--- a/libs/ftl/non_null_test.cpp
+++ b/libs/ftl/non_null_test.cpp
@@ -81,6 +81,31 @@ static_assert(static_cast<bool>(kApplePtr));
static_assert(std::is_same_v<decltype(ftl::as_non_null(std::declval<const int* const>())),
ftl::NonNull<const int*>>);
+class Base {};
+class Derived : public Base {};
+
+static_assert(std::is_constructible_v<ftl::NonNull<void*>, ftl::NonNull<int*>>);
+static_assert(!std::is_constructible_v<ftl::NonNull<int*>, ftl::NonNull<void*>>);
+static_assert(std::is_constructible_v<ftl::NonNull<const int*>, ftl::NonNull<int*>>);
+static_assert(!std::is_constructible_v<ftl::NonNull<int*>, ftl::NonNull<const int*>>);
+static_assert(std::is_constructible_v<ftl::NonNull<Base*>, ftl::NonNull<Derived*>>);
+static_assert(!std::is_constructible_v<ftl::NonNull<Derived*>, ftl::NonNull<Base*>>);
+static_assert(std::is_constructible_v<ftl::NonNull<std::unique_ptr<const int>>,
+ ftl::NonNull<std::unique_ptr<int>>>);
+static_assert(std::is_constructible_v<ftl::NonNull<std::unique_ptr<Base>>,
+ ftl::NonNull<std::unique_ptr<Derived>>>);
+
+static_assert(std::is_assignable_v<ftl::NonNull<void*>, ftl::NonNull<int*>>);
+static_assert(!std::is_assignable_v<ftl::NonNull<int*>, ftl::NonNull<void*>>);
+static_assert(std::is_assignable_v<ftl::NonNull<const int*>, ftl::NonNull<int*>>);
+static_assert(!std::is_assignable_v<ftl::NonNull<int*>, ftl::NonNull<const int*>>);
+static_assert(std::is_assignable_v<ftl::NonNull<Base*>, ftl::NonNull<Derived*>>);
+static_assert(!std::is_assignable_v<ftl::NonNull<Derived*>, ftl::NonNull<Base*>>);
+static_assert(std::is_assignable_v<ftl::NonNull<std::unique_ptr<const int>>,
+ ftl::NonNull<std::unique_ptr<int>>>);
+static_assert(std::is_assignable_v<ftl::NonNull<std::unique_ptr<Base>>,
+ ftl::NonNull<std::unique_ptr<Derived>>>);
+
} // namespace
TEST(NonNull, SwapRawPtr) {
@@ -156,4 +181,14 @@ TEST(NonNull, UnorderedSetOfSmartPtr) {
EXPECT_TRUE(ftl::contains(spi, *spi.begin()));
}
+TEST(NonNull, ImplicitConversion) {
+ int i = 123;
+ int j = 345;
+ auto ip = ftl::as_non_null(&i);
+ ftl::NonNull<void*> vp{ip};
+ EXPECT_EQ(vp.get(), &i);
+ vp = ftl::as_non_null(&j);
+ EXPECT_EQ(vp.get(), &j);
+}
+
} // namespace android::test