Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Macros | Functions | Variables
RefCntTest.cpp File Reference
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include "include/private/SkWeakRefCnt.h"
#include "include/private/base/SkDebug.h"
#include "tests/Test.h"
#include <thread>
#include <utility>

Go to the source code of this file.

Classes

class  Effect
 
class  Paint
 
struct  EffectImpl
 

Macros

#define check(reporter, ref, unref, make, kill)
 

Functions

static void bounce_ref (void *data)
 
static void test_refCnt (skiatest::Reporter *reporter)
 
static void bounce_weak_ref (void *data)
 
static void bounce_weak_weak_ref (void *data)
 
static void test_weakRefCnt (skiatest::Reporter *reporter)
 
 DEF_TEST (RefCnt, reporter)
 
static sk_sp< EffectCreate ()
 
static sk_sp< Effectmake_effect ()
 
static void reset_counters ()
 
 DEF_TEST (sk_sp, reporter)
 
static sk_sp< FooAbstract > make_foo ()
 
 DEF_TEST (sk_make_sp, r)
 
 DEF_TEST (sk_sp_reset, r)
 
 DEF_TEST (sk_sp_ref, r)
 

Variables

static int gRefCounter
 
static int gUnrefCounter
 
static int gNewCounter
 
static int gDeleteCounter
 

Macro Definition Documentation

◆ check

#define check (   reporter,
  ref,
  unref,
  make,
  kill 
)
Value:
REPORTER_ASSERT(reporter, gUnrefCounter == unref); \
REPORTER_ASSERT(reporter, gNewCounter == make); \
REPORTER_ASSERT(reporter, gDeleteCounter == kill)
reporter
static int gRefCounter
static int gDeleteCounter
static int gUnrefCounter
static int gNewCounter
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
static sk_sp< SkImage > make(sk_sp< SkColorSpace > cs)
Definition mipmap.cpp:65

Definition at line 85 of file RefCntTest.cpp.

