michael@0: /* michael@0: * Copyright (C) 2005 The Android Open Source Project michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #ifndef ANDROID_REF_BASE_H michael@0: #define ANDROID_REF_BASE_H michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: namespace android { michael@0: michael@0: template class wp; michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: michael@0: #define COMPARE(_op_) \ michael@0: inline bool operator _op_ (const sp& o) const { \ michael@0: return m_ptr _op_ o.m_ptr; \ michael@0: } \ michael@0: inline bool operator _op_ (const wp& o) const { \ michael@0: return m_ptr _op_ o.m_ptr; \ michael@0: } \ michael@0: inline bool operator _op_ (const T* o) const { \ michael@0: return m_ptr _op_ o; \ michael@0: } \ michael@0: template \ michael@0: inline bool operator _op_ (const sp& o) const { \ michael@0: return m_ptr _op_ o.m_ptr; \ michael@0: } \ michael@0: template \ michael@0: inline bool operator _op_ (const wp& o) const { \ michael@0: return m_ptr _op_ o.m_ptr; \ michael@0: } \ michael@0: template \ michael@0: inline bool operator _op_ (const U* o) const { \ michael@0: return m_ptr _op_ o; \ michael@0: } michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: michael@0: class RefBase michael@0: { michael@0: public: michael@0: void incStrong(const void* id) const; michael@0: void decStrong(const void* id) const; michael@0: michael@0: void forceIncStrong(const void* id) const; michael@0: michael@0: //! DEBUGGING ONLY: Get current strong ref count. michael@0: int32_t getStrongCount() const; michael@0: michael@0: class weakref_type michael@0: { michael@0: public: michael@0: RefBase* refBase() const; michael@0: michael@0: void incWeak(const void* id); michael@0: void decWeak(const void* id); michael@0: michael@0: bool attemptIncStrong(const void* id); michael@0: michael@0: //! This is only safe if you have set OBJECT_LIFETIME_FOREVER. michael@0: bool attemptIncWeak(const void* id); michael@0: michael@0: //! DEBUGGING ONLY: Get current weak ref count. michael@0: int32_t getWeakCount() const; michael@0: michael@0: //! DEBUGGING ONLY: Print references held on object. michael@0: void printRefs() const; michael@0: michael@0: //! DEBUGGING ONLY: Enable tracking for this object. michael@0: // enable -- enable/disable tracking michael@0: // retain -- when tracking is enable, if true, then we save a stack trace michael@0: // for each reference and dereference; when retain == false, we michael@0: // match up references and dereferences and keep only the michael@0: // outstanding ones. michael@0: michael@0: void trackMe(bool enable, bool retain); michael@0: }; michael@0: michael@0: weakref_type* createWeak(const void* id) const; michael@0: michael@0: weakref_type* getWeakRefs() const; michael@0: michael@0: //! DEBUGGING ONLY: Print references held on object. michael@0: inline void printRefs() const { getWeakRefs()->printRefs(); } michael@0: michael@0: //! DEBUGGING ONLY: Enable tracking of object. michael@0: inline void trackMe(bool enable, bool retain) michael@0: { michael@0: getWeakRefs()->trackMe(enable, retain); michael@0: } michael@0: michael@0: protected: michael@0: RefBase(); michael@0: virtual ~RefBase(); michael@0: michael@0: //! Flags for extendObjectLifetime() michael@0: enum { michael@0: OBJECT_LIFETIME_WEAK = 0x0001, michael@0: OBJECT_LIFETIME_FOREVER = 0x0003 michael@0: }; michael@0: michael@0: void extendObjectLifetime(int32_t mode); michael@0: michael@0: //! Flags for onIncStrongAttempted() michael@0: enum { michael@0: FIRST_INC_STRONG = 0x0001 michael@0: }; michael@0: michael@0: virtual void onFirstRef(); michael@0: virtual void onLastStrongRef(const void* id); michael@0: virtual bool onIncStrongAttempted(uint32_t flags, const void* id); michael@0: virtual void onLastWeakRef(const void* id); michael@0: michael@0: private: michael@0: friend class weakref_type; michael@0: class weakref_impl; michael@0: michael@0: RefBase(const RefBase& o); michael@0: RefBase& operator=(const RefBase& o); michael@0: michael@0: weakref_impl* const mRefs; michael@0: }; michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: michael@0: template michael@0: class LightRefBase michael@0: { michael@0: public: michael@0: inline LightRefBase() : mCount(0) { } michael@0: inline void incStrong(const void* id) const { michael@0: android_atomic_inc(&mCount); michael@0: } michael@0: inline void decStrong(const void* id) const { michael@0: if (android_atomic_dec(&mCount) == 1) { michael@0: delete static_cast(this); michael@0: } michael@0: } michael@0: //! DEBUGGING ONLY: Get current strong ref count. michael@0: inline int32_t getStrongCount() const { michael@0: return mCount; michael@0: } michael@0: michael@0: protected: michael@0: inline ~LightRefBase() { } michael@0: michael@0: private: michael@0: mutable volatile int32_t mCount; michael@0: }; michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: michael@0: template michael@0: class sp michael@0: { michael@0: public: michael@0: typedef typename RefBase::weakref_type weakref_type; michael@0: michael@0: inline sp() : m_ptr(0) { } michael@0: michael@0: sp(T* other); michael@0: sp(const sp& other); michael@0: template sp(U* other); michael@0: template sp(const sp& other); michael@0: michael@0: ~sp(); michael@0: michael@0: // Assignment michael@0: michael@0: sp& operator = (T* other); michael@0: sp& operator = (const sp& other); michael@0: michael@0: template sp& operator = (const sp& other); michael@0: template sp& operator = (U* other); michael@0: michael@0: //! Special optimization for use by ProcessState (and nobody else). michael@0: void force_set(T* other); michael@0: michael@0: // Reset michael@0: michael@0: void clear(); michael@0: michael@0: // Accessors michael@0: michael@0: inline T& operator* () const { return *m_ptr; } michael@0: inline T* operator-> () const { return m_ptr; } michael@0: inline T* get() const { return m_ptr; } michael@0: michael@0: // Operators michael@0: michael@0: COMPARE(==) michael@0: COMPARE(!=) michael@0: COMPARE(>) michael@0: COMPARE(<) michael@0: COMPARE(<=) michael@0: COMPARE(>=) michael@0: michael@0: private: michael@0: template friend class sp; michael@0: template friend class wp; michael@0: michael@0: // Optimization for wp::promote(). michael@0: sp(T* p, weakref_type* refs); michael@0: michael@0: T* m_ptr; michael@0: }; michael@0: michael@0: template michael@0: TextOutput& operator<<(TextOutput& to, const sp& val); michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: michael@0: template michael@0: class wp michael@0: { michael@0: public: michael@0: typedef typename RefBase::weakref_type weakref_type; michael@0: michael@0: inline wp() : m_ptr(0) { } michael@0: michael@0: wp(T* other); michael@0: wp(const wp& other); michael@0: wp(const sp& other); michael@0: template wp(U* other); michael@0: template wp(const sp& other); michael@0: template wp(const wp& other); michael@0: michael@0: ~wp(); michael@0: michael@0: // Assignment michael@0: michael@0: wp& operator = (T* other); michael@0: wp& operator = (const wp& other); michael@0: wp& operator = (const sp& other); michael@0: michael@0: template wp& operator = (U* other); michael@0: template wp& operator = (const wp& other); michael@0: template wp& operator = (const sp& other); michael@0: michael@0: void set_object_and_refs(T* other, weakref_type* refs); michael@0: michael@0: // promotion to sp michael@0: michael@0: sp promote() const; michael@0: michael@0: // Reset michael@0: michael@0: void clear(); michael@0: michael@0: // Accessors michael@0: michael@0: inline weakref_type* get_refs() const { return m_refs; } michael@0: michael@0: inline T* unsafe_get() const { return m_ptr; } michael@0: michael@0: // Operators michael@0: michael@0: COMPARE(==) michael@0: COMPARE(!=) michael@0: COMPARE(>) michael@0: COMPARE(<) michael@0: COMPARE(<=) michael@0: COMPARE(>=) michael@0: michael@0: private: michael@0: template friend class sp; michael@0: template friend class wp; michael@0: michael@0: T* m_ptr; michael@0: weakref_type* m_refs; michael@0: }; michael@0: michael@0: template michael@0: TextOutput& operator<<(TextOutput& to, const wp& val); michael@0: michael@0: #undef COMPARE michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: // No user serviceable parts below here. michael@0: michael@0: template michael@0: sp::sp(T* other) michael@0: : m_ptr(other) michael@0: { michael@0: if (other) other->incStrong(this); michael@0: } michael@0: michael@0: template michael@0: sp::sp(const sp& other) michael@0: : m_ptr(other.m_ptr) michael@0: { michael@0: if (m_ptr) m_ptr->incStrong(this); michael@0: } michael@0: michael@0: template template michael@0: sp::sp(U* other) : m_ptr(other) michael@0: { michael@0: if (other) other->incStrong(this); michael@0: } michael@0: michael@0: template template michael@0: sp::sp(const sp& other) michael@0: : m_ptr(other.m_ptr) michael@0: { michael@0: if (m_ptr) m_ptr->incStrong(this); michael@0: } michael@0: michael@0: template michael@0: sp::~sp() michael@0: { michael@0: if (m_ptr) m_ptr->decStrong(this); michael@0: } michael@0: michael@0: template michael@0: sp& sp::operator = (const sp& other) { michael@0: if (other.m_ptr) other.m_ptr->incStrong(this); michael@0: if (m_ptr) m_ptr->decStrong(this); michael@0: m_ptr = other.m_ptr; michael@0: return *this; michael@0: } michael@0: michael@0: template michael@0: sp& sp::operator = (T* other) michael@0: { michael@0: if (other) other->incStrong(this); michael@0: if (m_ptr) m_ptr->decStrong(this); michael@0: m_ptr = other; michael@0: return *this; michael@0: } michael@0: michael@0: template template michael@0: sp& sp::operator = (const sp& other) michael@0: { michael@0: if (other.m_ptr) other.m_ptr->incStrong(this); michael@0: if (m_ptr) m_ptr->decStrong(this); michael@0: m_ptr = other.m_ptr; michael@0: return *this; michael@0: } michael@0: michael@0: template template michael@0: sp& sp::operator = (U* other) michael@0: { michael@0: if (other) other->incStrong(this); michael@0: if (m_ptr) m_ptr->decStrong(this); michael@0: m_ptr = other; michael@0: return *this; michael@0: } michael@0: michael@0: template michael@0: void sp::force_set(T* other) michael@0: { michael@0: other->forceIncStrong(this); michael@0: m_ptr = other; michael@0: } michael@0: michael@0: template michael@0: void sp::clear() michael@0: { michael@0: if (m_ptr) { michael@0: m_ptr->decStrong(this); michael@0: m_ptr = 0; michael@0: } michael@0: } michael@0: michael@0: template michael@0: sp::sp(T* p, weakref_type* refs) michael@0: : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0) michael@0: { michael@0: } michael@0: michael@0: template michael@0: inline TextOutput& operator<<(TextOutput& to, const sp& val) michael@0: { michael@0: to << "sp<>(" << val.get() << ")"; michael@0: return to; michael@0: } michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: michael@0: template michael@0: wp::wp(T* other) michael@0: : m_ptr(other) michael@0: { michael@0: if (other) m_refs = other->createWeak(this); michael@0: } michael@0: michael@0: template michael@0: wp::wp(const wp& other) michael@0: : m_ptr(other.m_ptr), m_refs(other.m_refs) michael@0: { michael@0: if (m_ptr) m_refs->incWeak(this); michael@0: } michael@0: michael@0: template michael@0: wp::wp(const sp& other) michael@0: : m_ptr(other.m_ptr) michael@0: { michael@0: if (m_ptr) { michael@0: m_refs = m_ptr->createWeak(this); michael@0: } michael@0: } michael@0: michael@0: template template michael@0: wp::wp(U* other) michael@0: : m_ptr(other) michael@0: { michael@0: if (other) m_refs = other->createWeak(this); michael@0: } michael@0: michael@0: template template michael@0: wp::wp(const wp& other) michael@0: : m_ptr(other.m_ptr) michael@0: { michael@0: if (m_ptr) { michael@0: m_refs = other.m_refs; michael@0: m_refs->incWeak(this); michael@0: } michael@0: } michael@0: michael@0: template template michael@0: wp::wp(const sp& other) michael@0: : m_ptr(other.m_ptr) michael@0: { michael@0: if (m_ptr) { michael@0: m_refs = m_ptr->createWeak(this); michael@0: } michael@0: } michael@0: michael@0: template michael@0: wp::~wp() michael@0: { michael@0: if (m_ptr) m_refs->decWeak(this); michael@0: } michael@0: michael@0: template michael@0: wp& wp::operator = (T* other) michael@0: { michael@0: weakref_type* newRefs = michael@0: other ? other->createWeak(this) : 0; michael@0: if (m_ptr) m_refs->decWeak(this); michael@0: m_ptr = other; michael@0: m_refs = newRefs; michael@0: return *this; michael@0: } michael@0: michael@0: template michael@0: wp& wp::operator = (const wp& other) michael@0: { michael@0: if (other.m_ptr) other.m_refs->incWeak(this); michael@0: if (m_ptr) m_refs->decWeak(this); michael@0: m_ptr = other.m_ptr; michael@0: m_refs = other.m_refs; michael@0: return *this; michael@0: } michael@0: michael@0: template michael@0: wp& wp::operator = (const sp& other) michael@0: { michael@0: weakref_type* newRefs = michael@0: other != NULL ? other->createWeak(this) : 0; michael@0: if (m_ptr) m_refs->decWeak(this); michael@0: m_ptr = other.get(); michael@0: m_refs = newRefs; michael@0: return *this; michael@0: } michael@0: michael@0: template template michael@0: wp& wp::operator = (U* other) michael@0: { michael@0: weakref_type* newRefs = michael@0: other ? other->createWeak(this) : 0; michael@0: if (m_ptr) m_refs->decWeak(this); michael@0: m_ptr = other; michael@0: m_refs = newRefs; michael@0: return *this; michael@0: } michael@0: michael@0: template template michael@0: wp& wp::operator = (const wp& other) michael@0: { michael@0: if (other.m_ptr) other.m_refs->incWeak(this); michael@0: if (m_ptr) m_refs->decWeak(this); michael@0: m_ptr = other.m_ptr; michael@0: m_refs = other.m_refs; michael@0: return *this; michael@0: } michael@0: michael@0: template template michael@0: wp& wp::operator = (const sp& other) michael@0: { michael@0: weakref_type* newRefs = michael@0: other != NULL ? other->createWeak(this) : 0; michael@0: if (m_ptr) m_refs->decWeak(this); michael@0: m_ptr = other.get(); michael@0: m_refs = newRefs; michael@0: return *this; michael@0: } michael@0: michael@0: template michael@0: void wp::set_object_and_refs(T* other, weakref_type* refs) michael@0: { michael@0: if (other) refs->incWeak(this); michael@0: if (m_ptr) m_refs->decWeak(this); michael@0: m_ptr = other; michael@0: m_refs = refs; michael@0: } michael@0: michael@0: template michael@0: sp wp::promote() const michael@0: { michael@0: return sp(m_ptr, m_refs); michael@0: } michael@0: michael@0: template michael@0: void wp::clear() michael@0: { michael@0: if (m_ptr) { michael@0: m_refs->decWeak(this); michael@0: m_ptr = 0; michael@0: } michael@0: } michael@0: michael@0: template michael@0: inline TextOutput& operator<<(TextOutput& to, const wp& val) michael@0: { michael@0: to << "wp<>(" << val.unsafe_get() << ")"; michael@0: return to; michael@0: } michael@0: michael@0: }; // namespace android michael@0: michael@0: // --------------------------------------------------------------------------- michael@0: michael@0: #endif // ANDROID_REF_BASE_H