/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __SMART_PTR_H #define __SMART_PTR_H #include <cutils/threads.h> #include <cutils/atomic.h> template <class T, bool threadSafe = false> class SmartPtr { public: explicit SmartPtr(T* ptr = (T*)NULL) { if (threadSafe) { m_lock = new mutex_t; mutex_init(m_lock); } else m_lock = NULL; m_ptr = ptr; if (ptr) m_pRefCount = new int32_t(1); else m_pRefCount = NULL; } SmartPtr<T,threadSafe>(const SmartPtr<T,false>& rhs) { if (threadSafe) { m_lock = new mutex_t; mutex_init(m_lock); } else m_lock = NULL; m_pRefCount = rhs.m_pRefCount; m_ptr = rhs.m_ptr; use(); } SmartPtr<T,threadSafe>(SmartPtr<T,true>& rhs) { if (threadSafe) { m_lock = new mutex_t; mutex_init(m_lock); } else m_lock = NULL; if (rhs.m_lock) mutex_lock(rhs.m_lock); m_pRefCount = rhs.m_pRefCount; m_ptr = rhs.m_ptr; use(); if (rhs.m_lock) mutex_unlock(rhs.m_lock); } ~SmartPtr() { if (m_lock) mutex_lock(m_lock); release(); if (m_lock) { mutex_unlock(m_lock); mutex_destroy(m_lock); delete m_lock; } } T* Ptr() const { return m_ptr; } const T* constPtr() const { return m_ptr; } T* operator->() const { return m_ptr; } T& operator*() const { return *m_ptr; } operator void*() const { return (void *)m_ptr; } // This gives STL lists something to compare. bool operator <(const SmartPtr<T>& t1) const { return m_ptr < t1.m_ptr; } SmartPtr<T,threadSafe>& operator=(const SmartPtr<T,false>& rhs) { if (m_ptr == rhs.m_ptr) return *this; if (m_lock) mutex_lock(m_lock); release(); m_pRefCount = rhs.m_pRefCount; m_ptr = rhs.m_ptr; use(); if (m_lock) mutex_unlock(m_lock); return *this; } SmartPtr<T,threadSafe>& operator=(SmartPtr<T,true>& rhs) { if (m_ptr == rhs.m_ptr) return *this; if (m_lock) mutex_lock(m_lock); release(); if (rhs.m_lock) mutex_lock(rhs.m_lock); m_pRefCount = rhs.m_pRefCount; m_ptr = rhs.m_ptr; use(); if (rhs.m_lock) mutex_unlock(rhs.m_lock); if (m_lock) mutex_unlock(m_lock); return *this; } private: int32_t *m_pRefCount; mutex_t *m_lock; T* m_ptr; // Increment the reference count on this pointer by 1. int use() { if (!m_pRefCount) return 0; return android_atomic_inc(m_pRefCount) + 1; } // Decrement the reference count on the pointer by 1. // If the reference count goes to (or below) 0, the pointer is deleted. int release() { if (!m_pRefCount) return 0; int iVal = android_atomic_dec(m_pRefCount); if (iVal > 1) return iVal - 1; delete m_pRefCount; m_pRefCount = NULL; if (m_ptr) { delete m_ptr; m_ptr = NULL; } return 0; } }; #endif // of __SMART_PTR_H