90 {
91public:
92 Effect() : fRefCnt(1) {
93 gNewCounter += 1;
94 }
95 virtual ~Effect() {}
96
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() {
117 return sk_make_sp<Effect>();
118}
119
120class Paint {
121public:
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
131struct EffectImpl : public Effect {
132 ~EffectImpl() override {}
133
134 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 foo;
143}
144
145static void reset_counters() {
146 gRefCounter = 0;
147 gUnrefCounter = 0;
148 gNewCounter = 0;
149 gDeleteCounter = 0;
150}
153
154 Paint paint;
157 check(reporter, 0, 0, 0, 0);
158
159 paint.set(Create());
160 check(reporter, 0, 0, 1, 0);
162
163 if (paint.get()) {
165 } else {
167 }
168 if (!paint.get()) {
170 } else {
172 }
173
174 paint.set(nullptr);
175 check(reporter, 0, 1, 1, 1);
176
177 if (paint.get()) {
179 } else {
181 }
182 if (!paint.get()) {
184 } else {
186 }
187
188 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);
195
196 Paint paint2;
197 paint2.set(paint.get());
198 check(reporter, 2, 1, 2, 1);
200
201 // Test sk_sp::operator->
202 delete paint.get()->method();
203 check(reporter, 2, 1, 2, 1);
204
205 // Test sk_sp::operator*
206 delete (*paint.get()).method();
207 check(reporter, 2, 1, 2, 1);
208
209 paint.set(nullptr);
210 e = nullptr;
211 paint2.set(nullptr);
212 check(reporter, 2, 4, 2, 2);
213
215 {
216 // Test convertible sk_sp assignment.
217 check(reporter, 0, 0, 0, 0);
218 sk_sp<Effect> foo(nullptr);
220 foo = make_effect();
222 check(reporter, 0, 0, 1, 0);
223 }
224 check(reporter, 0, 1, 1, 1);
225
226 // Test passing convertible rvalue into funtion.
229 check(reporter, 0, 0, 1, 0);
230 paint.set(nullptr);
231 check(reporter, 0, 1, 1, 1);
232
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); // NOLINT(bugprone-use-after-move)
239 paint.set(nullptr);
240 check(reporter, 0, 1, 1, 1);
241
243 {
244 // test comparison operator with convertible type.
246 sk_sp<Effect> bar2(bar1); // convertible copy constructor
247 check(reporter, 1, 0, 1, 0);
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.
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);
271
272 {
274 sk_sp<SkRefCnt> notEmpty = sk_make_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);
283 }
284
285 {
286 sk_sp<SkRefCnt> a = sk_make_sp<SkRefCnt>();
287 sk_sp<SkRefCnt> b = sk_make_sp<SkRefCnt>();
290 }
291
292 // http://wg21.cmeerw.net/lwg/issue998
293 {
294 class foo : public SkRefCnt {
295 public:
296 foo() : bar(this) {}
297 void reset() { bar.reset(); }
298 private:
299 sk_sp<foo> bar;
300 };
301 // The following should properly delete the object and not cause undefined behavior.
302 // This is an ugly example, but the same issue can arise in more subtle ways.
303 (new foo)->reset();
304 }
305
306 // https://crrev.com/0d4ef2583a6f19c3e61be04d36eb1a60b133832c
307 {
308 struct StructB;
309 struct StructA : public SkRefCnt {
311 };
312
313 struct StructB : public SkRefCnt {
315 ~StructB() override {} // Some clang versions don't emit this implicitly.
316 };
317
318 // Create a reference cycle.
319 StructA* a = new StructA;
320 a->b.reset(new StructB);
321 a->b->a.reset(a);
322
323 // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|)
324 // to be deleted before the call to reset() returns. This tests that the
325 // implementation of sk_sp::reset() doesn't access |this| after it
326 // deletes the underlying pointer. This behaviour is consistent with the
327 // definition of unique_ptr::reset in C++11.
328 a->b.reset();
329 }
330}
331
332namespace {
333struct FooAbstract : public SkRefCnt {
334 virtual void f() = 0;
335};
336struct FooConcrete : public FooAbstract {
337 void f() override {}
338};
339} // namespace
341 // can not cast FooConcrete to FooAbstract.
342 // can cast FooConcrete* to FooAbstract*.
343 return sk_make_sp<FooConcrete>();
344}
346 auto x = make_foo();
347}
348
349// Test that reset() "adopts" ownership from the caller, even if we are given the same ptr twice
350//
351DEF_TEST(sk_sp_reset, r) {
352 SkRefCnt* rc = new SkRefCnt;
353 REPORTER_ASSERT(r, rc->unique());
354
356 sp.reset(rc);
357 // We have transfered our ownership over to sp
358 REPORTER_ASSERT(r, rc->unique());
359
360 rc->ref(); // now "rc" is also an owner
361 REPORTER_ASSERT(r, !rc->unique());
362
363 sp.reset(rc); // this should transfer our ownership over to sp
364 REPORTER_ASSERT(r, rc->unique());
365}
366
367DEF_TEST(sk_sp_ref, r) {
368 SkRefCnt* rc = new SkRefCnt;
369 REPORTER_ASSERT(r, rc->unique());
370
371 {
372 sk_sp<SkRefCnt> sp = sk_ref_sp(rc);
373 REPORTER_ASSERT(r, !rc->unique());
374 }
375
376 REPORTER_ASSERT(r, rc->unique());
377 rc->unref();
378}
m reset()
#define check(reporter, ref, unref, make, kill)
static sk_sp< Effect > make_effect()
static void reset_counters()
static sk_sp< FooAbstract > make_foo()
static sk_sp< Effect > Create()
#define SkASSERT(cond)
Definition SkAssert.h:116
sk_sp< T > sk_make_sp(Args &&... args)
Definition SkRefCnt.h:371
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
#define DEF_TEST(name, reporter)
Definition Test.h:312
Type::kYUV Type::kRGBA() int(0.7 *637)
int * method() const
int fRefCnt
void set(sk_sp< Effect > value)
sk_sp< Effect > fEffect
const sk_sp< Effect > & get() const
T * get() const
Definition SkRefCnt.h:303
void reset(T *ptr=nullptr)
Definition SkRefCnt.h:310
const Paint & paint
static bool b
struct MyStruct a[10]
EMSCRIPTEN_KEEPALIVE void empty()
uint8_t value
double x
~EffectImpl() override
static sk_sp< EffectImpl > Create()

Function Documentation

◆ bounce_ref()

static void bounce_ref ( void *  data)
static

Definition at line 17 of file RefCntTest.cpp.

17 {
18 SkRefCnt* ref = static_cast<SkRefCnt*>(data);
19 for (int i = 0; i < 100000; ++i) {
20 ref->ref();
21 ref->unref();
22 }
23}
void ref() const
Definition SkRefCnt.h:62
void unref() const
Definition SkRefCnt.h:72
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41

◆ bounce_weak_ref()

static void bounce_weak_ref ( void *  data)
static

Definition at line 38 of file RefCntTest.cpp.

38 {
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}
bool try_ref() const

◆ bounce_weak_weak_ref()

static void bounce_weak_weak_ref ( void *  data)
static

Definition at line 47 of file RefCntTest.cpp.

47 {
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}
void weak_ref() const
void weak_unref() const

◆ Create()

static sk_sp< Effect > Create ( )
static

Definition at line 117 of file RefCntTest.cpp.

117 {
118 return sk_make_sp<Effect>();
119}

◆ DEF_TEST() [1/5]

DEF_TEST ( RefCnt  ,
reporter   
)

