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 <PortableMutex.h>
20 
21 #include <cutils/atomic.h>
22 
23 template <class T, bool threadSafe = false>
24 class SmartPtr
25 {
26 public:
27     explicit SmartPtr(T* ptr = (T*)NULL) {
28         if (threadSafe) {
29             m_lock = new mutex_t;
30             mutex_init(m_lock);
31         }
32         else m_lock = NULL;
33 
34         m_ptr = ptr;
35         if (ptr)
36            m_pRefCount = new int32_t(1);
37         else
38            m_pRefCount = NULL;
39     }
40 
41     SmartPtr<T,threadSafe>(const SmartPtr<T,false>& rhs) {
42         if (threadSafe) {
43             m_lock = new mutex_t;
44             mutex_init(m_lock);
45         }
46         else m_lock = NULL;
47 
48         m_pRefCount = rhs.m_pRefCount;
49         m_ptr       = rhs.m_ptr;
50         use();
51     }
52 
53     SmartPtr<T,threadSafe>(SmartPtr<T,true>& rhs) {
54         if (threadSafe) {
55             m_lock = new mutex_t;
56             mutex_init(m_lock);
57         }
58         else m_lock = NULL;
59 
60         if (rhs.m_lock) mutex_lock(rhs.m_lock);
61         m_pRefCount = rhs.m_pRefCount;
62         m_ptr       = rhs.m_ptr;
63         use();
64         if (rhs.m_lock) mutex_unlock(rhs.m_lock);
65     }
66 
~SmartPtr()67     ~SmartPtr() {
68         if (m_lock) mutex_lock(m_lock);
69         release();
70         if (m_lock)
71         {
72             mutex_unlock(m_lock);
73             mutex_destroy(m_lock);
74             delete m_lock;
75         }
76     }
77 
Ptr()78     T* Ptr() const {
79         return m_ptr;
80     }
81 
constPtr()82     const T* constPtr() const
83     {
84         return m_ptr;
85     }
86 
87     T* operator->() const {
88         return m_ptr;
89     }
90 
91     T& operator*() const {
92         return *m_ptr;
93     }
94 
95     operator void*() const {
96         return (void *)m_ptr;
97     }
98 
99     // This gives STL lists something to compare.
100     bool operator <(const SmartPtr<T>& t1) const {
101         return m_ptr < t1.m_ptr;
102     }
103 
104     SmartPtr<T,threadSafe>& operator=(const SmartPtr<T,false>& rhs)
105     {
106         if (m_ptr == rhs.m_ptr)
107             return *this;
108 
109         if (m_lock) mutex_lock(m_lock);
110         release();
111         m_pRefCount = rhs.m_pRefCount;
112         m_ptr       = rhs.m_ptr;
113         use();
114         if (m_lock) mutex_unlock(m_lock);
115 
116         return *this;
117     }
118 
119     SmartPtr<T,threadSafe>& operator=(SmartPtr<T,true>& rhs)
120     {
121         if (m_ptr == rhs.m_ptr)
122             return *this;
123 
124         if (m_lock) mutex_lock(m_lock);
125         release();
126         if (rhs.m_lock) mutex_lock(rhs.m_lock);
127         m_pRefCount = rhs.m_pRefCount;
128         m_ptr       = rhs.m_ptr;
129         use();
130         if (rhs.m_lock) mutex_unlock(rhs.m_lock);
131         if (m_lock) mutex_unlock(m_lock);
132 
133         return *this;
134     }
135 
136 private:
137     int32_t  *m_pRefCount;
138     mutex_t  *m_lock;
139     T* m_ptr;
140 
141     // Increment the reference count on this pointer by 1.
use()142     int use() {
143         if (!m_pRefCount) return 0;
144         return android_atomic_inc(m_pRefCount) + 1;
145     }
146 
147     // Decrement the reference count on the pointer by 1.
148     // If the reference count goes to (or below) 0, the pointer is deleted.
release()149     int release() {
150         if (!m_pRefCount) return 0;
151 
152         int iVal = android_atomic_dec(m_pRefCount);
153         if (iVal > 1)
154             return iVal - 1;
155 
156         delete m_pRefCount;
157         m_pRefCount = NULL;
158 
159         if (m_ptr) {
160             delete m_ptr;
161             m_ptr = NULL;
162         }
163         return 0;
164     }
165 
166 };
167 
168 #endif // of  __SMART_PTR_H
169