#ifndef mem_h
#define mem_h
/*
* External declarations for the mem package.
*/
#ifndef   V_h
#include "V.h"
#endif
/*
* These variables may be set during compilation.  But note that it's dangerous
* to set MEMDESC to more that what the V package was compiled with.
*/
#ifndef MEMINFO
#define MEMINFO	 7	/* Keep extra info about each chunk, and when to dump it */
#endif
#ifndef MEMDESC
#define MEMDESC 15	/* Max size of chunk description (2^N-1) */
#endif
/*
* The mem routines return values of type MEMP, which need not be the
* same as malloc's value (which differs from system to system).
*/
#ifndef MEMP
#define MEMP char*
#endif
#ifndef MEMS	/* Memory unit size required by malloc() */
#define MEMS unsigned
#endif
/*
* Here's some information about the malloc package; you may need to change
* some of it for your system.
*/
#ifndef MEMO	/* Block overhead for malloc */
#if	defined(SUN)
#define MEMO 8
#endif
#endif
#ifndef MEMO	/* Block overhead for malloc */
#define MEMO 8	/* If not defined above */
#endif
#ifndef MEMT	/* Memory unit type returned by malloc() */
#define MEMT char
#endif
#ifndef MEMU	/* Define memory chunk-size as 8 bytes */
#define MEMU 8
#endif
/*
* Here's the layout of a "chunk header" in the mem package.  Note
* that  we  keep  these  headers  remote  from the data blocks that we
* return, so that if an applciation writes past the end of a chunk, it
* will tend not to destroy that chunk's header info.
*/
#define Chunk struct _chunk_
Chunk {
	MEMP   addr;	/* The chunk's base address */
	MEMS   size;	/* The chunk's actual size */
	int    algn;	/* The chunk's alignment */
	struct {
		unsigned free   :1;	/* The chunk is available for allocation */
		unsigned alloc  :1;	/* The chunk has been allocated by getachunk */
		unsigned malloc :1;	/* The chunk came from malloc and may be freed */
	} flag;
	Chunk* next;	/* The next-higher chunk */
#if MEMINFO > 0
	char   desc[MEMDESC+1];
#endif
};

/*
* This macro rounds x up to a multiple of a.  If x is a multiple of a, the value
* should be x, otherwise it should be the next-higher multiple of a.  This macro
* should work everywhere, but there are some flakey versions of C out there ....
*/
#ifndef MEMALIGN
/*efine	MEMALIGN(x,a) ((Uval(x)%Uval(a))?((Uval(x)+Uval(a))-(Uval(x)%Uval(a))):Uval(x))*/
/*efine MEMALIGN(x,a) (((Uval(x)+Uval(a)-1)/Uval(a))*Uval(a))*/
#define MEMALIGN(x,a) MemAlign((ulong)(x),(ulong)(a))
extern U32 MemAlign();
#endif

/*
* Here are the externally-defined things in the mem module:
*/
extern int    memalignsize;	/* Memory alignment size */
extern Chunk* badchunk();	/* Record a bad chunk address */
extern int    chkchunk();
extern void   dmpchunk();
extern void   dmpchunklist();
extern Chunk* hdrchunk();	/* Locate chunk header */
extern int    relchunk();
extern MEMP   getachunk();
extern MEMP   getchunk();
extern MEMP   sizchunk();
extern int    freechunk();

#define GetChunk(n,d)	getachunk((MEMS)(n),memalignsize,(CP)(d))
#define RelChunk(p,d)	relchunk((MEMP)(p),(CP)(d))
#define Destroy(p)		relchunk((MEMP)(p),(CP)0)

/*
* For the C++ fans:
*/
#define New(t)	(t*)getachunk((MEMS)sizeof(t),memalignsize,(CP)0)
#define NewM(t,d)	(t*)getachunk((MEMS)sizeof(t),memalignsize,(CP)(d))
#define NewMF(p,t,d)	if (!(p=(t*)getachunk((MEMS)sizeof(t),memalignsize,(CP)(d)))) Fail

