blob: 1a100b549cbd9afd00624372af748950feae393c [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"
Mike Klein03141d22017-10-30 11:57:15 -040012#include <thread>
bungeman@google.com55487522012-05-14 14:09:24 +000013
14static void bounce_ref(void* data) {
15 SkRefCnt* ref = static_cast<SkRefCnt*>(data);
16 for (int i = 0; i < 100000; ++i) {
17 ref->ref();
18 ref->unref();
19 }
20}
21
22static void test_refCnt(skiatest::Reporter* reporter) {
23 SkRefCnt* ref = new SkRefCnt();
24
Mike Klein03141d22017-10-30 11:57:15 -040025 std::thread thing1(bounce_ref, ref);
26 std::thread thing2(bounce_ref, ref);
bungeman@google.com55487522012-05-14 14:09:24 +000027
28 thing1.join();
29 thing2.join();
30
mtkleinbbb61d72014-11-24 13:09:39 -080031 REPORTER_ASSERT(reporter, ref->unique());
bungeman@google.com55487522012-05-14 14:09:24 +000032 ref->unref();
33}
34
bungeman@google.coma02bc152012-05-16 18:21:56 +000035static void bounce_weak_ref(void* data) {
36 SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
37 for (int i = 0; i < 100000; ++i) {
38 if (ref->try_ref()) {
39 ref->unref();
40 }
41 }
42}
43
44static void bounce_weak_weak_ref(void* data) {
45 SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
46 for (int i = 0; i < 100000; ++i) {
47 ref->weak_ref();
48 ref->weak_unref();
49 }
50}
51
52static void test_weakRefCnt(skiatest::Reporter* reporter) {
53 SkWeakRefCnt* ref = new SkWeakRefCnt();
54
Mike Klein03141d22017-10-30 11:57:15 -040055 std::thread thing1(bounce_ref, ref);
56 std::thread thing2(bounce_ref, ref);
57 std::thread thing3(bounce_weak_ref, ref);
58 std::thread thing4(bounce_weak_weak_ref, ref);
bungeman@google.coma02bc152012-05-16 18:21:56 +000059
60 thing1.join();
61 thing2.join();
62 thing3.join();
63 thing4.join();
64
mtkleinbbb61d72014-11-24 13:09:39 -080065 REPORTER_ASSERT(reporter, ref->unique());
bungeman2c4bd072016-04-08 06:58:51 -070066 SkDEBUGCODE(REPORTER_ASSERT(reporter, ref->getWeakCnt() == 1));
bungeman@google.coma02bc152012-05-16 18:21:56 +000067 ref->unref();
68}
69
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +000070DEF_TEST(RefCnt, reporter) {
bungeman@google.coma02bc152012-05-16 18:21:56 +000071 test_refCnt(reporter);
72 test_weakRefCnt(reporter);
73}
reedbb7b0432016-03-01 07:28:51 -080074
75///////////////////////////////////////////////////////////////////////////////////////////////////
76
77static int gRefCounter;
78static int gUnrefCounter;
79static int gNewCounter;
80static int gDeleteCounter;
81
82#define check(reporter, ref, unref, make, kill) \
83 REPORTER_ASSERT(reporter, gRefCounter == ref); \
84 REPORTER_ASSERT(reporter, gUnrefCounter == unref); \
85 REPORTER_ASSERT(reporter, gNewCounter == make); \
86 REPORTER_ASSERT(reporter, gDeleteCounter == kill);
87
88
89class Effect {
90public:
91 Effect() : fRefCnt(1) {
92 gNewCounter += 1;
93 }
mtklein71aca542016-03-07 12:28:17 -080094 virtual ~Effect() {}
reedbb7b0432016-03-01 07:28:51 -080095
96 int fRefCnt;
97
98 void ref() {
99 gRefCounter += 1;
100 fRefCnt += 1;
101 }
102 void unref() {
103 gUnrefCounter += 1;
104
105 SkASSERT(fRefCnt > 0);
106 if (0 == --fRefCnt) {
107 gDeleteCounter += 1;
108 delete this;
109 }
110 }
111
112 int* method() const { return new int; }
113};
114
115static sk_sp<Effect> Create() {
halcanary217c0b32016-03-02 08:06:20 -0800116 return sk_make_sp<Effect>();
reedbb7b0432016-03-01 07:28:51 -0800117}
118
119class Paint {
120public:
121 sk_sp<Effect> fEffect;
122
123 const sk_sp<Effect>& get() const { return fEffect; }
124
125 void set(sk_sp<Effect> value) {
126 fEffect = std::move(value);
127 }
128};
129
halcanarycb6cb382016-03-02 08:11:26 -0800130struct EffectImpl : public Effect {
mtklein71aca542016-03-07 12:28:17 -0800131 ~EffectImpl() override {}
132
halcanarycb6cb382016-03-02 08:11:26 -0800133 static sk_sp<EffectImpl> Create() {
134 return sk_sp<EffectImpl>(new EffectImpl);
135 }
136 int fValue;
137};
138static sk_sp<Effect> make_effect() {
139 auto foo = EffectImpl::Create();
140 foo->fValue = 42;
141 return std::move(foo);
142}
143
144static void reset_counters() {
reedbb7b0432016-03-01 07:28:51 -0800145 gRefCounter = 0;
146 gUnrefCounter = 0;
147 gNewCounter = 0;
148 gDeleteCounter = 0;
halcanarycb6cb382016-03-02 08:11:26 -0800149}
150DEF_TEST(sk_sp, reporter) {
151 reset_counters();
reedbb7b0432016-03-01 07:28:51 -0800152
153 Paint paint;
154 REPORTER_ASSERT(reporter, paint.fEffect.get() == nullptr);
155 REPORTER_ASSERT(reporter, !paint.get());
156 check(reporter, 0, 0, 0, 0);
157
158 paint.set(Create());
159 check(reporter, 0, 0, 1, 0);
160 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 1);
161
bungemanbeab9e72016-03-03 07:50:49 -0800162 if (paint.get()) {
163 REPORTER_ASSERT(reporter, true);
164 } else {
165 REPORTER_ASSERT(reporter, false);
166 }
167 if (!paint.get()) {
168 REPORTER_ASSERT(reporter, false);
169 } else {
170 REPORTER_ASSERT(reporter, true);
171 }
172
reedbb7b0432016-03-01 07:28:51 -0800173 paint.set(nullptr);
174 check(reporter, 0, 1, 1, 1);
175
bungemanbeab9e72016-03-03 07:50:49 -0800176 if (paint.get()) {
177 REPORTER_ASSERT(reporter, false);
178 } else {
179 REPORTER_ASSERT(reporter, true);
180 }
181 if (!paint.get()) {
182 REPORTER_ASSERT(reporter, true);
183 } else {
184 REPORTER_ASSERT(reporter, false);
185 }
186
reedbb7b0432016-03-01 07:28:51 -0800187 auto e = Create();
188 REPORTER_ASSERT(reporter, sizeof(e) == sizeof(void*));
189
190 check(reporter, 0, 1, 2, 1);
191 paint.set(e);
192 check(reporter, 1, 1, 2, 1);
193 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 2);
194
195 Paint paint2;
196 paint2.set(paint.get());
197 check(reporter, 2, 1, 2, 1);
198 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 3);
199
bungemanbeab9e72016-03-03 07:50:49 -0800200 // Test sk_sp::operator->
reedbb7b0432016-03-01 07:28:51 -0800201 delete paint.get()->method();
202 check(reporter, 2, 1, 2, 1);
halcanarycb6cb382016-03-02 08:11:26 -0800203
bungemanbeab9e72016-03-03 07:50:49 -0800204 // Test sk_sp::operator*
205 delete (*paint.get()).method();
206 check(reporter, 2, 1, 2, 1);
207
halcanarycb6cb382016-03-02 08:11:26 -0800208 paint.set(nullptr);
209 e = nullptr;
210 paint2.set(nullptr);
211 check(reporter, 2, 4, 2, 2);
212
213 reset_counters();
214 {
215 // Test convertible sk_sp assignment.
216 check(reporter, 0, 0, 0, 0);
217 sk_sp<Effect> foo(nullptr);
218 REPORTER_ASSERT(reporter, !foo);
219 foo = make_effect();
220 REPORTER_ASSERT(reporter, foo);
221 check(reporter, 0, 0, 1, 0);
222 }
223 check(reporter, 0, 1, 1, 1);
224
225 // Test passing convertible rvalue into funtion.
226 reset_counters();
227 paint.set(EffectImpl::Create());
228 check(reporter, 0, 0, 1, 0);
229 paint.set(nullptr);
230 check(reporter, 0, 1, 1, 1);
231
232 reset_counters();
233 auto baz = EffectImpl::Create();
234 check(reporter, 0, 0, 1, 0);
235 paint.set(std::move(baz));
236 check(reporter, 0, 0, 1, 0);
237 REPORTER_ASSERT(reporter, !baz);
238 paint.set(nullptr);
239 check(reporter, 0, 1, 1, 1);
240
241 reset_counters();
242 {
243 // test comparison operator with convertible type.
244 sk_sp<EffectImpl> bar1 = EffectImpl::Create();
245 sk_sp<Effect> bar2(bar1); // convertible copy constructor
246 check(reporter, 1, 0, 1, 0);
247 REPORTER_ASSERT(reporter, bar1);
248 REPORTER_ASSERT(reporter, bar2);
249 REPORTER_ASSERT(reporter, bar1 == bar2);
250 REPORTER_ASSERT(reporter, bar2 == bar1);
251 REPORTER_ASSERT(reporter, !(bar1 != bar2));
252 REPORTER_ASSERT(reporter, !(bar2 != bar1));
253 sk_sp<Effect> bar3(nullptr);
254 bar3 = bar1; // convertible copy assignment
255 check(reporter, 2, 0, 1, 0);
256
257 }
258 check(reporter, 2, 3, 1, 1);
259
260 // test passing convertible copy into funtion.
261 reset_counters();
262 baz = EffectImpl::Create();
263 check(reporter, 0, 0, 1, 0);
264 paint.set(baz);
265 check(reporter, 1, 0, 1, 0);
266 baz = nullptr;
267 check(reporter, 1, 1, 1, 0);
268 paint.set(nullptr);
269 check(reporter, 1, 2, 1, 1);
bungemanc901c112016-03-08 08:35:23 -0800270
271 {
272 sk_sp<SkRefCnt> empty;
273 sk_sp<SkRefCnt> notEmpty = sk_make_sp<SkRefCnt>();
274 REPORTER_ASSERT(reporter, empty == sk_sp<SkRefCnt>());
275
276 REPORTER_ASSERT(reporter, notEmpty != empty);
277 REPORTER_ASSERT(reporter, empty != notEmpty);
278
279 REPORTER_ASSERT(reporter, nullptr == empty);
280 REPORTER_ASSERT(reporter, empty == nullptr);
281 REPORTER_ASSERT(reporter, empty == empty);
282
283 REPORTER_ASSERT(reporter, nullptr <= empty);
284 REPORTER_ASSERT(reporter, empty <= nullptr);
285 REPORTER_ASSERT(reporter, empty <= empty);
286
287 REPORTER_ASSERT(reporter, nullptr >= empty);
288 REPORTER_ASSERT(reporter, empty >= nullptr);
289 REPORTER_ASSERT(reporter, empty >= empty);
290 }
291
292 {
293 sk_sp<SkRefCnt> a = sk_make_sp<SkRefCnt>();
294 sk_sp<SkRefCnt> b = sk_make_sp<SkRefCnt>();
295 REPORTER_ASSERT(reporter, a != b);
296 REPORTER_ASSERT(reporter, (a < b) != (b < a));
297 REPORTER_ASSERT(reporter, (b > a) != (a > b));
298 REPORTER_ASSERT(reporter, (a <= b) != (b <= a));
299 REPORTER_ASSERT(reporter, (b >= a) != (a >= b));
300
301 REPORTER_ASSERT(reporter, a == a);
302 REPORTER_ASSERT(reporter, a <= a);
303 REPORTER_ASSERT(reporter, a >= a);
304 }
305
306 // http://wg21.cmeerw.net/lwg/issue998
307 {
308 class foo : public SkRefCnt {
309 public:
310 foo() : bar(this) {}
311 void reset() { bar.reset(); }
312 private:
313 sk_sp<foo> bar;
314 };
315 // The following should properly delete the object and not cause undefined behavior.
316 // This is an ugly example, but the same issue can arise in more subtle ways.
317 (new foo)->reset();
318 }
319
320 // https://crrev.com/0d4ef2583a6f19c3e61be04d36eb1a60b133832c
321 {
322 struct StructB;
323 struct StructA : public SkRefCnt {
324 sk_sp<StructB> b;
325 };
326
327 struct StructB : public SkRefCnt {
328 sk_sp<StructA> a;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400329 ~StructB() override {} // Some clang versions don't emit this implicitly.
bungemanc901c112016-03-08 08:35:23 -0800330 };
331
332 // Create a reference cycle.
333 StructA* a = new StructA;
334 a->b.reset(new StructB);
335 a->b->a.reset(a);
336
337 // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|)
338 // to be deleted before the call to reset() returns. This tests that the
339 // implementation of sk_sp::reset() doesn't access |this| after it
340 // deletes the underlying pointer. This behaviour is consistent with the
341 // definition of unique_ptr::reset in C++11.
342 a->b.reset();
343 }
reedbb7b0432016-03-01 07:28:51 -0800344}
345
halcanaryffa39e02016-03-05 08:30:28 -0800346namespace {
347struct FooAbstract : public SkRefCnt {
348 virtual void f() = 0;
349};
350struct FooConcrete : public FooAbstract {
351 void f() override {}
352};
353}
354static sk_sp<FooAbstract> make_foo() {
355 // can not cast FooConcrete to FooAbstract.
356 // can cast FooConcrete* to FooAbstract*.
357 return sk_make_sp<FooConcrete>();
358}
359DEF_TEST(sk_make_sp, r) {
360 auto x = make_foo();
361}
reed941da9d2016-03-06 13:54:00 -0800362
363// Test that reset() "adopts" ownership from the caller, even if we are given the same ptr twice
364//
365DEF_TEST(sk_sp_reset, r) {
366 SkRefCnt* rc = new SkRefCnt;
367 REPORTER_ASSERT(r, rc->unique());
368
369 sk_sp<SkRefCnt> sp;
370 sp.reset(rc);
371 // We have transfered our ownership over to sp
372 REPORTER_ASSERT(r, rc->unique());
373
374 rc->ref(); // now "rc" is also an owner
375 REPORTER_ASSERT(r, !rc->unique());
376
377 sp.reset(rc); // this should transfer our ownership over to sp
378 REPORTER_ASSERT(r, rc->unique());
379}
reed647cc842016-03-08 12:54:48 -0800380
381DEF_TEST(sk_sp_ref, r) {
382 SkRefCnt* rc = new SkRefCnt;
383 REPORTER_ASSERT(r, rc->unique());
384
385 {
386 sk_sp<SkRefCnt> sp = sk_ref_sp(rc);
387 REPORTER_ASSERT(r, !rc->unique());
388 }
389
390 REPORTER_ASSERT(r, rc->unique());
391 rc->unref();
392}