/*
* 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