Definition at line 73 of file RefCntTest.cpp.

73 {
76}
static void test_weakRefCnt(skiatest::Reporter *reporter)
static void test_refCnt(skiatest::Reporter *reporter)

◆ DEF_TEST() [2/5]

DEF_TEST ( sk_make_sp  ,
 
)

Definition at line 346 of file RefCntTest.cpp.

346 {
347 auto x = make_foo();
348}

◆ DEF_TEST() [3/5]

DEF_TEST ( sk_sp  ,
reporter   
)

Definition at line 152 of file RefCntTest.cpp.

152 {
154
155 Paint paint;
158 check(reporter, 0, 0, 0, 0);
159
160 paint.set(Create());
161 check(reporter, 0, 0, 1, 0);
163
164 if (paint.get()) {
166 } else {
168 }
169 if (!paint.get()) {
171 } else {
173 }
174
175 paint.set(nullptr);
176 check(reporter, 0, 1, 1, 1);
177
178 if (paint.get()) {
180 } else {
182 }
183 if (!paint.get()) {
185 } else {
187 }
188
189 auto e = Create();
190 REPORTER_ASSERT(reporter, sizeof(e) == sizeof(void*));
191
192 check(reporter, 0, 1, 2, 1);
193 paint.set(e);
194 check(reporter, 1, 1, 2, 1);
196
197 Paint paint2;
198 paint2.set(paint.get());
199 check(reporter, 2, 1, 2, 1);
201
202 // Test sk_sp::operator->
203 delete paint.get()->method();
204 check(reporter, 2, 1, 2, 1);
205
206 // Test sk_sp::operator*
207 delete (*paint.get()).method();
208 check(reporter, 2, 1, 2, 1);
209
210 paint.set(nullptr);
211 e = nullptr;
212 paint2.set(nullptr);
213 check(reporter, 2, 4, 2, 2);
214
216 {
217 // Test convertible sk_sp assignment.
218 check(reporter, 0, 0, 0, 0);
219 sk_sp<Effect> foo(nullptr);
221 foo = make_effect();
223 check(reporter, 0, 0, 1, 0);
224 }
225 check(reporter, 0, 1, 1, 1);
226
227 // Test passing convertible rvalue into funtion.
230 check(reporter, 0, 0, 1, 0);
231 paint.set(nullptr);
232 check(reporter, 0, 1, 1, 1);
233
235 auto baz = EffectImpl::Create();
236 check(reporter, 0, 0, 1, 0);
237 paint.set(std::move(baz));
238 check(reporter, 0, 0, 1, 0);
239 REPORTER_ASSERT(reporter, !baz); // NOLINT(bugprone-use-after-move)
240 paint.set(nullptr);
241 check(reporter, 0, 1, 1, 1);
242
244 {
245 // test comparison operator with convertible type.
247 sk_sp<Effect> bar2(bar1); // convertible copy constructor
248 check(reporter, 1, 0, 1, 0);
251 REPORTER_ASSERT(reporter, bar1 == bar2);
252 REPORTER_ASSERT(reporter, bar2 == bar1);
253 REPORTER_ASSERT(reporter, !(bar1 != bar2));
254 REPORTER_ASSERT(reporter, !(bar2 != bar1));
255 sk_sp<Effect> bar3(nullptr);
256 bar3 = bar1; // convertible copy assignment
257 check(reporter, 2, 0, 1, 0);
258
259 }
260 check(reporter, 2, 3, 1, 1);
261
262 // test passing convertible copy into funtion.
264 baz = EffectImpl::Create();
265 check(reporter, 0, 0, 1, 0);
266 paint.set(baz);
267 check(reporter, 1, 0, 1, 0);
268 baz = nullptr;
269 check(reporter, 1, 1, 1, 0);
270 paint.set(nullptr);
271 check(reporter, 1, 2, 1, 1);
272
273 {
275 sk_sp<SkRefCnt> notEmpty = sk_make_sp<SkRefCnt>();
277
278 REPORTER_ASSERT(reporter, notEmpty != empty);
279 REPORTER_ASSERT(reporter, empty != notEmpty);
280
281 REPORTER_ASSERT(reporter, nullptr == empty);
282 REPORTER_ASSERT(reporter, empty == nullptr);
284 }
285
286 {
287 sk_sp<SkRefCnt> a = sk_make_sp<SkRefCnt>();
288 sk_sp<SkRefCnt> b = sk_make_sp<SkRefCnt>();
291 }
292
293 // http://wg21.cmeerw.net/lwg/issue998
294 {
295 class foo : public SkRefCnt {
296 public:
297 foo() : bar(this) {}
298 void reset() { bar.reset(); }
299 private:
300 sk_sp<foo> bar;
301 };
302 // The following should properly delete the object and not cause undefined behavior.
303 // This is an ugly example, but the same issue can arise in more subtle ways.
304 (new foo)->reset();
305 }
306
307 // https://crrev.com/0d4ef2583a6f19c3e61be04d36eb1a60b133832c
308 {
309 struct StructB;
310 struct StructA : public SkRefCnt {
312 };
313
314 struct StructB : public SkRefCnt {
316 ~StructB() override {} // Some clang versions don't emit this implicitly.
317 };
318
319 // Create a reference cycle.
320 StructA* a = new StructA;
321 a->b.reset(new StructB);
322 a->b->a.reset(a);
323
324 // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|)
325 // to be deleted before the call to reset() returns. This tests that the
326 // implementation of sk_sp::reset() doesn't access |this| after it
327 // deletes the underlying pointer. This behaviour is consistent with the
328 // definition of unique_ptr::reset in C++11.
329 a->b.reset();
330 }
331}

