/*
 * Copyright (c) 1999 Johnny C. Lam.
 * All rights reserved.
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  The author makes no representations
 * about the suitability of this software for any purpose.  It is
 * provided "as is" without express or implied warranty.
 */

///////////////////////////////////////////////////////////////////////////
// Implementation of template class rc_ptr<T>.
//
template <class T>
inline
void
rc_ptr<T>::init()
{
    // If the dumb pointer is null, so is the smart one.
    if (_pointee == 0)
	return;
    
    // If the value isn't shareable, copy it.
    if (! _pointee->is_shareable())
	_pointee = new T(*_pointee);
    
    // Note that there is now a new reference to the value.
    _pointee->add_reference();
}

template <class T>
inline
rc_ptr<T>::rc_ptr(T* realPtr)
    : _pointee(realPtr)
{
    init();
}

template <class T>
inline
rc_ptr<T>::rc_ptr(const rc_ptr<T>& rhs)
    : _pointee(rhs._pointee)
{
    init();
}

template <class T>
inline
rc_ptr<T>::~rc_ptr()
{
    if (_pointee)
	_pointee->remove_reference();
}

template <class T>
inline
rc_ptr<T>&
rc_ptr<T>::operator=(const rc_ptr<T>& rhs)
{
    // Skip assignments where the value doesn't change.
    if (_pointee != rhs._pointee) {
	if (_pointee)
	    _pointee->remove_reference(); // remove reference to current value
	_pointee = rhs._pointee;	  // point to new value
	
	// If possible, share it, else make own copy.
	init();
    }
    return *this;
}

template <class T>
inline
rc_ptr<T>&
rc_ptr<T>::operator=(T* rhs)
{
    // Skip assignments where the value doesn't change.
    if (_pointee != rhs) {
	if (_pointee)
	    _pointee->remove_reference(); // remove reference to current value
	_pointee = rhs;			  // point to new value
	
	// If possible, share it, else make own copy.
	init();
    }
    return *this;
}

template <class T>
inline
T*
rc_ptr<T>::operator->() const
{
    return _pointee;
}

template <class T>
inline
T&
rc_ptr<T>::operator*() const
{
    return *_pointee;
}

template <class T>
inline
bool
operator==(const rc_ptr<T>& lhs, const rc_ptr<T>& rhs)
{
    return lhs._pointee == rhs._pointee;
}

///////////////////////////////////////////////////////////////////////////
// Implementation of class rc_object
//
inline
rc_object::rc_object()
    : _refcount(0), _shareable(true)
{}

inline
rc_object::rc_object(const rc_object&)
    : _refcount(0), _shareable(true)
{}

inline
rc_object::~rc_object()
{}

inline
rc_object&
rc_object::operator=(const rc_object&)
{
    return *this;
}

inline
void
rc_object::add_reference()
{
    ++_refcount;
}

inline
void
rc_object::remove_reference()
{
    if ( --_refcount == 0 )
	delete this;
}

inline
void
rc_object::mark_unshareable()
{ 
    _shareable = false;
}

inline
bool
rc_object::is_shareable() const
{
    return _shareable;
}

inline
bool
rc_object::is_shared() const
{
    return _refcount > 1;
}
