#ifndef __C4D_MEMORY_MP_H
#define __C4D_MEMORY_MP_H


// --- Use to enable vtune api functions
//#define _USE_VTUNE_

// ---
#include "c4d_thread.h"
#include "c4d_misc.h"

// advanced mp array class
template<class TYPE> class MPAlloc
{
		c4d_misc::BaseArray<TYPE*> ptr;
		MPAlloc(const MPAlloc &);
		
	public:

		MPAlloc()
		{
		}

		~MPAlloc()
		{
			Free();
		}

		Bool Init(LONG maxthreads)
		{
			Free();

			if (!ptr.Resize(maxthreads))
				return FALSE;

			LONG i;
			for (i=0;i<maxthreads;i++)
			{
				CHAR *p = (CHAR*)C4DOS.Ge->AllocTH(i/*passthreadnum*/,sizeof(TYPE),TRUE);
				if (!p)
				{
					Free();
					return FALSE;
				}
				TYPE *res = new(p)TYPE;
				if (res!=(TYPE*)p)
				{
					// must never happen!
					// it's not allowed to use array types for MPAlloc<>, e.g. MPAlloc<CHAR> is fine, MPAlloc<CHAR[1000]> will not work
					// the reason is that the compiler adds the arraysize infront of the memoryblock. the destructor is also not called
					GeBoom();
					Free();
					return FALSE;
				}
				ptr[i] = res;
			}
			return TRUE;
		}
		
		void Free()
		{
			LONG i;
			for (i=0;i<ptr.GetCount();i++)
			{
				if (!ptr[i]) continue;
				ptr[i]->~TYPE();
				void *dat = ptr[i];
				C4DOS.Ge->FreeTH(i,dat);
				ptr[i] = NULL;
			}
			ptr.Flush();
		}

		const TYPE &operator [](LONG i) const { return *ptr[i]; }
		TYPE &operator [](LONG i) { return *ptr[i]; }

		MPAlloc &operator =(const MPAlloc &src)
		{
			Free();
			if (!Init(src.ptr.GetCount()))
				return *this;
				
			LONG i,cnt=LMin(ptr.GetCount(),src.ptr.GetCount());
			for (i=0;i<cnt;i++)
			{
				if (ptr[i] && src.ptr[i])
					*ptr[i] = *src.ptr[i];
			}
			return *this;
		}	
		
		LONG GetCount() const { return ptr.GetCount(); }
};

#endif
