DIRECTORY MonitoredQueue, NodeProps, Process, RopeFrom, TiogaLocks, TiogaLooks, TiogaLooksOps, TiogaNode, TiogaItemClass, TiogaBasicClass, TiogaNodeOps, Rope, RopeEdit; TiogaNodeOpsImpl: CEDAR PROGRAM IMPORTS MonitoredQueue, NodeProps, Process, RopeEdit, RopeFrom, TiogaLocks, TiogaLooksOps EXPORTS TiogaNodeOps SHARES TiogaNode = BEGIN OPEN TiogaNodeOps, TiogaNode, TiogaItemClass, TiogaBasicClass; ROPE: TYPE = Rope.ROPE; ItemClasses: TYPE = RECORD[SEQUENCE maxItems: ItemClassID OF ItemClass]; items: REF ItemClasses _ NEW[ItemClasses[4]]; itemsRegistered: ItemClassID _ 0; RegisterItemClass: PUBLIC PROC [classRec: ItemClassRec, OKToOverwritePrevious: BOOL --_ FALSE--] RETURNS [ItemClassID] = BEGIN class: ItemClass _ NEW[ItemClassRec _ classRec]; FOR i: ItemClassID IN [0..itemsRegistered) DO IF items[i].flavor=classRec.flavor THEN BEGIN --re-registration IF NOT OKToOverwritePrevious THEN ERROR; items[i] _ class; RETURN [i]; END; ENDLOOP; IF itemsRegistered >= items.maxItems THEN BEGIN -- expand class array newItems: REF ItemClasses; IF itemsRegistered+1 >= invalidItemID THEN ERROR; -- too many items registered newItems _ NEW[ItemClasses[items.maxItems*2]]; FOR i: ItemClassID IN [0..itemsRegistered) DO newItems[i] _ items[i]; ENDLOOP; items _ newItems; END; items[itemsRegistered] _ class; itemsRegistered _ itemsRegistered+1; RETURN[itemsRegistered-1]; END; LookupItemID: PUBLIC PROC [flavor: ItemFlavor, buildNewClassIfLookupFails: BOOL --_ FALSE--] RETURNS [ItemClassID] = BEGIN FOR i: ItemClassID IN [0..itemsRegistered) DO IF items[i].flavor=flavor THEN RETURN [i]; ENDLOOP; IF buildNewClassIfLookupFails THEN ERROR; --Sorry, not yet implemented. RETURN[invalidItemID]; END; FetchItemClass: PUBLIC PROC [id: ItemClassID] RETURNS [ItemClass] = BEGIN RETURN[IF id>=itemsRegistered THEN NIL ELSE items[id]]; END; BasicClasses: TYPE = RECORD[SEQUENCE maxBasics: BasicClassID OF BasicClass]; basics: REF BasicClasses _ NEW[BasicClasses[4]]; basicsRegistered: BasicClassID _ 0; RegisterBasicClass: PUBLIC PROC [classRec: BasicClassRec, OKToOverwritePrevious: BOOL --_ FALSE--] RETURNS [BasicClassID] = BEGIN class: BasicClass _ NEW[BasicClassRec _ classRec]; FOR i: BasicClassID IN [0..basicsRegistered) DO IF basics[i].flavor=classRec.flavor THEN BEGIN -- re-registration IF NOT OKToOverwritePrevious THEN ERROR; basics[i] _ class; RETURN [i]; END; ENDLOOP; IF basicsRegistered >= basics.maxBasics THEN BEGIN -- expand class array newBasics: REF BasicClasses; IF basicsRegistered+1 >= invalidBasicID THEN ERROR; -- too many basics registered newBasics _ NEW[BasicClasses[basics.maxBasics*2]]; FOR i: BasicClassID IN [0..basicsRegistered) DO newBasics[i] _ basics[i]; ENDLOOP; basics _ newBasics; END; basics[basicsRegistered] _ class; basicsRegistered _ basicsRegistered+1; RETURN[basicsRegistered-1]; END; LookupBasicID: PUBLIC PROC [flavor: BasicFlavor, buildNewClassIfLookupFails: BOOL --_ FALSE--] RETURNS [BasicClassID] = BEGIN FOR i: BasicClassID IN [0..basicsRegistered) DO IF basics[i].flavor=flavor THEN RETURN [i]; ENDLOOP; IF buildNewClassIfLookupFails THEN ERROR; --Sorry, not yet implemented. RETURN[invalidBasicID]; END; FetchBasicClass: PUBLIC PROC [id: BasicClassID] RETURNS [BasicClass] = BEGIN RETURN[IF id>=basicsRegistered THEN NIL ELSE basics[id]]; END; NewBranchNode: PUBLIC PROC RETURNS [br: RefBranchNode] = BEGIN br _ NEW[branch Node]; br.last _ TRUE; END; NewTextNode: PUBLIC PROC [class: ItemClassID] RETURNS [tx: RefTextNode] = BEGIN itemClass: TiogaItemClass.ItemClass _ FetchItemClass[class]; tx _ NEW[text item Node]; tx.last _ TRUE; tx.class _ class; IF itemClass.init#NIL THEN itemClass.init[tx]; END; NewListNode: PUBLIC PROC [class: ItemClassID] RETURNS [ls: RefListNode] = BEGIN itemClass: TiogaItemClass.ItemClass _ FetchItemClass[class]; ls _ NEW[list item Node]; ls.last _ TRUE; ls.class _ class; IF itemClass.init#NIL THEN itemClass.init[ls]; END; NewBoxNode: PUBLIC PROC [class: ItemClassID] RETURNS [bx: RefBoxNode] = BEGIN itemClass: TiogaItemClass.ItemClass _ FetchItemClass[class]; bx _ NEW[box item Node]; bx.last _ TRUE; bx.class _ class; IF itemClass.init#NIL THEN itemClass.init[bx]; END; NewBasicNode: PUBLIC PROC [class: BasicClassID] RETURNS [bs: RefBasicNode] = BEGIN basicClass: TiogaBasicClass.BasicClass _ FetchBasicClass[class]; bs _ NEW[basic Node]; bs.last _ TRUE; bs.class _ class; IF basicClass.init#NIL THEN basicClass.init[bs]; END; Fetch: PUBLIC PROC [text: RefTextNode, index: Offset] RETURNS [CHAR, TiogaLooks.Looks] = { RETURN [RopeEdit.Fetch[text.rope,index], TiogaLooksOps.FetchLooks[text.runs,index]] }; FetchChar: PUBLIC PROC [text: RefTextNode, index: Offset] RETURNS [CHAR] = { RETURN [RopeEdit.Fetch[text.rope,index]] }; FetchLooks: PUBLIC PROC [text: RefTextNode, index: Offset] RETURNS [TiogaLooks.Looks] = { RETURN [TiogaLooksOps.FetchLooks[text.runs,index]] }; GetRope: PUBLIC PROC [text: RefTextNode] RETURNS [ROPE] = { RETURN [IF text=NIL THEN NIL ELSE text.rope] }; GetRuns: PUBLIC PROC [text: RefTextNode] RETURNS [TiogaLooks.Runs] = { RETURN [IF text=NIL THEN NIL ELSE text.runs] }; Size: PUBLIC PROC [text: RefTextNode] RETURNS [Offset] = { RETURN [IF text=NIL THEN 0 ELSE RopeEdit.Size[text.rope]] }; treeQueue: MonitoredQueue.MQ _ MonitoredQueue.Create[]; FreeTree: PUBLIC PROC [root: RefBranchNode] = { IF root=NIL OR root.deleted THEN RETURN; root.deleted _ TRUE; MonitoredQueue.Add[root, treeQueue] }; FreeTrees: PROC = { DO -- forever tree: REF ANY _ MonitoredQueue.Remove[treeQueue]; DoFreeTree[NARROW[tree] ! ABORTED => CONTINUE]; ENDLOOP }; nodesFreed: INT _ 0; DoFreeTree: PROC [root: RefBranchNode] = { itemClassID: ItemClassID _ 0; itemClass: TiogaItemClass.ItemClass _ FetchItemClass[itemClassID]; basicClassID: BasicClassID _ 0; basicClass: TiogaBasicClass.BasicClass _ FetchBasicClass[basicClassID]; DestroyItem: PROC [item: RefItemNode] = INLINE { IF item.class # itemClassID THEN itemClass _ FetchItemClass[itemClassID _ item.class]; IF itemClass.destroy # NIL THEN itemClass.destroy[item] }; DestroyBasic: PROC [basic: RefBasicNode] = INLINE { IF basic.class # basicClassID THEN basicClass _ FetchBasicClass[basicClassID _ basic.class]; IF basicClass.destroy # NIL THEN basicClass.destroy[basic] }; next, node: Ref; IF root.child = NIL THEN RETURN; -- has already been freed TRUSTED {Process.SetPriority[Process.priorityBackground]}; -- no rush to finish this Process.Yield[]; [] _ TiogaLocks.Lock[root, "DoFreeTree", write]; -- must make sure no one still reading it. never unlock it. node _ root; next _ NIL; DO -- go through the tree zapping REF's WITH node SELECT FROM br: RefBranchNode => IF br.contents # NIL THEN { next _ br.contents; br.contents _ NIL } ELSE { next _ br.child; br.child _ NIL }; bx: RefBoxNode => next _ bx.contents; ls: RefListNode => next _ ls.contents; ENDCASE; IF next # NIL THEN { node _ next; next _ NIL; LOOP }; next _ node.next; node.next _ NIL; node.last _ node.deleted _ TRUE; WITH node SELECT FROM tx: RefTextNode => { DestroyItem[tx]; tx.rope _ NIL; tx.runs _ NIL }; bx: RefBoxNode => { DestroyItem[bx]; bx.data _ NIL }; ls: RefListNode => { DestroyItem[ls]; ls.data _ NIL }; bc: RefBasicNode => { DestroyBasic[bc]; bc.data _ NIL }; ENDCASE; IF node.hasPropList THEN NodeProps.RemProps[node]; nodesFreed _ nodesFreed+1; IF (node _ next) = NIL THEN EXIT; ENDLOOP }; FromRope: PUBLIC PROC [rope: ROPE, class: ItemClassID _ defaultTextClassID] RETURNS [new: RefTextNode] = { new _ NewTextNode[class]; new.rope _ rope; new.last _ TRUE; new.runs _ TiogaLooksOps.CreateRun[RopeEdit.Size[rope]] }; FromString: PUBLIC PROC [ string: REF READONLY TEXT, class: ItemClassID _ defaultTextClassID] RETURNS [new: RefTextNode] = { new _ NewTextNode[class]; new.last _ TRUE; new.rope _ RopeFrom.String[string]; new.runs _ TiogaLooksOps.CreateRun[RopeEdit.Size[new.rope]] }; DocFromNode: PUBLIC PROC [child: RefItemNode] RETURNS [root: RefBranchNode] = { br: TiogaNode.RefBranchNode _ NewBranchNode[]; root _ NewBranchNode[]; root.child _ br; root.last _ TRUE; br.contents _ child; br.last _ TRUE; br.next _ root; child.last _ TRUE; child.next _ br; }; MakeNodeLoc: PUBLIC PROC [n: Ref] RETURNS [Location] = { RETURN [[[n, NIL], NodeItself]] }; MakeNodeSpan: PUBLIC PROC [first, last: Ref] RETURNS [Span] = { RETURN [[MakeNodeLoc[first], MakeNodeLoc[last]]] }; EndPos: PUBLIC PROC [n: RefTextNode] RETURNS [Offset] = {RETURN[IF n=NIL THEN 0 ELSE MAX[RopeEdit.Size[n.rope],1]-1]}; END. œTiogaNodeOpsImpl.mesa; Written by S. McGregor, February 1983 Edited by Paxton, August 30, 1983 9:40 am Edited by McGregor, August 12, 1983 11:09 am ***** Item Class registration the ItemClassID could be saved on the atom property list if this search is too slow ***** Basic Class registration the BasicClassID could be saved on the atom property list if this search is too slow ***** Node creation ***** Text node operations fetches the indexed information use readers if want info from contiquous locations fetches the indexed information use readers if want info from contiquous locations returns the looks for the character at the given location use reader's if getting looks for sequence of locations ***** Operation to free a tree by clearing all REF's FOR event: EditEvent _ editEvent.next, event.next UNTIL event = editEvent DO FOR sub: UndoEvent.SubEvent _ editEvent.undo.subevents, sub.next UNTIL sub=NIL DO IF sub.undoRef # NIL THEN WITH sub.undoRef SELECT FROM x: REF UndoEvent.Change.ChangingText => IF x.root = root THEN RETURN; x: REF UndoEvent.Change.ChangingProp => IF x.root = root THEN RETURN; x: REF UndoEvent.Change.MovingNodes => IF x.destRoot = root OR x.sourceRoot = root THEN RETURN; x: REF UndoEvent.Change.NodeNesting => IF x.root = root THEN RETURN; x: REF UndoEvent.Change.InsertingNode => IF x.root = root THEN RETURN; ENDCASE; ENDLOOP; ENDLOOP; The node has now been removed from the tree and its contents have been destroyed. ***** Operations to create a text node from a rope or a string create a text node with looks from a normal rope copies the contents of the string ***** Operation to create a document from an item node ***** Miscellaneous Κ Δ˜Jšœ<™Jšœœ˜Jšœ œ˜Jšœ˜—J˜š ž œœœœ˜OJšœ<˜J˜—J˜—šœŸ.™4J˜Jšœœ˜7J˜šžœœœ˜/Jš œœœœœ˜(Jšœœ˜šœ/œ™Lšœ>œœ™Qš œœœœ œ™6Jš œœ"œœœ™EJš œœ"œœœ™EJš œœ!œœœœ™_Jš œœ!œœœ™DJš œœ#œœœ™FJšœ™—Jšœ™—Jšœ™—J˜&J˜—šž œœ˜šœŸ ˜ Jšœœœ$˜1Jšœ œ œœ˜/Jšœ˜ J˜——Jšœ œ˜šž œœ˜*Jšœ˜JšœB˜BJšœ˜JšœG˜Gšž œœœ˜0šœ˜ Jšœ6˜6—Jšœœœ˜:—šž œœœ˜3šœ˜"Jšœ9˜9—Jšœœœ˜=—J˜Jš œœœœŸ˜:Jšœ4Ÿ˜TJ˜Jšœ1Ÿ;˜lJšœœ˜šœŸ$˜'šœœ˜šœ˜Jšœœœ%œ˜CJšœœ˜)—Jšœ%˜%Jšœ&˜&Jšœ˜—Jš œœœœœ˜5Jšœœœ˜CJ™Qšœœ˜Jšœ0œ œ˜EJšœ/œ˜5Jšœ0œ˜6Jšœ2œ˜8Jšœ˜—Jšœœ˜2J˜Jšœœœœ˜!Jšœ˜ J˜———šœŸ8™>J˜šžœœœœ*˜KJšœ˜Jšœ0™0Jšœ˜Jšœœ˜!Jšœ:˜:J˜—šž œœœ˜Jšœœœœ*˜CJšœ˜Jšœ!™!Jšœ%œ˜*J˜#Jšœ>˜>J˜——šœŸ0™6J˜šž œœœœ˜OJ˜.J˜Jšœœ˜"Jšœœ˜5Jšœ œ˜#Jšœ˜J˜——šœ™J˜š ž œœœ œœœ˜[J˜—šž œœœœ ˜?Jšœ-˜3J˜—šžœœœœ ˜7š œœœœœœœ˜?J˜———Jšœ˜J˜J˜—…—!4v