internal static void HandleChildReplaced <K, T>(this IAListTreeObserver <K, T> self, AListNode <K, T> oldNode, AListNode <K, T> newLeft, AListNode <K, T> newRight, AListInnerBase <K, T> parent) { self.HandleNodeReplaced(oldNode, newLeft, newRight); if (parent != null) { self.NodeRemoved(oldNode, parent); self.NodeAdded(newLeft, parent); if (newRight != null) { self.NodeAdded(newRight, parent); } } }
/// <summary> /// This is called by RemoveAt(), DoSingleOperation() for B+ trees, or by /// the constructor called by CopySection(), when child [i] drops below its /// normal size range. We'll either distribute the child's items to its /// siblings, or transfer ONE item from a sibling to increase the node's /// size. /// </summary> /// <param name="i">Index of undersized child</param> /// <param name="tob">Observer to notify about node movements</param> /// <returns>True iff this node has become undersized.</returns> protected virtual bool HandleUndersized(int i, IAListTreeObserver <K, T> tob) { AListNode <K, T> node = _children[i].Node; Debug.Assert(!node.IsFrozen); // Examine the fullness of the siblings of e.Node. uint ui = (uint)i; AListNode <K, T> left = null, right = null; int leftCap = 0, rightCap = 0; if (ui - 1u < (uint)_children.Length) { AutoClone(ref _children[ui - 1u].Node, this, tob); left = _children[ui - 1u].Node; leftCap = left.CapacityLeft; } if (ui + 1u < (uint)LocalCount) { AutoClone(ref _children[ui + 1u].Node, this, tob); right = _children[ui + 1u].Node; rightCap = right.CapacityLeft; } // If the siblings have enough capacity... if (leftCap + rightCap >= node.LocalCount) { // Unload data from 'node' into its siblings int oldRightCap = rightCap; uint rightAdjustment = 0, a; while (node.LocalCount > 0) { if (leftCap >= rightCap) { Verify(left.TakeFromRight(node, tob) != 0); leftCap--; } else { Verify((a = right.TakeFromLeft(node, tob)) != 0); rightAdjustment += a; rightCap--; } } if (rightAdjustment != 0) // if rightAdjustment==0, _children[i+1] might not exist { _children[i + 1].Index -= rightAdjustment; } if (tob != null) { tob.NodeRemoved(node, this); } LLDelete(i, false); // Return true if this node has become undersized. return(IsUndersized); } else if (left != null || right != null) { // Transfer an element from the fullest sibling so that 'node' // is no longer undersized. if (left == null) { leftCap = int.MaxValue; } if (right == null) { rightCap = int.MaxValue; } if (leftCap < rightCap) { Debug.Assert(i > 0); uint amt = node.TakeFromLeft(left, tob); Debug.Assert(amt > 0); _children[i].Index -= amt; } else { uint amt = node.TakeFromRight(right, tob); Debug.Assert(amt > 0); _children[i + 1].Index += amt; } } return(false); }
/// <summary> /// This is called by RemoveAt(), DoSingleOperation() for B+ trees, or by /// the constructor called by CopySection(), when child [i] drops below its /// normal size range. We'll either distribute the child's items to its /// siblings, or transfer ONE item from a sibling to increase the node's /// size. /// </summary> /// <param name="i">Index of undersized child</param> /// <param name="tob">Observer to notify about node movements</param> /// <returns>True iff this node has become undersized.</returns> protected virtual bool HandleUndersized(int i, IAListTreeObserver <K, T> tob) { AListNode <K, T> node = _children[i].Node; Debug.Assert(!node.IsFrozen); // Examine the fullness of the siblings of e.Node. uint ui = (uint)i; AListNode <K, T> left = null, right = null; int leftCap = 0, rightCap = 0; if (ui - 1u < (uint)_children.Length) { AutoClone(ref _children[ui - 1u].Node, this, tob); left = _children[ui - 1u].Node; leftCap = left.CapacityLeft; } if (ui + 1u < (uint)LocalCount) { AutoClone(ref _children[ui + 1u].Node, this, tob); right = _children[ui + 1u].Node; rightCap = right.CapacityLeft; } if (left == null && right == null) { if (node.TotalCount == 0) { if (tob != null) { tob.NodeRemoved(node, this); } LLDelete(i, false); } return(IsUndersized); } else if (leftCap + rightCap >= node.LocalCount) { // There's enough capacity to move all items from `node` into its siblings. // Move items in such a way that the left and right nodes have equal size if possible. int dif = leftCap - rightCap; int itemsToMoveLeft = dif + ((node.LocalCount - dif) >> 1); if (left != null && itemsToMoveLeft >= 0) { left.TakeFromRight(node, Math.Min(itemsToMoveLeft, node.LocalCount), tob); } if (node.TotalCount > 0) { uint rightAdjustment = right.TakeFromLeft(node, node.LocalCount, tob); _children[i + 1].Index -= rightAdjustment; } Debug.Assert(node.LocalCount == 0); // Sparse leaves can have empty space without any items, but TakeFromLeft/Right takes all space Debug.Assert(node.TotalCount == 0); if (tob != null) { tob.NodeRemoved(node, this); } LLDelete(i, false); return(IsUndersized); } else { // Try to transfer element(s) from sibling(s) so that 'node' is no longer undersized. int targetSize = ((left?.LocalCount ?? 0) + (right?.LocalCount ?? 0) + node.LocalCount + 2) / 3; if (left != null && targetSize < left.LocalCount) { uint spaceMoved = node.TakeFromLeft(left, left.LocalCount - targetSize, tob); _children[i].Index -= spaceMoved; } if (right != null && targetSize < right.LocalCount) { uint spaceMoved = node.TakeFromRight(right, right.LocalCount - targetSize, tob); _children[i + 1].Index += spaceMoved; } return(false); } }
internal static void HandleRootUnsplit <K, T>(this IAListTreeObserver <K, T> self, AListInnerBase <K, T> oldRoot, AListNode <K, T> newRoot) { Debug.Assert(oldRoot.LocalCount == 0 || (oldRoot.LocalCount == 1 && oldRoot.Child(0) == newRoot)); self.NodeRemoved(newRoot, oldRoot); self.RootChanged(newRoot, false); }
internal static void NodeMoved <K, T>(this IAListTreeObserver <K, T> self, AListNode <K, T> child, AListInnerBase <K, T> oldParent, AListInnerBase <K, T> newParent) { self.NodeRemoved(child, oldParent); self.NodeAdded(child, newParent); }
/// <summary> /// This is called by RemoveAt(), DoSingleOperation() for B+ trees, or by /// the constructor called by CopySection(), when child [i] drops below its /// normal size range. We'll either distribute the child's items to its /// siblings, or transfer ONE item from a sibling to increase the node's /// size. /// </summary> /// <param name="i">Index of undersized child</param> /// <param name="tob">Observer to notify about node movements</param> /// <returns>True iff this node has become undersized.</returns> protected virtual bool HandleUndersized(int i, IAListTreeObserver <K, T> tob) { AListNode <K, T> node = _children[i].Node; Debug.Assert(!node.IsFrozen); // Examine the fullness of the siblings of e.Node. uint ui = (uint)i; AListNode <K, T> left = null, right = null; int leftCap = 0, rightCap = 0; if (ui - 1u < (uint)_children.Length) { AutoClone(ref _children[ui - 1u].Node, this, tob); left = _children[ui - 1u].Node; leftCap = left.CapacityLeft; } if (ui + 1u < (uint)LocalCount) { AutoClone(ref _children[ui + 1u].Node, this, tob); right = _children[ui + 1u].Node; rightCap = right.CapacityLeft; } if (left == null && right == null) { if (node.TotalCount == 0) { if (tob != null) { tob.NodeRemoved(node, this); } LLDelete(i, false); } return(IsUndersized); } else if (leftCap + rightCap >= node.LocalCount) { // The siblings have enough capacity that we can data from 'node' // into its siblings int oldRightCap = rightCap; uint rightAdjustment = 0, a; while (node.LocalCount > 0) { if (leftCap >= rightCap) { Verify(left.TakeFromRight(node, tob) != 0); leftCap--; } else { Verify((a = right.TakeFromLeft(node, tob)) != 0); rightAdjustment += a; rightCap--; } } if (node.TotalCount > 0) { Debug.Assert(node is SparseAListLeaf <T>); // Bug fix: in case of a sparse leaf it is possible to have LocalCount==0 // but TotalCount>0. In that case leftCap and rightCap could both be zero. // Originally this case was handled within SparseAListLeaf.TakeFromLeft/Right, // but this method must also be aware of this case because it's possible that // LocalCount==0 when this method starts, so the loop is skipped. if (left != null) { left.TakeFromRight(node, tob); } else { rightAdjustment += right.TakeFromLeft(node, tob); } } if (rightAdjustment != 0) // if rightAdjustment==0, _children[i+1] might not exist { _children[i + 1].Index -= rightAdjustment; } if (tob != null) { tob.NodeRemoved(node, this); } LLDelete(i, false); return(IsUndersized); } else { // Transfer an element from the fullest sibling so that 'node' // is no longer undersized. if (left == null) { leftCap = int.MaxValue; } if (right == null) { rightCap = int.MaxValue; } do { if (leftCap < rightCap) { Debug.Assert(i > 0); uint amt = node.TakeFromLeft(left, tob); leftCap++; Debug.Assert(amt > 0); _children[i].Index -= amt; } else { uint amt = node.TakeFromRight(right, tob); rightCap++; Debug.Assert(amt > 0); _children[i + 1].Index += amt; } } while (node.IsUndersized); return(false); } }