-- RopeFromEditImpl.Mesa
-- written by Bill Paxton, February 1981
-- last edit by Bill Paxton, August 11, 1982 10:32 am
Last 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: BOOLEAN ← FALSE;
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 [qZone.
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 [qZone.
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 [qZone.
NEW[Tsubstr ←
[node[substr[len,base,loc,1+RopeEdit.Depth[base]]]]]]};
FlatConcat:
PUBLIC
PROC
[base, rest: ROPE, baseSize, restSize: Offset ← MaxLen, tryAppend: BOOLEAN ← TRUE]
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 [qZone.
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 [qZone.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 [qZone.
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 [qZone.
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,
locseNum+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 [qZone.
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: ROPE ← NIL,
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 [qZone.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 (sizestSize+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 [qZone.NEW[Tsubstr ← [node[substr[size,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]};
-- ***** Initialization
StartRopeFromEdit:
PUBLIC
PROC = {
};
END.