/* * 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 <feng.yuan@intel.com> */ #ifndef XCAM_SMARTPTR_H #define XCAM_SMARTPTR_H #include <stdint.h> #include <atomic> #include <type_traits> #include <base/xcam_defs.h> namespace XCam { 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<uint32_t> _ref_count; }; class RefCount : public RefObj { public: RefCount () : RefObj (1) {} virtual bool is_a_object () const { return false; } }; template<typename Obj> RefObj* generate_ref_count (Obj *obj, std::true_type) { XCAM_ASSERT (obj); obj->ref (); return obj; } template<typename Obj> RefCount* generate_ref_count (Obj *, std::false_type) { return new RefCount; } template <typename Obj> class SmartPtr { private: template<typename ObjDerive> friend class SmartPtr; public: SmartPtr (Obj *obj = NULL) : _ptr (obj), _ref(NULL) { if (obj) init_ref (obj); } template <typename ObjDerive> SmartPtr (ObjDerive *obj) : _ptr (obj), _ref(NULL) { if (obj) init_ref (obj); } // copy from pointer SmartPtr (const SmartPtr<Obj> &obj) : _ptr(obj._ptr), _ref(obj._ref) { if (_ref) { _ref->ref(); XCAM_ASSERT (_ptr); } } template <typename ObjDerive> SmartPtr (const SmartPtr<ObjDerive> &obj) : _ptr(obj._ptr), _ref(obj._ref) { if (_ref) { _ref->ref(); XCAM_ASSERT (_ptr); } } ~SmartPtr () { release(); } /* operator = */ SmartPtr<Obj> & operator = (Obj *obj) { release (); set_pointer (obj, NULL); return *this; } template <typename ObjDerive> SmartPtr<Obj> & operator = (ObjDerive *obj) { release (); set_pointer (obj, NULL); return *this; } SmartPtr<Obj> & operator = (const SmartPtr<Obj> &obj) { release (); set_pointer (obj._ptr, obj._ref); return *this; } template <typename ObjDerive> SmartPtr<Obj> & operator = (const SmartPtr<ObjDerive> &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; XCAM_ASSERT (_ref); if (!_ref->unref()) { if (!_ref->is_a_object ()) { XCAM_ASSERT (dynamic_cast<RefCount*>(_ref)); delete _ref; } else { XCAM_ASSERT (dynamic_cast<Obj*>(_ref) == _ptr); } delete _ptr; } _ptr = NULL; _ref = NULL; } template <typename ObjDerive> SmartPtr<ObjDerive> dynamic_cast_ptr () const { SmartPtr<ObjDerive> ret(NULL); ObjDerive *obj_derive(NULL); if (!_ref) return ret; obj_derive = dynamic_cast<ObjDerive*>(_ptr); if (!obj_derive) return ret; ret.set_pointer (obj_derive, _ref); return ret; } private: template <typename ObjD> void set_pointer (ObjD *obj, RefObj *ref) { if (!obj) return; _ptr = obj; if (ref) { _ref = ref; _ref->ref(); } else { init_ref (obj); } } template <typename ObjD> void init_ref (ObjD *obj) { // consider is_base_of or dynamic_cast ? typedef std::is_base_of<RefObj, ObjD> BaseCheck; _ref = generate_ref_count (obj, BaseCheck()); XCAM_ASSERT (_ref); } private: Obj *_ptr; mutable RefObj *_ref; }; }; // end namespace #endif //XCAM_SMARTPTR_H