/* * xcam_SmartPtr.h - start pointer * * Copyright (c) 2014 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Author: Wind Yuan */ #ifndef XCAM_SMARTPTR_H #define XCAM_SMARTPTR_H #include #include #include #include #include #include namespace XCam { #ifndef M_Assert #ifndef NDEBUG # define M_Assert(Expr, Msg) \ __M_Assert(#Expr, Expr, __FILE__, __LINE__, Msg) #else # define M_Assert(Expr, Msg) ; #endif #endif static void __M_Assert(const char* expr_str, bool expr, const char* file, int line, const char* msg) { if (!expr) { std::cerr << "Assert failed:\t" << msg << "\n" << "Expected:\t" << expr_str << "\n" << "Source:\t\t" << file << ", line " << line << "\n"; abort(); } } class RefCount; class RefObj { friend class RefCount; public: RefObj (): _ref_count(0) {} // derived class must set to SmartPtr at birth virtual ~RefObj () {} void ref() const { ++_ref_count; } uint32_t unref() const { return --_ref_count; } virtual bool is_a_object () const { return true; } private: explicit RefObj (uint32_t i) : _ref_count (i) {} XCAM_DEAD_COPY (RefObj); private: mutable std::atomic _ref_count; }; class RefCount : public RefObj { public: RefCount () : RefObj (1) {} virtual bool is_a_object () const { return false; } }; template RefObj* generate_ref_count (Obj *obj, std::true_type) { M_Assert(obj != nullptr, "smartptr generate_ref_count failed\n"); obj->ref (); return obj; } template RefCount* generate_ref_count (Obj *, std::false_type) { return new RefCount; } template class SmartPtr { private: template friend class SmartPtr; public: SmartPtr (Obj *obj = NULL) : _ptr (obj), _ref(NULL) { if (obj) init_ref (obj); } template SmartPtr (ObjDerive *obj) : _ptr (obj), _ref(NULL) { if (obj) init_ref (obj); } // copy from pointer SmartPtr (const SmartPtr &obj) : _ptr(obj._ptr), _ref(obj._ref) { if (_ref) { _ref->ref(); M_Assert(_ptr != nullptr, "smartptr copy from pointer failed\n"); } } template SmartPtr (const SmartPtr &obj) : _ptr(obj._ptr), _ref(obj._ref) { if (_ref) { _ref->ref(); M_Assert(_ptr != nullptr, "smartptr copy from derived pointer failed\n"); } } ~SmartPtr () { release(); } /* operator = */ SmartPtr & operator = (Obj *obj) { release (); set_pointer (obj, NULL); return *this; } template SmartPtr & operator = (ObjDerive *obj) { release (); set_pointer (obj, NULL); return *this; } SmartPtr & operator = (const SmartPtr &obj) { release (); set_pointer (obj._ptr, obj._ref); return *this; } template SmartPtr & operator = (const SmartPtr &obj) { release (); set_pointer (obj._ptr, obj._ref); return *this; } Obj *operator -> () const { return _ptr; } Obj *ptr() const { return _ptr; } void release() { if (!_ptr) return; M_Assert(_ref != nullptr, "smartptr release ref failed\n"); if (!_ref->unref()) { if (!_ref->is_a_object ()) { M_Assert(dynamic_cast(_ref), "smartptr release dcast obj failed\n"); delete _ref; } else { M_Assert(dynamic_cast(_ref) == _ptr, "smartptr release dcast obj failed\n"); } delete _ptr; } _ptr = NULL; _ref = NULL; } template SmartPtr dynamic_cast_ptr () const { SmartPtr ret(NULL); ObjDerive *obj_derive(NULL); if (!_ref) return ret; obj_derive = dynamic_cast(_ptr); if (!obj_derive) return ret; ret.set_pointer (obj_derive, _ref); return ret; } template ObjDerive* get_cast_ptr () const { ObjDerive *obj_derive(NULL); if (!_ref) return NULL; obj_derive = dynamic_cast(_ptr); if (!obj_derive) return NULL; return obj_derive; } private: template void set_pointer (ObjD *obj, RefObj *ref) { if (!obj) return; _ptr = obj; if (ref) { _ref = ref; _ref->ref(); } else { init_ref (obj); } } template void init_ref (ObjD *obj) { // consider is_base_of or dynamic_cast ? typedef std::is_base_of BaseCheck; _ref = generate_ref_count (obj, BaseCheck()); M_Assert(_ref != nullptr, "smartptr init_ref failed\n"); } private: Obj *_ptr; mutable RefObj *_ref; }; } // end namespace #endif //XCAM_SMARTPTR_H