sk_sp: Covariant Move Constructor and Move Assignment

Also Covariant Copy Constructor, Copy Assignment,
and comparison operators.

GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1752093002

Review URL: https://codereview.chromium.org/1752093002
This commit is contained in:
halcanary 2016-03-02 08:11:26 -08:00 committed by Commit bot
parent c803ef125d
commit cb6cb3841a
2 changed files with 102 additions and 4 deletions

View File

@ -247,6 +247,9 @@ public:
* created sk_sp both have a reference to it.
*/
sk_sp(const sk_sp<T>& that) : fPtr(SkSafeRef(that.get())) {}
template <typename U,
typename = skstd::enable_if_t<skstd::is_convertible<U, T>::value>>
sk_sp(const sk_sp<U>& that) : fPtr(SkSafeRef(that.get())) {}
/**
* Move the underlying object from the argument to the newly created sk_sp. Afterwards only
@ -254,6 +257,9 @@ public:
* No call to ref() or unref() will be made.
*/
sk_sp(sk_sp<T>&& that) : fPtr(that.release()) {}
template <typename U,
typename = skstd::enable_if_t<skstd::is_convertible<U, T>::value>>
sk_sp(sk_sp<U>&& that) : fPtr(that.release()) {}
/**
* Adopt the bare pointer into the newly created sk_sp.
@ -268,7 +274,7 @@ public:
SkSafeUnref(fPtr);
}
sk_sp<T>& operator=(std::nullptr_t) { this->reset(); }
sk_sp<T>& operator=(std::nullptr_t) { this->reset(); return *this; }
/**
* Shares the underlying object referenced by the argument by calling ref() on it. If this
@ -279,6 +285,12 @@ public:
this->reset(SkSafeRef(that.get()));
return *this;
}
template <typename U,
typename = skstd::enable_if_t<skstd::is_convertible<U, T>::value>>
sk_sp<T>& operator=(const sk_sp<U>& that) {
this->reset(SkSafeRef(that.get()));
return *this;
}
/**
* Move the underlying object from the argument to the sk_sp. If the sk_sp previously held
@ -289,12 +301,20 @@ public:
this->reset(that.release());
return *this;
}
template <typename U,
typename = skstd::enable_if_t<skstd::is_convertible<U, T>::value>>
sk_sp<T>& operator=(sk_sp<U>&& that) {
this->reset(that.release());
return *this;
}
bool operator==(std::nullptr_t) const { return this->get() == nullptr; }
bool operator!=(std::nullptr_t) const { return this->get() != nullptr; }
bool operator==(const sk_sp<T>& that) const { return this->get() == that.get(); }
bool operator!=(const sk_sp<T>& that) const { return this->get() != that.get(); }
template <typename U>
bool operator==(const sk_sp<U>& that) const { return this->get() == that.get(); }
template <typename U>
bool operator!=(const sk_sp<U>& that) const { return this->get() != that.get(); }
explicit operator bool() const { return this->get() != nullptr; }

View File

@ -134,11 +134,26 @@ public:
}
};
DEF_TEST(sk_sp, reporter) {
struct EffectImpl : public Effect {
static sk_sp<EffectImpl> Create() {
return sk_sp<EffectImpl>(new EffectImpl);
}
int fValue;
};
static sk_sp<Effect> make_effect() {
auto foo = EffectImpl::Create();
foo->fValue = 42;
return std::move(foo);
}
static void reset_counters() {
gRefCounter = 0;
gUnrefCounter = 0;
gNewCounter = 0;
gDeleteCounter = 0;
}
DEF_TEST(sk_sp, reporter) {
reset_counters();
Paint paint;
REPORTER_ASSERT(reporter, paint.fEffect.get() == nullptr);
@ -167,5 +182,68 @@ DEF_TEST(sk_sp, reporter) {
delete paint.get()->method();
check(reporter, 2, 1, 2, 1);
paint.set(nullptr);
e = nullptr;
paint2.set(nullptr);
check(reporter, 2, 4, 2, 2);
reset_counters();
{
// Test convertible sk_sp assignment.
check(reporter, 0, 0, 0, 0);
sk_sp<Effect> foo(nullptr);
REPORTER_ASSERT(reporter, !foo);
foo = make_effect();
REPORTER_ASSERT(reporter, foo);
check(reporter, 0, 0, 1, 0);
}
check(reporter, 0, 1, 1, 1);
// Test passing convertible rvalue into funtion.
reset_counters();
paint.set(EffectImpl::Create());
check(reporter, 0, 0, 1, 0);
paint.set(nullptr);
check(reporter, 0, 1, 1, 1);
reset_counters();
auto baz = EffectImpl::Create();
check(reporter, 0, 0, 1, 0);
paint.set(std::move(baz));
check(reporter, 0, 0, 1, 0);
REPORTER_ASSERT(reporter, !baz);
paint.set(nullptr);
check(reporter, 0, 1, 1, 1);
reset_counters();
{
// test comparison operator with convertible type.
sk_sp<EffectImpl> bar1 = EffectImpl::Create();
sk_sp<Effect> bar2(bar1); // convertible copy constructor
check(reporter, 1, 0, 1, 0);
REPORTER_ASSERT(reporter, bar1);
REPORTER_ASSERT(reporter, bar2);
REPORTER_ASSERT(reporter, bar1 == bar2);
REPORTER_ASSERT(reporter, bar2 == bar1);
REPORTER_ASSERT(reporter, !(bar1 != bar2));
REPORTER_ASSERT(reporter, !(bar2 != bar1));
sk_sp<Effect> bar3(nullptr);
bar3 = bar1; // convertible copy assignment
check(reporter, 2, 0, 1, 0);
}
check(reporter, 2, 3, 1, 1);
// test passing convertible copy into funtion.
reset_counters();
baz = EffectImpl::Create();
check(reporter, 0, 0, 1, 0);
paint.set(baz);
check(reporter, 1, 0, 1, 0);
baz = nullptr;
check(reporter, 1, 1, 1, 0);
paint.set(nullptr);
check(reporter, 1, 2, 1, 1);
}