/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 ***********************************************************************/

#ifndef SMARTPTR_H
#define SMARTPTR_H

/*******************************************************************************
*                         Include Files
*******************************************************************************/

/*******************************************************************************
*                         Definitions
*******************************************************************************/

/*******************************************************************************
*                         Types and Classes
*******************************************************************************/


//------------------------------------------------------------------------------
//                        Reference Object
//
//  In order to use the SmartPtr<> class, the object type used to instantiate
//  the SmartPtr template must inheirit from the ObjRef class.
//
//------------------------------------------------------------------------------
class ObjRef
{
   //---------------------------------------------------------------------------
   // Public interface
   //
   public:

   ObjRef() : m_Count(0) {}

   void IncRefCount(void)
   {
      InterlockedIncrement(&m_Count);
   }

   bool DecRefCount(void)
   {
      if ((m_Count > 0) && (InterlockedDecrement(&m_Count) == 0))
      {
         return true;
      }
      else
      {
         return false;
      }
   }

   unsigned int GetRefCount(void) const
   {
      return m_Count;
   }

   //---------------------------------------------------------------------------
   // Private data
   //
   private:

   mutable unsigned long m_Count;
};


//------------------------------------------------------------------------------
//                        SmartPtr Object
//
//------------------------------------------------------------------------------
template<class T>
class SmartPtr
{
   //---------------------------------------------------------------------------
   // Public interface
   //
   public:

   SmartPtr();
   SmartPtr(T* ptr);
   SmartPtr(const SmartPtr<T>& ref);

   virtual ~SmartPtr();

   operator bool (void) const;
   bool operator! (void) const;
   bool operator== (SmartPtr<T>& ref) const;
   bool operator!= (SmartPtr<T>& ref) const;

   SmartPtr<T>& operator= (const SmartPtr<T>& ref);
   SmartPtr<T>& operator= (T* ptr);

   T& operator* (void) const;
   T* operator-> (void) const;
   operator T* (void) const;

   //---------------------------------------------------------------------------
   // Private interface
   //
   private:

   void deleteObject(void);
   void resetPtr(T* newPtr);

   //---------------------------------------------------------------------------
   // Private data
   //
   private:

    T* m_Ptr;

};



template<class T>
inline SmartPtr<T>::SmartPtr() :
   m_Ptr(0)
{
}  // End of SmartPtr::SmartPtr()


template<class T>
inline SmartPtr<T>::SmartPtr(T* ptr) :
   m_Ptr(0)
{
   resetPtr(ptr);

}  // End of SmartPtr::SmartPtr()


template<class T>
inline SmartPtr<T>::SmartPtr(const SmartPtr<T>& ref) :
   m_Ptr(0)
{
   resetPtr(ref.m_Ptr);

}  // End of SmartPtr::SmartPtr()


template<class T>
inline SmartPtr<T>::~SmartPtr()
{
   deleteObject();

}  // End of SmartPtr::~SmartPtr()


template<class T>
inline SmartPtr<T>::operator bool (void) const
{
   return m_Ptr != 0;

}  // End of SmartPtr::operator bool()


template<class T>
inline bool SmartPtr<T>::operator! (void) const
{
   return m_Ptr == 0;

}  // End of SmartPtr::operator!()


template<class T>
inline bool SmartPtr<T>::operator== (SmartPtr<T>& ref) const
{
   return m_Ptr == ref.m_Ptr;

}  // End of SmartPtr::operator==()


template<class T>
inline bool SmartPtr<T>::operator!= (SmartPtr<T>& ref) const
{
   return m_Ptr != ref.m_Ptr;

}  // End of SmartPtr::operator==()


template<class T>
inline SmartPtr<T>& SmartPtr<T>::operator= (const SmartPtr<T>& ref)
{
   resetPtr(ref.m_Ptr);
   return *this;

}  // End of SmartPtr::operator=()


template<class T>
inline SmartPtr<T>& SmartPtr<T>::operator= (T* ptr)
{
   resetPtr(ptr);
   return *this;

}  // End of SmartPtr::operator=()


template<class T>
inline T& SmartPtr<T>::operator* (void) const
{
   return *m_Ptr;

}  // End of SmartPtr::operator*()


template<class T>
inline T* SmartPtr<T>::operator-> (void) const
{
   return m_Ptr;

}  // End of SmartPtr::operator->()


template<class T>
inline SmartPtr<T>::operator T* (void) const
{
   return m_Ptr;

}  // End of SmartPtr::operator T*()


template<class T>
inline void SmartPtr<T>::deleteObject(void)
{
   if (m_Ptr && m_Ptr->DecRefCount())
   {
      delete m_Ptr;
      m_Ptr = 0;
   }

}  // End of SmartPtr::deleteObject()


template<class T>
inline void SmartPtr<T>::resetPtr(T* newPtr)
{
   if (m_Ptr != newPtr)
   {
      deleteObject();
      m_Ptr = newPtr;

      if (m_Ptr)
      {
         // New object reference.
         m_Ptr->IncRefCount();
      }
   }

}  // End of SmartPtr::resetPtr()

#endif      // SMARTPTR_H
            
/******************************************************************************/
/******************************************************************************/