<> <> <> <> <<*** Part 1: Basic operations and definitions>> <<*** Part 2: Extended operations and definitions>> <<*** Part 3: Miscellaneous definitions >> <> <> DIRECTORY Basics USING [Comparison, LowHalf], PrincOps USING [zRSTRL, zLI0]; Rope: CEDAR DEFINITIONS IMPORTS Basics -- *** Part 1: Basic operations and definitions *** -- = BEGIN ROPE: TYPE = REF RopeRep; NoRope: ERROR; <> <> <> <> Cat: PROC [r1, r2, r3, r4, r5, r6: ROPE _ NIL] RETURNS [ROPE]; <> <> Concat: PROC [base,rest: ROPE _ NIL] RETURNS [ROPE]; <> <> Compare: PROC [s1, s2: ROPE, case: BOOL _ TRUE] RETURNS [Basics.Comparison]; <> < case of characters is significant>> Equal: PROC [s1, s2: ROPE, case: BOOL _ TRUE] RETURNS [BOOL]; <> < case of characters is significant>> Fetch: PROC [base: ROPE, index: INT _ 0] RETURNS [c: CHAR]; <> <= the rope size>> InlineFetch: PROC [base: ROPE, index: INT] RETURNS [c: CHAR] = TRUSTED INLINE { IF base # NIL THEN {first: INTEGER _ LOOPHOLE[base, LONG POINTER TO INTEGER]^; IF first > 0 AND index < first THEN RETURN [QFetch[LOOPHOLE[base, Text], Basics.LowHalf[index]]]}; RETURN [Fetch[base, index]]}; Find: PROC [s1, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE] RETURNS [INT]; <> <> < case of characters is significant>> Index: PROC [s1: ROPE, pos1: INT _ 0, s2: ROPE, case: BOOL _ TRUE] RETURNS [INT]; <> <= pos1. If s2 does not>> <> < case of characters is significant>> IsEmpty: PROC [r: ROPE] RETURNS [BOOL] = INLINE {RETURN [InlineSize[r] = 0]}; InlineIsEmpty: PROC [r: ROPE] RETURNS [BOOL] = INLINE {RETURN [InlineSize[r] = 0]}; Length: PROC [base: ROPE] RETURNS [INT]; Size: PROC [base: ROPE] RETURNS [INT]; <> Replace: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen, with: ROPE _ NIL] RETURNS [ROPE]; <> <> <> InlineLength, InlineSize: PROC [base: ROPE] RETURNS [INT] = TRUSTED INLINE { IF base = NIL THEN RETURN [0]; {first: INTEGER _ LOOPHOLE[base, LONG POINTER TO INTEGER]^; IF first >= 0 THEN RETURN [ExtendPositive[first]]}; RETURN [LOOPHOLE[base, REF object node RopeRep].size]; }; Substr: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen] RETURNS [ROPE]; <> <> -- *** Part 2: Extended operations and definitions *** -- Run: PROC [s1: ROPE, pos1: INT _ 0, s2: ROPE, pos2: INT _ 0, case: BOOL _ TRUE] RETURNS [INT]; <> <> <> <> Match: PROC [pattern, object: ROPE, case: BOOL _ TRUE] RETURNS [BOOL]; <> <<* to indicate that 0 or more characters will match.>> <> SkipTo: PROC [s: ROPE, pos: INT _ 0, skip: ROPE] RETURNS [INT]; <> <= pos. If no such character occurs in s, then return s.length.>> SkipOver: PROC [s: ROPE, pos: INT _ 0, skip: ROPE] RETURNS [INT]; <> <= pos. If no such character occurs in s, then return s.length.>> Map: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen, action: ActionType] RETURNS [BOOL]; <> <> <> Translate: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen, translator: TranslatorType _ NIL] RETURNS [new: ROPE]; <> < 0, then new does not share with the original rope!>> <> Flatten: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen] RETURNS [Text]; <> < LAST[NAT]>> InlineFlatten: PROC [r: ROPE] RETURNS [Text] = TRUSTED INLINE { IF r = NIL THEN RETURN [NIL]; IF LOOPHOLE[r, LONG POINTER TO INTEGER]^ >= 0 THEN RETURN [LOOPHOLE[r]]; RETURN [Flatten[r]]}; FromProc: PROC [len: INT, p: PROC RETURNS [CHAR], maxPiece: INT _ MaxLen] RETURNS [ROPE]; <> NewText: PROC [size: NAT] RETURNS [Text]; FromRefText: PROC [s: REF READONLY TEXT] RETURNS [Text]; <> <> ToRefText: PROC [base: ROPE] RETURNS [REF TEXT]; <> <> FromChar: PROC [c: CHAR] RETURNS [Text]; <> MakeRope: PROC [base: REF, size: INT, fetch: FetchType, map: MapType _ NIL, pieceMap: PieceMapType _ NIL] RETURNS [ROPE]; <> <> PieceMap: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen, action: PieceActionType, mapUser: BOOL _ TRUE] RETURNS [BOOL]; <> <<2 pieces/Concat, 3 pieces/Replace, either 1 piece/MakeRope or use user's>> <> <> ContainingPiece: PROC [ref: ROPE, index: INT _ 0] RETURNS [base: ROPE, start: INT, len: INT]; <> <> <<(NIL, 0, 0) is returned if the index is NOT in the given rope>> Balance: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen, flat: INT _ FlatMax] RETURNS [ROPE]; <> <> <> < Size[base] => bounds fault >> <> VerifyStructure: PROC [s: ROPE] RETURNS [leaves, nodes, maxDepth: INT]; <> <> <> <> VerifyFailed: ERROR; <> <> -- *** Part 3: Miscellaneous definitions *** -- FetchType: TYPE = PROC [data: REF, index: INT] RETURNS [CHAR]; <> MapType: TYPE = PROC [base: REF, start, len: INT, action: ActionType] RETURNS [quit: BOOL _ FALSE]; <> <> ActionType: TYPE = PROC [c: CHAR] RETURNS [quit: BOOL _ FALSE]; <> <> TranslatorType: TYPE = PROC [old: CHAR] RETURNS [new: CHAR]; <> PieceMapType: TYPE = PROC [base: REF, start, len: INT, action: PieceActionType] RETURNS [quit: BOOL _ FALSE]; <> <> PieceActionType: TYPE = PROC [base: ROPE, start: INT, len: INT] RETURNS [quit: BOOL _ FALSE]; <> <> ExtendPositive: PRIVATE PROC [x: INTEGER] RETURNS [INT] = TRUSTED MACHINE CODE {PrincOps.zLI0}; QFetch: PRIVATE PROC [base: Text, index: CARDINAL] RETURNS [CHAR] = TRUSTED MACHINE CODE {PrincOps.zRSTRL, 4}; <> RopeRep: PRIVATE TYPE = RECORD [SELECT tag: * FROM text => [length: NAT, text: PACKED SEQUENCE max: CARDINAL OF CHAR], node => [SELECT case: * FROM substr => [size: INT, base: ROPE, start: INT, depth: INTEGER], concat => [size: INT, base, rest: ROPE, pos: INT, depth: INTEGER], replace => [size: INT, base, replace: ROPE, start, oldPos, newPos: INT, depth: INTEGER], object => [size: INT, base: REF, fetch: FetchType, map: MapType, pieceMap: PieceMapType] ENDCASE] ENDCASE]; MaxLen: INT = LAST[INT]; FlatMax: CARDINAL = 24; Text: TYPE = REF TextRep; -- the small, flat variant handle TextRep: TYPE = RopeRep[text]; -- useful for creating new text variants END. For those who care, this is the official explanation of the RopeRep variants: Note: NIL is allowed as a valid ROPE. Note: ALL integer components of the representation must be non-negative. SELECT x: x FROM text => {-- [0..x.length) is the range of char indexes <<[0..x.max) is the number of chars of storage reserved>> <> <> <> }; node => {SELECT x:x FROM substr => {-- [0..x.size) is the range of char indexes <> <<[0..x.size) in x ==> [x.start..x.start+x.size) in x.base>> <= x.start + x.base >> }; concat => {-- [0..x.size) is the range of char indexes <> <<[0..x.pos) in x ==> [0..x.pos) in x.base>> <> <<[x.pos..x.size) in x ==> [0..x.size-x.pos) in x.base>> <> }; replace => {-- [0..x.size) is the range of char indexes <> <<[0..x.start) in x ==> [0..x.start) in x.base>> <<[x.newPos..x.size) in x ==> [x.oldPos..Size[x.base]) in x.base>> <> <<[x.start..x.newPos) in x => [0..x.newPos-x.start) in x.base>> <= x.newPos >= x.start AND x.oldPos >= x.start>> <> }; object => {-- [0..x.size) is the range of char indexes <> <> <> <> <> <> <> }; ENDCASE => ERROR NoRope} ENDCASE => ERROR NoRope};