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 <base/xcam_defs.h>
24 #include <stdint.h>
25
26 #include <atomic>
27 #include <cassert>
28 #include <iostream>
29 #include <type_traits>
30
31 namespace XCam {
32
33 #ifndef M_Assert
34 #ifndef NDEBUG
35 # define M_Assert(Expr, Msg) \
36 __M_Assert(#Expr, Expr, __FILE__, __LINE__, Msg)
37 #else
38 # define M_Assert(Expr, Msg) ;
39 #endif
40 #endif
41
__M_Assert(const char * expr_str,bool expr,const char * file,int line,const char * msg)42 static void __M_Assert(const char* expr_str, bool expr, const char* file, int line, const char* msg)
43 {
44 if (!expr)
45 {
46 std::cerr << "Assert failed:\t" << msg << "\n"
47 << "Expected:\t" << expr_str << "\n"
48 << "Source:\t\t" << file << ", line " << line << "\n";
49 abort();
50 }
51 }
52
53 class RefCount;
54
55 class RefObj {
56 friend class RefCount;
57 public:
RefObj()58 RefObj (): _ref_count(0) {} // derived class must set to SmartPtr at birth
~RefObj()59 virtual ~RefObj () {}
60
ref()61 void ref() const {
62 ++_ref_count;
63 }
unref()64 uint32_t unref() const {
65 return --_ref_count;
66 }
is_a_object()67 virtual bool is_a_object () const {
68 return true;
69 }
70
71 private:
RefObj(uint32_t i)72 explicit RefObj (uint32_t i) : _ref_count (i) {}
73 XCAM_DEAD_COPY (RefObj);
74
75 private:
76 mutable std::atomic<uint32_t> _ref_count;
77 };
78
79 class RefCount
80 : public RefObj
81 {
82 public:
RefCount()83 RefCount () : RefObj (1) {}
is_a_object()84 virtual bool is_a_object () const {
85 return false;
86 }
87 };
88
89 template<typename Obj>
generate_ref_count(Obj * obj,std::true_type)90 RefObj* generate_ref_count (Obj *obj, std::true_type)
91 {
92 M_Assert(obj != nullptr, "smartptr generate_ref_count failed\n");
93 obj->ref ();
94 return obj;
95 }
96
97 template<typename Obj>
generate_ref_count(Obj *,std::false_type)98 RefCount* generate_ref_count (Obj *, std::false_type)
99 {
100 return new RefCount;
101 }
102
103 template <typename Obj>
104 class SmartPtr {
105 private:
106 template<typename ObjDerive> friend class SmartPtr;
107 public:
108 SmartPtr (Obj *obj = NULL)
_ptr(obj)109 : _ptr (obj), _ref(NULL)
110 {
111 if (obj)
112 init_ref (obj);
113 }
114
115 template <typename ObjDerive>
SmartPtr(ObjDerive * obj)116 SmartPtr (ObjDerive *obj)
117 : _ptr (obj), _ref(NULL)
118 {
119 if (obj)
120 init_ref (obj);
121 }
122
123 // copy from pointer
SmartPtr(const SmartPtr<Obj> & obj)124 SmartPtr (const SmartPtr<Obj> &obj)
125 : _ptr(obj._ptr), _ref(obj._ref)
126 {
127 if (_ref) {
128 _ref->ref();
129 M_Assert(_ptr != nullptr, "smartptr copy from pointer failed\n");
130 }
131 }
132
133 template <typename ObjDerive>
SmartPtr(const SmartPtr<ObjDerive> & obj)134 SmartPtr (const SmartPtr<ObjDerive> &obj)
135 : _ptr(obj._ptr), _ref(obj._ref)
136 {
137 if (_ref) {
138 _ref->ref();
139 M_Assert(_ptr != nullptr, "smartptr copy from derived pointer failed\n");
140 }
141 }
142
~SmartPtr()143 ~SmartPtr () {
144 release();
145 }
146
147 /* operator = */
148 SmartPtr<Obj> & operator = (Obj *obj) {
149 release ();
150 set_pointer (obj, NULL);
151 return *this;
152 }
153
154 template <typename ObjDerive>
155 SmartPtr<Obj> & operator = (ObjDerive *obj) {
156 release ();
157 set_pointer (obj, NULL);
158 return *this;
159 }
160
161 SmartPtr<Obj> & operator = (const SmartPtr<Obj> &obj) {
162 release ();
163 set_pointer (obj._ptr, obj._ref);
164 return *this;
165 }
166
167 template <typename ObjDerive>
168 SmartPtr<Obj> & operator = (const SmartPtr<ObjDerive> &obj) {
169 release ();
170 set_pointer (obj._ptr, obj._ref);
171 return *this;
172 }
173
174 Obj *operator -> () const {
175 return _ptr;
176 }
177
ptr()178 Obj *ptr() const {
179 return _ptr;
180 }
181
release()182 void release() {
183 if (!_ptr)
184 return;
185
186 M_Assert(_ref != nullptr, "smartptr release ref failed\n");
187 if (!_ref->unref()) {
188 if (!_ref->is_a_object ()) {
189 M_Assert(dynamic_cast<RefCount*>(_ref), "smartptr release dcast obj failed\n");
190 delete _ref;
191 } else {
192 M_Assert(dynamic_cast<Obj*>(_ref) == _ptr, "smartptr release dcast obj failed\n");
193 }
194 delete _ptr;
195 }
196 _ptr = NULL;
197 _ref = NULL;
198 }
199
200 template <typename ObjDerive>
dynamic_cast_ptr()201 SmartPtr<ObjDerive> dynamic_cast_ptr () const {
202 SmartPtr<ObjDerive> ret(NULL);
203 ObjDerive *obj_derive(NULL);
204 if (!_ref)
205 return ret;
206 obj_derive = dynamic_cast<ObjDerive*>(_ptr);
207 if (!obj_derive)
208 return ret;
209 ret.set_pointer (obj_derive, _ref);
210 return ret;
211 }
212
213 template <typename ObjDerive>
get_cast_ptr()214 ObjDerive* get_cast_ptr () const {
215 ObjDerive *obj_derive(NULL);
216 if (!_ref)
217 return NULL;
218 obj_derive = dynamic_cast<ObjDerive*>(_ptr);
219 if (!obj_derive)
220 return NULL;
221 return obj_derive;
222 }
223
224 private:
225 template <typename ObjD>
set_pointer(ObjD * obj,RefObj * ref)226 void set_pointer (ObjD *obj, RefObj *ref) {
227 if (!obj)
228 return;
229
230 _ptr = obj;
231 if (ref) {
232 _ref = ref;
233 _ref->ref();
234 } else {
235 init_ref (obj);
236 }
237 }
238
239 template <typename ObjD>
init_ref(ObjD * obj)240 void init_ref (ObjD *obj)
241 {
242 // consider is_base_of or dynamic_cast ?
243 typedef std::is_base_of<RefObj, ObjD> BaseCheck;
244 _ref = generate_ref_count (obj, BaseCheck());
245 M_Assert(_ref != nullptr, "smartptr init_ref failed\n");
246 }
247
248 private:
249 Obj *_ptr;
250 mutable RefObj *_ref;
251 };
252
253 } // end namespace
254 #endif //XCAM_SMARTPTR_H
255