/** * <summary>Adds an entry under the given tree node.</summary> * <param name="key">New entry's key.</param> * <param name="value">New entry's value.</param> * <param name="overwrite">Whether the entry is allowed to replace an existing one having the same * key.</param> * <param name="nodeReference">Current node reference.</param> */ private void Add( TKey key, TValue value, bool overwrite, PdfDictionary node ) { Children children = Children.Get(node, pairsKey); if (children.IsLeaf()) // Leaf node. { int childrenSize = children.Items.Count; int low = 0, high = childrenSize - children.Info.ItemCount; while (true) { if (low > high) { // Insert the entry! children.Items.Insert(low, key); children.Items.Insert(++low, value.BaseObject); break; } int mid = (mid = ((low + high) / 2)) - (mid % 2); if (mid >= childrenSize) { // Append the entry! children.Items.Add(key); children.Items.Add(value.BaseObject); break; } int comparison = key.CompareTo(children.Items[mid]); if (comparison < 0) // Before. { high = mid - 2; } else if (comparison > 0) // After. { low = mid + 2; } else // Matching entry. { if (!overwrite) { throw new ArgumentException("Key '" + key + "' already exists.", "key"); } // Overwrite the entry! children.Items[mid] = key; children.Items[++mid] = value.BaseObject; break; } } // Update the key limits! UpdateNodeLimits(children); } else // Intermediate node. { int low = 0, high = children.Items.Count - children.Info.ItemCount; while (true) { bool matched = false; int mid = (low + high) / 2; PdfReference kidReference = (PdfReference)children.Items[mid]; PdfDictionary kid = (PdfDictionary)kidReference.DataObject; PdfArray limits = (PdfArray)kid.Resolve(PdfName.Limits); if (key.CompareTo(limits[0]) < 0) // Before the lower limit. { high = mid - 1; } else if (key.CompareTo(limits[1]) > 0) // After the upper limit. { low = mid + 1; } else // Limit range matched. { matched = true; } if (matched || // Limit range matched. low > high) // No limit range match. { Children kidChildren = Children.Get(kid, pairsKey); if (kidChildren.IsFull()) { // Split the node! SplitFullNode( children.Items, mid, kidChildren.TypeName ); // Is the key before the split node? if (key.CompareTo(((PdfArray)kid.Resolve(PdfName.Limits))[0]) < 0) { kidReference = (PdfReference)children.Items[mid]; kid = (PdfDictionary)kidReference.DataObject; } } Add(key, value, overwrite, kid); // Update the key limits! UpdateNodeLimits(children); break; } } } }
public virtual bool Remove( TKey key ) { PdfDictionary node = BaseDataObject; Stack <PdfReference> nodeReferenceStack = new Stack <PdfReference>(); while (true) { Children nodeChildren = Children.Get(node, pairsKey); if (nodeChildren.IsLeaf()) // Leaf node. { int low = 0, high = nodeChildren.Items.Count - nodeChildren.Info.ItemCount; while (true) { if (low > high) // No match. { return(false); } int mid = (mid = ((low + high) / 2)) - (mid % 2); int comparison = key.CompareTo(nodeChildren.Items[mid]); if (comparison < 0) // Key before. { high = mid - 2; } else if (comparison > 0) // Key after. { low = mid + 2; } else // Key matched. { // We got it! nodeChildren.Items.RemoveAt(mid + 1); // Removes value. nodeChildren.Items.RemoveAt(mid); // Removes key. if (mid == 0 || mid == nodeChildren.Items.Count) // Limits changed. { // Update key limits! UpdateNodeLimits(nodeChildren); // Updating key limits on ascendants... PdfReference rootReference = (PdfReference)BaseObject; PdfReference nodeReference; while (nodeReferenceStack.Count > 0 && !(nodeReference = nodeReferenceStack.Pop()).Equals(rootReference)) { PdfArray parentChildren = (PdfArray)nodeReference.Parent; int nodeIndex = parentChildren.IndexOf(nodeReference); if (nodeIndex == 0 || nodeIndex == parentChildren.Count - 1) { PdfDictionary parent = (PdfDictionary)parentChildren.Parent; UpdateNodeLimits(parent, parentChildren, PdfName.Kids); } else { break; } } } return(true); } } } else // Intermediate node. { int low = 0, high = nodeChildren.Items.Count - nodeChildren.Info.ItemCount; while (true) { if (low > high) // Outside the limit range. { return(false); } int mid = (low + high) / 2; PdfReference kidReference = (PdfReference)nodeChildren.Items[mid]; PdfDictionary kid = (PdfDictionary)kidReference.DataObject; PdfArray limits = (PdfArray)kid.Resolve(PdfName.Limits); if (key.CompareTo(limits[0]) < 0) // Before the lower limit. { high = mid - 1; } else if (key.CompareTo(limits[1]) > 0) // After the upper limit. { low = mid + 1; } else // Limit range matched. { Children kidChildren = Children.Get(kid, pairsKey); if (kidChildren.IsUndersized()) { /* * NOTE: Rebalancing is required as minimum node size invariant is violated. */ PdfDictionary leftSibling = null; Children leftSiblingChildren = null; if (mid > 0) { leftSibling = (PdfDictionary)nodeChildren.Items.Resolve(mid - 1); leftSiblingChildren = Children.Get(leftSibling, pairsKey); } PdfDictionary rightSibling = null; Children rightSiblingChildren = null; if (mid < nodeChildren.Items.Count - 1) { rightSibling = (PdfDictionary)nodeChildren.Items.Resolve(mid + 1); rightSiblingChildren = Children.Get(rightSibling, pairsKey); } if (leftSiblingChildren != null && !leftSiblingChildren.IsUndersized()) { // Move the last child subtree of the left sibling to be the first child subtree of the kid! for (int index = 0, endIndex = leftSiblingChildren.Info.ItemCount; index < endIndex; index++) { int itemIndex = leftSiblingChildren.Items.Count - 1; PdfDirectObject item = leftSiblingChildren.Items[itemIndex]; leftSiblingChildren.Items.RemoveAt(itemIndex); kidChildren.Items.Insert(0, item); } // Update left sibling's key limits! UpdateNodeLimits(leftSiblingChildren); } else if (rightSiblingChildren != null && !rightSiblingChildren.IsUndersized()) { // Move the first child subtree of the right sibling to be the last child subtree of the kid! for (int index = 0, endIndex = rightSiblingChildren.Info.ItemCount; index < endIndex; index++) { int itemIndex = 0; PdfDirectObject item = rightSiblingChildren.Items[itemIndex]; rightSiblingChildren.Items.RemoveAt(itemIndex); kidChildren.Items.Add(item); } // Update right sibling's key limits! UpdateNodeLimits(rightSiblingChildren); } else { if (leftSibling != null) { // Merging with the left sibling... for (int index = leftSiblingChildren.Items.Count; index-- > 0;) { PdfDirectObject item = leftSiblingChildren.Items[index]; leftSiblingChildren.Items.RemoveAt(index); kidChildren.Items.Insert(0, item); } nodeChildren.Items.RemoveAt(mid - 1); leftSibling.Reference.Delete(); } else if (rightSibling != null) { // Merging with the right sibling... for (int index = rightSiblingChildren.Items.Count; index-- > 0;) { int itemIndex = 0; PdfDirectObject item = rightSiblingChildren.Items[itemIndex]; rightSiblingChildren.Items.RemoveAt(itemIndex); kidChildren.Items.Add(item); } nodeChildren.Items.RemoveAt(mid + 1); rightSibling.Reference.Delete(); } if (nodeChildren.Items.Count == 1) { // Collapsing root... nodeChildren.Items.RemoveAt(0); for (int index = kidChildren.Items.Count; index-- > 0;) { int itemIndex = 0; PdfDirectObject item = kidChildren.Items[itemIndex]; kidChildren.Items.RemoveAt(itemIndex); nodeChildren.Items.Add(item); } kid.Reference.Delete(); kid = node; kidReference = kid.Reference; kidChildren = nodeChildren; } } // Update key limits! UpdateNodeLimits(kidChildren); } // Go down one level! nodeReferenceStack.Push(kidReference); node = kid; break; } } } } }
public virtual TValue this[ TKey key ] { get { PdfDictionary parent = BaseDataObject; while (true) { Children children = Children.Get(parent, pairsKey); if (children.IsLeaf()) // Leaf node. { int low = 0, high = children.Items.Count - children.Info.ItemCount; while (true) { if (low > high) { return(null); } int mid = (mid = ((low + high) / 2)) - (mid % 2); int comparison = key.CompareTo(children.Items[mid]); if (comparison < 0) { high = mid - 2; } else if (comparison > 0) { low = mid + 2; } else { // We got it! return(WrapValue(children.Items[mid + 1])); } } } else // Intermediate node. { int low = 0, high = children.Items.Count - children.Info.ItemCount; while (true) { if (low > high) { return(null); } int mid = (low + high) / 2; PdfDictionary kid = (PdfDictionary)children.Items.Resolve(mid); PdfArray limits = (PdfArray)kid.Resolve(PdfName.Limits); if (key.CompareTo(limits[0]) < 0) { high = mid - 1; } else if (key.CompareTo(limits[1]) > 0) { low = mid + 1; } else { // Go down one level! parent = kid; break; } } } } } set { Add(key, value, true); } }
private KeyValuePair <TKey, TValue>?GetNext( ) { /* * NOTE: Algorithm: * 1. [Vertical, down] We have to go downward the name tree till we reach * a names collection (leaf node). * 2. [Horizontal] Then we iterate across the names collection. * 3. [Vertical, up] When leaf-nodes scan is complete, we go upward solving * parent nodes, repeating step 1. */ while (true) { if (names == null) { if (kids == null || kids.Count == levelIndex) // Kids subtree complete. { if (levels.Count == 0) { return(null); } // 3. Go upward one level. // Restore current level! object[] level = levels.Pop(); container = (PdfIndirectObject)level[0]; kids = (PdfArray)level[1]; levelIndex = ((int)level[2]) + 1; // Next node (partially scanned level). } else // Kids subtree incomplete. { // 1. Go downward one level. // Save current level! levels.Push(new object[] { container, kids, levelIndex }); // Move downward! PdfReference kidReference = (PdfReference)kids[levelIndex]; container = kidReference.IndirectObject; PdfDictionary kid = (PdfDictionary)kidReference.DataObject; PdfDirectObject kidsObject = kid[PdfName.Kids]; if (kidsObject == null) // Leaf node. { PdfDirectObject namesObject = kid[PdfName.Names]; if (namesObject is PdfReference) { container = ((PdfReference)namesObject).IndirectObject; } names = (PdfArray)namesObject.Resolve(); kids = null; } else // Intermediate node. { if (kidsObject is PdfReference) { container = ((PdfReference)kidsObject).IndirectObject; } kids = (PdfArray)kidsObject.Resolve(); } levelIndex = 0; // First node (new level). } } else { if (names.Count == levelIndex) // Names complete. { names = null; } else // Names incomplete. { // 2. Object found. TKey key = (TKey)names[levelIndex]; TValue value = tree.WrapValue(names[levelIndex + 1]); levelIndex += 2; return(new KeyValuePair <TKey, TValue>(key, value)); } } } }