// buffer.cpp: implementation of the memory class, idea originated by
// Dr. Jianfei Zhu
//////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include "buffer.h"
#include "common.h"
#include <malloc.h>

memory::memory()
{
	BUFPOS=20;
//	BUFS_BIG=5122880L;
//	BUFS_SMALL=1024576L;
	BUFS_BIG=1024576L;
	BUFS_SMALL=4096L;
	BUFSBSWITCH=2;
	init();
}

memory::memory(int bufpos, long bufs_small, long bufs_big, int bufsbswitch)
{
	BUFPOS=bufpos;
	BUFS_BIG=bufs_big;
	BUFS_SMALL=bufs_small;
	BUFSBSWITCH=bufsbswitch;
	init();
}

void memory::init()
{ 
	buffer = new char*[BUFPOS];
	start = new char*[BUFPOS];
	rest = new unsigned int[BUFPOS];        /* number of free positions */
	restsize = new unsigned int[BUFPOS];    /* max. size of buffer */

	buffer[0] = new char[BUFS_SMALL];
//	buffer[0] = new char[BUFS_BIG];
	if (buffer[0] == NULL) {
#ifdef DEBUG
		perror("initbuf 2"); 
#endif
		printf("INIT: not enough memory to run this program\n");
		exit(0);
	}
	start[0] = buffer[0];
	markbuf = buffer[0];
	markcount = 0;
//	markrest = BUFS_BIG;
//	rest[0] = BUFS_BIG;
//	restsize[0] = BUFS_BIG;
	markrest = BUFS_SMALL;
	rest[0] = BUFS_SMALL;
	restsize[0] = BUFS_SMALL;
	bufcount = 0;
}

memory::~memory()
{
	int i;
	for(i=0; i <= bufcount; i++)delete []buffer[i];

	delete []buffer;
	delete []start;
	delete []rest;
	delete []restsize;
}

char* memory::newbuf(unsigned int num,unsigned int size)
//	get num times size bytes from the buffer (if possible) 
//  RETURN: pointer to the first element
{ 
	register unsigned int i;
  	register int pos;
  	char *hlp;			// save current position in hlp 

	size += (i=(size & L2BITS))? MULTOF - i : 0;     // size must be a multiple of MULTOF
	i = num * size;
	for(pos=markcount; pos < bufcount; pos++)
		if (rest[pos] >= i) break;
	
	if (rest[pos] < i) pos = switchbuf(i);
	hlp = start[pos];
	start[pos] += i; // adjust start and rest
	rest[pos] -= i;

	return hlp;
}

int memory::switchbuf(unsigned int i)  // creates a new buffer with size >= i 
{
	bufcount++;		// the new buffer has number bufcount
	if (bufcount == BUFPOS) 
	{ 
		buffree(); bufcount--; 
		printf("The blocks are used up.\n");
		delete this;
		exit(0);

  //		freebuf(); 
	}
	if (bufcount < BUFSBSWITCH) rest[bufcount] = BUFS_SMALL;
	else{
		int j = BUFPOS/(BUFPOS-bufcount);
		if(j<12)
			rest[bufcount] = power2[j-1]*BUFS_BIG;
		else 
			rest[bufcount] = power2[11]*BUFS_BIG;
	}

	if (rest[bufcount] < i) rest[bufcount] = i;
	restsize[bufcount] = rest[bufcount];

	buffer[bufcount] = new char[rest[bufcount]];
	if (buffer[bufcount] == NULL) {
#ifdef DEBUG
		perror("switchbuf 1");
#endif
		buffree(); 
		printf("Not enough memory!\n");
		delete this;
//		freebuf(); 
	}
	start[bufcount] = buffer[bufcount]; 
	return bufcount;
} // switchbuf 

char* memory::bufmark(unsigned int*MR, int* MC)		// set a mark in the buffer for freebuf
{	
	markbuf = start[bufcount]; markcount = bufcount;
	// markrest = restsize[bufcount] - rest[bufcount];
    markrest = rest[bufcount];
	*MR=markrest; *MC = markcount;
	return markbuf;
}

/*void memory::bufmark()		// set a mark in the buffer for freebuf
{	
	markbuf = start[bufcount]; markcount = bufcount;
	// markrest = restsize[bufcount] - rest[bufcount];
    markrest = rest[bufcount]; 
}*/
void memory::freebuf(unsigned int MR, int MC, char* MB)	//clear the buffer above the mark 
{	
	int i;
//	register char *pts;
//	for(i=markcount+1; i <= bufcount; i++) 
	for(i=MC+1; i <= bufcount; i++) 
	{
//		dispose(buffer[i]);
		delete []buffer[i];
		rest[i] = 0; 
		restsize[i] = 0;
		start[i] = NULL; 
		buffer[i] = NULL;
	}
    bufcount=MC;
	
	// clear area: positions markbuf to start-1 are used
//	for(pts = start[MC]; pts != MB; *(--pts) = 0);

	start[bufcount] = MB; rest[bufcount] = MR;
}


void memory::buffree()   // delete the mark
{	
	markbuf = buffer[0]; markcount = 0; markrest = BUFS_SMALL;
}

