aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2016-03-02 08:11:26 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-03-02 08:11:26 -0800
commitcb6cb3841adec77d178c6d6ed006102077fd3c48 (patch)
treee9559e28272bd9750dcaca48e74975297107c607
parentc803ef125d98429abbbe2679f4a8c6bc7bf10f85 (diff)
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
-rw-r--r--include/core/SkRefCnt.h26
-rw-r--r--tests/RefCntTest.cpp80
2 files changed, 102 insertions, 4 deletions
diff --git a/include/core/SkRefCnt.h b/include/core/SkRefCnt.h
index e2cf4456f8..02df993261 100644
--- a/include/core/SkRefCnt.h
+++ b/include/core/SkRefCnt.h
@@ -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; }
diff --git a/tests/RefCntTest.cpp b/tests/RefCntTest.cpp
index e9d582d809..bda45317bc 100644
--- a/tests/RefCntTest.cpp
+++ b/tests/RefCntTest.cpp
@@ -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);
}