!	Dynamic memory mangement routines for T3X
!	Copyright (C) 1997,1998 Nils M Holm

const	FREEBIT		= 32768;


mem_init(arena, size) do
	arena[1] := size-2 | FREEBIT;
	arena[size-1] := 0;
	arena[0] := 1;
end


mem_walk(blk, sizep, statp, start) do
	var	b;

	if (\start) blk := @blk[(blk[%1] & ~FREEBIT) - 1];
	if (sizep) sizep[0] := (blk[0] & ~FREEBIT) - 1;
	if (statp) statp[0] := (blk[0] & FREEBIT) \= 0;
	if (\blk[0]) return 0;
	return @blk[1];
end


mem_alloc(arena, size) do
	var	ap, k, i;

	while (1) do
		size := size+1;
		ap := arena[0];
		while (arena[ap]) do
			k := arena[ap];
			if (k & FREEBIT) do
				k := k & ~FREEBIT;
				ie (size = k) do
					arena[0] := ap;
					arena[ap] := k;
					return(@arena[ap+1]);
				end
				else if (size < k) do
					arena[0] := ap;
					arena[ap] := size;
					arena[ap+size] := k-size | FREEBIT;
					return(@arena[ap+1]);
				end
			end
			ap := ap + (k & ~FREEBIT);
		end
		if (arena[0] = 1) return 0;
		arena[0] := 1;
	end
end


mem_free(arena, blk) do
	var	ap, k;
	var	head, tail;

	if (blk .< arena \/ blk[%1] & FREEBIT) do
		select(1, 2);
		writes("mem_free(): bad block"); newline();
		halt;
	end
	blk[%1] := blk[%1] | FREEBIT;
	ap := 1;
	head := %1;
	while (@arena[ap] .< blk) do
		if (arena[ap] = 0) do
			select(1, 2);
			writes("mem_free(): bad block"); newline();
			halt;
		end
		ie (arena[ap] & FREEBIT) do
			if (head = %1) head := ap;
			if (ap .< arena[0]) arena[0] := ap;
		end
		else do
			head := %1;
		end
		tail := ap;
		ap := ap + (arena[ap] & ~FREEBIT);
	end
	while (arena[ap]) do
		if (\(arena[ap] & FREEBIT)) leave;
		tail := ap;
		ap := ap + (arena[ap] & ~FREEBIT);
	end
	tail := tail + (arena[tail] & ~FREEBIT);
	arena[head] := tail-head | FREEBIT;
end

