// Copyright (C) 2004-2009 Christoph Kubisch & Eike Decker
// This file is part of the "Luxinia Engine".
// For conditions of distribution and use, see copyright notice in luxiniapublicsdk.txt
//
// <Author: Christoph Kubisch, Eike Decker>


#ifndef __LUXCORE_MEMORYGEN_H__
#define __LUXCORE_MEMORYGEN_H__


#include "memorybase.h"

#ifdef __cplusplus
extern "C"{
#endif

//////////////////////////////////////////////////////////////////////////
// MemoryGeneric
// generic allocator, mostly for profiling/ debugging/ stat tracking
// NOT THREADSAFE!!
// zalloc = set to 0

typedef struct lxMemoryGenericInfo_s{
	ptrdiff_t	allocs;
	ptrdiff_t	mem;
}lxMemoryGenericInfo_t;

LUX_API lxMemoryGenericInfo_t	lxMemoryGeneric_getInfo();
// returns FALSE on error
LUX_API booln	lxMemoryGeneric_deinitStats();
LUX_API	void	lxMemoryGeneric_dumpStats(const char* fname);

LUX_API void*	lxMemoryGeneric_zalloc(size_t size);
LUX_API void*	lxMemoryGeneric_malloc(size_t size);
LUX_API void*	lxMemoryGeneric_calloc(size_t num, size_t size);
LUX_API void	lxMemoryGeneric_free(void *ptr);
LUX_API void*	lxMemoryGeneric_realloc(void* ptr, size_t size);
LUX_API void*	lxMemoryGeneric_zallocAligned(size_t size, size_t alignsize);
LUX_API void*	lxMemoryGeneric_mallocAligned(size_t size, size_t alignsize);
LUX_API void*	lxMemoryGeneric_reallocAligned(void* ptr,size_t size,size_t alignsize);
LUX_API void	lxMemoryGeneric_freeAligned(void *ptr);
LUX_API size_t	lxMemoryGeneric_offsetAligned(void *ptr);

#if defined(MEMORY_GENERIC_STATS)
LUX_API void*	lxMemoryGeneric_zallocStats(size_t size,const char *source,int line);
LUX_API void*	lxMemoryGeneric_mallocStats(size_t size,const char *source,int line);
LUX_API void*	lxMemoryGeneric_callocStats(size_t num, size_t size,const char *source,int line);
LUX_API void*	lxMemoryGeneric_reallocStats(void *ptr, size_t size, size_t oldsize, const char *source, int line);
LUX_API void	lxMemoryGeneric_freeStats(void *ptr, size_t size,const char *source,int line);
LUX_API void*	lxMemoryGeneric_mallocAlignedStats(size_t size, size_t alignsize,const char *source,int line);
LUX_API void*	lxMemoryGeneric_zallocAlignedStats(size_t size, size_t alignsize,const char *source,int line);
LUX_API void*	lxMemoryGeneric_reallocAlignedStats(void* ptr,size_t size,size_t alignsize,size_t oldsize,const char *source,int line);
LUX_API void	lxMemoryGeneric_freeAlignedStats(void *ptr, size_t size,const char *source,int line);
LUX_API size_t	lxMemoryGeneric_offsetAlignedStats(void *ptr);

#endif




//////////////////////////////////////////////////////////////////////////

#if defined(MEMORY_GENERIC_STATS)
	#define lxMemGenZalloc(size)					lxMemoryGeneric_zallocStats(size,__FILE__,__LINE__)
	#define lxMemGenAlloc(size)					lxMemoryGeneric_mallocStats(size,__FILE__,__LINE__)
	#define lxMemGenCalloc(size,cnt)				lxMemoryGeneric_callocStats(size,cnt,__FILE__,__LINE__)
	#define lxMemGenRealloc(ptr,size,oldsize)	lxMemoryGeneric_reallocStats(ptr,size,oldsize,__FILE__,__LINE__)
	#define lxMemGenFree(ptr,size)				lxMemoryGeneric_freeStats(ptr,size,__FILE__,__LINE__)

	#define lxMemGenReallocAligned(ptr,size,aligned,oldsize)	lxMemoryGeneric_reallocAlignedStats(ptr,size,aligned,oldsize,__FILE__,__LINE__)
	#define lxMemGenAllocAligned(size,aligned)	lxMemoryGeneric_mallocAlignedStats(size,aligned,__FILE__,__LINE__)
	#define lxMemGenZallocAligned(size,aligned)	lxMemoryGeneric_zallocAlignedStats(size,aligned,__FILE__,__LINE__)
	#define lxMemGenFreeAligned(ptr,size)		lxMemoryGeneric_freeAlignedStats(ptr,size,__FILE__,__LINE__)
	#define lxMemGenOffsetAligned(ptr)				lxMemoryGeneric_offsetAlignedStats(ptr)
#else
	#define lxMemGenZalloc(a)					lxMemoryGeneric_zalloc(a)
	#define lxMemGenAlloc(a)					lxMemoryGeneric_malloc(a)
	#define lxMemGenCalloc(a,b)					lxMemoryGeneric_calloc(a,b)
	#define lxMemGenRealloc(ptr,size,oldsize)	lxMemoryGeneric_realloc(ptr,size)
	#define lxMemGenFree(ptr,size)				lxMemoryGeneric_free(ptr)

	#define lxMemGenReallocAligned(ptr,size,aligned,oldsize)	lxMemoryGeneric_reallocAligned(ptr,size,aligned)
	#define lxMemGenAllocAligned(a,aligned)		lxMemoryGeneric_mallocAligned(a,aligned)
	#define lxMemGenZallocAligned(a,aligned)		lxMemoryGeneric_zallocAligned(a,aligned)
	#define lxMemGenFreeAligned(ptr,size)		lxMemoryGeneric_freeAligned(ptr)
	#define lxMemGenOffsetAligned(ptr)				lxMemoryGeneric_offsetAligned(ptr)
#endif



//////////////////////////////////////////////////////////////////////////

// dont access!
extern	lxMemoryGenericInfo_t	g_CoreMemGen;

LUX_INLINE void lxMemoryGeneric_free(void *ptr) {
	LUX_PROFILING_OP (g_CoreMemGen.allocs--);
	MEMORY_GLOBAL_FREE(ptr);
}

LUX_INLINE void *lxMemoryGeneric_zalloc(size_t size)
{
	LUX_PROFILING_OP (g_CoreMemGen.allocs++);

	{
		void *ptr = MEMORY_GLOBAL_CALLOC(1,size);

		return ptr;
	}
}

LUX_INLINE void *lxMemoryGeneric_calloc(size_t num, size_t size)
{
	LUX_PROFILING_OP (g_CoreMemGen.allocs++);

	{
		void *ptr = MEMORY_GLOBAL_CALLOC(num,size);

		return ptr;
	}
}

LUX_INLINE void *lxMemoryGeneric_malloc(size_t size)
{
	LUX_PROFILING_OP (g_CoreMemGen.allocs++);

	{
		void *ptr = MEMORY_GLOBAL_MALLOC(size);

		return ptr;
	}
}

LUX_INLINE void *lxMemoryGeneric_realloc(void* ptr, size_t size)
{
	ptr = MEMORY_GLOBAL_REALLOC(ptr,size);

	return ptr;
}

LUX_INLINE void lxMemoryGeneric_freeAligned(void *ptr) {
	//LUX_PROFILING_OP (g_CoreMemGen.mem-= (ptrdiff_t)size);
	LUX_PROFILING_OP (g_CoreMemGen.allocs--);
	ptr = lxMemAlignedToOrig(ptr);
	MEMORY_GLOBAL_FREE(ptr);
}

LUX_INLINE void *lxMemoryGeneric_zallocAligned(size_t size, size_t alignsize)
{
	void *ptr = MEMORY_GLOBAL_MALLOC(size + alignsize + sizeof(size_t));
	
	ptr = lxMemAlignedFromOrig(ptr,alignsize);
	memset(ptr,0,size);

	LUX_PROFILING_OP (g_CoreMemGen.allocs++);

	return ptr;
}

LUX_INLINE void *lxMemoryGeneric_mallocAligned(size_t size, size_t alignsize)
{
	void *ptr = MEMORY_GLOBAL_MALLOC(size + alignsize + sizeof(size_t));

	ptr = lxMemAlignedFromOrig(ptr,alignsize);

	LUX_PROFILING_OP (g_CoreMemGen.allocs++);

	return ptr;
}

LUX_INLINE void *lxMemoryGeneric_reallocAligned(void* ptr, size_t newsize, size_t alignsize)
{
	byte* oldptr = (byte*)lxMemAlignedToOrig(ptr);
	size_t shiftold = (((byte*)ptr)-oldptr)-sizeof(size_t);

	ptr = MEMORY_GLOBAL_REALLOC(ptr,newsize + alignsize + sizeof(size_t));
	lxMemAlignedRealloc(ptr,alignsize,newsize,sizeof(size_t),shiftold);

	return lxMemAlignedFromOrig(ptr,alignsize);
}

LUX_INLINE size_t lxMemoryGeneric_offsetAligned(void *ptr)
{
	byte*	inptr = (byte*)ptr;
	byte*	optr  = (byte*)lxMemAlignedToOrig(ptr);

	return (inptr-optr);
}

#ifdef __cplusplus
}
#endif

#endif

