<> <> <> <> DIRECTORY Basics USING [bytesPerWord], Checksum USING [ComputeChecksum], Rope, RopePrivate, RopeHash USING [PureText], RefText USING [ObtainScratch, ReleaseScratch]; RopeHashImpl: CEDAR PROGRAM IMPORTS Checksum, Rope, RopePrivate, RefText EXPORTS RopeHash SHARES Rope = BEGIN OPEN RopeHash; ROPE: TYPE = Rope.ROPE; Text: TYPE = Rope.Text; defaultSeed: CARDINAL = 31415; bytesPerWord: NAT = Basics.bytesPerWord; bufSize: NAT = 128*bytesPerWord; TextSize: NAT = SIZE[TEXT[0]]; WordAsChars: TYPE = PACKED ARRAY [0..bytesPerWord) OF CHAR; FromRefText: PUBLIC PROC [text: PureText, seed: CARDINAL] RETURNS [hash: CARDINAL] = TRUSTED { len: NAT _ text.length; nLeft: NAT = len MOD bytesPerWord; nWhole: NAT = len - nLeft; p: LONG POINTER = LOOPHOLE[text, LONG POINTER] + TextSize; hash _ seed; IF nWhole >= bytesPerWord THEN { hash _ Checksum.ComputeChecksum[hash, nWhole/bytesPerWord, p]; }; IF nLeft # 0 THEN TRUSTED { leftovers: WordAsChars _ ALL[0C]; FOR j: NAT IN [0..nLeft) DO leftovers[j] _ Rope.QFetch[LOOPHOLE[text], nWhole+j]; ENDLOOP; hash _ Checksum.ComputeChecksum[hash, SIZE[WordAsChars], @leftovers]; }; }; FromRope: PUBLIC PROC [rope: ROPE, case: BOOL, start: INT, len: INT, seed: CARDINAL] RETURNS [hash: CARDINAL] = TRUSTED { rem: INT _ RopePrivate.NonNeg[Rope.InlineLength[rope] - RopePrivate.NonNeg[start]]; IF rem < len THEN len _ rem; <> IF case AND start = 0 AND rem = len THEN WITH rope SELECT FROM text: Text => <> RETURN[FromRefText[LOOPHOLE[text], seed]]; ENDCASE; { <> buf: REF TEXT _ RefText.ObtainScratch[bufSize]; p: LONG POINTER = LOOPHOLE[buf, LONG POINTER] + SIZE[TEXT[0]]; bytes: NAT _ 0; hash _ seed; WHILE rem > 0 DO buf.length _ 0; bytes _ Rope.AppendChars[buf, rope, start, rem]; IF NOT case THEN <> FOR i: NAT IN [0..bytes) DO c: CHAR = Rope.QFetch[LOOPHOLE[buf], i]; IF c <= 'Z AND c >= 'A THEN RopePrivate.QStore[c + ('a-'A), LOOPHOLE[buf], i]; ENDLOOP; hash _ FromRefText[buf, hash]; start _ start + bytes; rem _ rem - bytes; ENDLOOP; RefText.ReleaseScratch[buf]; RETURN [hash]; }; }; END.