// This may look like C code, but it is really -*- C++ -*-

#ifndef RCPTR_H
#define RCPTR_H

/*!
  \class RCPtr
  \ingroup BaseTools
  This implements a very simple "smart pointer" with reference counting.
  Many refinements are possible
  Eric Aubourg  1999   CEA/DAPNIA/SPP

  \verbatim
  Principle :  use RCPtr<T> instead of T*
  To use with type X, define
  typedef RCPtr<X> Xp;
  When creating a new object, use
  Xp xp = new X(...);
  xp can be used like a X*   xp->field, xp->method(), *xp ...
  can be passed by reference, copied, etc
  the object is destroyed when the last Xp is destroyed.

  The class RCCPtr<X> is a const smart pointer, to be used like
  a X const *.
  \endverbatim
*/

template <class T> class RCCPtr;

template <class T>
class RCPtr {
public:
  RCPtr(T* obj=0) {
    x = obj;
    cnt = new int;
    *cnt = 1;
  }
  
  RCPtr(RCPtr<T> const& other) {
    x = other.x;
    cnt = other.cnt;
    (*cnt)++;
  }

  RCPtr<T>& operator = (RCPtr<T> const& other) {
    (*cnt)--;
    if (!*cnt) {
      delete x;
      delete cnt;
    }
    x = other.x;
    cnt = other.cnt;
    (*cnt)++;
    return *this;
  }
  
  ~RCPtr() {
    (*cnt)--;
    if (!*cnt) {
      delete x;
      delete cnt;
    }
  }

  T* operator->() {return x;}
  T& operator*()  {return *x;}

private:
  T* x;                  // the object we are referring
  int* cnt;              // how many smart pointers ?
  friend class RCCPtr<T>;
};


//! A const smart pointer class
template <class T>
class RCCPtr {
public:
  RCCPtr(T const* obj=0) {
    x = obj;
    cnt = new int;
    *cnt = 1;
  }
  
  RCCPtr(RCCPtr<T> const& other) {
    x = other.x;
    cnt = other.cnt;
    (*cnt)++;
  }

  RCCPtr(RCPtr<T> const& other) {
    x = other.x;
    cnt = other.cnt;
    (*cnt)++;
  }

  RCCPtr<T>& operator = (RCCPtr<T> const& other) {
    (*cnt)--;
    if (!*cnt) {
      delete (T*) x;
      delete cnt;
    }
    x = other.x;
    cnt = other.cnt;
    (*cnt)++;
    return *this;
  }
  
  ~RCCPtr() {
    (*cnt)--;
    if (!*cnt) {
      delete (T*) x;
      delete cnt;
    }
  }

  T const* operator->() {return x;}
  T const& operator*()  {return *x;}

private:
  T const * x;           // the object we are referring
  int* cnt;              // how many smart pointers ?
};

#endif