◆ DEF_TEST() [4/5]

DEF_TEST ( sk_sp_ref  ,
 
)

Definition at line 368 of file RefCntTest.cpp.

368 {
369 SkRefCnt* rc = new SkRefCnt;
370 REPORTER_ASSERT(r, rc->unique());
371
372 {
373 sk_sp<SkRefCnt> sp = sk_ref_sp(rc);
374 REPORTER_ASSERT(r, !rc->unique());
375 }
376
377 REPORTER_ASSERT(r, rc->unique());
378 rc->unref();
379}

◆ DEF_TEST() [5/5]

DEF_TEST ( sk_sp_reset  ,
 
)

Definition at line 352 of file RefCntTest.cpp.

352 {
353 SkRefCnt* rc = new SkRefCnt;
354 REPORTER_ASSERT(r, rc->unique());
355
357 sp.reset(rc);
358 // We have transfered our ownership over to sp
359 REPORTER_ASSERT(r, rc->unique());
360
361 rc->ref(); // now "rc" is also an owner
362 REPORTER_ASSERT(r, !rc->unique());
363
364 sp.reset(rc); // this should transfer our ownership over to sp
365 REPORTER_ASSERT(r, rc->unique());
366}

◆ make_effect()

static sk_sp< Effect > make_effect ( )
static

Definition at line 140 of file RefCntTest.cpp.

140 {
141 auto foo = EffectImpl::Create();
142 foo->fValue = 42;
143 return foo;
144}

◆ make_foo()

static sk_sp< FooAbstract > make_foo ( )
static

Definition at line 341 of file RefCntTest.cpp.

341 {
342 // can not cast FooConcrete to FooAbstract.
343 // can cast FooConcrete* to FooAbstract*.
344 return sk_make_sp<FooConcrete>();
345}

◆ reset_counters()

static void reset_counters ( )
static

Definition at line 146 of file RefCntTest.cpp.

146 {
147 gRefCounter = 0;
148 gUnrefCounter = 0;
149 gNewCounter = 0;
150 gDeleteCounter = 0;
151}

◆ test_refCnt()

static void test_refCnt ( skiatest::Reporter reporter)
static

Definition at line 25 of file RefCntTest.cpp.

25 {
26 SkRefCnt* ref = new SkRefCnt();
27
28 std::thread thing1(bounce_ref, ref);
29 std::thread thing2(bounce_ref, ref);
30
31 thing1.join();
32 thing2.join();
33
35 ref->unref();
36}
static void bounce_ref(void *data)
bool unique() const
Definition SkRefCnt.h:50

◆ test_weakRefCnt()

static void test_weakRefCnt ( skiatest::Reporter reporter)
static

Definition at line 55 of file RefCntTest.cpp.

55 {
56 SkWeakRefCnt* ref = new SkWeakRefCnt();
57
58 std::thread thing1(bounce_ref, ref);
59 std::thread thing2(bounce_ref, ref);
60 std::thread thing3(bounce_weak_ref, ref);
61 std::thread thing4(bounce_weak_weak_ref, ref);
62
63 thing1.join();
64 thing2.join();
65 thing3.join();
66 thing4.join();
67
69 SkDEBUGCODE(REPORTER_ASSERT(reporter, ref->getWeakCnt() == 1));
70 ref->unref();
71}
static void bounce_weak_ref(void *data)
static void bounce_weak_weak_ref(void *data)
#define SkDEBUGCODE(...)
Definition SkDebug.h:23

Variable Documentation

◆ gDeleteCounter

int gDeleteCounter
static

Definition at line 83 of file RefCntTest.cpp.

◆ gNewCounter

int gNewCounter
static

Definition at line 82 of file RefCntTest.cpp.

◆ gRefCounter

int gRefCounter
static

Definition at line 80 of file RefCntTest.cpp.

◆ gUnrefCounter

int gUnrefCounter
static

Definition at line 81 of file RefCntTest.cpp.