Skip to content

Commit

Permalink
Bug 1296760 - Allow Some(nullptr) and Some(Derived*) to convert to Ma…
Browse files Browse the repository at this point in the history
…ybe<Base*>. r=froydnj

--HG--
extra : rebase_source : 478e825f476a671e07a94f483b88cbc2d4ae8d13
  • Loading branch information
jswalden committed Aug 24, 2016
1 parent c0468b5 commit 34e7d5b
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 0 deletions.
42 changes: 42 additions & 0 deletions mfbt/Maybe.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "mozilla/TypeTraits.h"

#include <new> // for placement new
#include <type_traits>

namespace mozilla {

Expand Down Expand Up @@ -101,6 +102,26 @@ class Maybe
}
}

/**
* Maybe<T*> can be copy-constructed from a Maybe<U*> if U* and T* are
* compatible, or from Maybe<decltype(nullptr)>.
*/
template<typename U,
typename =
typename std::enable_if<std::is_pointer<T>::value &&
(std::is_same<U, decltype(nullptr)>::value ||
(std::is_pointer<U>::value &&
std::is_base_of<typename std::remove_pointer<T>::type,
typename std::remove_pointer<U>::type>::value))>::type>
MOZ_IMPLICIT
Maybe(const Maybe<U>& aOther)
: mIsSome(false)
{
if (aOther.isSome()) {
emplace(*aOther);
}
}

Maybe(Maybe&& aOther)
: mIsSome(false)
{
Expand All @@ -110,6 +131,27 @@ class Maybe
}
}

/**
* Maybe<T*> can be move-constructed from a Maybe<U*> if U* and T* are
* compatible, or from Maybe<decltype(nullptr)>.
*/
template<typename U,
typename =
typename std::enable_if<std::is_pointer<T>::value &&
(std::is_same<U, decltype(nullptr)>::value ||
(std::is_pointer<U>::value &&
std::is_base_of<typename std::remove_pointer<T>::type,
typename std::remove_pointer<U>::type>::value))>::type>
MOZ_IMPLICIT
Maybe(Maybe<U>&& aOther)
: mIsSome(false)
{
if (aOther.isSome()) {
emplace(Move(*aOther));
aOther.reset();
}
}

Maybe& operator=(const Maybe& aOther)
{
if (&aOther != this) {
Expand Down
83 changes: 83 additions & 0 deletions mfbt/tests/TestMaybe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,87 @@ TestVirtualFunction() {
return true;
}

static Maybe<int*>
ReturnSomeNullptr()
{
return Some(nullptr);
}

struct D
{
explicit D(Maybe<int*>) {}
};

static bool
TestSomeNullptrConversion()
{
Maybe<int*> m1 = Some(nullptr);
MOZ_RELEASE_ASSERT(m1.isSome());
MOZ_RELEASE_ASSERT(m1);
MOZ_RELEASE_ASSERT(!*m1);

auto m2 = ReturnSomeNullptr();
MOZ_RELEASE_ASSERT(m2.isSome());
MOZ_RELEASE_ASSERT(m2);
MOZ_RELEASE_ASSERT(!*m2);

Maybe<decltype(nullptr)> m3 = Some(nullptr);
MOZ_RELEASE_ASSERT(m3.isSome());
MOZ_RELEASE_ASSERT(m3);
MOZ_RELEASE_ASSERT(*m3 == nullptr);

D d(Some(nullptr));

return true;
}

struct Base {};
struct Derived : Base {};

static Maybe<Base*>
ReturnDerivedPointer()
{
Derived* d = nullptr;
return Some(d);
}

struct ExplicitConstructorBasePointer
{
explicit ExplicitConstructorBasePointer(Maybe<Base*>) {}
};

static bool
TestSomePointerConversion()
{
Base base;
Derived derived;

Maybe<Base*> m1 = Some(&derived);
MOZ_RELEASE_ASSERT(m1.isSome());
MOZ_RELEASE_ASSERT(m1);
MOZ_RELEASE_ASSERT(*m1 == &derived);

auto m2 = ReturnDerivedPointer();
MOZ_RELEASE_ASSERT(m2.isSome());
MOZ_RELEASE_ASSERT(m2);
MOZ_RELEASE_ASSERT(*m2 == nullptr);

Maybe<Base*> m3 = Some(&base);
MOZ_RELEASE_ASSERT(m3.isSome());
MOZ_RELEASE_ASSERT(m3);
MOZ_RELEASE_ASSERT(*m3 == &base);

auto s1 = Some(&derived);
Maybe<Base*> c1(s1);
MOZ_RELEASE_ASSERT(c1.isSome());
MOZ_RELEASE_ASSERT(c1);
MOZ_RELEASE_ASSERT(*c1 == &derived);

ExplicitConstructorBasePointer ecbp(Some(&derived));

return true;
}

int
main()
{
Expand All @@ -772,6 +853,8 @@ main()
RUN_TEST(TestToMaybe);
RUN_TEST(TestComparisonOperators);
RUN_TEST(TestVirtualFunction);
RUN_TEST(TestSomeNullptrConversion);
RUN_TEST(TestSomePointerConversion);

return 0;
}

0 comments on commit 34e7d5b

Please sign in to comment.