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

		MCSMPCountedObject.h
		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Arnaud
		Date:	3/21/2005

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

#ifndef __MCSMPCountedObject__
#define __MCSMPCountedObject__

#if CP_PRAGMA_ONCE
#pragma once
#endif


#include "MCCompiler.h"
#include "MCBasicTypes.h"
#include "MCCompObj.h"
#include "MCSMP.h"


class TMCAtomicCounter;

/// \addtogroup MCCore
/// \{

///	<P>Counted objects are objects that use a counter to keep track of how many other objects need them, 
/// and delete themselves when nobody needs them anymore. A counted object has an AddRef method that increments its counter, 
/// and a Release method that decrements it. When the value of the counter reaches zero, the object is deleted.</P>
///
/// Take a look at TMCCountedCreateHelper to see how to create and return a counted object
///
class TMCSMPCountedObject : public IMCUnknown
{
	public:
	
		// we cannot use TMCObject because of problem with CW8 for TransPoser ! (Charles 05/18/2005)
		void*	operator new			(MCSize byteCount) throw();
		void	operator delete			(void* block);
		void*	operator new[]			(MCSize byteCount) throw();
		void	operator delete[]		(void* block);

	public:
		static void Create	(TMCSMPCountedObject** outObject);

	protected:
		TMCSMPCountedObject();
		virtual ~TMCSMPCountedObject();
		
	public:
	
		virtual MCErr	MCCOMAPI QueryInterface	(const MCIID& riid, void** ppvObj);
		virtual uint32	MCCOMAPI AddRef			();
		virtual uint32	MCCOMAPI Release		();

		inline int32	GetReferenceCount() { return GetAtomicCounterValue(fRefCountAC); }
	
	protected:

#if !(Debug_ && qRecordCountedPtrRefs)
		TMCAtomicCounterHolder		fRefCountAC;	
#else

	public:

		TMCAtomicCounterHolder		fRefCountAC;	
		uint32					fUniqueObjectNumber;
		TMCSMPCountedObject*	fPreviousCountedObject; // to chain every objects existing at one given instant
		TMCSMPCountedObject*	fNextCountedObject;
#endif
};
/// \}

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

inline uint32 TMCSMPCountedObject::AddRef()
{
	return IncrementAtomicCounter(fRefCountAC);
}

inline uint32 TMCSMPCountedObject::Release()
{
	const int32 unreleasedCount = DecrementAtomicCounter(fRefCountAC);

	if (unreleasedCount == 0)
	{
			delete this;
	}
	else if (unreleasedCount < 0)
	{
		MCAssertMessage("TMCSMPCountedObject: ref count < 0");
	}
	return unreleasedCount;
}

#endif