/*
* 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