/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
****************************************************************************/

#pragma once

#include "glmCoreAPI.h"
#include "glmCoreDefinitions.h"
#include "glmMemoryStats.h"
#ifdef GLM_ENABLE_TRACY_MEMORY_PROFILER //in header files, tracy needs to be protected beacause it is not fully exported in the golaem devkit
	#include "glmTracy.h"
#endif

#define SINGLE_ARG(...) __VA_ARGS__

#if GLM_IS_COMPILER_MSVC
	#define GLM_ALLOCA _alloca
#else
	#include <alloca.h>
	#define GLM_ALLOCA alloca
#endif


namespace glm
{
	typedef MemoryStatIds::Value MemAllocStatId;
}
#define GLM_CLASS_STAT_ID(memStatId)			static glm::MemAllocStatId getClassMemoryStatId() { return memStatId; }
#define GLM_ABSTRACTCLASS_STAT_ID(memStatId)	static glm::MemAllocStatId getClassMemoryStatId() { return memStatId; }

////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The following preprocessor definitions should only be used instead of any new/malloc or new[]
// The golaem class needs to define a stat IDs by using the preprocessor GLM_CLASS_STAT_ID(glm::MemoryStatIds::Value) in the public part of the class
////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef GLM_ENABLE_TRACY_MEMORY_PROFILER

	//malloc/free with tracy profiling
	#define GLM_ALLOC(size, p,  memStatId)				malloc(size);	\
														TracySecureAlloc(p, size/*, getMemoryStatName(memStatId)*/);
	#define GLM_ALLOC_CAST(T, size, p,  memStatId)		(T)malloc(size);	\
														TracySecureAlloc(p, size/*, getMemoryStatName(memStatId)*/);
	#define GLM_FREE(p,  memStatId)						{ TracySecureFree(p/*, getMemoryStatName(memStatId)*/);        \
														free(p);	\
														p = NULL;	}

	//new/delete with tracy profiling
	#define GLM_NEW(T, p, memStatId,  ...)	new T(__VA_ARGS__);    \
											TracySecureAlloc(p, sizeof(T)/*, getMemoryStatName(T::getClassMemoryStatId())*/);
	#define GLM_DELETE(p, memStatId)		{ TracySecureFree(p/*, getMemoryStatName((p)->getClassMemoryStatId())*/);        \
											delete (p);            \
											(p) = NULL;	}
	#define GLM_SAFE_DELETE(p)				{ TracySecureFree(p/*, getMemoryStatName((p)->getClassMemoryStatId())*/);    \
											delete (p);            \
											(p) = NULL;	}
	#define GLM_CAST_DELETE(T, p, memStatId)	{ TracySecureFree(p/*, getMemoryStatName((p)->getClassMemoryStatId())*/);        \
												delete static_cast<T>(p);	}

	//new/delete array with tracy profiling
	#define GLM_NEW_ARRAY(T, count, p, memStatId)		new T[count];    \
														TracySecureAlloc(p, count*sizeof(T)/*, getMemoryStatName(memStatId)*/);
	#define GLM_SAFE_DELETE_ARRAY(p,  memStatId)	{ TracySecureFree(p/*, getMemoryStatName(memStatId)*/);    \
														delete[] (p);            \
														(p) = NULL; }

#else

	//malloc/free with tracy profiling (disabled)
	#define GLM_ALLOC(size, p,  memStatId)				malloc(size);
	#define GLM_ALLOC_CAST(T, size, p,  memStatId)		(T)malloc(size);
	#define GLM_FREE(p,  memStatId)						{ free(p);	\
														p = NULL;	}

	//new/delete with tracy profiling (disabled)
	#define GLM_NEW(T, p, memStatId,  ...)	new T(__VA_ARGS__);
	#define GLM_DELETE(p, memStatId)		{ delete (p);            \
											(p) = NULL;	}
	#define GLM_SAFE_DELETE(p)				{ delete (p);	\
											(p) = NULL; }
	#define GLM_CAST_DELETE(T, p, memStatId)	delete static_cast<T>(p);

	//new/delete array with tracy profiling (disabled)
	#define GLM_NEW_ARRAY(T, count, p, memStatId)		new T[count];
	#define GLM_SAFE_DELETE_ARRAY(p,  memStatId)	{ delete[] (p);		\
														(p) = NULL; }


#endif




////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Disabling Tracy memory profling : 
// The following preprocessor definitions should only be used for classes and arrays for which we don't want to trace memory
// Every Golaem class should be instancied with the macros that uses the memory profiling.
////////////////////////////////////////////////////////////////////////////////////////////////////////////

//malloc/free without tracy profiling
#define GLM_ALLOC_NOPROFILING( size,  memStatId)					malloc(size)
#define GLM_ALLOC_ALIGNED_NOPROFILING( size,  align,  memStatId)	malloc(size)
#define GLM_FREE_NOPROFILING( p,  memStatId)						{ free(p);	\
																	p = NULL; }

//safe delete without tracy profiling
#define GLM_SAFE_DELETE_NOPROFILING(p)	{ delete (p);            \
                                        (p) = NULL; }

//new/delete array without tracy profiling
#define GLM_NEW_ARRAY_NOPROFILING(T,  count)	new T[count]
#define GLM_SAFE_DELETE_ARRAY_NOPROFILING(p)	{ delete[] (p);		\
												(p) = NULL; }

