//===========================================================================//
// 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                         //
//===========================================================================//

#pragma once

#include "Stuff.hpp"

namespace Stuff {

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryBlockHeader ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	class MemoryBlockHeader
	{
	public:
		MemoryBlockHeader
			*m_next;
		size_t
			m_size;

		void
			TestInstance()
				{}
	};

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

	class MemoryBlockBase
		#if defined(_ARMOR)
			: public Stuff::Signature
		#endif
	{
	public:
		void
			TestInstance()
				{Verify(m_blockMemory != NULL);}

		static void
			UsageReport();
		static void
			CollapseBlocks();

	protected:
		const char
			*m_name;

		MemoryBlockHeader
			*m_blockMemory;			// the first record block allocated

		size_t
			m_size,					// size in bytes of the current record block
			m_recordSize,			// size in bytes of the individual record
			m_growthSize;				// size in bytes of the growth blocks

		BYTE
			*m_firstHeaderRecord,	// the beginning of useful free space
			*m_freeRecord,			// the next address to allocate from the block
			*m_deletedRecord;		// the next record to reuse

		MemoryBlockBase(
			size_t rec_size,
			size_t start,
			size_t delta,
			const char* name,
			HGOSHEAP parent = ParentClientHeap
		);
		~MemoryBlockBase();

		void*
			Grow();

		HGOSHEAP
			m_heap;

	private:
		static MemoryBlockBase
			*s_firstBlock;
		MemoryBlockBase
			*m_next,
			*m_previous;

		void
			Collapse();
	};

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

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

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

		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,
			HGOSHEAP parent = ParentClientHeap
		):
			MemoryBlock(sizeof(T), start, delta, name, parent)
		{}

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

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

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

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

	protected:
		BYTE
			*m_topOfStack;
	
		MemoryStack(
			size_t rec_size,
			size_t start,
			size_t delta,
			const char* name,
			HGOSHEAP parent = ParentClientHeap
		):
			MemoryBlockBase(rec_size, start, delta, name, parent)
				{m_topOfStack = NULL;}

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

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

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

		T*
			Push(const T *what)
				{return Cast_Pointer(T*, MemoryStack::Push(what));}
		T*
			Peek()
				{return static_cast<T*>(MemoryStack::Peek());}
		void
			Pop()
				{MemoryStack::Pop();}
	};

}
