blob: 4bdfbe4100f32790dbc1bc58286c58e99d32fe2c [file] [log] [blame]
keunyoungb85b2752013-03-08 12:28:03 -08001/*
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