Flutter Engine
The Flutter Engine
reference_counting.h
Go to the documentation of this file.
1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_BIN_REFERENCE_COUNTING_H_
6#define RUNTIME_BIN_REFERENCE_COUNTING_H_
7
8#include <atomic>
9
10#include "platform/assert.h"
11
12namespace dart {
13namespace bin {
14
15// Forward declaration.
16template <class Target>
17class RefCntReleaseScope;
18
19// Inherit from this class where instances of the derived class should be
20// reference counted. Reference counts on instances are incremented and
21// decremented explicitly with calls to Retain() and Release(). E.g.:
22//
23// class Foo : public ReferenceCounted<Foo> {
24// public:
25// Foo() : ReferenceCounted() {}
26// ...
27// };
28//
29// void DoStuffWithAFoo() {
30// Foo* foo = new Foo(); // Reference count starts at 1, so no explicit
31// // call to Retain is needed after allocation.
32// ...
33// foo->Release();
34// }
35template <class Derived>
37 public:
38 ReferenceCounted() : ref_count_(1) {
39#if defined(DEBUG)
40 instances_.fetch_add(1u, std::memory_order_relaxed);
41#endif // defined(DEBUG)
42 }
43
45 ASSERT(ref_count_ == 0);
46#if defined(DEBUG)
47 instances_.fetch_sub(1u, std::memory_order_relaxed);
48#endif // defined(DEBUG)
49 }
50
51 void Retain() {
52 intptr_t old = ref_count_.fetch_add(1u, std::memory_order_relaxed);
53 ASSERT(old > 0);
54 }
55
56 void Release() {
57 intptr_t old = ref_count_.fetch_sub(1u, std::memory_order_acq_rel);
58 ASSERT(old > 0);
59 if (old == 1) {
60 delete static_cast<Derived*>(this);
61 }
62 }
63
64#if defined(DEBUG)
65 static intptr_t instances() {
66 return instances_.load(std::memory_order_relaxed);
67 }
68#endif // defined(DEBUG)
69
70 private:
71#if defined(DEBUG)
72 static std::atomic<intptr_t> instances_;
73#endif // defined(DEBUG)
74
75 std::atomic<intptr_t> ref_count_;
76
77 // These are used only in the ASSERT below in RefCntReleaseScope.
78 intptr_t ref_count() const {
79 return ref_count_.load(std::memory_order_relaxed);
80 }
81 friend class RefCntReleaseScope<Derived>;
83};
84
85#if defined(DEBUG)
86template <class Derived>
87std::atomic<intptr_t> ReferenceCounted<Derived>::instances_ = {0};
88#endif
89
90// Creates a scope at the end of which a reference counted object is
91// Released. This is useful for reference counted objects received by the IO
92// Service, which have already been Retained E.g.:
93//
94// CObject* Foo::FooRequest(const CObjectArray& request) {
95// Foo* foo = CObjectToFoo(request[0]);
96// RefCntReleaseScope<Foo> rs(foo);
97// ...
98// }
99template <class Target>
101 public:
103 ASSERT(target_ != nullptr);
104 ASSERT(target_->ref_count() > 0);
105 }
106 ~RefCntReleaseScope() { target_->Release(); }
107
108 private:
110
111 DISALLOW_ALLOCATION();
112 DISALLOW_COPY_AND_ASSIGN(RefCntReleaseScope);
113};
114
115// Instances of RetainedPointer manage Retaining and Releasing reference counted
116// objects. There are two ways to use it. First, it can be used as a field in
117// a class, e.g.:
118//
119// class Foo {
120// private:
121// RetainedPointer<Bar> bar_;
122// public:
123// explicit Foo(Bar* b) : bar_(b) {}
124// }
125//
126// In this case, b will be Retained in Foo's constructor, and Released
127// automatically during Foo's destructor.
128//
129// RetainedPointer can also be used as a scope, as with RefCntReleaseScope,
130// with the difference that entering the scope also Retains the pointer, e.g.:
131//
132// void RetainAndDoStuffWithFoo(Foo* foo) {
133// RetainedPointer<Foo> retained(foo);
134// ..
135// }
136//
137// This Retains foo on entry and Releases foo at every exit from the scope.
138//
139// The underlying pointer can be accessed with the get() and set() methods.
140// Overwriting a non-null pointer with set causes that pointer to be Released.
141template <class Target>
143 public:
144 RetainedPointer() : target_(nullptr) {}
145
146 explicit RetainedPointer(ReferenceCounted<Target>* t) : target_(t) {
147 if (target_ != nullptr) {
148 target_->Retain();
149 }
150 }
151
153 if (target_ != nullptr) {
154 target_->Release();
155 }
156 }
157
159 if (target_ != nullptr) {
160 target_->Release();
161 }
162 target_ = t;
163 if (target_ != nullptr) {
164 target_->Retain();
165 }
166 }
167
168 Target* get() const { return static_cast<Target*>(target_); }
169
170 private:
172
173 DISALLOW_ALLOCATION();
174 DISALLOW_COPY_AND_ASSIGN(RetainedPointer);
175};
176
177} // namespace bin
178} // namespace dart
179
180#endif // RUNTIME_BIN_REFERENCE_COUNTING_H_
RefCntReleaseScope(ReferenceCounted< Target > *t)
RetainedPointer(ReferenceCounted< Target > *t)
void set(ReferenceCounted< Target > *t)
#define ASSERT(E)
Definition: dart_vm.cc:33
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581