Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / SplayTreeNode.cs / 1305600 / SplayTreeNode.cs
//---------------------------------------------------------------------------- // // File: SplayTreeNode.cs // // Description: Base class for all nodes in a TextContainer or TextBlock splay // tree. // //--------------------------------------------------------------------------- using System; using MS.Internal; namespace System.Windows.Documents { // Base class for all nodes in a TextContainer or TextBlock splay tree. internal abstract class SplayTreeNode { //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods // Returns the SplayTreeNode at a symbol offset relative to this node. // On return, nodeOffset holds the relative offset of the node start // (the node may span several symbols surrounding the desired offset). internal SplayTreeNode GetSiblingAtOffset(int offset, out int nodeOffset) { SplayTreeNode node; int nodeSymbolCount; int nodeLeftSymbolCount; node = this; nodeOffset = 0; while (true) { nodeLeftSymbolCount = node.LeftSymbolCount; if (offset < nodeOffset + nodeLeftSymbolCount) { // This node is to the right of the one we're looking for. node = node.LeftChildNode; } else { nodeSymbolCount = node.SymbolCount; if (offset <= nodeOffset + nodeLeftSymbolCount + nodeSymbolCount) { // We're somewhere inside this node. nodeOffset += nodeLeftSymbolCount; break; } else { // This node is to the left of the one we're looking for. nodeOffset += nodeLeftSymbolCount + nodeSymbolCount; node = node.RightChildNode; } } } // Splay the found node. This pulls the node up to the root and // gives us amortized constant time for sequential accesses. node.Splay(); return node; } // Returns the SplayTreeNode at a char offset relative to this node. // On return, nodeCharOffset holds the relative char offset of the node start // (the node may span several symbols surrounding the desired char offset). internal SplayTreeNode GetSiblingAtCharOffset(int charOffset, out int nodeCharOffset) { SplayTreeNode node; int nodeCharCount; int nodeLeftCharCount; node = this; nodeCharOffset = 0; while (true) { nodeLeftCharCount = node.LeftCharCount; if (charOffset < nodeCharOffset + nodeLeftCharCount) { // This node is to the right of the one we're looking for. node = node.LeftChildNode; } else if (charOffset == nodeCharOffset + nodeLeftCharCount && charOffset > 0) { // This node starts at the desired char offset. // But we want instead to continue searching for the node // that ends at the char offset. node = node.LeftChildNode; } else { nodeCharCount = node.IMECharCount; if (nodeCharCount > 0 && charOffset <= nodeCharOffset + nodeLeftCharCount + nodeCharCount) { // We're somewhere inside this node. nodeCharOffset += nodeLeftCharCount; break; } else { // This node is to the left of the one we're looking for. nodeCharOffset += nodeLeftCharCount + nodeCharCount; node = node.RightChildNode; } } } // Splay the found node. This pulls the node up to the root and // gives us amortized constant time for sequential accesses. node.Splay(); return node; } // Returns the first (lowest symbol offset) logical child of a node, if // any. Only TextTreeRootNode and TextTreeTextElement nodes // ever have contained nodes. internal SplayTreeNode GetFirstContainedNode() { SplayTreeNode containedNode; containedNode = this.ContainedNode; if (containedNode == null) return null; return containedNode.GetMinSibling(); } // Returns the last (highest symbol offset) logical child of a node, if // any. Only TextTreeRootNode and TextTreeTextElement nodes // ever have contained nodes. internal SplayTreeNode GetLastContainedNode() { SplayTreeNode containedNode; containedNode = this.ContainedNode; if (containedNode == null) return null; return containedNode.GetMaxSibling(); } // Returns a node's containing node. If the node is a TextTreeRootNode, // returns null. internal SplayTreeNode GetContainingNode() { // Splaying moves this node up to the local root, so // the containing node must, afterwards, be our parent. // // Splaying here is also important for performance. // Searches with good locality will be much faster // since Splay is very cheap when called repeatedly. Splay(); return this.ParentNode; } // Returns the previous sibling node in logical (symbol offset) order. // If this node is the first node in its local binary tree, returns // null. // // This method will splay the returned node up to local root. internal SplayTreeNode GetPreviousNode() { SplayTreeNode walkerNode; SplayTreeNode previousNode; SplayTreeNodeRole role; previousNode = this.LeftChildNode; if (previousNode != null) { // Return the max node of the left child. while (true) { walkerNode = previousNode.RightChildNode; if (walkerNode == null) break; previousNode = walkerNode; } } else { // No left child, walk up the tree. role = this.Role; previousNode = this.ParentNode; while (true) { if (role == SplayTreeNodeRole.LocalRoot) { previousNode = null; break; } if (role == SplayTreeNodeRole.RightChild) break; role = previousNode.Role; previousNode = previousNode.ParentNode; } } if (previousNode != null) { // Splay to keep the tree balanced. previousNode.Splay(); } return previousNode; } // Returns the next sibling node in logical (symbol offset) order. // If this node is the last node in its local binary tree, returns // null. // // This method will splay the returned node up to local root. internal SplayTreeNode GetNextNode() { SplayTreeNode walkerNode; SplayTreeNode nextNode; SplayTreeNodeRole role; nextNode = this.RightChildNode; if (nextNode != null) { // Return the min node of the right child. while (true) { walkerNode = nextNode.LeftChildNode; if (walkerNode == null) break; nextNode = walkerNode; } } else { // No right child, walk up the tree. role = this.Role; nextNode = this.ParentNode; while (true) { if (role == SplayTreeNodeRole.LocalRoot) { nextNode = null; break; } if (role == SplayTreeNodeRole.LeftChild) break; role = nextNode.Role; nextNode = nextNode.ParentNode; } } if (nextNode != null) { // Splay to keep the tree balanced. nextNode.Splay(); } return nextNode; } // Returns the symbol offset of a node. // In the worst case this takes log time, but we use a cache that's // good for a tree generation. internal int GetSymbolOffset(uint treeGeneration) { SplayTreeNode node; int offset; offset = 0; node = this; // Each iteration walks a sibling tree. while (true) { // We can early out if we have a cache hit. // We'll always get a cache hit on the root node, if not earlier. if (node.Generation == treeGeneration && node.SymbolOffsetCache >= 0) { offset += node.SymbolOffsetCache; break; } // Splay this node up to the root, we're referencing it. node.Splay(); // Offset gets everything to the left of this node. offset += node.LeftSymbolCount; // Add the parent start edge. offset += 1; node = node.ParentNode; } // Update this node's generation and cache. this.Generation = treeGeneration; this.SymbolOffsetCache = offset; return offset; } // Returns the character offset of a node. // In the worst case this takes log time. internal int GetIMECharOffset() { SplayTreeNode node; int charOffset; charOffset = 0; node = this; // Each iteration walks a sibling tree. while (true) { // Splay this node up to the root, we're referencing it. node.Splay(); // Offset gets everything to the left of this node. charOffset += node.LeftCharCount; node = node.ParentNode; if (node == null) break; // Add the parent start edge. TextTreeTextElementNode elementNode = node as TextTreeTextElementNode; if (elementNode != null) { charOffset += elementNode.IMELeftEdgeCharCount; } } return charOffset; } // Inserts a node at a specified position. internal void InsertAtNode(SplayTreeNode positionNode, ElementEdge edge) { SplayTreeNode locationNode; bool insertBefore; if (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd) { // Insert to this node's tree. InsertAtNode(positionNode, edge == ElementEdge.BeforeStart /* insertBefore */); } else { // Insert to this node's contained tree. if (edge == ElementEdge.AfterStart) { locationNode = positionNode.GetFirstContainedNode(); insertBefore = true; } else // ElementEdge == BeforeEnd { locationNode = positionNode.GetLastContainedNode(); insertBefore = false; } if (locationNode == null) { // Inserting the first contained node. positionNode.ContainedNode = this; this.ParentNode = positionNode; Invariant.Assert(this.LeftChildNode == null); Invariant.Assert(this.RightChildNode == null); Invariant.Assert(this.LeftSymbolCount == 0); } else { InsertAtNode(locationNode, insertBefore); } } } // Inserts a node before or after an existing node. // The new node becomes the local root. internal void InsertAtNode(SplayTreeNode location, bool insertBefore) { SplayTreeNode leftSubTree; SplayTreeNode rightSubTree; SplayTreeNode containingNode; Invariant.Assert(this.ParentNode == null, "Can't insert child node!"); Invariant.Assert(this.LeftChildNode == null, "Can't insert node with left children!"); Invariant.Assert(this.RightChildNode == null, "Can't insert node with right children!"); leftSubTree = insertBefore ? location.GetPreviousNode() : location; if (leftSubTree != null) { rightSubTree = leftSubTree.Split(); containingNode = leftSubTree.ParentNode; } else { rightSubTree = location; location.Splay(); Invariant.Assert(location.Role == SplayTreeNodeRole.LocalRoot, "location should be local root!"); containingNode = location.ParentNode; } // Merge everything into a new tree. Join(this, leftSubTree, rightSubTree); // Hook up the new tree to the containing node. this.ParentNode = containingNode; if (containingNode != null) { containingNode.ContainedNode = this; } } // Removes this node from its tree. internal void Remove() { SplayTreeNode containerNode; SplayTreeNode root; SplayTreeNode leftSubTree; SplayTreeNode rightSubTree; Splay(); Invariant.Assert(this.Role == SplayTreeNodeRole.LocalRoot); containerNode = this.ParentNode; leftSubTree = this.LeftChildNode; rightSubTree = this.RightChildNode; if (leftSubTree != null) { leftSubTree.ParentNode = null; } if (rightSubTree != null) { rightSubTree.ParentNode = null; } root = Join(leftSubTree, rightSubTree); if (containerNode != null) { containerNode.ContainedNode = root; } if (root != null) { root.ParentNode = containerNode; } this.ParentNode = null; this.LeftChildNode = null; this.RightChildNode = null; } // Parents leftSubTree and rightSubTree to root. Either leftSubTree and/or // rightSubTree may be null. internal static void Join(SplayTreeNode root, SplayTreeNode leftSubTree, SplayTreeNode rightSubTree) { root.LeftChildNode = leftSubTree; root.RightChildNode = rightSubTree; Invariant.Assert(root.Role == SplayTreeNodeRole.LocalRoot); if (leftSubTree != null) { leftSubTree.ParentNode = root; root.LeftSymbolCount = leftSubTree.LeftSymbolCount + leftSubTree.SymbolCount; root.LeftCharCount = leftSubTree.LeftCharCount + leftSubTree.IMECharCount; } else { root.LeftSymbolCount = 0; root.LeftCharCount = 0; } if (rightSubTree != null) { rightSubTree.ParentNode = root; } } // Combines two trees. Every node in leftSubTree will precede every node // in rightSubTree. // leftSubTree and/or rightSubTree may be null, returns null if both // trees are null. internal static SplayTreeNode Join(SplayTreeNode leftSubTree, SplayTreeNode rightSubTree) { SplayTreeNode maxNode; Invariant.Assert(leftSubTree == null || leftSubTree.ParentNode == null); Invariant.Assert(rightSubTree == null || rightSubTree.ParentNode == null); if (leftSubTree != null) { // Get max of leftSubTree, and splay it. maxNode = leftSubTree.GetMaxSibling(); maxNode.Splay(); Invariant.Assert(maxNode.Role == SplayTreeNodeRole.LocalRoot); Invariant.Assert(maxNode.RightChildNode == null); // Then merge the two trees. // No change to any LeftSymbolCounts. maxNode.RightChildNode = rightSubTree; if (rightSubTree != null) { rightSubTree.ParentNode = maxNode; } } else if (rightSubTree != null) { maxNode = rightSubTree; Invariant.Assert(maxNode.Role == SplayTreeNodeRole.LocalRoot); } else { maxNode = null; } return maxNode; } // Splits the node's tree into two trees. This node becomes the root of // a tree containing itself and all nodes preceding. The return value // is a tree of all remaining nodes, the nodes that follow this node. internal SplayTreeNode Split() { SplayTreeNode rightSubTree; Splay(); Invariant.Assert(this.Role == SplayTreeNodeRole.LocalRoot, "location should be local root!"); rightSubTree = this.RightChildNode; if (rightSubTree != null) { rightSubTree.ParentNode = null; this.RightChildNode = null; } return rightSubTree; } // Returns the node with lowest symbol offset rooted by this node. internal SplayTreeNode GetMinSibling() { SplayTreeNode node; SplayTreeNode leftChildNode; node = this; while (true) { leftChildNode = node.LeftChildNode; if (leftChildNode == null) break; node = leftChildNode; } // Splay to keep the tree balanced. node.Splay(); return node; } // Returns the node with highest symbol offset rooted by this node. internal SplayTreeNode GetMaxSibling() { SplayTreeNode node; SplayTreeNode rightChildNode; node = this; while (true) { rightChildNode = node.RightChildNode; if (rightChildNode == null) break; node = rightChildNode; } // Splay to keep the tree balanced. node.Splay(); return node; } // Rotates this node to the top of its tree -- on exit this node will be // a tree root. // // Splaying is more than just a convenience function. It is the // mechanism we use to keep our sibling trees balanced. On each access // of a node (after moving a TextPointer to a node, or finding a // node by symbol offset, etc.) we Splay the node. With random access // this keeps the tree balanced with a maximum depth logrithmic // to its size. On sequential access, we get even better performance -- // constant time overhead in the best case. // // Many algorithm books and the internet have descriptions of the splay // tree algorithm. This is a standard implementation, nothing fancy. internal void Splay() { SplayTreeNode node; SplayTreeNode parentNode; SplayTreeNode grandParentNode; SplayTreeNodeRole nodeRole; SplayTreeNodeRole parentNodeRole; node = this; while (true) { nodeRole = node.Role; // Stop when node is the local root. if (nodeRole == SplayTreeNodeRole.LocalRoot) break; parentNode = node.ParentNode; parentNodeRole = parentNode.Role; if (parentNodeRole == SplayTreeNodeRole.LocalRoot) { // ZIG: Parent is the local root. // // | | // Y X // / \ / \ // X c ==> a Y // / \ / \ // a b b c // if (nodeRole == SplayTreeNodeRole.LeftChild) { parentNode.RotateRight(); } else { parentNode.RotateLeft(); } break; } else { grandParentNode = parentNode.ParentNode; if (nodeRole == parentNodeRole) { // ZIG-ZIG: node and parent are both left/right children. // // | | // Z X // / \ / \ // Y d a Y // / \ ==> / \ // X c b Z // / \ / \ // a b c d // if (nodeRole == SplayTreeNodeRole.LeftChild) { grandParentNode.RotateRight(); parentNode.RotateRight(); } else { grandParentNode.RotateLeft(); parentNode.RotateLeft(); } } else { // ZIG-ZAG: node is left/right child and parent is right/left child. // // | | // Z X // / \ / \ // Y d Y Z // / \ ==> / \ / \ // a X a b c d // / \ // b c // if (nodeRole == SplayTreeNodeRole.LeftChild) { parentNode.RotateRight(); grandParentNode.RotateLeft(); } else { parentNode.RotateLeft(); grandParentNode.RotateRight(); } } } } Invariant.Assert(this.Role == SplayTreeNodeRole.LocalRoot, "Splay didn't move node to root!"); } // Returns true if this node is the left/right/contained node of parentNode. internal bool IsChildOfNode(SplayTreeNode parentNode) { return (parentNode.LeftChildNode == this || parentNode.RightChildNode == this || parentNode.ContainedNode == this); } #if DEBUG // Allocates a unique debug-only identifier for a node. internal static int GetDebugId() { return _debugIdCounter++; } #endif // DEBUG #endregion Internal methods //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- #region Internal Properties // If this node is a local root, then ParentNode contains it. // Otherwise, this is the node parenting this node within its tree. internal abstract SplayTreeNode ParentNode { get; set; } // Root node of a contained tree, if any. internal abstract SplayTreeNode ContainedNode { get; set; } // Left child node in a sibling tree. internal abstract SplayTreeNode LeftChildNode { get; set; } // Right child node in a sibling tree. internal abstract SplayTreeNode RightChildNode { get; set; } // Count of symbols covered by this node and any contained nodes. internal abstract int SymbolCount { get; set; } // Count of unicode chars covered by this node and any contained nodes. internal abstract int IMECharCount { get; set; } // Count of symbols of all siblings preceding this node. internal abstract int LeftSymbolCount { get; set; } // Count of unicode chars of all siblings preceding this node. internal abstract int LeftCharCount { get; set; } // The TextContainer's generation when SymbolOffsetCache was last updated. // If the current generation doesn't match TextContainer.Generation, then // SymbolOffsetCache is invalid. internal abstract uint Generation { get; set; } // Cached symbol offset. internal abstract int SymbolOffsetCache { get; set; } // The relative position of this node in its sibling tree. internal SplayTreeNodeRole Role { get { SplayTreeNode parentNode; SplayTreeNodeRole role; parentNode = this.ParentNode; if (parentNode == null || parentNode.ContainedNode == this) { role = SplayTreeNodeRole.LocalRoot; } else if (parentNode.LeftChildNode == this) { role = SplayTreeNodeRole.LeftChild; } else { Invariant.Assert(parentNode.RightChildNode == this, "Node has no relation to parent!"); role = SplayTreeNodeRole.RightChild; } return role; } } #if DEBUG // Debug-only identifier for this node. internal int DebugId { get { return _debugId; } } #endif // DEBUG #endregion Internal Properties //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods // Moves this node up one level in its tree, while preserving the // relative order of all other nodes in the tree. // // this == X below: // // | | // X Y // / \ / \ // a Y ==> X c // / \ / \ // b c a b // private void RotateLeft() { SplayTreeNode parentNode; SplayTreeNode rightChildNode; SplayTreeNode rightChildNodeChild; Invariant.Assert(this.RightChildNode != null, "Can't rotate left with null right child!"); rightChildNode = this.RightChildNode; this.RightChildNode = rightChildNode.LeftChildNode; if (rightChildNode.LeftChildNode != null) { rightChildNode.LeftChildNode.ParentNode = this; } parentNode = this.ParentNode; rightChildNode.ParentNode = parentNode; if (parentNode == null) { // rightChildNode is the new local root. // But the local root isn't parented. } else if (parentNode.ContainedNode == this) { // rightChildNode is the new local root. parentNode.ContainedNode = rightChildNode; } else { // rightChildNode is not local root. if (this.Role == SplayTreeNodeRole.LeftChild) { parentNode.LeftChildNode = rightChildNode; } else { parentNode.RightChildNode = rightChildNode; } } rightChildNode.LeftChildNode = this; this.ParentNode = rightChildNode; // Fix rightChildNode.LeftChildNode (which has now moved to be node's LeftChildNode). rightChildNodeChild = this.RightChildNode; // Fix up the LeftSymbolCount for rightChildNode. // This node's LeftSymbolCount hasn't changed. rightChildNode.LeftSymbolCount += this.LeftSymbolCount + this.SymbolCount; rightChildNode.LeftCharCount += this.LeftCharCount + this.IMECharCount; } // Moves this node up one level in its tree, while preserving the // relative order of all other nodes in the tree. // // this == Y below: // // | | // Y X // / \ / \ // X c ==> a Y // / \ / \ // a b b c // private void RotateRight() { SplayTreeNode parentNode; SplayTreeNode leftChildNode; SplayTreeNode leftChildNodeChild; Invariant.Assert(this.LeftChildNode != null, "Can't rotate right with null left child!"); leftChildNode = this.LeftChildNode; this.LeftChildNode = leftChildNode.RightChildNode; if (leftChildNode.RightChildNode != null) { leftChildNode.RightChildNode.ParentNode = this; } parentNode = this.ParentNode; leftChildNode.ParentNode = parentNode; if (parentNode == null) { // leftChildNode is the new local root. // But the local root isn't parented. } else if (parentNode.ContainedNode == this) { // leftChildNode is the new local root. parentNode.ContainedNode = leftChildNode; } else { // leftChildNode is not local root. if (this.Role == SplayTreeNodeRole.LeftChild) { parentNode.LeftChildNode = leftChildNode; } else { parentNode.RightChildNode = leftChildNode; } } leftChildNode.RightChildNode = this; this.ParentNode = leftChildNode; // Fix leftChildNode.RightChildNode (which has now moved to be node's LeftChildNode). leftChildNodeChild = this.LeftChildNode; // Fix up the LeftSymbolCount for node. // leftChildNode's LeftSymbolCount hasn't changed. this.LeftSymbolCount -= leftChildNode.LeftSymbolCount + leftChildNode.SymbolCount; this.LeftCharCount -= leftChildNode.LeftCharCount + leftChildNode.IMECharCount; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields #if DEBUG // A debug-only identifier for this node. private int _debugId = GetDebugId(); // Debug-only counter for allocating debug ids. private static int _debugIdCounter; #endif // DEBUG #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // File: SplayTreeNode.cs // // Description: Base class for all nodes in a TextContainer or TextBlock splay // tree. // //--------------------------------------------------------------------------- using System; using MS.Internal; namespace System.Windows.Documents { // Base class for all nodes in a TextContainer or TextBlock splay tree. internal abstract class SplayTreeNode { //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods // Returns the SplayTreeNode at a symbol offset relative to this node. // On return, nodeOffset holds the relative offset of the node start // (the node may span several symbols surrounding the desired offset). internal SplayTreeNode GetSiblingAtOffset(int offset, out int nodeOffset) { SplayTreeNode node; int nodeSymbolCount; int nodeLeftSymbolCount; node = this; nodeOffset = 0; while (true) { nodeLeftSymbolCount = node.LeftSymbolCount; if (offset < nodeOffset + nodeLeftSymbolCount) { // This node is to the right of the one we're looking for. node = node.LeftChildNode; } else { nodeSymbolCount = node.SymbolCount; if (offset <= nodeOffset + nodeLeftSymbolCount + nodeSymbolCount) { // We're somewhere inside this node. nodeOffset += nodeLeftSymbolCount; break; } else { // This node is to the left of the one we're looking for. nodeOffset += nodeLeftSymbolCount + nodeSymbolCount; node = node.RightChildNode; } } } // Splay the found node. This pulls the node up to the root and // gives us amortized constant time for sequential accesses. node.Splay(); return node; } // Returns the SplayTreeNode at a char offset relative to this node. // On return, nodeCharOffset holds the relative char offset of the node start // (the node may span several symbols surrounding the desired char offset). internal SplayTreeNode GetSiblingAtCharOffset(int charOffset, out int nodeCharOffset) { SplayTreeNode node; int nodeCharCount; int nodeLeftCharCount; node = this; nodeCharOffset = 0; while (true) { nodeLeftCharCount = node.LeftCharCount; if (charOffset < nodeCharOffset + nodeLeftCharCount) { // This node is to the right of the one we're looking for. node = node.LeftChildNode; } else if (charOffset == nodeCharOffset + nodeLeftCharCount && charOffset > 0) { // This node starts at the desired char offset. // But we want instead to continue searching for the node // that ends at the char offset. node = node.LeftChildNode; } else { nodeCharCount = node.IMECharCount; if (nodeCharCount > 0 && charOffset <= nodeCharOffset + nodeLeftCharCount + nodeCharCount) { // We're somewhere inside this node. nodeCharOffset += nodeLeftCharCount; break; } else { // This node is to the left of the one we're looking for. nodeCharOffset += nodeLeftCharCount + nodeCharCount; node = node.RightChildNode; } } } // Splay the found node. This pulls the node up to the root and // gives us amortized constant time for sequential accesses. node.Splay(); return node; } // Returns the first (lowest symbol offset) logical child of a node, if // any. Only TextTreeRootNode and TextTreeTextElement nodes // ever have contained nodes. internal SplayTreeNode GetFirstContainedNode() { SplayTreeNode containedNode; containedNode = this.ContainedNode; if (containedNode == null) return null; return containedNode.GetMinSibling(); } // Returns the last (highest symbol offset) logical child of a node, if // any. Only TextTreeRootNode and TextTreeTextElement nodes // ever have contained nodes. internal SplayTreeNode GetLastContainedNode() { SplayTreeNode containedNode; containedNode = this.ContainedNode; if (containedNode == null) return null; return containedNode.GetMaxSibling(); } // Returns a node's containing node. If the node is a TextTreeRootNode, // returns null. internal SplayTreeNode GetContainingNode() { // Splaying moves this node up to the local root, so // the containing node must, afterwards, be our parent. // // Splaying here is also important for performance. // Searches with good locality will be much faster // since Splay is very cheap when called repeatedly. Splay(); return this.ParentNode; } // Returns the previous sibling node in logical (symbol offset) order. // If this node is the first node in its local binary tree, returns // null. // // This method will splay the returned node up to local root. internal SplayTreeNode GetPreviousNode() { SplayTreeNode walkerNode; SplayTreeNode previousNode; SplayTreeNodeRole role; previousNode = this.LeftChildNode; if (previousNode != null) { // Return the max node of the left child. while (true) { walkerNode = previousNode.RightChildNode; if (walkerNode == null) break; previousNode = walkerNode; } } else { // No left child, walk up the tree. role = this.Role; previousNode = this.ParentNode; while (true) { if (role == SplayTreeNodeRole.LocalRoot) { previousNode = null; break; } if (role == SplayTreeNodeRole.RightChild) break; role = previousNode.Role; previousNode = previousNode.ParentNode; } } if (previousNode != null) { // Splay to keep the tree balanced. previousNode.Splay(); } return previousNode; } // Returns the next sibling node in logical (symbol offset) order. // If this node is the last node in its local binary tree, returns // null. // // This method will splay the returned node up to local root. internal SplayTreeNode GetNextNode() { SplayTreeNode walkerNode; SplayTreeNode nextNode; SplayTreeNodeRole role; nextNode = this.RightChildNode; if (nextNode != null) { // Return the min node of the right child. while (true) { walkerNode = nextNode.LeftChildNode; if (walkerNode == null) break; nextNode = walkerNode; } } else { // No right child, walk up the tree. role = this.Role; nextNode = this.ParentNode; while (true) { if (role == SplayTreeNodeRole.LocalRoot) { nextNode = null; break; } if (role == SplayTreeNodeRole.LeftChild) break; role = nextNode.Role; nextNode = nextNode.ParentNode; } } if (nextNode != null) { // Splay to keep the tree balanced. nextNode.Splay(); } return nextNode; } // Returns the symbol offset of a node. // In the worst case this takes log time, but we use a cache that's // good for a tree generation. internal int GetSymbolOffset(uint treeGeneration) { SplayTreeNode node; int offset; offset = 0; node = this; // Each iteration walks a sibling tree. while (true) { // We can early out if we have a cache hit. // We'll always get a cache hit on the root node, if not earlier. if (node.Generation == treeGeneration && node.SymbolOffsetCache >= 0) { offset += node.SymbolOffsetCache; break; } // Splay this node up to the root, we're referencing it. node.Splay(); // Offset gets everything to the left of this node. offset += node.LeftSymbolCount; // Add the parent start edge. offset += 1; node = node.ParentNode; } // Update this node's generation and cache. this.Generation = treeGeneration; this.SymbolOffsetCache = offset; return offset; } // Returns the character offset of a node. // In the worst case this takes log time. internal int GetIMECharOffset() { SplayTreeNode node; int charOffset; charOffset = 0; node = this; // Each iteration walks a sibling tree. while (true) { // Splay this node up to the root, we're referencing it. node.Splay(); // Offset gets everything to the left of this node. charOffset += node.LeftCharCount; node = node.ParentNode; if (node == null) break; // Add the parent start edge. TextTreeTextElementNode elementNode = node as TextTreeTextElementNode; if (elementNode != null) { charOffset += elementNode.IMELeftEdgeCharCount; } } return charOffset; } // Inserts a node at a specified position. internal void InsertAtNode(SplayTreeNode positionNode, ElementEdge edge) { SplayTreeNode locationNode; bool insertBefore; if (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd) { // Insert to this node's tree. InsertAtNode(positionNode, edge == ElementEdge.BeforeStart /* insertBefore */); } else { // Insert to this node's contained tree. if (edge == ElementEdge.AfterStart) { locationNode = positionNode.GetFirstContainedNode(); insertBefore = true; } else // ElementEdge == BeforeEnd { locationNode = positionNode.GetLastContainedNode(); insertBefore = false; } if (locationNode == null) { // Inserting the first contained node. positionNode.ContainedNode = this; this.ParentNode = positionNode; Invariant.Assert(this.LeftChildNode == null); Invariant.Assert(this.RightChildNode == null); Invariant.Assert(this.LeftSymbolCount == 0); } else { InsertAtNode(locationNode, insertBefore); } } } // Inserts a node before or after an existing node. // The new node becomes the local root. internal void InsertAtNode(SplayTreeNode location, bool insertBefore) { SplayTreeNode leftSubTree; SplayTreeNode rightSubTree; SplayTreeNode containingNode; Invariant.Assert(this.ParentNode == null, "Can't insert child node!"); Invariant.Assert(this.LeftChildNode == null, "Can't insert node with left children!"); Invariant.Assert(this.RightChildNode == null, "Can't insert node with right children!"); leftSubTree = insertBefore ? location.GetPreviousNode() : location; if (leftSubTree != null) { rightSubTree = leftSubTree.Split(); containingNode = leftSubTree.ParentNode; } else { rightSubTree = location; location.Splay(); Invariant.Assert(location.Role == SplayTreeNodeRole.LocalRoot, "location should be local root!"); containingNode = location.ParentNode; } // Merge everything into a new tree. Join(this, leftSubTree, rightSubTree); // Hook up the new tree to the containing node. this.ParentNode = containingNode; if (containingNode != null) { containingNode.ContainedNode = this; } } // Removes this node from its tree. internal void Remove() { SplayTreeNode containerNode; SplayTreeNode root; SplayTreeNode leftSubTree; SplayTreeNode rightSubTree; Splay(); Invariant.Assert(this.Role == SplayTreeNodeRole.LocalRoot); containerNode = this.ParentNode; leftSubTree = this.LeftChildNode; rightSubTree = this.RightChildNode; if (leftSubTree != null) { leftSubTree.ParentNode = null; } if (rightSubTree != null) { rightSubTree.ParentNode = null; } root = Join(leftSubTree, rightSubTree); if (containerNode != null) { containerNode.ContainedNode = root; } if (root != null) { root.ParentNode = containerNode; } this.ParentNode = null; this.LeftChildNode = null; this.RightChildNode = null; } // Parents leftSubTree and rightSubTree to root. Either leftSubTree and/or // rightSubTree may be null. internal static void Join(SplayTreeNode root, SplayTreeNode leftSubTree, SplayTreeNode rightSubTree) { root.LeftChildNode = leftSubTree; root.RightChildNode = rightSubTree; Invariant.Assert(root.Role == SplayTreeNodeRole.LocalRoot); if (leftSubTree != null) { leftSubTree.ParentNode = root; root.LeftSymbolCount = leftSubTree.LeftSymbolCount + leftSubTree.SymbolCount; root.LeftCharCount = leftSubTree.LeftCharCount + leftSubTree.IMECharCount; } else { root.LeftSymbolCount = 0; root.LeftCharCount = 0; } if (rightSubTree != null) { rightSubTree.ParentNode = root; } } // Combines two trees. Every node in leftSubTree will precede every node // in rightSubTree. // leftSubTree and/or rightSubTree may be null, returns null if both // trees are null. internal static SplayTreeNode Join(SplayTreeNode leftSubTree, SplayTreeNode rightSubTree) { SplayTreeNode maxNode; Invariant.Assert(leftSubTree == null || leftSubTree.ParentNode == null); Invariant.Assert(rightSubTree == null || rightSubTree.ParentNode == null); if (leftSubTree != null) { // Get max of leftSubTree, and splay it. maxNode = leftSubTree.GetMaxSibling(); maxNode.Splay(); Invariant.Assert(maxNode.Role == SplayTreeNodeRole.LocalRoot); Invariant.Assert(maxNode.RightChildNode == null); // Then merge the two trees. // No change to any LeftSymbolCounts. maxNode.RightChildNode = rightSubTree; if (rightSubTree != null) { rightSubTree.ParentNode = maxNode; } } else if (rightSubTree != null) { maxNode = rightSubTree; Invariant.Assert(maxNode.Role == SplayTreeNodeRole.LocalRoot); } else { maxNode = null; } return maxNode; } // Splits the node's tree into two trees. This node becomes the root of // a tree containing itself and all nodes preceding. The return value // is a tree of all remaining nodes, the nodes that follow this node. internal SplayTreeNode Split() { SplayTreeNode rightSubTree; Splay(); Invariant.Assert(this.Role == SplayTreeNodeRole.LocalRoot, "location should be local root!"); rightSubTree = this.RightChildNode; if (rightSubTree != null) { rightSubTree.ParentNode = null; this.RightChildNode = null; } return rightSubTree; } // Returns the node with lowest symbol offset rooted by this node. internal SplayTreeNode GetMinSibling() { SplayTreeNode node; SplayTreeNode leftChildNode; node = this; while (true) { leftChildNode = node.LeftChildNode; if (leftChildNode == null) break; node = leftChildNode; } // Splay to keep the tree balanced. node.Splay(); return node; } // Returns the node with highest symbol offset rooted by this node. internal SplayTreeNode GetMaxSibling() { SplayTreeNode node; SplayTreeNode rightChildNode; node = this; while (true) { rightChildNode = node.RightChildNode; if (rightChildNode == null) break; node = rightChildNode; } // Splay to keep the tree balanced. node.Splay(); return node; } // Rotates this node to the top of its tree -- on exit this node will be // a tree root. // // Splaying is more than just a convenience function. It is the // mechanism we use to keep our sibling trees balanced. On each access // of a node (after moving a TextPointer to a node, or finding a // node by symbol offset, etc.) we Splay the node. With random access // this keeps the tree balanced with a maximum depth logrithmic // to its size. On sequential access, we get even better performance -- // constant time overhead in the best case. // // Many algorithm books and the internet have descriptions of the splay // tree algorithm. This is a standard implementation, nothing fancy. internal void Splay() { SplayTreeNode node; SplayTreeNode parentNode; SplayTreeNode grandParentNode; SplayTreeNodeRole nodeRole; SplayTreeNodeRole parentNodeRole; node = this; while (true) { nodeRole = node.Role; // Stop when node is the local root. if (nodeRole == SplayTreeNodeRole.LocalRoot) break; parentNode = node.ParentNode; parentNodeRole = parentNode.Role; if (parentNodeRole == SplayTreeNodeRole.LocalRoot) { // ZIG: Parent is the local root. // // | | // Y X // / \ / \ // X c ==> a Y // / \ / \ // a b b c // if (nodeRole == SplayTreeNodeRole.LeftChild) { parentNode.RotateRight(); } else { parentNode.RotateLeft(); } break; } else { grandParentNode = parentNode.ParentNode; if (nodeRole == parentNodeRole) { // ZIG-ZIG: node and parent are both left/right children. // // | | // Z X // / \ / \ // Y d a Y // / \ ==> / \ // X c b Z // / \ / \ // a b c d // if (nodeRole == SplayTreeNodeRole.LeftChild) { grandParentNode.RotateRight(); parentNode.RotateRight(); } else { grandParentNode.RotateLeft(); parentNode.RotateLeft(); } } else { // ZIG-ZAG: node is left/right child and parent is right/left child. // // | | // Z X // / \ / \ // Y d Y Z // / \ ==> / \ / \ // a X a b c d // / \ // b c // if (nodeRole == SplayTreeNodeRole.LeftChild) { parentNode.RotateRight(); grandParentNode.RotateLeft(); } else { parentNode.RotateLeft(); grandParentNode.RotateRight(); } } } } Invariant.Assert(this.Role == SplayTreeNodeRole.LocalRoot, "Splay didn't move node to root!"); } // Returns true if this node is the left/right/contained node of parentNode. internal bool IsChildOfNode(SplayTreeNode parentNode) { return (parentNode.LeftChildNode == this || parentNode.RightChildNode == this || parentNode.ContainedNode == this); } #if DEBUG // Allocates a unique debug-only identifier for a node. internal static int GetDebugId() { return _debugIdCounter++; } #endif // DEBUG #endregion Internal methods //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- #region Internal Properties // If this node is a local root, then ParentNode contains it. // Otherwise, this is the node parenting this node within its tree. internal abstract SplayTreeNode ParentNode { get; set; } // Root node of a contained tree, if any. internal abstract SplayTreeNode ContainedNode { get; set; } // Left child node in a sibling tree. internal abstract SplayTreeNode LeftChildNode { get; set; } // Right child node in a sibling tree. internal abstract SplayTreeNode RightChildNode { get; set; } // Count of symbols covered by this node and any contained nodes. internal abstract int SymbolCount { get; set; } // Count of unicode chars covered by this node and any contained nodes. internal abstract int IMECharCount { get; set; } // Count of symbols of all siblings preceding this node. internal abstract int LeftSymbolCount { get; set; } // Count of unicode chars of all siblings preceding this node. internal abstract int LeftCharCount { get; set; } // The TextContainer's generation when SymbolOffsetCache was last updated. // If the current generation doesn't match TextContainer.Generation, then // SymbolOffsetCache is invalid. internal abstract uint Generation { get; set; } // Cached symbol offset. internal abstract int SymbolOffsetCache { get; set; } // The relative position of this node in its sibling tree. internal SplayTreeNodeRole Role { get { SplayTreeNode parentNode; SplayTreeNodeRole role; parentNode = this.ParentNode; if (parentNode == null || parentNode.ContainedNode == this) { role = SplayTreeNodeRole.LocalRoot; } else if (parentNode.LeftChildNode == this) { role = SplayTreeNodeRole.LeftChild; } else { Invariant.Assert(parentNode.RightChildNode == this, "Node has no relation to parent!"); role = SplayTreeNodeRole.RightChild; } return role; } } #if DEBUG // Debug-only identifier for this node. internal int DebugId { get { return _debugId; } } #endif // DEBUG #endregion Internal Properties //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods // Moves this node up one level in its tree, while preserving the // relative order of all other nodes in the tree. // // this == X below: // // | | // X Y // / \ / \ // a Y ==> X c // / \ / \ // b c a b // private void RotateLeft() { SplayTreeNode parentNode; SplayTreeNode rightChildNode; SplayTreeNode rightChildNodeChild; Invariant.Assert(this.RightChildNode != null, "Can't rotate left with null right child!"); rightChildNode = this.RightChildNode; this.RightChildNode = rightChildNode.LeftChildNode; if (rightChildNode.LeftChildNode != null) { rightChildNode.LeftChildNode.ParentNode = this; } parentNode = this.ParentNode; rightChildNode.ParentNode = parentNode; if (parentNode == null) { // rightChildNode is the new local root. // But the local root isn't parented. } else if (parentNode.ContainedNode == this) { // rightChildNode is the new local root. parentNode.ContainedNode = rightChildNode; } else { // rightChildNode is not local root. if (this.Role == SplayTreeNodeRole.LeftChild) { parentNode.LeftChildNode = rightChildNode; } else { parentNode.RightChildNode = rightChildNode; } } rightChildNode.LeftChildNode = this; this.ParentNode = rightChildNode; // Fix rightChildNode.LeftChildNode (which has now moved to be node's LeftChildNode). rightChildNodeChild = this.RightChildNode; // Fix up the LeftSymbolCount for rightChildNode. // This node's LeftSymbolCount hasn't changed. rightChildNode.LeftSymbolCount += this.LeftSymbolCount + this.SymbolCount; rightChildNode.LeftCharCount += this.LeftCharCount + this.IMECharCount; } // Moves this node up one level in its tree, while preserving the // relative order of all other nodes in the tree. // // this == Y below: // // | | // Y X // / \ / \ // X c ==> a Y // / \ / \ // a b b c // private void RotateRight() { SplayTreeNode parentNode; SplayTreeNode leftChildNode; SplayTreeNode leftChildNodeChild; Invariant.Assert(this.LeftChildNode != null, "Can't rotate right with null left child!"); leftChildNode = this.LeftChildNode; this.LeftChildNode = leftChildNode.RightChildNode; if (leftChildNode.RightChildNode != null) { leftChildNode.RightChildNode.ParentNode = this; } parentNode = this.ParentNode; leftChildNode.ParentNode = parentNode; if (parentNode == null) { // leftChildNode is the new local root. // But the local root isn't parented. } else if (parentNode.ContainedNode == this) { // leftChildNode is the new local root. parentNode.ContainedNode = leftChildNode; } else { // leftChildNode is not local root. if (this.Role == SplayTreeNodeRole.LeftChild) { parentNode.LeftChildNode = leftChildNode; } else { parentNode.RightChildNode = leftChildNode; } } leftChildNode.RightChildNode = this; this.ParentNode = leftChildNode; // Fix leftChildNode.RightChildNode (which has now moved to be node's LeftChildNode). leftChildNodeChild = this.LeftChildNode; // Fix up the LeftSymbolCount for node. // leftChildNode's LeftSymbolCount hasn't changed. this.LeftSymbolCount -= leftChildNode.LeftSymbolCount + leftChildNode.SymbolCount; this.LeftCharCount -= leftChildNode.LeftCharCount + leftChildNode.IMECharCount; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields #if DEBUG // A debug-only identifier for this node. private int _debugId = GetDebugId(); // Debug-only counter for allocating debug ids. private static int _debugIdCounter; #endif // DEBUG #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- StyleSelector.cs
- LinqDataSourceHelper.cs
- WorkerRequest.cs
- ImmutableDispatchRuntime.cs
- ProcessThread.cs
- XmlSerializerVersionAttribute.cs
- BeginEvent.cs
- GridSplitterAutomationPeer.cs
- RequestCache.cs
- InkCanvasSelectionAdorner.cs
- ReadWriteObjectLock.cs
- SqlTriggerAttribute.cs
- ExpressionEditorSheet.cs
- SoapUnknownHeader.cs
- CodeTypeDeclarationCollection.cs
- ClientBuildManagerCallback.cs
- FileDialogPermission.cs
- ParallelDesigner.cs
- ConfigurationElementProperty.cs
- Enumerable.cs
- GridViewSelectEventArgs.cs
- ZipIOLocalFileHeader.cs
- FindResponse.cs
- RegexStringValidatorAttribute.cs
- RootAction.cs
- ToolStripItemTextRenderEventArgs.cs
- ColumnMapVisitor.cs
- DesignerUtils.cs
- HitTestResult.cs
- ProviderCollection.cs
- Trace.cs
- FrameworkPropertyMetadata.cs
- ProcessModelSection.cs
- InvalidWMPVersionException.cs
- DbParameterCollectionHelper.cs
- GC.cs
- ProxyWebPart.cs
- AnnotationResourceChangedEventArgs.cs
- RefreshPropertiesAttribute.cs
- TreeNodeCollection.cs
- Brush.cs
- DBConnection.cs
- RootBuilder.cs
- OneWayBindingElement.cs
- TraceLevelStore.cs
- Models.cs
- Helper.cs
- WorkflowTimerService.cs
- TextWriterEngine.cs
- EntitySqlQueryCacheKey.cs
- WizardPanel.cs
- Stream.cs
- MultipartIdentifier.cs
- Activity.cs
- ResourceBinder.cs
- TransformPattern.cs
- ScrollChrome.cs
- ObjectStateEntryDbUpdatableDataRecord.cs
- LinkDescriptor.cs
- VisualCollection.cs
- ValidatingReaderNodeData.cs
- QuaternionKeyFrameCollection.cs
- ColumnMapCopier.cs
- Faults.cs
- iisPickupDirectory.cs
- ToolStripDesigner.cs
- NullableIntAverageAggregationOperator.cs
- XmlAttributeAttribute.cs
- Condition.cs
- SafePipeHandle.cs
- Comparer.cs
- DbCommandDefinition.cs
- DynamicRendererThreadManager.cs
- SystemPens.cs
- UnsafeNativeMethods.cs
- MarshalByRefObject.cs
- SymLanguageVendor.cs
- Trace.cs
- Line.cs
- EditorPartChrome.cs
- CRYPTPROTECT_PROMPTSTRUCT.cs
- MenuTracker.cs
- ChtmlFormAdapter.cs
- ColumnMapTranslator.cs
- HtmlTableRowCollection.cs
- TextEditorDragDrop.cs
- KoreanCalendar.cs
- ServiceOperationParameter.cs
- WeakEventManager.cs
- Mouse.cs
- UnmanagedMemoryStream.cs
- ApplicationManager.cs
- XmlDesignerDataSourceView.cs
- ModelEditingScope.cs
- FunctionCommandText.cs
- LexicalChunk.cs
- ResourcesChangeInfo.cs
- SqlDataReaderSmi.cs
- TypeSystemHelpers.cs
- XmlSchemaExporter.cs