/*
* Here are some extra functions that are mostly useful for debugging C memory
* problems. The ones with the 'n' arg have the extra capability of being able
* to handle memory chunks of any size; this is incompatible  with  the  usual
* malloc/free  package,  and  shouldn't be used if you want to go back to the
* standard C routines.
*/
#ifndef BadChunk
#define BadChunk(p,d)	badchunk((MEMP)(p),(CP)(d))
#endif
#ifndef ChkChunk
#define ChkChunk(p,d)	chkchunk((MEMP)(p),(CP)(d))
#endif
#ifndef DmpChunk
#define DmpChunk(p,d)	dmpchunk((Chunk*)(p),(CP)(d))
#endif
#ifndef DmpChunkList
#define DmpChunkList	dmpchunklist()
#endif
#ifndef HdrChunk
#define HdrChunk(p,d)	hdrchunk((MEMP)(p),(CP)(d))
#endif
#ifndef IRelChunk
#define IRelChunk(p,d)	((p)?RelChunk(p,d):0)
#endif
#ifndef GetAChunk
#define GetAChunk(n,a,d)	getachunk((MEMS)(n),(int)(a),(CP)(d))
#endif
#ifndef FreeChunk
#define FreeChunk(p,n,d)	freechunk((MEMP)(p),(MEMS)(n),(CP)(d))
#endif
#ifndef SizChunk
#define SizChunk(p,m,n,d)	sizchunk((MEMP)(p),(MEMS)(m),(MEMS)(n),(CP)(d))
#endif

/*
* Here are some versions that also test  for  failure  and  invoke  the  Fail
* macro.  They all have the return variable as the first arg. The Get* macros
* also have a type as the second arg.
*/
#ifndef BadChunkF
#define BadChunkF(r,p,d)	if (!(r=badchunk((MEMP)(p),(CP)(d)))) Fail
#endif
#ifndef ChkChunkF
#define ChkChunkF(r,p,d)	if (!(r=chkchunk((MEMP)(p),(CP)(d)))) Fail
#endif
#ifndef DmpChunkF
#define DmpChunkF(r,p,d)	if (!(r=dmpchunk((Chunk*)(p),(CP)(d)))) Fail
#endif
#ifndef HdrChunkF
#define HdrChunkF(r,p,d)	if (!(r=hdrchunk((MEMP)(p),(CP)(d)))) Fail
#endif
#ifndef RelChunkF
#define RelChunkF(r,p,d)	if (!(r=RelChunk(p,d))) Fail
#endif
#ifndef IRelChunkF
#define IRelChunkF(r,p,d)	if (!(r=((p)?RelChunk(p,d):0))) Fail
#endif
#ifndef GetAChunkF
#define GetAChunkF(r,t,n,a,d)	if (!(r=(t)getachunk((MEMS)(n),(int)(a),(CP)(d)))) Fail
#endif
#ifndef GetChunkF
#define GetChunkF(r,t,n,d)	if (!(r=(t)GetChunk(n,d))) Fail
#endif
#ifndef FreeChunkF
#define FreeChunkF(r,p,n,d)	if (!(r=freechunk((MEMP)(p),(MEMS)(n),(CP)(d)))) Fail
#endif

/*
* Here's a very special macro, which accepts a pointer to a type t, and if it
* is  null, gets a chunk of type t.  All the error handling is taken care of.
* You must give the description d, and there must be a fail label visible. An
* important  thing  about  this  macro  is  that  you  must  not use it on an
* uninitialized local variable, which will generally be filled  with  nonnull
* junk;  p  must  be  properly  initialized  to  null  for  FillChunk to work
* correctly.
*/
#ifndef FillChunk
#define FillChunk(p,t,d) if (!p) if (!(p=(t*)GetChunk(sizeof(t),d))) Fail
#endif

/*
* Here's a simpler macro which gets a chunk of type t for the pointer p.  All
* the  error  handling is taken care of.  There must be a fail label visible.
* The important difference from FillChunk is that NewChunk doesn't  check  to
* see  that  p is null, so this macro could result in a memory leak if you're
* not careful with p's old value.
*/
#ifndef NewChunk
#define NewChunk(p,t,d) if (!(p=(t*)GetChunk(sizeof(t),d))) Fail
#endif

#endif
