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..4922f15b49d296cf091434d09592afc6a4c3f4bf |
| --- /dev/null |
| +++ b/runtime/bin/reference_counting.h |
| @@ -0,0 +1,126 @@ |
| +// 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 { |
| + |
| +// 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 reinterpret_cast<Derived*>(this); |
| + } |
| + } |
| + |
| + private: |
| + uintptr_t ref_count_; |
| + |
| + 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); |
|
Ivan Posva
2016/04/08 13:18:21
ASSERT that ref_count_ is greater than 1?
zra
2016/04/08 16:07:48
Done.
|
| + } |
| + ~RefCntReleaseScope() { |
| + target_->Release(); |
| + } |
| + |
| + private: |
| + ReferenceCounted<Target>* target_; |
| + |
| + DISALLOW_ALLOCATION(); |
| + DISALLOW_COPY_AND_ASSIGN(RefCntReleaseScope); |
| +}; |
| + |
| +template <class Target> |
|
Ivan Posva
2016/04/08 13:18:21
There is good documentation for the above classes,
zra
2016/04/08 16:07:48
Done.
|
| +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 reinterpret_cast<Target*>(target_); |
| + } |
| + |
| + private: |
| + ReferenceCounted<Target>* target_; |
| + |
| + DISALLOW_ALLOCATION(); |
| + DISALLOW_COPY_AND_ASSIGN(RetainedPointer); |
| +}; |
| + |
| +} // namespace bin |
| +} // namespace dart |
| + |
| +#endif // BIN_REFERENCE_COUNTING_H_ |