/****************************************************************************************************

		MCCopyOnWritePtr.h
		Copyright: (c) 2007 Daz Productions Inc. All rights reserved.

		Author:	Charles
		Date:	6/13/2007

****************************************************************************************************/

#ifndef __MCCopyOnWritePtr__
#define __MCCopyOnWritePtr__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCCountedPtr.h"

/// This class is used to create "Copy on Write" caches. This is used to avoid making multiple
/// copies of identical data
template <class T> class TMCCopyOnWritePtr : public TMCObject1
{
public:
	TMCCopyOnWritePtr() {}

	TMCCopyOnWritePtr(const TMCCopyOnWritePtr<T>& ptr)
	{
		fPtr = ptr.fPtr;
	}

	void operator=(const TMCCopyOnWritePtr<T>& ptr)
	{
		fPtr = ptr.fPtr;
	}

	/// Allocates the object
	void			Allocate();
	void			Release();

	/// Returns a pointer that does not let you modify the data
	inline const T*	GetPointerForRead();

	/// Returns a pointer that let's you modify the data (note that it might make a copy
	/// if others are referencing the same object).
	inline T*		GetPointerForWrite();

protected:
	//inline T*		CastPointer() const	{ MCAssert(fPtr); return static_cast<T*>(*&fPtr); }

protected:
	TMCCountedPtr< T >		fPtr;
};


template <class T> void	TMCCopyOnWritePtr<T>::Allocate()
{
	T::Create(&fPtr);
}

template <class T> void	TMCCopyOnWritePtr<T>::Release()
{
	fPtr = NULL;
}


template <class T> inline const T* TMCCopyOnWritePtr<T>::GetPointerForRead()
{
	return fPtr;
}

template <class T> inline T* TMCCopyOnWritePtr<T>::GetPointerForWrite()
{
	if (fPtr)
	{
		if (fPtr->GetReferenceCount()>1)
		{
			// someone else is already referencing this, so we should make a copy of it
			T* const oldObject = fPtr;

			oldObject->Clone(&fPtr);

			MCAssert( fPtr->GetReferenceCount()==1 ); // just in case the copy contructor was not implemented properly
		}
	}
	else
	{
		Allocate();
	}
	return fPtr;
}


#endif
