blob: 7ea0b338111bf7b72902fb3cd14901ec2a4b4b2c [file] [log] [blame]
bungeman@google.com55487522012-05-14 14:09:24 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
bungeman@google.com55487522012-05-14 14:09:24 +00008#include "SkRefCnt.h"
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00009#include "SkTypes.h"
10#include "SkWeakRefCnt.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "Test.h"
Hal Canary8a001442018-09-19 11:31:27 -040012
Mike Klein03141d22017-10-30 11:57:15 -040013#include <thread>
bungeman@google.com55487522012-05-14 14:09:24 +000014
15static void bounce_ref(void* data) {
16 SkRefCnt* ref = static_cast<SkRefCnt*>(data);
17 for (int i = 0; i < 100000; ++i) {
18 ref->ref();
19 ref->unref();
20 }
21}
22
23static void test_refCnt(skiatest::Reporter* reporter) {
24 SkRefCnt* ref = new SkRefCnt();
25
Mike Klein03141d22017-10-30 11:57:15 -040026 std::thread thing1(bounce_ref, ref);
27 std::thread thing2(bounce_ref, ref);
bungeman@google.com55487522012-05-14 14:09:24 +000028
29 thing1.join();
30 thing2.join();
31
mtkleinbbb61d72014-11-24 13:09:39 -080032 REPORTER_ASSERT(reporter, ref->unique());
bungeman@google.com55487522012-05-14 14:09:24 +000033 ref->unref();
34}
35
bungeman@google.coma02bc152012-05-16 18:21:56 +000036static void bounce_weak_ref(void* data) {
37 SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
38 for (int i = 0; i < 100000; ++i) {
39 if (ref->try_ref()) {
40 ref->unref();
41 }
42 }
43}
44
45static void bounce_weak_weak_ref(void* data) {
46 SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
47 for (int i = 0; i < 100000; ++i) {
48 ref->weak_ref();
49 ref->weak_unref();
50 }
51}
52
53static void test_weakRefCnt(skiatest::Reporter* reporter) {
54 SkWeakRefCnt* ref = new SkWeakRefCnt();
55
Mike Klein03141d22017-10-30 11:57:15 -040056 std::thread thing1(bounce_ref, ref);
57 std::thread thing2(bounce_ref, ref);
58 std::thread thing3(bounce_weak_ref, ref);
59 std::thread thing4(bounce_weak_weak_ref, ref);
bungeman@google.coma02bc152012-05-16 18:21:56 +000060
61 thing1.join();
62 thing2.join();
63 thing3.join();
64 thing4.join();
65
mtkleinbbb61d72014-11-24 13:09:39 -080066 REPORTER_ASSERT(reporter, ref->unique());
bungeman2c4bd072016-04-08 06:58:51 -070067 SkDEBUGCODE(REPORTER_ASSERT(reporter, ref->getWeakCnt() == 1));
bungeman@google.coma02bc152012-05-16 18:21:56 +000068 ref->unref();
69}
70
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +000071DEF_TEST(RefCnt, reporter) {
bungeman@google.coma02bc152012-05-16 18:21:56 +000072 test_refCnt(reporter);
73 test_weakRefCnt(reporter);
74}
reedbb7b0432016-03-01 07:28:51 -080075
76///////////////////////////////////////////////////////////////////////////////////////////////////
77
78static int gRefCounter;
79static int gUnrefCounter;
80static int gNewCounter;
81static int gDeleteCounter;
82
83#define check(reporter, ref, unref, make, kill) \
84 REPORTER_ASSERT(reporter, gRefCounter == ref); \
85 REPORTER_ASSERT(reporter, gUnrefCounter == unref); \
86 REPORTER_ASSERT(reporter, gNewCounter == make); \
87 REPORTER_ASSERT(reporter, gDeleteCounter == kill);
88
89
90class Effect {
91public:
92 Effect() : fRefCnt(1) {
93 gNewCounter += 1;
94 }
mtklein71aca542016-03-07 12:28:17 -080095 virtual ~Effect() {}
reedbb7b0432016-03-01 07:28:51 -080096
97 int fRefCnt;
98
99 void ref() {
100 gRefCounter += 1;
101 fRefCnt += 1;
102 }
103 void unref() {
104 gUnrefCounter += 1;
105
106 SkASSERT(fRefCnt > 0);
107 if (0 == --fRefCnt) {
108 gDeleteCounter += 1;
109 delete this;
110 }
111 }
112
113 int* method() const { return new int; }
114};
115
116static sk_sp<Effect> Create() {
halcanary217c0b32016-03-02 08:06:20 -0800117 return sk_make_sp<Effect>();
reedbb7b0432016-03-01 07:28:51 -0800118}
119
120class Paint {
121public:
122 sk_sp<Effect> fEffect;
123
124 const sk_sp<Effect>& get() const { return fEffect; }
125
126 void set(sk_sp<Effect> value) {
127 fEffect = std::move(value);
128 }
129};
130
halcanarycb6cb382016-03-02 08:11:26 -0800131struct EffectImpl : public Effect {
mtklein71aca542016-03-07 12:28:17 -0800132 ~EffectImpl() override {}
133
halcanarycb6cb382016-03-02 08:11:26 -0800134 static sk_sp<EffectImpl> Create() {
135 return sk_sp<EffectImpl>(new EffectImpl);
136 }
137 int fValue;
138};
139static sk_sp<Effect> make_effect() {
140 auto foo = EffectImpl::Create();
141 foo->fValue = 42;
142 return std::move(foo);
143}
144
145static void reset_counters() {
reedbb7b0432016-03-01 07:28:51 -0800146 gRefCounter = 0;
147 gUnrefCounter = 0;
148 gNewCounter = 0;
149 gDeleteCounter = 0;
halcanarycb6cb382016-03-02 08:11:26 -0800150}
151DEF_TEST(sk_sp, reporter) {
152 reset_counters();
reedbb7b0432016-03-01 07:28:51 -0800153
154 Paint paint;
155 REPORTER_ASSERT(reporter, paint.fEffect.get() == nullptr);
156 REPORTER_ASSERT(reporter, !paint.get());
157 check(reporter, 0, 0, 0, 0);
158
159 paint.set(Create());
160 check(reporter, 0, 0, 1, 0);
161 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 1);
162
bungemanbeab9e72016-03-03 07:50:49 -0800163 if (paint.get()) {
164 REPORTER_ASSERT(reporter, true);
165 } else {
166 REPORTER_ASSERT(reporter, false);
167 }
168 if (!paint.get()) {
169 REPORTER_ASSERT(reporter, false);
170 } else {
171 REPORTER_ASSERT(reporter, true);
172 }
173
reedbb7b0432016-03-01 07:28:51 -0800174 paint.set(nullptr);
175 check(reporter, 0, 1, 1, 1);
176
bungemanbeab9e72016-03-03 07:50:49 -0800177 if (paint.get()) {
178 REPORTER_ASSERT(reporter, false);
179 } else {
180 REPORTER_ASSERT(reporter, true);
181 }
182 if (!paint.get()) {
183 REPORTER_ASSERT(reporter, true);
184 } else {
185 REPORTER_ASSERT(reporter, false);
186 }
187
reedbb7b0432016-03-01 07:28:51 -0800188 auto e = Create();
189 REPORTER_ASSERT(reporter, sizeof(e) == sizeof(void*));
190
191 check(reporter, 0, 1, 2, 1);
192 paint.set(e);
193 check(reporter, 1, 1, 2, 1);
194 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 2);
195
196 Paint paint2;
197 paint2.set(paint.get());
198 check(reporter, 2, 1, 2, 1);
199 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 3);
200
bungemanbeab9e72016-03-03 07:50:49 -0800201 // Test sk_sp::operator->
reedbb7b0432016-03-01 07:28:51 -0800202 delete paint.get()->method();
203 check(reporter, 2, 1, 2, 1);
halcanarycb6cb382016-03-02 08:11:26 -0800204
bungemanbeab9e72016-03-03 07:50:49 -0800205 // Test sk_sp::operator*
206 delete (*paint.get()).method();
207 check(reporter, 2, 1, 2, 1);
208
halcanarycb6cb382016-03-02 08:11:26 -0800209 paint.set(nullptr);
210 e = nullptr;
211 paint2.set(nullptr);
212 check(reporter, 2, 4, 2, 2);
213
214 reset_counters();
215 {
216 // Test convertible sk_sp assignment.
217 check(reporter, 0, 0, 0, 0);
218 sk_sp<Effect> foo(nullptr);
219 REPORTER_ASSERT(reporter, !foo);
220 foo = make_effect();
221 REPORTER_ASSERT(reporter, foo);
222 check(reporter, 0, 0, 1, 0);
223 }
224 check(reporter, 0, 1, 1, 1);
225
226 // Test passing convertible rvalue into funtion.
227 reset_counters();
228 paint.set(EffectImpl::Create());
229 check(reporter, 0, 0, 1, 0);
230 paint.set(nullptr);
231 check(reporter, 0, 1, 1, 1);
232
233 reset_counters();
234 auto baz = EffectImpl::Create();
235 check(reporter, 0, 0, 1, 0);
236 paint.set(std::move(baz));
237 check(reporter, 0, 0, 1, 0);
238 REPORTER_ASSERT(reporter, !baz);
239 paint.set(nullptr);
240 check(reporter, 0, 1, 1, 1);
241
242 reset_counters();
243 {
244 // test comparison operator with convertible type.
245 sk_sp<EffectImpl> bar1 = EffectImpl::Create();
246 sk_sp<Effect> bar2(bar1); // convertible copy constructor
247 check(reporter, 1, 0, 1, 0);
248 REPORTER_ASSERT(reporter, bar1);
249 REPORTER_ASSERT(reporter, bar2);
250 REPORTER_ASSERT(reporter, bar1 == bar2);
251 REPORTER_ASSERT(reporter, bar2 == bar1);
252 REPORTER_ASSERT(reporter, !(bar1 != bar2));
253 REPORTER_ASSERT(reporter, !(bar2 != bar1));
254 sk_sp<Effect> bar3(nullptr);
255 bar3 = bar1; // convertible copy assignment
256 check(reporter, 2, 0, 1, 0);
257
258 }
259 check(reporter, 2, 3, 1, 1);
260
261 // test passing convertible copy into funtion.
262 reset_counters();
263 baz = EffectImpl::Create();
264 check(reporter, 0, 0, 1, 0);
265 paint.set(baz);
266 check(reporter, 1, 0, 1, 0);
267 baz = nullptr;
268 check(reporter, 1, 1, 1, 0);
269 paint.set(nullptr);
270 check(reporter, 1, 2, 1, 1);
bungemanc901c112016-03-08 08:35:23 -0800271
272 {
273 sk_sp<SkRefCnt> empty;
274 sk_sp<SkRefCnt> notEmpty = sk_make_sp<SkRefCnt>();
275 REPORTER_ASSERT(reporter, empty == sk_sp<SkRefCnt>());
276
277 REPORTER_ASSERT(reporter, notEmpty != empty);
278 REPORTER_ASSERT(reporter, empty != notEmpty);
279
280 REPORTER_ASSERT(reporter, nullptr == empty);
281 REPORTER_ASSERT(reporter, empty == nullptr);
282 REPORTER_ASSERT(reporter, empty == empty);
283
284 REPORTER_ASSERT(reporter, nullptr <= empty);
285 REPORTER_ASSERT(reporter, empty <= nullptr);
286 REPORTER_ASSERT(reporter, empty <= empty);
287
288 REPORTER_ASSERT(reporter, nullptr >= empty);
289 REPORTER_ASSERT(reporter, empty >= nullptr);
290 REPORTER_ASSERT(reporter, empty >= empty);
291 }
292
293 {
294 sk_sp<SkRefCnt> a = sk_make_sp<SkRefCnt>();
295 sk_sp<SkRefCnt> b = sk_make_sp<SkRefCnt>();
296 REPORTER_ASSERT(reporter, a != b);
297 REPORTER_ASSERT(reporter, (a < b) != (b < a));
298 REPORTER_ASSERT(reporter, (b > a) != (a > b));
299 REPORTER_ASSERT(reporter, (a <= b) != (b <= a));
300 REPORTER_ASSERT(reporter, (b >= a) != (a >= b));
301
302 REPORTER_ASSERT(reporter, a == a);
303 REPORTER_ASSERT(reporter, a <= a);
304 REPORTER_ASSERT(reporter, a >= a);
305 }
306
307 // http://wg21.cmeerw.net/lwg/issue998
308 {
309 class foo : public SkRefCnt {
310 public:
311 foo() : bar(this) {}
312 void reset() { bar.reset(); }
313 private:
314 sk_sp<foo> bar;
315 };
316 // The following should properly delete the object and not cause undefined behavior.
317 // This is an ugly example, but the same issue can arise in more subtle ways.
318 (new foo)->reset();
319 }
320
321 // https://crrev.com/0d4ef2583a6f19c3e61be04d36eb1a60b133832c
322 {
323 struct StructB;
324 struct StructA : public SkRefCnt {
325 sk_sp<StructB> b;
326 };
327
328 struct StructB : public SkRefCnt {
329 sk_sp<StructA> a;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400330 ~StructB() override {} // Some clang versions don't emit this implicitly.
bungemanc901c112016-03-08 08:35:23 -0800331 };
332
333 // Create a reference cycle.
334 StructA* a = new StructA;
335 a->b.reset(new StructB);
336 a->b->a.reset(a);
337
338 // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|)
339 // to be deleted before the call to reset() returns. This tests that the
340 // implementation of sk_sp::reset() doesn't access |this| after it
341 // deletes the underlying pointer. This behaviour is consistent with the
342 // definition of unique_ptr::reset in C++11.
343 a->b.reset();
344 }
reedbb7b0432016-03-01 07:28:51 -0800345}
346
halcanaryffa39e02016-03-05 08:30:28 -0800347namespace {
348struct FooAbstract : public SkRefCnt {
349 virtual void f() = 0;
350};
351struct FooConcrete : public FooAbstract {
352 void f() override {}
353};
354}
355static sk_sp<FooAbstract> make_foo() {
356 // can not cast FooConcrete to FooAbstract.
357 // can cast FooConcrete* to FooAbstract*.
358 return sk_make_sp<FooConcrete>();
359}
360DEF_TEST(sk_make_sp, r) {
361 auto x = make_foo();
362}
reed941da9d2016-03-06 13:54:00 -0800363
364// Test that reset() "adopts" ownership from the caller, even if we are given the same ptr twice
365//
366DEF_TEST(sk_sp_reset, r) {
367 SkRefCnt* rc = new SkRefCnt;
368 REPORTER_ASSERT(r, rc->unique());
369
370 sk_sp<SkRefCnt> sp;
371 sp.reset(rc);
372 // We have transfered our ownership over to sp
373 REPORTER_ASSERT(r, rc->unique());
374
375 rc->ref(); // now "rc" is also an owner
376 REPORTER_ASSERT(r, !rc->unique());
377
378 sp.reset(rc); // this should transfer our ownership over to sp
379 REPORTER_ASSERT(r, rc->unique());
380}
reed647cc842016-03-08 12:54:48 -0800381
382DEF_TEST(sk_sp_ref, r) {
383 SkRefCnt* rc = new SkRefCnt;
384 REPORTER_ASSERT(r, rc->unique());
385
386 {
387 sk_sp<SkRefCnt> sp = sk_ref_sp(rc);
388 REPORTER_ASSERT(r, !rc->unique());
389 }
390
391 REPORTER_ASSERT(r, rc->unique());
392 rc->unref();
393}