1/*
2* Copyright (C) 2011 The Android Open Source Project
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16#ifndef __SMART_PTR_H
17#define __SMART_PTR_H
18
19#include <cutils/threads.h>
20#include <cutils/atomic.h>
21
22template <class T, bool threadSafe = false>
23class SmartPtr
24{
25public:
26    explicit SmartPtr(T* ptr = (T*)NULL) {
27        if (threadSafe) {
28            m_lock = new mutex_t;
29            mutex_init(m_lock);
30        }
31        else m_lock = NULL;
32
33        m_ptr = ptr;
34        if (ptr)
35           m_pRefCount = new int32_t(1);
36        else
37           m_pRefCount = NULL;
38    }
39
40    SmartPtr<T,threadSafe>(const SmartPtr<T,false>& rhs) {
41        if (threadSafe) {
42            m_lock = new mutex_t;
43            mutex_init(m_lock);
44        }
45        else m_lock = NULL;
46
47        m_pRefCount = rhs.m_pRefCount;
48        m_ptr       = rhs.m_ptr;
49        use();
50    }
51
52    SmartPtr<T,threadSafe>(SmartPtr<T,true>& rhs) {
53        if (threadSafe) {
54            m_lock = new mutex_t;
55            mutex_init(m_lock);
56        }
57        else m_lock = NULL;
58
59        if (rhs.m_lock) mutex_lock(rhs.m_lock);
60        m_pRefCount = rhs.m_pRefCount;
61        m_ptr       = rhs.m_ptr;
62        use();
63        if (rhs.m_lock) mutex_unlock(rhs.m_lock);
64    }
65
66    ~SmartPtr() {
67        if (m_lock) mutex_lock(m_lock);
68        release();
69        if (m_lock)
70        {
71            mutex_unlock(m_lock);
72            mutex_destroy(m_lock);
73            delete m_lock;
74        }
75    }
76
77    T* Ptr() const {
78        return m_ptr;
79    }
80
81    const T* constPtr() const
82    {
83        return m_ptr;
84    }
85
86    T* operator->() const {
87        return m_ptr;
88    }
89
90    T& operator*() const {
91        return *m_ptr;
92    }
93
94    operator void*() const {
95        return (void *)m_ptr;
96    }
97
98    // This gives STL lists something to compare.
99    bool operator <(const SmartPtr<T>& t1) const {
100        return m_ptr < t1.m_ptr;
101    }
102
103    SmartPtr<T,threadSafe>& operator=(const SmartPtr<T,false>& rhs)
104    {
105        if (m_ptr == rhs.m_ptr)
106            return *this;
107
108        if (m_lock) mutex_lock(m_lock);
109        release();
110        m_pRefCount = rhs.m_pRefCount;
111        m_ptr       = rhs.m_ptr;
112        use();
113        if (m_lock) mutex_unlock(m_lock);
114
115        return *this;
116    }
117
118    SmartPtr<T,threadSafe>& operator=(SmartPtr<T,true>& rhs)
119    {
120        if (m_ptr == rhs.m_ptr)
121            return *this;
122
123        if (m_lock) mutex_lock(m_lock);
124        release();
125        if (rhs.m_lock) mutex_lock(rhs.m_lock);
126        m_pRefCount = rhs.m_pRefCount;
127        m_ptr       = rhs.m_ptr;
128        use();
129        if (rhs.m_lock) mutex_unlock(rhs.m_lock);
130        if (m_lock) mutex_unlock(m_lock);
131
132        return *this;
133    }
134
135private:
136    int32_t  *m_pRefCount;
137    mutex_t  *m_lock;
138    T* m_ptr;
139
140    // Increment the reference count on this pointer by 1.
141    int use() {
142        if (!m_pRefCount) return 0;
143        return android_atomic_inc(m_pRefCount) + 1;
144    }
145
146    // Decrement the reference count on the pointer by 1.
147    // If the reference count goes to (or below) 0, the pointer is deleted.
148    int release() {
149        if (!m_pRefCount) return 0;
150
151        int iVal = android_atomic_dec(m_pRefCount);
152        if (iVal > 1)
153            return iVal - 1;
154
155        delete m_pRefCount;
156        m_pRefCount = NULL;
157
158        if (m_ptr) {
159            delete m_ptr;
160            m_ptr = NULL;
161        }
162        return 0;
163    }
164
165};
166
167#endif // of  __SMART_PTR_H
168