Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
weakreferent.h
Go to the documentation of this file.
1 
18 #ifndef ION_BASE_WEAKREFERENT_H_
19 #define ION_BASE_WEAKREFERENT_H_
20 
21 #include <algorithm>
22 
23 #include "base/macros.h"
24 #include "ion/base/lockguards.h"
25 #include "ion/base/logging.h"
26 #include "ion/base/referent.h"
27 #include "ion/base/sharedptr.h"
28 #include "ion/port/atomic.h"
29 
30 namespace ion {
31 namespace base {
32 
40 class WeakReferent : public Referent {
41  protected:
42  WeakReferent() : proxy_(NULL) {}
43 
45  ~WeakReferent() override {
46  DCHECK(proxy_.load() == NULL);
47  }
48 
49  private:
59  class Proxy : public Allocatable, public Shareable {
60  public:
61  explicit Proxy(WeakReferent* ptr) : ptr_(ptr) { DCHECK(ptr_); }
62 
64  WeakReferent* Get() const {
65  DCHECK(mutex_.IsLocked());
66  return ptr_;
67  }
68 
70  WeakReferent* GetUnsynchronized() const {
71  return ptr_;
72  }
73 
76  void SetOrphaned() {
77  DCHECK(mutex_.IsLocked());
78  ptr_ = NULL;
79  }
80 
82  SpinMutex* GetMutex() const { return &mutex_; }
83 
84  private:
86  WeakReferent* ptr_;
87 
90  mutable SpinMutex mutex_;
91  };
92 
94  Proxy* GetProxy() const {
96  Proxy* proxy = proxy_.load(std::memory_order_acquire);
97  if (proxy) {
98  return proxy;
99  }
100 
103  proxy = new(GetAllocator()) Proxy(const_cast<WeakReferent*>(this));
107  proxy->IncrementRefCount();
108  Proxy* null = NULL;
109  if (proxy_.compare_exchange_strong(null, proxy)) {
111  DCHECK(proxy == proxy_);
112  return proxy;
113  } else {
114 #if !defined(ION_COVERAGE) // COV_NF_START
115  proxy->DecrementRefCount();
119  proxy = proxy_;
121  DCHECK(proxy_.load() != NULL) << "proxy should not be NULL after CAS";
122  return proxy;
123 #endif // COV_NF_END
124  }
125  }
126 
131  void OnZeroRefCount() const override {
135  Proxy* proxy = proxy_.exchange(NULL, std::memory_order_acquire);
136  if (proxy) {
143  {
144  SpinLockGuard proxy_guard(proxy->GetMutex());
146  DCHECK(proxy->Get() != NULL) << "SetOrphaned() already called.";
148  DCHECK_EQ(ref_count_.load(), 0);
149  proxy->SetOrphaned();
150  }
151  proxy->DecrementRefCount();
152  }
153  delete this;
154  }
155 
157  std::atomic<int>& GetRefCountRef() { return ref_count_; }
158 
160  mutable std::atomic<Proxy*> proxy_;
161 
164  template <typename T> friend class SharedPtr;
165  template <typename T> friend class WeakReferentPtr;
166 
167  DISALLOW_COPY_AND_ASSIGN(WeakReferent);
168 };
169 
181 template <typename T>
183  public:
185 
186  WeakReferentPtr() { Reset(NULL); }
187  explicit WeakReferentPtr(T* ptr) { Reset(ptr); }
188  explicit WeakReferentPtr(const ReferentPtrType& ref_ptr) {
189  Reset(ref_ptr.Get());
190  }
193  : proxy_(other.proxy_) {}
194 
203  ReferentPtrType result;
204 
206  if (proxy_.Get()) {
210  SpinLockGuard proxy_guard(proxy_->GetMutex());
213  WeakReferent* referent = proxy_->Get();
214  if (!referent) {
216  } else {
229 
234  if (referent->GetRefCountRef()++) {
238  result = referent;
239  }
242  --referent->GetRefCountRef();
243  }
244  }
245 
246  return result;
247  }
248 
250  void Reset() {
251  Reset(NULL);
252  }
253 
256  Reset(p.Get());
257  return *this;
258  }
259 
261  bool operator==(const WeakReferentPtr& p) const {
262  return p.proxy_ == proxy_;
263  }
264 
266  bool operator!=(const WeakReferentPtr& p) const {
267  return p.proxy_ != proxy_;
268  }
269 
274  if (WeakReferent::Proxy* proxy = proxy_.Get()) {
275  if (WeakReferent* referent = proxy->GetUnsynchronized()) {
276  return referent->GetRefCount();
277  }
278  }
279  return 0;
280  }
281 
282  private:
284  void Reset(T* new_referent) {
286  proxy_ = NULL;
287  if (new_referent) {
288  if (new_referent->GetRefCount() == 0)
289  LOG(ERROR) << "Input pointer was not owned by a ReferentPtr and will "
290  << "be deleted";
291  ReferentPtrType ref_p(new_referent);
292  proxy_ = ref_p->GetProxy();
293  }
294  }
295 
296  mutable ReferentPtr<WeakReferent::Proxy>::Type proxy_;
297 };
298 
299 } // namespace base
300 } // namespace ion
301 
302 #endif // ION_BASE_WEAKREFERENT_H_
int GetUnderlyingRefCountUnsynchronized() const
This function returns the reference count of the underlying referent that points to.
Definition: weakreferent.h:273
#define DCHECK(expr)
Definition: logging.h:331
ReferentPtr< T >::Type ReferentPtrType
Definition: weakreferent.h:184
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
Definition: logging.h:216
void Reset()
Set this WeakPointer to not refer to anything.
Definition: weakreferent.h:250
WeakReferentPtr(const ReferentPtrType &ref_ptr)
Definition: weakreferent.h:188
Shareable is an abstract base class for any object that can be shared via the SharedPtr class...
Definition: shareable.h:31
Thread-safe abstract base class.
Definition: referent.h:49
GenericLockGuard< SpinMutex > SpinLockGuard
Convenient typedefs for SpinMutex.
Definition: lockguards.h:197
T * Get() const
Returns a raw pointer to the instance, which may be NULL.
Definition: sharedptr.h:89
A LockGuard locks a mutex when created, and unlocks it when destroyed.
Definition: lockguards.h:90
Allocatable is an abstract base class for classes whose memory is managed by an Allocator.
Definition: allocatable.h:60
bool operator==(const WeakReferentPtr &p) const
The equality operator returns true if the proxies are the same.
Definition: weakreferent.h:261
WeakReferentPtr< T > & operator=(const ReferentPtrType &p)
Allow assignment from a SharedPtr of the same type.
Definition: weakreferent.h:255
WeakReferentPtr(const WeakReferentPtr &other)
Copy constructor.
Definition: weakreferent.h:192
Copyright 2016 Google Inc.
Abstract base class that inherits from Referent, and adds the ability for instances to be referenced ...
Definition: weakreferent.h:40
#define DCHECK_EQ(val1, val2)
Definition: logging.h:332
bool operator!=(const WeakReferentPtr &p) const
The inequality operator returns true if the proxies differ.
Definition: weakreferent.h:266
~WeakReferent() override
The destructor is protected to disallow creating instances on the stack.
Definition: weakreferent.h:45
ReferentPtrType Acquire() const
Attempts to construct a ReferentPtr of the reference.
Definition: weakreferent.h:201
port::Mutex mutex_
Protects shared access to the Allocator and FT_Library.
const AllocatorPtr & GetAllocator() const
Returns the Allocator that was used for the instance.
Definition: allocatable.h:68
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
A WeakReferentPtr is a weak reference to an instance of some class derived from Referent.
Definition: weakreferent.h:182