#ifndef _ref_ptr_
#define _ref_ptr_

#include<stdlib.h>
#include<iostream>

/* Policy Counter_impl */ 

class Handle {
private:
  size_t _count;
public:
  Handle():_count(0){};

  void add_ref()           { ++_count;}
  bool remove_ref()        {--_count; return _count == 0;}
  size_t count() const     {return _count;};
};



template<typename T> struct Intrusive_counter_impl {


  Intrusive_counter_impl()           {};
  Intrusive_counter_impl(T* p):_p(p) {};

  T* pointee()   {return _p;};
  void cleanup() {delete _p;}

  void add_ref() {_p->add_ref();};
  bool remove_ref() {_p->remove_ref();return _p->count() == 0;};

  size_t count() {return _p->count();}
private:
  T* _p;

};


template<typename T> struct Linked_reference_counter {


  Linked_reference_counter *_next;
  Linked_reference_counter *_prev;

  Linked_reference_counter() {};
  Linked_reference_counter(T *p):_p(p) {
    _next=this;
    _prev=this;
  };
  
  T* pointee() {return _p;};
  
  bool remove_ref() {
    if(_prev == this ) return true;
    
    _prev->_next=_next;
    _next->_prev=_prev;

    return false;

  }
  
  bool add_ref() {
  
    Linked_reference_counter *current=_next->_prev;
    current->_next=this;
    _next->_prev=this;
    _prev=current;
  }

  void cleanup() {delete _p;};
  T* _p;
};


template<typename T> struct Extra_counter_impl {

  Extra_counter_impl():_c(0)                    {};
  Extra_counter_impl(T* p):_c(new size_t),_p(p) {*_c=0;};
  
  T* pointee() {return _p;}

  void cleanup() {
    delete _c;
    delete _p;
    _p=0;
  }

  bool remove_ref()    {--(*_c);return *_c==0;};
  void add_ref()       {++(*_c);};
  

  size_t count() {return *_c;};
private:
  size_t *_c;
  T*  _p;
};

template<typename T> class Indirect_counter_impl {
  
  struct p_type {T *_p; size_t  count;} ;
public:
  Indirect_counter_impl():_c() {};
  Indirect_counter_impl(T* p):_c(new p_type) {_c->count=0;_c->_p=p;};
  
  T* pointee() {return _c->_p;}

  void cleanup(){
    delete _c->_p;
    delete _c;
  }


  bool remove_ref()    {--(_c->count); return _c->count==0;};
  void add_ref()       {++(_c->count);};

  size_t count() {return _c->count;};

private:
  p_type *_c;
};


template<typename T,typename counter_impl = Extra_counter_impl<T>  > 
class Ref_ptr {
public:
  Ref_ptr() {};
  Ref_ptr(T *p):_c(p) {
    _c.add_ref();
  };

  ~Ref_ptr() {
    detach();
  }

  Ref_ptr(const Ref_ptr &p):_c(p._c) {
    _c.add_ref();
  }

  Ref_ptr &operator=(const Ref_ptr &rhs) {
    if(this!=&rhs) {
      detach();
      _c=rhs._c;
      _c.add_ref();
    }
    return *this;
  }
  
  T* operator->() {return _c.pointee();}
  T &operator*()  {return *(_c.pointee());}

  size_t count() {return _c.count();};

private:
  mutable counter_impl _c;
  void detach() {      
    
    if (_c.remove_ref() ) {
      _c.cleanup();
    }
  };
  

};

#endif
