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

#ifndef RCPTR_H
#define RCPTR_H

// This implements a very simple "smart pointer" with reference counting.
// Many refinements are possible

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

// Eric Aubourg  1999   CEA/DAPNIA/SPP


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