-- TextLooksSupport.mesa
-- written by Bill Paxton, February 1981
-- last edit by Bill Paxton, March 24, 1981 2:27 PM

-- Internal support interface for TextLooks

DIRECTORY
Inline,
Mopcodes,
TextLooks;

TextLooksSupport: DEFINITIONS
IMPORTS Inline, Mopcodes
SHARES TextLooks =
BEGIN OPEN ops:Mopcodes, TextLooks;

-- support procedures

BaseRun: PROC
[x: BaseRuns, index: Card, lower: NAT ← 0, upper: NAT ← LAST[NAT]]
RETURNS [NAT];

ExtractRuns: PROC
[base: BaseRuns, ref: Runs, start, len: Card, index: NAT ← 0]
RETURNS [NAT]; -- value is next index

CountRunsAfterChanges: PROC
[ref: Runs, start, len: Card, limit: Card ← MaxCard,
remove, add: Looks, merge: BOOLEAN ← FALSE, firstLooks: Looks ← noLooks]
RETURNS [count: NAT, nonempty: BOOLEAN, lastLooks: Looks];

ExtractRunsAfterChanges: PROC
[base: BaseRuns, ref: Runs, remove, add: Looks,
start: Card, len: Card, index: NAT ← 0]
RETURNS [NAT]; -- value is next index

-- inlines

TbaseSize: PROC [x: BaseRuns] RETURNS [Card] = INLINE {
RETURN [IF x.length=0 THEN 0 ELSE x[x.length-1].after] };

InsertRun: PROC
[base: BaseRuns, len: Card, looks: Looks, index: NAT]
RETURNS [NAT] = INLINE { -- value is next index
IF index=0 THEN { base[0] ← [len, looks]; index ← 1 }
ELSE {
loc: Card ← base[index-1].after + len;
IF base[index-1].looks=looks -- merge runs
THEN base[index-1].after ← loc
ELSE { base[index] ← [loc, looks]; index ← index+1 }};
RETURN [index]};

NewBase: PROC [runs: Card] RETURNS [BaseRuns];
-- = INLINE { RETURN [NEW[base RunsBody[Short[runs]]]] };
-- can’t be an inline until compiler is fixed!

FindBaseRuns: PROC [x: BaseRuns, start, len: Card]
RETURNS [first, last: NAT] = INLINE {
first ← BaseRun[x, start];
last ← IF len>1 THEN BaseRun[x, start+len-1, first] ELSE first };

BaseRunLengths: PROC [x: BaseRuns, start, len: Card, first, last: NAT]
RETURNS [firstLen, lastLen: Card] = INLINE {
IF first=last THEN RETURN[len,len];
RETURN[x[first].after-start, start+len-x[last-1].after] };

CopyRuns: PROC [to, from: BaseRuns, toLoc, fromLoc, nRuns: NAT] = INLINE {
RunsOffset: NAT = SIZE[base RunsBody[0]];
nLeft: NAT;
IF nRuns=0 THEN RETURN;
IF fromLoc >= from.length OR toLoc >= to.length THEN ERROR;
nLeft ← nRuns-1;
to[toLoc+nLeft] ← from[fromLoc+nLeft]; -- bounds check
Inline.LongCOPY[
from: LOOPHOLE[from,LONG POINTER]+fromLoc*SIZE[Run]+RunsOffset,
to: LOOPHOLE[to,LONG POINTER]+toLoc*SIZE[Run]+RunsOffset,
nwords: nLeft*SIZE[Run]]};

CARD: PROC [u: UNSPECIFIED] RETURNS [CARDINAL] =
INLINE { RETURN [LOOPHOLE[u]] };

LU: PROC [u: Looks] RETURNS [LONG UNSPECIFIED] =
INLINE { RETURN [LOOPHOLE[u]] };

ModifyLooks: PROC [old, remove, add: Looks] RETURNS [Looks] = INLINE {
-- compute (old & ~remove) v add
OPEN Inline;
lowbits: CARDINAL ← CARD[BITOR[LowHalf[LU[add]],
BITAND[BITNOT[LowHalf[LU[remove]]],LowHalf[LU[old]]]]];
highbits: CARDINAL ← CARD[BITOR[HighHalf[LU[add]],
BITAND[BITNOT[HighHalf[LU[remove]]],HighHalf[LU[old]]]]];
looks: num LongNumber ← LongNumber[num[lowbits:lowbits, highbits:highbits]];
RETURN [LOOPHOLE[looks]] };

MergeChanges: PROC [oldrem, oldadd, rem, add: Looks]
RETURNS [newrem, newadd: Looks] = INLINE {
--
((lks & ~oldrem) v oldadd) & ~rem) v add ==
--
lks & ~(oldrem v rem)) v ((oldadd & ~rem) v add
--
thus, newrem ← oldrem v rem, newadd ← (oldadd & ~rem) v add
OPEN Inline;
lowbits: CARDINAL ← CARD[BITOR[LowHalf[LU[oldrem]],LowHalf[LU[rem]]]];
highbits: CARDINAL ← CARD[BITOR[HighHalf[LU[oldrem]],HighHalf[LU[rem]]]];
looks: num LongNumber ← LongNumber[num[lowbits:lowbits, highbits:highbits]];
newrem ← LOOPHOLE[looks];
newadd ← ModifyLooks[oldadd, rem, add]};

-- miscellaneous support routines

Pair: TYPE = MACHINE DEPENDENT RECORD [low,high: CARDINAL];

Short: PROC [x: Card] RETURNS [NAT] = MACHINE CODE {
-- quick range check and shortening
ops.zLI1; ops.zBNDCK; ops.zPOP; ops.zLINI; ops.zBNDCK};

CheckLongSub: PROC [x,y: Card] RETURNS [Card] = MACHINE CODE {
ops.zDSUB; ops.zLINI; ops.zBNDCK};

END.