/* $Header$ */
/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 */
#include	"param.h"
#include	"impl.h"
#include	"check.h"
#include	"log.h"

/*	Logical manipulations.
	The chunks are properly chained in the physical chain.
*/

privatedata mallink *free_list[MAX_FLIST];

public
link_free_chunk(register mallink *ml)
{
	/*	The free chunk ml is inserted in its proper logical
		chain.
	*/
	register mallink **mlp = &free_list[-1];
	register size_type n = size_of(ml);
	register mallink *ml1;

	assert(n < (1L << LOG_MAX_SIZE));

	do {
		n >>= 1;
		mlp++;
	}
	while (n >= MIN_SIZE);

	ml1 = *mlp;
	set_log_prev(ml, MAL_NULL);
	set_log_next(ml, ml1);
	calc_checksum(ml);
	if (ml1) {
		/* link backwards
		*/
		set_log_prev(ml1, ml);
		calc_checksum(ml1);
	}
	*mlp = ml;
}

public
unlink_free_chunk(register mallink *ml)
{
	/*	Unlinks a free chunk from (the middle of) the
		logical chain.
	*/
	register mallink *next = log_next_of(ml);
	register mallink *prev = log_prev_of(ml);

	if (!prev)	{
		/* it is the first in the chain */
		register mallink **mlp = &free_list[-1];
		register size_type n = size_of(ml);

		assert(n < (1L << LOG_MAX_SIZE));
		do {
			n >>= 1;
			mlp++;
		}
		while (n >= MIN_SIZE);
		*mlp = next;
	}
	else	{
		set_log_next(prev, next);
		calc_checksum(prev);
	}
	if (next) {
		set_log_prev(next, prev);
		calc_checksum(next);
	}
}

public mallink *
search_free_list(int class, size_t n)
{
	/*	Searches the free_list[class] for a chunk of at least size n;
		since it is searching a slightly undersized list,
		such a block may not be there.
	*/
	register mallink *ml;
	
	for (ml = free_list[class]; ml; ml = log_next_of(ml))
		if (size_of(ml) >= n)
			return ml;
	return MAL_NULL;		/* nothing found */
}

public mallink *
first_present(int class)
{
	/*	Find the index i in free_list[] such that:
			i >= class && free_list[i] != MAL_NULL.
		Return MAL_NULL if no such i exists;
		Otherwise, return the first block of this list, after
		unlinking it.
	*/
	register mallink **mlp, *ml;

	for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) {
		if ((ml = *mlp) != MAL_NULL)	{
	
			*mlp = log_next_of(ml);	/* may be MAL_NULL */
			if (*mlp) {
				/* unhook backward link
				*/
				set_log_prev(*mlp, MAL_NULL);
				calc_checksum(*mlp);
			}
			return ml;
		}
	}
	return MAL_NULL;
}

#ifdef	CHECK
public mallink *
free_list_entry(int i)	{
	/*	To allow maldump.c access to log.c's private data.
	*/
	return free_list[i];
}
#endif	/* CHECK */