-- RopeFromEditImpl.Mesa -- written by Bill Paxton, February 1981 -- last edit by Bill Paxton, December 22, 1981 9:51 am DIRECTORY RopeFrom, RopeEdit, RopeEditingAlloc, RopeReader, Rope, RopeInline, File; RopeFromEditImpl: 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] = { 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 half: Offset ← len/2; front: ROPE ← FlatSubstr[rope, start, half]; back: ROPE ← 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 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] = { 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, loc←baseNum+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, strt, oldpos, repsize, tailsize, sze: NAT; reader: RopeReader.Ref; Get: PROC [r: ROPE, begin,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]]; repsize ← Short[repSize]; tailsize ← Short[baseSize]-(oldpos←Short[len]+(strt←Short[start])); [chars,loc,charsRope] ← RopeEditingAlloc.AllocChars[sze←Short[size]]; initloc ← loc; reader ← RopeReader.GetRopeReader[]; Get[base,0,strt]; Get[replace,0,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 (size←destSize+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]]]]]]}; FlatMove: PUBLIC PROC [ base: ROPE, destLoc, start: Offset ← 0, len, baseSize: Offset ← MaxLen] RETURNS [ROPE] = { -- no-op if destLoc in [start..start+len] chars: Chars; charsRope: ROPE; initloc, loc, strt, dst, num, end, basesze: NAT; reader: RopeReader.Ref; Get: PROC [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 baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base]; IF baseSize=0 THEN RETURN[NIL]; IF start > baseSize THEN start ← baseSize; IF len=MaxLen THEN len ← MIN[len,baseSize-start]; IF destLoc IN [start..start+len] THEN RETURN[base]; IF baseSize > charsPerArray THEN { -- treat separately moving: ROPE ← FlatSubstr[base, start, len]; newbase: ROPE ← FlatDelete[base, start, len, baseSize]; IF destLoc > start THEN destLoc ← destLoc-len; RETURN [FlatInsert[newbase, destLoc, moving, baseSize-len, len]]}; dst ← Short[destLoc]; end ← (strt ← Short[start]) + (num ← Short[len]); IF dst < end THEN { -- moving left -- same as moving [dst..strt) right to end temp: NAT ← dst; dst ← end; end ← strt; strt ← temp; num ← end-strt }; [chars,loc,charsRope] ← RopeEditingAlloc.AllocChars[basesze←Short[baseSize]]; initloc ← loc; reader ← RopeReader.GetRopeReader[]; Get[0,strt]; Get[end,dst-end]; Get[strt,num]; Get[dst,basesze-dst]; RopeReader.FreeRopeReader[reader]; IF loc-initloc # basesze THEN ERROR; RETURN [qZone.NEW[Tsubstr ← [node[substr[baseSize,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]}; FlatTranspose: PUBLIC PROC [ base: ROPE, astart, alen, bstart, blen: Offset, baseSize: Offset ← MaxLen] RETURNS [ROPE] = { -- [astart..astart+alen) must not intersect [bstart..bstart+blen) chars: Chars; charsRope: ROPE; astrt, anum, bstrt, bnum, aend, bend, initloc, loc, sze: NAT; reader: RopeReader.Ref; Get: PROC [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 astart > bstart THEN { -- switch them start: Offset ← astart; len: Offset ← alen; astart ← bstart; bstart ← start; alen ← blen; blen ← len }; IF baseSize=MaxLen THEN baseSize ← RopeInline.InlineSize[base]; IF baseSize=0 THEN RETURN[NIL]; IF baseSize > charsPerArray THEN { -- treat separately newbase: ROPE ← FlatMove[base, baseSize, bstart+blen, astart, alen]; RETURN [FlatMove[newbase, baseSize, astart, bstart-alen, blen]]}; aend ← (astrt ← Short[astart])+(anum ← Short[alen]); bend ← (bstrt ← Short[bstart])+(bnum ← Short[blen]); sze ← Short[baseSize]; [chars, loc, charsRope] ← RopeEditingAlloc.AllocChars[sze]; initloc ← loc; reader ← RopeReader.GetRopeReader[]; Get[0,astrt]; Get[bstrt,bnum]; Get[aend,bstrt-aend]; Get[astrt,anum]; Get[bend,sze-bend]; RopeReader.FreeRopeReader[reader]; IF loc-initloc # sze THEN ERROR; RETURN [qZone.NEW[Tsubstr ← [node[substr[baseSize,charsRope,initloc,1+RopeEdit.Depth[charsRope]]]]]]}; -- ***** Initialization StartRopeFromEdit: PUBLIC PROC = { }; END.