Home | History | Annotate | Download | only in xcore
      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 (at) 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:
     35     RefObj (): _ref_count(0) {} // derived class must set to SmartPtr at birth
     36     virtual ~RefObj () {}
     37 
     38     void ref() const {
     39         ++_ref_count;
     40     }
     41     uint32_t unref() const {
     42         return --_ref_count;
     43     }
     44     virtual bool is_a_object () const {
     45         return true;
     46     }
     47 
     48 private:
     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:
     60     RefCount () : RefObj (1) {}
     61     virtual bool is_a_object () const {
     62         return false;
     63     }
     64 };
     65 
     66 template<typename Obj>
     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>
     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)
     86         : _ptr (obj), _ref(NULL)
     87     {
     88         if (obj)
     89             init_ref (obj);
     90     }
     91 
     92     template <typename ObjDerive>
     93     SmartPtr (ObjDerive *obj)
     94         : _ptr (obj), _ref(NULL)
     95     {
     96         if (obj)
     97             init_ref (obj);
     98     }
     99 
    100     // copy from pointer
    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>
    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 
    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 
    155     Obj *ptr() const {
    156         return _ptr;
    157     }
    158 
    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>
    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>
    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>
    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