-- RopeFromEditImpl.Mesa; written by Bill Paxton, February 1981
-- edited by McGregor, February 8, 1983 11:02 am
-- edited by Bill Paxton, July 11, 1983 10:57 am
-- edited by Maxwell, January 5, 1983 12:09 pm
DIRECTORY
RopeFrom,
RopeEdit,
RopeEditingAlloc,
RopeReader,
Rope,
RopeInline,
File;
RopeFromEditImpl: CEDAR MONITOR
IMPORTS RopeInline, RopeFrom, RopeEdit, RopeEditingAlloc, RopeReader, Rope
EXPORTS RopeFrom
SHARES Rope =
BEGIN
OPEN RopeFrom, RopeInline;
CharsArray: TYPE = RopeReader.CharsArray;
Chars: TYPE = REF CharsArray;
charsPerArray: NAT = RopeReader.charsPerArray;
-- Editing Operations
FlatSubstr: PUBLIC PROC
[rope: ROPE, start: Offset ← 0, len: Offset ← MaxLen] RETURNS [ROPE] = TRUSTED {
chars: Chars;
loc, num: NAT;
base: ROPE;
substr: BOOLEANFALSE;
size: Offset ← RopeInline.InlineSize[rope];
reader: RopeReader.Ref;
IF len=MaxLen THEN {
IF start >= size THEN RETURN [NIL];
len ← MIN[len,size-start] };
IF len=0 OR rope=NIL THEN RETURN [NIL];
IF len > charsPerArray THEN { -- split into balanced parts
front, back: ROPE;
half: Offset ← len/2;
half ← ((half+charsPerArray-1)/charsPerArray)*charsPerArray; -- round up
front ← FlatSubstr[rope, start, half];
back ← FlatSubstr[rope, start+half, len-half];
RETURN [NEW[Tconcat ← [node[concat[len,front,back,half,
1+MAX[RopeEdit.Depth[front],RopeEdit.Depth[back]]]]]]] };
WITH x:rope SELECT FROM
node => WITH x:x SELECT FROM
substr => substr ← TRUE;
object => IF x.size=charsPerArray THEN
WITH x.base SELECT FROM
z: Chars => -- don't need to move the characters
IF len=charsPerArray AND start=0 THEN RETURN [rope]
ELSE RETURN [NEW[Tsubstr ←
[node[substr[len,rope,start,1+RopeEdit.Depth[rope]]]]]];
ENDCASE;
ENDCASE; ENDCASE;
[chars,loc,base] ← RopeEditingAlloc.AllocChars[num ← Short[len]];
reader ← RopeReader.GetRopeReader[];
RopeReader.SetPosition[reader, rope, start];
IF RopeReader.GetChars[reader, chars, num, loc] # num THEN ERROR;
RopeReader.FreeRopeReader[reader];
IF substr AND start=0 AND len=size THEN -- just flattening an existing substr
WITH x:rope SELECT FROM
node => WITH x:x SELECT FROM
substr => { x.base ← base; x.start ← loc; RETURN [@x] };
ENDCASE; ENDCASE;
RETURN [NEW[Tsubstr ←
[node[substr[len,base,loc,1+RopeEdit.Depth[base]]]]]]};
FlatConcat: PUBLIC PROC
[base, rest: ROPE, baseSize, restSize: Offset ← MaxLen, tryAppend: BOOLEANTRUE]
RETURNS [new: ROPE] = {
chars: Chars;
loc, baseNum, restNum: NAT;
reader: RopeReader.Ref;
charsRope: ROPE;
size: Offset;
IF baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base];
IF restSize=MaxLen THEN restSize ← RopeInline.InlineSize[rest];
IF (size ← baseSize+restSize) > charsPerArray THEN -- treat separately
RETURN [NEW[Tconcat ← [node[concat[size,base,rest,baseSize,
1+MAX[RopeEdit.Depth[base],RopeEdit.Depth[rest]]]]]]];
IF size=0 THEN RETURN[NIL];
IF tryAppend AND (new ← TryAppendConcat[base, rest, baseSize, restSize]) # NIL
THEN RETURN;
baseNum ← Short[baseSize];
restNum ← Short[restSize];
[chars, loc, charsRope] ← RopeEditingAlloc.AllocChars[Short[size]];
reader ← RopeReader.GetRopeReader[];
RopeReader.SetPosition[reader, base];
IF RopeReader.GetChars[reader, chars, baseNum, loc] # baseNum THEN ERROR;
RopeReader.SetPosition[reader, rest];
IF RopeReader.GetChars[reader, chars, restNum, loc+baseNum] # restNum THEN ERROR;
RopeReader.FreeRopeReader[reader];
RETURN [NEW[Tsubstr ← [node[substr[size,charsRope,loc,1+RopeEdit.Depth[charsRope]]]]]]};
TryAppendConcat: PUBLIC PROC [base, rest: ROPE, baseSize, restSize: Offset ← MaxLen]
RETURNS [ROPE] = TRUSTED {
chars: Chars;
size: Offset;
IF baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base];
IF restSize=MaxLen THEN restSize ← RopeInline.InlineSize[rest];
IF (size ← baseSize+restSize) > charsPerArray THEN -- treat separately
RETURN [NEW[Tconcat ← [node[concat[size,base,rest,baseSize,
1+MAX[RopeEdit.Depth[base],RopeEdit.Depth[rest]]]]]]];
IF size=0 THEN RETURN[NIL];
IF base#NIL AND rest#NIL THEN WITH--1-- x:base SELECT FROM node => WITH--2-- x:x SELECT FROM
substr => WITH--3-- z:x.base SELECT FROM node => WITH--4-- z:z SELECT FROM
object => IF z.size=charsPerArray THEN WITH--5-- z.base SELECT FROM
w: Chars => { -- base is a substr of a charsarray
WITH--6-- y:rest SELECT FROM node => WITH--7-- y:y SELECT FROM
substr => IF x.base=y.base AND x.start+x.size=y.start THEN
WITH--8-- z:x.base SELECT FROM node => WITH--9-- z:z SELECT FROM
object => IF z.size=charsPerArray THEN
WITH--10-- z.base SELECT FROM
w: Chars => -- don't need to move the characters
RETURN [NEW[Tsubstr ←
[node[substr[x.size+y.size,x.base,x.start,
1+RopeEdit.Depth[x.base]]]]]];
ENDCASE; ENDCASE; ENDCASE; ENDCASE; ENDCASE; --6..10--
{ -- try to allocate room adjacent to base
ok: BOOLEAN;
loc: NAT;
newbase: ROPE ← x.base;
xstart: Offset ← x.start;
count: NAT ← Short[restSize];
baseNum: NAT ← Short[baseSize];
[ok,chars] ← RopeEditingAlloc.TryAllocAdjacent[newbase,
loc�seNum+Short[xstart],count];
IF ok THEN { -- transfer the chars
reader: RopeReader.Ref ← RopeReader.GetRopeReader[];
RopeReader.SetPosition[reader,rest];
IF RopeReader.GetChars[reader,chars,count,loc] # count THEN ERROR;
RopeReader.FreeRopeReader[reader];
RETURN [NEW[Tsubstr ←
[node[substr[size,newbase,xstart,1+RopeEdit.Depth[newbase]]]]]] }}};
ENDCASE; ENDCASE; ENDCASE; ENDCASE; ENDCASE; --1..5--
RETURN [NIL] };
FlatReplace: PUBLIC PROC [
base: ROPE, start: Offset ← 0, len: Offset ← MaxLen, replace: ROPENIL,
size, baseSize, repSize: Offset ← MaxLen]
RETURNS [ROPE] = {
chars: Chars;
charsRope: ROPE;
initloc, loc, tailsize, sze: NAT;
reader: RopeReader.Ref;
oldpos: Offset;
Get: PROC [r: ROPE, begin: Offset, count: NAT] = {
IF count > 0 THEN {
RopeReader.SetPosition[reader,r,begin];
IF RopeReader.GetChars[reader,chars,count,loc] # count THEN ERROR;
loc ← loc+count}};
IF baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base];
IF start >= baseSize THEN
RETURN [FlatConcat[base,replace,baseSize,repSize]];
IF len=MaxLen THEN len ← MIN[len,baseSize-start];
IF repSize=MaxLen THEN repSize ← RopeInline.InlineSize[replace];
IF size=MaxLen THEN size ← baseSize-len+repSize;
IF size=0 THEN RETURN [NIL];
IF size > charsPerArray THEN -- treat separately
RETURN [Rope.Replace[base, start, len, replace]];
tailsize ← Short[baseSize-(oldpos←len+start)];
[chars,loc,charsRope] ← RopeEditingAlloc.AllocChars[sze←Short[size]];
initloc ← loc;
reader ← RopeReader.GetRopeReader[];
Get[base,0,Short[start]];
Get[replace,0,Short[repSize]];
Get[base,oldpos,tailsize];
RopeReader.FreeRopeReader[reader];
IF loc-initloc#sze THEN ERROR;
RETURN [NEW[Tsubstr ← [node[substr[size,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]};
FlatCopy: PUBLIC PROC [
dest: ROPE, destLoc: Offset ← 0,
source: ROPE, start: Offset ← 0, len: Offset ← MaxLen,
destSize: Offset ← MaxLen]
RETURNS [ROPE] = {
chars: Chars;
charsRope: ROPE;
size: Offset;
initloc, loc, dst, sze: NAT;
reader: RopeReader.Ref;
Get: PROC [base: ROPE, begin, count: NAT] = {
IF count > 0 THEN {
RopeReader.SetPosition[reader,base,begin];
IF RopeReader.GetChars[reader,chars,count,loc] # count THEN ERROR;
loc ← loc+count}};
IF len=MaxLen THEN {
sourceSize: Offset ← RopeInline.InlineSize[source];
IF start >= sourceSize THEN RETURN [dest];
len ← MIN[len,sourceSize-start] };
IF destSize=MaxLen THEN destSize ← RopeInline.InlineSize[dest];
IF destLoc > destSize THEN destLoc ← destSize;
IF (size�stSize+len) > charsPerArray THEN -- treat separately
RETURN [FlatInsert[dest,destLoc,FlatSubstr[source,start,len],destSize,len]];
IF size=0 THEN RETURN[NIL];
[chars, loc, charsRope] ← RopeEditingAlloc.AllocChars[sze ← Short[size]];
initloc ← loc;
reader ← RopeReader.GetRopeReader[];
Get[dest,0,dst←Short[destLoc]];
Get[source,Short[start],Short[len]];
Get[dest,dst,Short[destSize]-dst];
RopeReader.FreeRopeReader[reader];
IF loc-initloc # sze THEN ERROR;
RETURN [NEW[Tsubstr ← [node[substr[size,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]};
END.