Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6aa3b893 authored by Lloyd Pique's avatar Lloyd Pique
Browse files

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
parent 6d17c9b3
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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(); }

+35 −0
Original line number Diff line number Diff line
@@ -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