Chromium Code Reviews| Index: runtime/bin/reference_counting.h |
| diff --git a/runtime/bin/reference_counting.h b/runtime/bin/reference_counting.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a138526041716291b52dc69506474a4e7126df56 |
| --- /dev/null |
| +++ b/runtime/bin/reference_counting.h |
| @@ -0,0 +1,159 @@ |
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +#ifndef BIN_REFERENCE_COUNTING_H_ |
| +#define BIN_REFERENCE_COUNTING_H_ |
| + |
| +#include "vm/atomic.h" |
| + |
| +namespace dart { |
| +namespace bin { |
| + |
| +// Forward declaration. |
| +template <class Target> class RefCntReleaseScope; |
| + |
| +// Inherit from this class where instances of the derived class should be |
| +// reference counted. Reference counts on instances are incremented and |
| +// decremented explicitly with calls to Retain() and Release(). E.g.: |
| +// |
| +// class Foo : public ReferenceCounted<Foo> { |
| +// public: |
| +// Foo() : ReferenceCounted() {} |
| +// ... |
| +// }; |
| +// |
| +// void DoStuffWithAFoo() { |
| +// Foo* foo = new Foo(); |
| +// foo->Retain(); |
| +// ... |
| +// foo->Release(); |
| +// } |
| +template <class Derived> |
| +class ReferenceCounted { |
| + public: |
| + ReferenceCounted() : |
| + ref_count_(0) { |
| + } |
| + |
| + ~ReferenceCounted() { |
| + ASSERT(ref_count_ == 0); |
| + } |
| + |
| + void Retain() { |
| + uintptr_t old = AtomicOperations::FetchAndIncrement(&ref_count_); |
| + ASSERT(old >= 0); |
| + } |
| + |
| + void Release() { |
| + uintptr_t old = AtomicOperations::FetchAndDecrement(&ref_count_); |
| + ASSERT(old > 0); |
| + if (old == 1) { |
| + delete static_cast<Derived*>(this); |
|
siva
2016/04/12 19:03:01
You are using atomic operations so I assume the in
zra
2016/04/13 16:46:21
Changed so that ref_count_ is initialized to 1 in
|
| + } |
| + } |
| + |
| + private: |
| + uintptr_t ref_count() const { return ref_count_; } |
|
siva
2016/04/12 19:03:00
ref_count() is private and never used in this clas
zra
2016/04/13 16:46:21
It's used only for the ASSERT below in RefCntRelea
|
| + |
| + uintptr_t ref_count_; |
| + |
| + friend class RefCntReleaseScope<Derived>; |
| + DISALLOW_COPY_AND_ASSIGN(ReferenceCounted); |
| +}; |
| + |
| +// Creates a scope at the end of which a reference counted object is |
| +// Released. This is useful for reference counted objects recieved by the IO |
| +// Service, which have already been Retained E.g.: |
| +// |
| +// CObject* Foo::FooRequest(const CObjectArray& request) { |
| +// Foo* foo = CObjectToFoo(request[0]); |
| +// RefCntReleaseScope<Foo> rs(foo); |
| +// ... |
| +// } |
| +template <class Target> |
| +class RefCntReleaseScope { |
| + public: |
| + explicit RefCntReleaseScope(ReferenceCounted<Target>* t) : target_(t) { |
| + ASSERT(target_ != NULL); |
| + ASSERT(target_->ref_count() > 0); |
| + } |
| + ~RefCntReleaseScope() { |
| + target_->Release(); |
| + } |
| + |
| + private: |
| + ReferenceCounted<Target>* target_; |
| + |
| + DISALLOW_ALLOCATION(); |
| + DISALLOW_COPY_AND_ASSIGN(RefCntReleaseScope); |
| +}; |
| + |
| +// Instances of RetainedPointer manage Retaining and Releasing reference counted |
| +// objects. There are two ways to use it. First, it can be used as a field in |
| +// a class, e.g.: |
| +// |
| +// class Foo { |
| +// private: |
| +// RetainedPointer<Bar> bar_; |
| +// public: |
| +// explicit Foo(Bar* b) : bar_(b) {} |
| +// } |
| +// |
| +// In this case, b will be Retained in Foo's constructor, and Released |
| +// automatically during Foo's destructor. |
| +// |
| +// RetainedPointer can also be used as a scope, as with RefCntReleaseScope, |
| +// with the difference that entering the scope also Retains the pointer, e.g.: |
| +// |
| +// void RetainAndDoStuffWithFoo(Foo* foo) { |
| +// RetainedPointer<Foo> retained(foo); |
| +// .. |
| +// } |
| +// |
| +// This Retains foo on entry and Releases foo at every exit from the scope. |
| +// |
| +// The underlying pointer can be accessed with the get() and set() methods. |
| +// Overwriting a non-NULL pointer with set causes that pointer to be Released. |
| +template <class Target> |
| +class RetainedPointer { |
| + public: |
| + RetainedPointer() : target_(NULL) {} |
| + |
| + explicit RetainedPointer(ReferenceCounted<Target>* t) : target_(t) { |
| + if (target_ != NULL) { |
| + target_->Retain(); |
| + } |
| + } |
| + |
| + ~RetainedPointer() { |
| + if (target_ != NULL) { |
| + target_->Release(); |
| + } |
| + } |
| + |
| + void set(ReferenceCounted<Target>* t) { |
| + if (target_ != NULL) { |
| + target_->Release(); |
| + } |
| + target_ = t; |
| + if (target_ != NULL) { |
| + target_->Retain(); |
| + } |
| + } |
| + |
| + Target* get() const { |
| + return static_cast<Target*>(target_); |
| + } |
|
siva
2016/04/12 19:03:01
Should this 'get' method be provided because it ma
zra
2016/04/13 16:46:21
When the RetainedPointer is a field in a class, th
|
| + |
| + private: |
| + ReferenceCounted<Target>* target_; |
| + |
| + DISALLOW_ALLOCATION(); |
| + DISALLOW_COPY_AND_ASSIGN(RetainedPointer); |
| +}; |
| + |
| +} // namespace bin |
| +} // namespace dart |
| + |
| +#endif // BIN_REFERENCE_COUNTING_H_ |