blob: 8914ccff49a092fc2ca8d337cf80a1f9090fb15a [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 "SkThreadUtils.h"
10#include "SkTypes.h"
11#include "SkWeakRefCnt.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000012#include "Test.h"
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
25 SkThread thing1(bounce_ref, ref);
26 SkThread thing2(bounce_ref, ref);
27
bungeman@google.com55487522012-05-14 14:09:24 +000028 SkASSERT(thing1.start());
29 SkASSERT(thing2.start());
30
31 thing1.join();
32 thing2.join();
33
mtkleinbbb61d72014-11-24 13:09:39 -080034 REPORTER_ASSERT(reporter, ref->unique());
bungeman@google.com55487522012-05-14 14:09:24 +000035 ref->unref();
36}
37
bungeman@google.coma02bc152012-05-16 18:21:56 +000038static void bounce_weak_ref(void* data) {
39 SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
40 for (int i = 0; i < 100000; ++i) {
41 if (ref->try_ref()) {
42 ref->unref();
43 }
44 }
45}
46
47static void bounce_weak_weak_ref(void* data) {
48 SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
49 for (int i = 0; i < 100000; ++i) {
50 ref->weak_ref();
51 ref->weak_unref();
52 }
53}
54
55static void test_weakRefCnt(skiatest::Reporter* reporter) {
56 SkWeakRefCnt* ref = new SkWeakRefCnt();
57
58 SkThread thing1(bounce_ref, ref);
59 SkThread thing2(bounce_ref, ref);
60 SkThread thing3(bounce_weak_ref, ref);
61 SkThread thing4(bounce_weak_weak_ref, ref);
62
bungeman@google.coma02bc152012-05-16 18:21:56 +000063 SkASSERT(thing1.start());
64 SkASSERT(thing2.start());
65 SkASSERT(thing3.start());
66 SkASSERT(thing4.start());
67
68 thing1.join();
69 thing2.join();
70 thing3.join();
71 thing4.join();
72
mtkleinbbb61d72014-11-24 13:09:39 -080073 REPORTER_ASSERT(reporter, ref->unique());
Mike Klein874a62a2014-07-09 09:04:07 -040074 REPORTER_ASSERT(reporter, ref->getWeakCnt() == 1);
bungeman@google.coma02bc152012-05-16 18:21:56 +000075 ref->unref();
76}
77
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +000078DEF_TEST(RefCnt, reporter) {
bungeman@google.coma02bc152012-05-16 18:21:56 +000079 test_refCnt(reporter);
80 test_weakRefCnt(reporter);
81}
reedbb7b0432016-03-01 07:28:51 -080082
83///////////////////////////////////////////////////////////////////////////////////////////////////
84
85static int gRefCounter;
86static int gUnrefCounter;
87static int gNewCounter;
88static int gDeleteCounter;
89
90#define check(reporter, ref, unref, make, kill) \
91 REPORTER_ASSERT(reporter, gRefCounter == ref); \
92 REPORTER_ASSERT(reporter, gUnrefCounter == unref); \
93 REPORTER_ASSERT(reporter, gNewCounter == make); \
94 REPORTER_ASSERT(reporter, gDeleteCounter == kill);
95
96
97class Effect {
98public:
99 Effect() : fRefCnt(1) {
100 gNewCounter += 1;
101 }
102
103 int fRefCnt;
104
105 void ref() {
106 gRefCounter += 1;
107 fRefCnt += 1;
108 }
109 void unref() {
110 gUnrefCounter += 1;
111
112 SkASSERT(fRefCnt > 0);
113 if (0 == --fRefCnt) {
114 gDeleteCounter += 1;
115 delete this;
116 }
117 }
118
119 int* method() const { return new int; }
120};
121
122static sk_sp<Effect> Create() {
halcanary217c0b32016-03-02 08:06:20 -0800123 return sk_make_sp<Effect>();
reedbb7b0432016-03-01 07:28:51 -0800124}
125
126class Paint {
127public:
128 sk_sp<Effect> fEffect;
129
130 const sk_sp<Effect>& get() const { return fEffect; }
131
132 void set(sk_sp<Effect> value) {
133 fEffect = std::move(value);
134 }
135};
136
halcanarycb6cb382016-03-02 08:11:26 -0800137struct EffectImpl : public Effect {
138 static sk_sp<EffectImpl> Create() {
139 return sk_sp<EffectImpl>(new EffectImpl);
140 }
141 int fValue;
142};
143static sk_sp<Effect> make_effect() {
144 auto foo = EffectImpl::Create();
145 foo->fValue = 42;
146 return std::move(foo);
147}
148
149static void reset_counters() {
reedbb7b0432016-03-01 07:28:51 -0800150 gRefCounter = 0;
151 gUnrefCounter = 0;
152 gNewCounter = 0;
153 gDeleteCounter = 0;
halcanarycb6cb382016-03-02 08:11:26 -0800154}
155DEF_TEST(sk_sp, reporter) {
156 reset_counters();
reedbb7b0432016-03-01 07:28:51 -0800157
158 Paint paint;
159 REPORTER_ASSERT(reporter, paint.fEffect.get() == nullptr);
160 REPORTER_ASSERT(reporter, !paint.get());
161 check(reporter, 0, 0, 0, 0);
162
163 paint.set(Create());
164 check(reporter, 0, 0, 1, 0);
165 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 1);
166
bungemanbeab9e72016-03-03 07:50:49 -0800167 if (paint.get()) {
168 REPORTER_ASSERT(reporter, true);
169 } else {
170 REPORTER_ASSERT(reporter, false);
171 }
172 if (!paint.get()) {
173 REPORTER_ASSERT(reporter, false);
174 } else {
175 REPORTER_ASSERT(reporter, true);
176 }
177
reedbb7b0432016-03-01 07:28:51 -0800178 paint.set(nullptr);
179 check(reporter, 0, 1, 1, 1);
180
bungemanbeab9e72016-03-03 07:50:49 -0800181 if (paint.get()) {
182 REPORTER_ASSERT(reporter, false);
183 } else {
184 REPORTER_ASSERT(reporter, true);
185 }
186 if (!paint.get()) {
187 REPORTER_ASSERT(reporter, true);
188 } else {
189 REPORTER_ASSERT(reporter, false);
190 }
191
reedbb7b0432016-03-01 07:28:51 -0800192 auto e = Create();
193 REPORTER_ASSERT(reporter, sizeof(e) == sizeof(void*));
194
195 check(reporter, 0, 1, 2, 1);
196 paint.set(e);
197 check(reporter, 1, 1, 2, 1);
198 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 2);
199
200 Paint paint2;
201 paint2.set(paint.get());
202 check(reporter, 2, 1, 2, 1);
203 REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 3);
204
bungemanbeab9e72016-03-03 07:50:49 -0800205 // Test sk_sp::operator->
reedbb7b0432016-03-01 07:28:51 -0800206 delete paint.get()->method();
207 check(reporter, 2, 1, 2, 1);
halcanarycb6cb382016-03-02 08:11:26 -0800208
bungemanbeab9e72016-03-03 07:50:49 -0800209 // Test sk_sp::operator*
210 delete (*paint.get()).method();
211 check(reporter, 2, 1, 2, 1);
212
halcanarycb6cb382016-03-02 08:11:26 -0800213 paint.set(nullptr);
214 e = nullptr;
215 paint2.set(nullptr);
216 check(reporter, 2, 4, 2, 2);
217
218 reset_counters();
219 {
220 // Test convertible sk_sp assignment.
221 check(reporter, 0, 0, 0, 0);
222 sk_sp<Effect> foo(nullptr);
223 REPORTER_ASSERT(reporter, !foo);
224 foo = make_effect();
225 REPORTER_ASSERT(reporter, foo);
226 check(reporter, 0, 0, 1, 0);
227 }
228 check(reporter, 0, 1, 1, 1);
229
230 // Test passing convertible rvalue into funtion.
231 reset_counters();
232 paint.set(EffectImpl::Create());
233 check(reporter, 0, 0, 1, 0);
234 paint.set(nullptr);
235 check(reporter, 0, 1, 1, 1);
236
237 reset_counters();
238 auto baz = EffectImpl::Create();
239 check(reporter, 0, 0, 1, 0);
240 paint.set(std::move(baz));
241 check(reporter, 0, 0, 1, 0);
242 REPORTER_ASSERT(reporter, !baz);
243 paint.set(nullptr);
244 check(reporter, 0, 1, 1, 1);
245
246 reset_counters();
247 {
248 // test comparison operator with convertible type.
249 sk_sp<EffectImpl> bar1 = EffectImpl::Create();
250 sk_sp<Effect> bar2(bar1); // convertible copy constructor
251 check(reporter, 1, 0, 1, 0);
252 REPORTER_ASSERT(reporter, bar1);
253 REPORTER_ASSERT(reporter, bar2);
254 REPORTER_ASSERT(reporter, bar1 == bar2);
255 REPORTER_ASSERT(reporter, bar2 == bar1);
256 REPORTER_ASSERT(reporter, !(bar1 != bar2));
257 REPORTER_ASSERT(reporter, !(bar2 != bar1));
258 sk_sp<Effect> bar3(nullptr);
259 bar3 = bar1; // convertible copy assignment
260 check(reporter, 2, 0, 1, 0);
261
262 }
263 check(reporter, 2, 3, 1, 1);
264
265 // test passing convertible copy into funtion.
266 reset_counters();
267 baz = EffectImpl::Create();
268 check(reporter, 0, 0, 1, 0);
269 paint.set(baz);
270 check(reporter, 1, 0, 1, 0);
271 baz = nullptr;
272 check(reporter, 1, 1, 1, 0);
273 paint.set(nullptr);
274 check(reporter, 1, 2, 1, 1);
reedbb7b0432016-03-01 07:28:51 -0800275}
276
halcanaryffa39e02016-03-05 08:30:28 -0800277namespace {
278struct FooAbstract : public SkRefCnt {
279 virtual void f() = 0;
280};
281struct FooConcrete : public FooAbstract {
282 void f() override {}
283};
284}
285static sk_sp<FooAbstract> make_foo() {
286 // can not cast FooConcrete to FooAbstract.
287 // can cast FooConcrete* to FooAbstract*.
288 return sk_make_sp<FooConcrete>();
289}
290DEF_TEST(sk_make_sp, r) {
291 auto x = make_foo();
292}