1 /*
2 * xcam_SmartPtr.h - start pointer
3 *
4 * Copyright (c) 2014 Intel Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Wind Yuan <feng.yuan@intel.com>
19 */
20 #ifndef XCAM_SMARTPTR_H
21 #define XCAM_SMARTPTR_H
22
23 #include <stdint.h>
24 #include <atomic>
25 #include <type_traits>
26 #include <base/xcam_defs.h>
27
28 namespace XCam {
29
30 class RefCount;
31
32 class RefObj {
33 friend class RefCount;
34 public:
RefObj()35 RefObj (): _ref_count(0) {} // derived class must set to SmartPtr at birth
~RefObj()36 virtual ~RefObj () {}
37
ref()38 void ref() const {
39 ++_ref_count;
40 }
unref()41 uint32_t unref() const {
42 return --_ref_count;
43 }
is_a_object()44 virtual bool is_a_object () const {
45 return true;
46 }
47
48 private:
RefObj(uint32_t i)49 explicit RefObj (uint32_t i) : _ref_count (i) {}
50 XCAM_DEAD_COPY (RefObj);
51
52 private:
53 mutable std::atomic<uint32_t> _ref_count;
54 };
55
56 class RefCount
57 : public RefObj
58 {
59 public:
RefCount()60 RefCount () : RefObj (1) {}
is_a_object()61 virtual bool is_a_object () const {
62 return false;
63 }
64 };
65
66 template<typename Obj>
generate_ref_count(Obj * obj,std::true_type)67 RefObj* generate_ref_count (Obj *obj, std::true_type)
68 {
69 XCAM_ASSERT (obj);
70 obj->ref ();
71 return obj;
72 }
73
74 template<typename Obj>
generate_ref_count(Obj *,std::false_type)75 RefCount* generate_ref_count (Obj *, std::false_type)
76 {
77 return new RefCount;
78 }
79
80 template <typename Obj>
81 class SmartPtr {
82 private:
83 template<typename ObjDerive> friend class SmartPtr;
84 public:
85 SmartPtr (Obj *obj = NULL)
_ptr(obj)86 : _ptr (obj), _ref(NULL)
87 {
88 if (obj)
89 init_ref (obj);
90 }
91
92 template <typename ObjDerive>
SmartPtr(ObjDerive * obj)93 SmartPtr (ObjDerive *obj)
94 : _ptr (obj), _ref(NULL)
95 {
96 if (obj)
97 init_ref (obj);
98 }
99
100 // copy from pointer
SmartPtr(const SmartPtr<Obj> & obj)101 SmartPtr (const SmartPtr<Obj> &obj)
102 : _ptr(obj._ptr), _ref(obj._ref)
103 {
104 if (_ref) {
105 _ref->ref();
106 XCAM_ASSERT (_ptr);
107 }
108 }
109
110 template <typename ObjDerive>
SmartPtr(const SmartPtr<ObjDerive> & obj)111 SmartPtr (const SmartPtr<ObjDerive> &obj)
112 : _ptr(obj._ptr), _ref(obj._ref)
113 {
114 if (_ref) {
115 _ref->ref();
116 XCAM_ASSERT (_ptr);
117 }
118 }
119
~SmartPtr()120 ~SmartPtr () {
121 release();
122 }
123
124 /* operator = */
125 SmartPtr<Obj> & operator = (Obj *obj) {
126 release ();
127 set_pointer (obj, NULL);
128 return *this;
129 }
130
131 template <typename ObjDerive>
132 SmartPtr<Obj> & operator = (ObjDerive *obj) {
133 release ();
134 set_pointer (obj, NULL);
135 return *this;
136 }
137
138 SmartPtr<Obj> & operator = (const SmartPtr<Obj> &obj) {
139 release ();
140 set_pointer (obj._ptr, obj._ref);
141 return *this;
142 }
143
144 template <typename ObjDerive>
145 SmartPtr<Obj> & operator = (const SmartPtr<ObjDerive> &obj) {
146 release ();
147 set_pointer (obj._ptr, obj._ref);
148 return *this;
149 }
150
151 Obj *operator -> () const {
152 return _ptr;
153 }
154
ptr()155 Obj *ptr() const {
156 return _ptr;
157 }
158
release()159 void release() {
160 if (!_ptr)
161 return;
162
163 XCAM_ASSERT (_ref);
164 if (!_ref->unref()) {
165 if (!_ref->is_a_object ()) {
166 XCAM_ASSERT (dynamic_cast<RefCount*>(_ref));
167 delete _ref;
168 } else {
169 XCAM_ASSERT (dynamic_cast<Obj*>(_ref) == _ptr);
170 }
171 delete _ptr;
172 }
173 _ptr = NULL;
174 _ref = NULL;
175 }
176
177 template <typename ObjDerive>
dynamic_cast_ptr()178 SmartPtr<ObjDerive> dynamic_cast_ptr () const {
179 SmartPtr<ObjDerive> ret(NULL);
180 ObjDerive *obj_derive(NULL);
181 if (!_ref)
182 return ret;
183 obj_derive = dynamic_cast<ObjDerive*>(_ptr);
184 if (!obj_derive)
185 return ret;
186 ret.set_pointer (obj_derive, _ref);
187 return ret;
188 }
189
190 private:
191 template <typename ObjD>
set_pointer(ObjD * obj,RefObj * ref)192 void set_pointer (ObjD *obj, RefObj *ref) {
193 if (!obj)
194 return;
195
196 _ptr = obj;
197 if (ref) {
198 _ref = ref;
199 _ref->ref();
200 } else {
201 init_ref (obj);
202 }
203 }
204
205 template <typename ObjD>
init_ref(ObjD * obj)206 void init_ref (ObjD *obj)
207 {
208 // consider is_base_of or dynamic_cast ?
209 typedef std::is_base_of<RefObj, ObjD> BaseCheck;
210 _ref = generate_ref_count (obj, BaseCheck());
211 XCAM_ASSERT (_ref);
212 }
213
214 private:
215 Obj *_ptr;
216 mutable RefObj *_ref;
217 };
218
219 }; // end namespace
220 #endif //XCAM_SMARTPTR_H