//===========================================================================//
// File:	memblock.hh                                                         //
// Project: MUNGA           Brick: Memory Manager                            //
// Contents: Interface specification of the memory block class               //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 10/20/94  JMA  Initial coding.                                            //
// 10/28/94  JMA  Made compatible with SGI CC                                //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#if !defined(MEMBLOCK_HPP)
#	define MEMBLOCK_HPP

#	if !defined(STYLE_HPP)
#		include <style.hpp>
#	endif

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryBlockHeader ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	class MemoryBlockHeader
	{
	public:
		#if defined(USE_SIGNATURE)
			friend int
				Is_Signature_Bad(const volatile MemoryBlockHeader *p);
		#endif

		MemoryBlockHeader
			*nextBlock;
		size_t
			blockSize;

		Logical
			TestInstance();
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryBlockBase ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class MemoryBlockBase SIGNATURED
	{
	public:
		Logical
			TestInstance()
				{return blockMemory != NULL;}

		static void
			UsageReport();
		static void
			Collapse();

	protected:
		const char
			*blockName;

		MemoryBlockHeader
			*blockMemory;			// the first record block allocated

		size_t
			blockSize,				// size in bytes of the current record block
			recordSize,				// size in bytes of the individual record
			deltaSize;				// size in bytes of the growth blocks

		Byte
			*firstHeaderRecord,	// the beginning of useful free space
			*freeRecord,			// the next address to allocate from the block
			*deletedRecord;		// the next record to reuse

		MemoryBlockBase(
			size_t rec_size,
			size_t start,
			size_t delta,
			const char* name = NULL
		);
		~MemoryBlockBase();

		void*
			Grow();

	private:
		static MemoryBlockBase
			*firstBlock;
		MemoryBlockBase
			*nextBlock,
			*previousBlock;

		static void
			SortDeletions();
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryBlock ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class MemoryBlock:
		public MemoryBlockBase
	{
	public:
		static Logical
			TestClass();

		MemoryBlock(
			size_t rec_size,
			size_t start,
			size_t delta,
			const char* name = NULL
		):
			MemoryBlockBase(rec_size, start, delta, name)
				{}

		void*
			New();
		void
			Delete(void *Where);

		void*
			operator[](size_t Index);
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryBlockOf ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	template <class T> class MemoryBlockOf:
		public MemoryBlock
	{
	public:
		MemoryBlockOf(
			size_t start,
			size_t delta,
			const char* name=NULL
		):
			MemoryBlock(sizeof(T), start, delta, name)
		{}

		T*
			New()
				{return (T*)MemoryBlock::New();}
		void
			Delete(void *where)
				{MemoryBlock::Delete(where);}

		T*
			operator[](size_t index)
				{return (T*)MemoryBlock::operator[](index);}
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class MemoryStack:
		public MemoryBlockBase
	{
	public:
		static Logical
			TestClass();

	protected:
		Byte
			*topOfStack;
	
		MemoryStack(
			size_t rec_size,
			size_t start,
			size_t delta,
			const char* name = NULL
		):
			MemoryBlockBase(rec_size, start, delta, name)
				{topOfStack = NULL;}

		void*
			Push(const void *What);
		void*
			Push();
		void*
			Peek()
				{return (void*)topOfStack;}
		void
			Pop();
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryStackOf ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	template <class T> class MemoryStackOf:
		public MemoryStack
	{
	public:
		MemoryStackOf(
			size_t start,
			size_t delta,
			const char *name
		):
			MemoryStack(sizeof(T), start, delta, name)
		{}

		T*
			Push(const T *what)
				{return (T*)MemoryStack::Push(what);}
		T*
			Peek()
				{return (T*)MemoryStack::Peek();}
		void
			Pop()
				{MemoryStack::Pop();}
	};

#endif
