/* File: z-virt.h */

#ifndef INCLUDED_Z_VIRT_H
#define INCLUDED_Z_VIRT_H

#include "h-basic.h"

/*
 * Memory management routines.
 *
 * Set ralloc_aux to modify the memory allocation routine.
 * Set rnfree_aux to modify the memory de-allocation routine.
 * Set rpanic_aux to let the program react to memory failures.
 *
 * These routines will not work as well if the program calls malloc/free.
 *
 * The string_make() and string_free() routines handle dynamic strings.
 * A dynamic string is a string allocated at run-time, but not really
 * intended to be modified once allocated.
 *
 * Note the macros below which simplify the details of allocation,
 * clearing, casting, and size extraction.
 *
 * The macros MAKE/C_MAKE and KILL/C_KILL have a "procedural" metaphor.
 *
 * NOTE: For some reason, many allocation macros disallow "stars"
 * in type names, but you can use typedefs to circumvent this.
 * For example, instead of "type **p; MAKE(p,type*);" you can use
 * "typedef type *type_ptr; type_ptr *p; MAKE(p,type_ptr)".
 *
 * Note that it is assumed that "memset()" will function correctly,
 * in particular, that it returns its first argument.
 *
 * The 'GROW' macro is very tentative.
 */



/**** Available variables ****/

/* Replacement hook for "rnfree()" */
extern errr (*rnfree_aux)(vptr, huge);

/* Replacement hook for "rpanic()" */
extern vptr (*rpanic_aux)(huge);

/* Replacement hook for "ralloc()" */
extern vptr (*ralloc_aux)(huge);


/**** Available Routines ****/

/* De-allocate a given amount of memory */
extern errr rnfree(vptr p, huge len);

/* Panic, attempt to Allocate 'len' bytes */
extern vptr rpanic(huge len);

/* Allocate (and return) 'len', or dump core */
extern vptr ralloc(huge len);

/* Create a "dynamic string" */
extern cptr string_make(cptr str);

/* Free a string allocated with "string_make()" */
extern errr string_free(cptr str);




/**** Memory Macros ****/


/* Size of 'N' things of type 'T' */
#define C_SIZE(N,T) \
        ((huge)((N)*(sizeof(T))))

/* Size of one thing of type 'T' */
#define SIZE(T) \
        ((huge)(sizeof(T)))


/* Bool: True when P1 and P2 both point to N T's, which have same contents */
#define C_SAME(P1,P2,N,T) \
        (!memcmp((char*)(P1),(char*)(P2),C_SIZE(N,T)))

/* Bool: True when P1 and P2 both point to T's, and they have same contents */
#define SAME(P1,P2,T) \
        (!memcmp((char*)(P1),(char*)(P2),SIZE(T)))


/* Wipe an array of N things of type T at location P, return T */
#define C_WIPE(P,N,T) \
        memset((char*)(P),0,C_SIZE(N,T))

/* Wipe a single thing of type T at location P, return T */
#define WIPE(P,T) \
        memset((char*)(P),0,SIZE(T))


/* When P1 and P2 both point to N T's, Load P1 from P2 explicitly */
#define C_COPY(P1,P2,N,T) \
        memcpy((char*)(P1),(char*)(P2),C_SIZE(N,T))

/* When P1 and P2 both point to T's, Load P1 from P2 explicitly */
#define COPY(P1,P2,T) \
        memcpy((char*)(P1),(char*)(P2),SIZE(T))



/* Free an array of N things of type T at P, return ??? */
#define C_FREE(P,N,T) \
        (rnfree(P,C_SIZE(N,T)))

/* Free one thing of type T at P, return ??? */
#define FREE(P,T) \
        (rnfree(P,SIZE(T)))


/* Allocate and return an array of N things of type T */
#define C_NEW(N,T) \
        ((T*)(ralloc(C_SIZE(N,T))))

/* Allocate and return one thing of type T */
#define NEW(T) \
        ((T*)(ralloc(SIZE(T))))


/* Allocate, wipe, and return an array of N things of type T */
#define C_ZNEW(N,T) \
        ((T*)(C_WIPE(ralloc(C_SIZE(N,T)),N,T)))

/* Allocate, wipe, and return one thing of type T */
#define ZNEW(T) \
        ((T*)(WIPE(ralloc(SIZE(T)),T)))


/* Allocate a wiped array of N things of type T, let P point at them */
#define C_MAKE(P,N,T) \
        (P)=C_ZNEW(N,T)

/* Allocate a wiped thing of type T, let P point at it */
#define MAKE(P,T) \
        (P)=ZNEW(T)


/* Free an array of N things of type T at P, and reset P to NULL */
#define C_KILL(P,N,T) \
        (C_FREE(P,N,T), (P)=(T*)NULL)

/* Free a single thing of type T at P, and reset P to NULL */
#define KILL(P,T) \
        (FREE(P,T), (P)=(T*)NULL)



/* Mega-Hack -- Cleanly "grow" 'P' from N1 T's to N2 T's */
#define GROW(P,N1,N2,T) \
        (C_MAKE(vptr_tmp,N2,T), C_COPY(vptr_tmp,P,MIN(N1,N2),T), \
         C_FREE(P,N1,T), (P)=vptr_tmp)



#endif



