-- RopeEditingAllocImpl.Mesa
-- written by Bill Paxton,  March 1981
-- last edit by Bill Paxton,  December 22, 1981 9:56 am

DIRECTORY
RopeEditingAlloc,
Rope,
RopeReader,
RopeFrom;

RopeEditingAllocImpl: MONITOR
	IMPORTS RopeReader, RopeFrom
   EXPORTS RopeEditingAlloc =
BEGIN OPEN RopeEditingAlloc;

charsPerArray: NAT = RopeReader.charsPerArray;
wordsPerArray: NAT = charsPerArray/2;
charsArray: Chars ← NIL; -- current shared array of chars
charsRemaining: NAT ← 0; -- amount of room remaining in current chars array
charsRope: ROPE; -- rope pointing to current chars array

AllocChars: PUBLIC ENTRY PROC [len: NAT]
	RETURNS [chars: Chars, start: NAT, base: ROPE] = {
	-- returns chars array & starting index to fill with characters
	-- and a rope that points to that substring of the chars array
	IF len > charsRemaining THEN {
		IF len > charsPerArray THEN ERROR;
		IF charsPerArray-len < charsRemaining THEN { -- keep the current one
			chars ← RopeFrom.pZone.NEW[CharsArray]; start ← 0;
			base ← RopeReader.CharsRope[chars];
			RETURN };
		charsArray ← RopeFrom.pZone.NEW[CharsArray]; charsRemaining ← charsPerArray;
		charsRope ← RopeReader.CharsRope[charsArray] };
	chars ← charsArray;
	start ← charsPerArray-charsRemaining;
	charsRemaining ← charsRemaining-len;
	base ← charsRope };

AllocWords: PUBLIC ENTRY PROC [nwords: NAT]
	RETURNS [chars: Chars, start: NAT, base: ROPE] = {
	-- ensures that start is even, i.e., start on word boundary
	wordsRemaining: NAT;
	IF nwords > (wordsRemaining ← charsRemaining/2) THEN {
		IF nwords > wordsPerArray THEN ERROR;
		IF wordsPerArray-nwords < wordsRemaining THEN {
			chars ← RopeFrom.pZone.NEW[CharsArray]; start ← 0;
			base ← RopeReader.CharsRope[chars];
			RETURN };
		charsArray ← RopeFrom.pZone.NEW[CharsArray];
		wordsRemaining ← wordsPerArray;
		charsRope ← RopeReader.CharsRope[charsArray] };
	chars ← charsArray;
	start ← (wordsPerArray-wordsRemaining)*2;
	charsRemaining ← (wordsRemaining-nwords)*2;
	base ← charsRope };

TryAllocAdjacent: PUBLIC ENTRY PROC [base: ROPE, start: NAT, len: NAT]
	RETURNS [ok: BOOLEAN, chars: Chars] = {
	IF base=charsRope AND
		start=charsPerArray-charsRemaining AND
			charsRemaining >= len THEN {
		charsRemaining ← charsRemaining-len; RETURN [TRUE, charsArray]};
	RETURN [FALSE, charsArray]};

-- ***** buffer cache

blockSize: NAT = 512;
blk1, blk2: REF TEXT; -- shared buffers

GetBlock: PUBLIC ENTRY PROC RETURNS [blk: REF TEXT] = {
	IF blk2 # NIL THEN { blk ← blk2; blk2 ← NIL }
	ELSE IF blk1 # NIL THEN { blk ← blk1; blk1 ← NIL }
	ELSE blk ← RopeFrom.pZone.NEW[TEXT[blockSize]];
	blk.length ← 0 };

FreeBlock: PUBLIC ENTRY PROC [blk: REF TEXT] = {
	IF blk2 = NIL THEN blk2 ← blk ELSE IF blk1 = NIL THEN blk1 ← blk };


-- ***** Initialization

Start: PUBLIC PROC = {
	};

END.