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 
22 template <class T, bool threadSafe = false>
23 class SmartPtr
24 {
25 public:
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 
~SmartPtr()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 
Ptr()77     T* Ptr() const {
78         return m_ptr;
79     }
80 
constPtr()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 
135 private:
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.
use()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.
release()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