Example #1
0
 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);
         }
     }
 }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <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);
            }
        }
Example #4
0
 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);
 }
Example #5
0
 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);
 }
Example #6
0
        /// <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);
            }
        }