<> <> <> <> <> <> <> <<>> <> <<>> <> DIRECTORY Basics USING [Comparison], PrincOps USING [zBNDCK, zLI0, zRSTRL]; Rope: CEDAR DEFINITIONS = BEGIN <> ROPE: TYPE = REF RopeRep; NoRope: ERROR; <<... is signalled if rope is invalid variant or some other invariant has broken. This is a serious error, and indicates that either storage is corrupted, or the user has supplied a bad routine when making a rope, or some other nasty bug.>> <> <<>> <> Cat: PROC [r1, r2, r3, r4, r5: ROPE _ NIL] RETURNS [ROPE]; <<... returns the concatenation of up to five ropes (limit based on eval stack depth). BoundsFault occurs if the result would be longer than LAST[INT].>> Concat: PROC [base,rest: ROPE _ NIL] RETURNS [ROPE]; <<... is the two-rope (faster) version of Cat. BoundsFault occurs if the result would be longer than LAST[INT].>> Compare: PROC [s1, s2: ROPE, case: BOOL _ TRUE] RETURNS [Basics.Comparison]; <<... returns the lexicographic comparison of the two ropes based on CHAR collating sequence. case => case of characters is significant.>> Equal: PROC [s1, s2: ROPE, case: BOOL _ TRUE] RETURNS [BOOL]; <<... tests contents equality of s1 and s2. Faster than Compare. case => case of characters is significant.>> Fetch: PROC [base: ROPE, index: INT _ 0] RETURNS [c: CHAR]; <<... fetches indexed character from given ropes. BoundsFault occurs if index < 0 or index is >= Length[base].>> InlineFetch: PROC [base: ROPE, index: INT] RETURNS [c: CHAR] = TRUSTED INLINE { <<... is the fast version of Fetch, since no procedure call is done when the rope is flat.>> IF base # NIL THEN { first: CARDINAL _ LOOPHOLE[base, LONG POINTER TO CARDINAL]^; IF first < 100000B --base.tag=text-- THEN RETURN [QFX[base, index, first]]; }; RETURN [Fetch[base, index]]; }; Index: PROC [s1: ROPE, pos1: INT _ 0, s2: ROPE, case: BOOL _ TRUE] RETURNS [INT]; <<... returns the smallest character position N such that N >= pos1 and Equal[Substr[s1, N, Length[s2], s2, case]. If s2 does not occur in s1 at or after pos1, Length[s1] is returned. case => case of characters is significant. BoundsFault occurs when pos1 < 0.>> Find: PROC [s1, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE] RETURNS [INT]; <<... is like Index, returning the smallest character position N such that N >= pos1 and Equal[Substr[s1, N, Length[s2], s2, case], except that Find returns -1 if not found. case => case of characters is significant. BoundsFault occurs when pos1 < 0.>> IsEmpty: PROC [r: ROPE] RETURNS [BOOL]; <<... is equivalent to Length[r] = 0.>> InlineIsEmpty: PROC [r: ROPE] RETURNS [BOOL] = TRUSTED INLINE { <<... is the fast version of IsEmpty.>> IF r = NIL THEN RETURN [TRUE]; { first: INTEGER _ LOOPHOLE[r, LONG POINTER TO INTEGER]^; IF first > 0 THEN RETURN [FALSE]; IF first = 0 THEN RETURN [TRUE]; }; RETURN [LOOPHOLE[r, REF node RopeRep].size = 0]; }; Length: PROC [base: ROPE] RETURNS [INT]; <<... returns the # of characters in the given rope.>> InlineLength: PROC [base: ROPE] RETURNS [INT] = TRUSTED INLINE { <<... returns Length[base].>> 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 node RopeRep].size]; }; Size: PROC [base: ROPE] RETURNS [INT]; <> 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 node RopeRep].size]; }; Replace: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen, with: ROPE _ NIL] RETURNS [ROPE]; <<... returns rope with given range replaced by new. BoundsFault occurs when start < 0 or start > Length[base] or the result would be longer than LAST[INT].>> Substr: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen] RETURNS [ROPE]; <<... returns a subrope of the base. BoundsFault occurs if start < 0 or start > Length[base].>> <> Run: PROC [s1: ROPE, pos1: INT _ 0, s2: ROPE, pos2: INT _ 0, case: BOOL _ TRUE] RETURNS [INT]; <<... returns largest number of chars N such that Equal[Substr[s1,pos1,N], Substr[s2,pos2,N], case]. 0 is returned if pos1 >= Length[s1] or pos2 >= Length[s2]. BoundsFault is raised if pos1 < 0 or pos2 < 0.>> Match: PROC [pattern, object: ROPE, case: BOOL _ TRUE] RETURNS [BOOL]; <<... returns TRUE iff object matches the pattern, where the pattern may contain * to indicate that 0 or more characters will match. If case is true, then case matters. >> SkipTo: PROC [s: ROPE, pos: INT _ 0, skip: ROPE] RETURNS [INT]; <<... returns the lowest position N in s such that s[N] is in the skip rope and N >= pos. If pos > Length[s] or no such character occurs in s, then return Length[s]. BoundsFault occurs when pos < 0.>> SkipOver: PROC [s: ROPE, pos: INT _ 0, skip: ROPE] RETURNS [INT]; <<... returns the lowest position N in s such that s[N] is NOT in the skip rope and N >= pos. If pos > Length[s] or no such character occurs in s, then return Length[s]. BoundsFault occurs when pos < 0.>> Map: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen, action: ActionType] RETURNS [BOOL]; <<... applies the action to the given range of characters in the rope. Returns TRUE when some action returns TRUE. BoundsFault occurs when start < 0 or start > Length[base].>> Translate: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen, translator: TranslatorType _ NIL] RETURNS [new: ROPE]; <<... applies the translation to get a new rope. If the resulting size > 0, then new does not share with the original rope! If translator = NIL, the identity translation is performed>> Flatten: PROC [base: ROPE, start: INT _ 0, len: INT _ MaxLen] RETURNS [Text]; <<... returns a flat rope from the given range of characters. BoundsFault occurs if the resulting length would be > LAST[NAT].>> InlineFlatten: PROC [r: ROPE] RETURNS [Text] = TRUSTED INLINE { <<... is the fast version of Flatten, since there is no procedure call for something already flat.>> 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]; <<... returns a new rope given a proc to apply for each CHAR>> NewText: PROC [size: NAT] RETURNS [Text]; <<... returns a new Rope.Text, contents uninitialized, Length[NewText[size]] = size>> FromRefText: PROC [s: REF READONLY TEXT] RETURNS [Text]; <<... makes a rope from a REF READONLY TEXT>> <> ToRefText: PROC [base: ROPE] RETURNS [REF TEXT]; <<... makes a REF TEXT from a rope>> <> FromChar: PROC [c: CHAR] RETURNS [Text]; <<... makes a rope from a character>> MakeRope: PROC [base: REF, size: INT, fetch: FetchType, map: MapType _ NIL, append: AppendCharsType _ NIL] RETURNS [ROPE]; <<... returns a rope using user-supplied procedures and data. Note that the user procedures MUST survive as long as the rope does!>> AppendChars: PROC[buffer: REF TEXT, rope: ROPE, start: INT _ 0, len: INT _ LAST[INT]] RETURNS [charsMoved: NAT]; <<... appends characters to the end of a REF TEXT buffer, starting at start within the rope. The move stops if there are no more characters from the rope OR len characters have been moved OR the buffer is full (buffer.length = buffer.maxLength). charsMoved is always the # of characters appended. NOTE: the user is responsible for protecting buffer from concurrent modifications.>> ContainingPiece: PROC [rope: ROPE, index: INT _ 0] RETURNS [base: ROPE, start: INT, len: INT]; <<... finds the largest piece containg the given index such that the result is either a text or an object variant. (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]; <<... returns a balanced rope, possibly with much copying of components>> <> <> < Size[base] => bounds fault >> <> VerifyStructure: PROC [s: ROPE] RETURNS [leaves, nodes, maxDepth: INT]; <<... traverses the structure of the given rope; return the number of leaves, nodes and the max depth of the rope extra checking is performed to verify invariants a leaf is a text or object variant a node is a non-NIL, non-leaf variant shared leaves and nodes are multiply counted.>> VerifyFailed: ERROR; <> <> <> FetchType: TYPE = PROC [data: REF, index: INT] RETURNS [CHAR]; <<... is the type of fetch routine used to make a user rope.>> MapType: TYPE = PROC [base: REF, start, len: INT, action: ActionType] RETURNS [quit: BOOL _ FALSE]; <<... is the type of user routine used to map over a subrope; returns TRUE if some action returns TRUE.>> ActionType: TYPE = PROC [c: CHAR] RETURNS [quit: BOOL _ FALSE]; <<... is the type of routine applied when mapping; returns TRUE to quit from Map.>> TranslatorType: TYPE = PROC [old: CHAR] RETURNS [new: CHAR]; <<... is the type of routine supplied to Translate.>> AppendCharsType: TYPE = PROC [buffer: REF TEXT, data: REF, start: INT, len: INT] RETURNS [charsMoved: NAT]; <<... is the type of user routine used to append characters to the end of a REF TEXT buffer. The move should stop if there are no more characters from the rope OR len characters have been moved OR the buffer is full (buffer.length = buffer.maxLength). charsMoved is always the # of characters appended. The data given is from the object variant.>> 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 }; <> QFX: PRIVATE PROC [base: ROPE, index: CARDINAL, bound: CARDINAL] RETURNS [CHAR] = TRUSTED MACHINE CODE { PrincOps.zBNDCK; PrincOps.zRSTRL, 4 }; <> RopeRep: PRIVATE TYPE = RECORD [ SELECT tag: * FROM text => [length: NAT, text: PACKED SEQUENCE max: CARDINAL OF CHAR], node => [ size: INT, cases: SELECT case: * FROM substr => [base: ROPE, start: INT, depth: INTEGER], concat => [base, rest: ROPE, pos: INT, depth: INTEGER], replace => [base, replace: ROPE, start, oldPos, newPos: INT, depth: INTEGER], object => [base: REF, fetch: FetchType, map: MapType, append: AppendCharsType] 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. <> <<>> <> <<>> <> <<>> <> < {>> <> <<[0..x.size) in x ==> [x.start..x.start+x.size) in x.base>> <= x.start + x.size >> <<};>> < {>> <> <<[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>> <> <<};>> < {>> <> <<[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>> <> <<};>> < {>> <> <> <> <> <> <<};>> < ERROR NoRope>> <<}>> < ERROR NoRope>>