// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#ifndef _MALLOC_H_
#define _MALLOC_H_
#ifndef __NETBSD__
#if __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
# define __func__ __FUNCTION__
# else
# define __func__ ""
# endif
#endif
#endif
#define ALC_MARK __FILE__, __LINE__, __func__
//////////////////////////////////////////////////////////////////////
// Whether to use Athena's built-in Memory Manager (enabled by default)
// To disable just comment the following line
#if !defined(DMALLOC) && !defined(BCHECK)
#define USE_MEMMGR
#endif
// Whether to enable Memory Manager's logging
#define LOG_MEMMGR
#ifdef USE_MEMMGR
# define aMalloc(n) _mmalloc(n,ALC_MARK)
# define aMallocA(n) _mmalloc(n,ALC_MARK)
# define aCalloc(m,n) _mcalloc(m,n,ALC_MARK)
# define aCallocA(m,n) _mcalloc(m,n,ALC_MARK)
# define aRealloc(p,n) _mrealloc(p,n,ALC_MARK)
# define aStrdup(p) _mstrdup(p,ALC_MARK)
# define aFree(p) _mfree(p,ALC_MARK)
void* _mmalloc (size_t, const char *, int, const char *);
void* _mcalloc (size_t, size_t, const char *, int, const char *);
void* _mrealloc (void *, size_t, const char *, int, const char *);
char* _mstrdup (const char *, const char *, int, const char *);
void _mfree (void *, const char *, int, const char *);
#else
# define aMalloc(n) aMalloc_(n,ALC_MARK)
# define aMallocA(n) aMallocA_(n,ALC_MARK)
# define aCalloc(m,n) aCalloc_(m,n,ALC_MARK)
# define aCallocA(m,n) aCallocA_(m,n,ALC_MARK)
# define aRealloc(p,n) aRealloc_(p,n,ALC_MARK)
# define aStrdup(p) aStrdup_(p,ALC_MARK)
# define aFree(p) aFree_(p,ALC_MARK)
void* aMalloc_ (size_t, const char *, int, const char *);
void* aMallocA_ (size_t, const char *, int, const char *);
void* aCalloc_ (size_t, size_t, const char *, int, const char *);
void* aCallocA_ (size_t, size_t, const char *, int, const char *);
void* aRealloc_ (void *, size_t, const char *, int, const char *);
char* aStrdup_ (const char *, const char *, int, const char *);
void aFree_ (void *, const char *, int, const char *);
#endif
////////////// Memory Managers //////////////////
#ifdef MEMWATCH
# include "memwatch.h"
# define MALLOC(n) mwMalloc(n,__FILE__, __LINE__)
# define MALLOCA(n) mwMalloc(n,__FILE__, __LINE__)
# define CALLOC(m,n) mwCalloc(m,n,__FILE__, __LINE__)
# define CALLOCA(m,n) mwCalloc(m,n,__FILE__, __LINE__)
# define REALLOC(p,n) mwRealloc(p,n,__FILE__, __LINE__)
# define STRDUP(p) mwStrdup(p,__FILE__, __LINE__)
# define FREE(p) mwFree(p,__FILE__, __LINE__)
#elif defined(DMALLOC)
# include "dmalloc.h"
# define MALLOC(n) dmalloc_malloc(__FILE__, __LINE__, (n), DMALLOC_FUNC_MALLOC, 0, 0)
# define MALLOCA(n) dmalloc_malloc(__FILE__, __LINE__, (n), DMALLOC_FUNC_MALLOC, 0, 0)
# define CALLOC(m,n) dmalloc_malloc(__FILE__, __LINE__, (m)*(n), DMALLOC_FUNC_CALLOC, 0, 0)
# define CALLOCA(m,n) dmalloc_malloc(__FILE__, __LINE__, (m)*(n), DMALLOC_FUNC_CALLOC, 0, 0)
# define REALLOC(p,n) dmalloc_realloc(__FILE__, __LINE__, (p), (n), DMALLOC_FUNC_REALLOC, 0)
# define STRDUP(p) strdup(p)
# define FREE(p) free(p)
#elif defined(GCOLLECT)
# include "gc.h"
# define MALLOC(n) GC_MALLOC(n)
# define MALLOCA(n) GC_MALLOC_ATOMIC(n)
# define CALLOC(m,n) _bcalloc(m,n)
# define CALLOCA(m,n) _bcallocA(m,n)
# define REALLOC(p,n) GC_REALLOC(p,n)
# define STRDUP(p) _bstrdup(p)
# define FREE(p) GC_FREE(p)
void * _bcalloc(size_t, size_t);
void * _bcallocA(size_t, size_t);
char * _bstrdup(const char *);
#elif defined(BCHECK)
# define MALLOC(n) malloc(n)
# define MALLOCA(n) malloc(n)
# define CALLOC(m,n) calloc(m,n)
# define CALLOCA(m,n) calloc(m,n)
# define REALLOC(p,n) realloc(p,n)
# define STRDUP(p) strdup(p)
# define FREE(p) free(p)
#else
# define MALLOC(n) malloc(n)
# define MALLOCA(n) malloc(n)
# define CALLOC(m,n) calloc(m,n)
# define CALLOCA(m,n) calloc(m,n)
# define REALLOC(p,n) realloc(p,n)
# define STRDUP(p) strdup(p)
# define FREE(p) free(p)
#endif
/////////////// Buffer Creation /////////////////
// Full credit for this goes to Shinomori [Ajarn]
#ifdef __GNUC__ // GCC has variable length arrays
#define CREATE_BUFFER(name, type, size) type name[size]
#define DELETE_BUFFER(name)
#else // others don't, so we emulate them
#define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type))
#define DELETE_BUFFER(name) aFree(name)
#endif
////////////// Others //////////////////////////
// should be merged with any of above later
#define CREATE(result, type, number) (result) = (type *) aCalloc ((number), sizeof(type));
#define CREATE_A(result, type, number) (result) = (type *) aCallocA ((number), sizeof(type));
#define RECREATE(result, type, number) (result) = (type *) aRealloc ((result), sizeof(type) * (number));
////////////////////////////////////////////////
unsigned int malloc_usage (void);
void malloc_init (void);
void malloc_final (void);
#endif