
//
// AT_OBJPTR.H -- reference to objects created with AT_OBJECTS.H
//
// These templates provide pointer access to Objs and ConstObjs.
// There are three types of pointers: PtrConst, Ptr, and SPtr.
// a PtrConst<T> is constructed from a ConstObj or an Obj, and provides
// read-only access to a ConstObj (or an Obj).  A Ptr or an SPtr may be
// consructed only from an Obj (not a ConstObj), and provide read/write access.
// Constructing a Ptr or an SPtr entail physically copying the object if it's
// been logically copied, so PtrConst is preferred unless write access is
// necessary.  Ptr construction causes a deep copy (i.e. Obj<T>.placeClone
// is called), while SPtr causes a (shallow) bitwise copy.
//
// Once constructed, these may be used like auto-ptrs, plus an implicit cast
// to T* is provided.
//

#ifndef AT_OBJPTRCONST_H
#define AT_OBJPTRCONST_H

#include "at_objects.h"

// ================================== OBJECT POINTERS =========

// ptr-to-const
template <class T> class PtrConst
{
public :
  PtrConst
    ();

  explicit PtrConst
    (const ConstObj<T>& o);
  PtrConst
    (const PtrConst<T>& rhs);

  PtrConst& operator=
    (const ConstObj<T>& o);
  PtrConst& operator=
    (const PtrConst<T>& o);

  bool operator!
    ()
    const;

  ~PtrConst
    ();

  operator const T *const
    ()
    const;
  const T& operator*
    ()
    const;
  T *const operator->
    ()
    const;

protected :
  static refBuf *getObjRB
    (const ConstObj<T>& o)
  { return o.rb; };
  static refBuf *setObjRB
    (ConstObj<T>& o,
     refBuf *rb)
  { return (o.rb = rb); };

  refBuf *rb;
  T* ptr;
};

template <class T> class PtrBase : public PtrConst<T>
{
public :
  virtual PtrBase& operator=
    (const ConstObj<T>& o);

  operator T*
    ()
    const;
  T& operator*
    ()
    const;
  T* operator->
    ()
    const;

protected :
  PtrBase
    ();
  PtrBase
    (Obj<T>& o);
  void finishInit
    (Obj<T>& o);
};

// shallow pointer
template <class T> class SPtr : public PtrBase<T>
{
public :
  explicit SPtr
    (Obj<T>& o);
  explicit SPtr
    ();
};

// "normal" (deep) pointer
template <class T> class Ptr : public PtrBase<T>
{
public :
  explicit Ptr
    (Obj<T>& o);
  explicit Ptr
    ();

  #define newObj(T, obj, params)  \
    Obj<T> obj; { PtrConst<T> ptr(obj); new((T*) ptr) T params; }

  #define newObjPtr(T, obj, ptr, params)  \
    Obj<T> obj; Ptr<T> ptr(obj); new((T*) ptr) T params;
};


// ============================================================
// ================================== INLINES =================

// ================================== PTR CONST ===============

template <class T> inline
PtrConst<T>::PtrConst
  () :
    rb(0),
    ptr(0)
{
}

template <class T> inline
PtrConst<T>::PtrConst
  (const ConstObj<T>& o) :
    rb(o.rb),
    ptr(rb ? (T*) rb->lock() : 0)
{
}

template <class T> inline
PtrConst<T>::PtrConst
  (const PtrConst<T>& rhs) :
    rb(rhs.rb),
    ptr(rb ? (T*) rb->lock() : 0)
{
}


template <class T> inline
PtrConst<T>& PtrConst<T>::operator=
  (const ConstObj<T>& rhs)
{
  if (rb)
  {
    T* t = (T*) rb->unlock();
    if (t)
    {
      t->~T();
      delete rb;
    }
  }

  ptr = (rb = rhs.rb) ? (T*) rb->lock() : 0;
  return *this;
}

template <class T> inline
PtrConst<T>& PtrConst<T>::operator=
  (const PtrConst<T>& rhs)
{
  if (rb)
  {
    T* t = (T*) rb->unlock();
    if (t)
    {
      t->~T();
      delete rb;
    }
  }

  ptr = (rb = rhs.rb) ? (T*) rb->lock() : 0;

  return *this;
}

template <class T> inline
bool PtrConst<T>::operator!
  ()
  const
{ return !rb; };

template <class T> inline
PtrConst<T>::~PtrConst
  ()
{
  if (rb)
  {
    T *t = (T*) rb->unlock();
    if (t)
    {
      t->~T();
      delete rb;
    }
  }
}

template <class T> inline
PtrConst<T>::operator const T *const
  ()
  const
{
  return ptr;
}

template <class T> inline
const T& PtrConst<T>::operator*
  ()
  const
{
  return *ptr;
}

template <class T> inline
T *const PtrConst<T>::operator->
  ()
  const
{
  return ptr;
}

#endif
