Ejemplo n.º 1
0
 /// <summary>Inserts a list of items at the specified index. This method
 /// may not insert all items at once, so there is a sourceIndex parameter
 /// which points to the next item to be inserted. When sourceIndex reaches
 /// source.Count, the insertion is complete.</summary>
 /// <param name="index">The index at which to insert the contents of
 /// source. Important: if sourceIndex > 0, insertion of the remaining
 /// items starts at [index + sourceIndex].</param>
 /// <returns>Returns non-null if the node is split, as explained
 /// in the documentation of <see cref="Insert"/>.</returns>
 /// <remarks>This method can only be called for ALists, since other tree
 /// types don't allow insertion at a specific index.</remarks>
 /// <exception cref="NotSupportedException">This node does not allow insertion at an arbitrary location (e.g. BList node).</exception>
 public virtual AListNode <K, T> InsertRange(uint index, IListSource <T> source, ref int sourceIndex, out AListNode <K, T> splitRight, IAListTreeObserver <K, T> tob)
 {
     throw new NotSupportedException();
 }
Ejemplo n.º 2
0
 /// <summary>Takes an element from a left sibling.</summary>
 /// <returns>Returns the number of elements moved on success (1 if a leaf
 /// node, TotalCount of the child moved otherwise), or 0 if either (1)
 /// IsFullLeaf is true, or (2) one or both nodes is frozen.</returns>
 internal abstract uint TakeFromLeft(AListNode <K, T> leftSibling, IAListTreeObserver <K, T> tob);
Ejemplo n.º 3
0
 /// <summary>Inserts an item at the specified index. This method can only
 /// be called for ALists, since other tree types don't allow insertion at
 /// a specific index.</summary>
 /// <returns>Returns null if the insert completed normally. If the node
 /// split in half, the return value is the left side, and splitRight is
 /// set to the right side.</returns>
 /// <exception cref="NotSupportedException">This node does not allow insertion at an arbitrary location (e.g. BList node).</exception>
 public virtual AListNode <K, T> Insert(uint index, T item, out AListNode <K, T> splitRight, IAListTreeObserver <K, T> tob)
 {
     throw new NotSupportedException();
 }
Ejemplo n.º 4
0
 /// <summary>Performs an insert or replace operation in a <see cref="SparseAList{T}"/>.</summary>
 /// <param name="op">Describes the operation to be performed</param>
 /// <param name="index">Relative index in child node where the sparse
 /// operation began; <c>index + op.SourceIndex</c> is where the next
 /// insertion or replacement must occur. For example if the child
 /// node represents items 100-200, and op.SourceIndex is 7, and
 /// the absolute index of the start of the operation (op.AbsoluteIndex)
 /// is 98, then <c>index</c> will be -2 (98-100) and the next insertion
 /// or replacement will occur at index 5 in the child. <c>index</c> may
 /// be negative but <c>index + op.SourceIndex >= 0</c>.</param>
 /// <param name="splitLeft">If the node needs to split, splitLeft and
 /// splitRight are set to the new pieces. If the node is undersized,
 /// splitLeft is set to <c>this</c> (the called node) and splitRight
 /// is set to null.</param>
 /// <returns>Size change (always 0 for a replacement operation)</returns>
 /// <remarks>In a language with templates, I would change a couple
 /// of elements of <see cref="AListSparseOperation{T}"/> into
 /// template parameters.</remarks>
 internal virtual int DoSparseOperation(ref AListSparseOperation <T> op, int index, out AListNode <K, T> splitLeft, out AListNode <K, T> splitRight)
 {
     throw new NotSupportedException();
 }
Ejemplo n.º 5
0
 /// <summary>Takes an element from a right sibling.</summary>
 /// <returns>Returns the number of elements moved on success (1 if a leaf
 /// node, TotalCount of the child moved otherwise), or 0 if either (1)
 /// IsFullLeaf is true, or (2) one or both nodes is frozen.</returns>
 internal abstract uint TakeFromRight(AListNode <K, T> rightSibling, IAListTreeObserver <K, T> tob);
Ejemplo n.º 6
0
 internal override int DoSparseOperation(ref AListSparseOperation <T> op, int index, out AListNode <int, T> splitLeft, out AListNode <int, T> splitRight)
 {
     Debug.Assert(!IsFrozen);
     if (op.IsInsert)
     {
         return(DoInsert(ref op, index, out splitLeft, out splitRight));
     }
     else
     {
         return(DoReplace(ref op, index, out splitLeft, out splitRight));
     }
 }
Ejemplo n.º 7
0
 /// <summary>Performs a retrieve, add, remove or replace operation on a
 /// single item in an organized A-list (such as a BList or BDictionary).</summary>
 /// <param name="op">An object that describes the operation to be performed
 /// and the parameters of the tree (comparers and observers).</param>
 /// <param name="splitLeft">null if the operation completed normally. If an
 /// item was added and the node split, splitLeft and splitRight are new
 /// nodes that each contain roughly half of the items from this node.
 /// <para/>
 /// If an item was removed and the node became undersized, splitLeft is set
 /// to this (the node itself) and splitRight is set to null. Likewise, if
 /// the aggregate value of the node changed (in a B+tree, this means that
 /// the highest key changed) then splitLeft is set to the node itself and
 /// splitRight is set to null.
 /// </param>
 /// <returns>Returns 1 if a new item was added, -1 if an item was removed,
 /// or 0 if the number of items in the tree did not change.</returns>
 /// <exception cref="NotSupportedException">This node does not belong to an
 /// organized tree (e.g. normal AList).</exception>
 /// <exception cref="KeyAlreadyExistsException">The key op.NewKey already
 /// existed in the tree and op.Mode was
 /// <see cref="AListOperation"/>.AddOrThrow.</exception>
 /// <remarks>
 /// If op.Mode is <see cref="AListOperation"/>.ReplaceIfPresent, this method
 /// informs the caller when replacement occurs in this mode by changing
 /// op.Mode to AddDuplicateMode.ReplaceExisting.
 /// </remarks>
 internal virtual int DoSingleOperation(ref AListSingleOperation <K, T> op, out AListNode <K, T> splitLeft, out AListNode <K, T> splitRight)
 {
     throw new NotSupportedException();
 }
Ejemplo n.º 8
0
 public BDictionaryInner(AListNode <K, KeyValuePair <K, V> > left, AListNode <K, KeyValuePair <K, V> > right, int maxNodeSize) : base(left, right, maxNodeSize)
 {
 }
Ejemplo n.º 9
0
 protected override AListInnerBase <K, KeyValuePair <K, V> > SplitAt(int divAt, out AListNode <K, KeyValuePair <K, V> > right)
 {
     right = new BDictionaryInner <K, V>(this, divAt, LocalCount - divAt, _children[divAt].Index, MaxNodeSize);
     return(new BDictionaryInner <K, V>(this, 0, divAt, 0, MaxNodeSize));
 }
Ejemplo n.º 10
0
 public BListInner(AListNode <K, T> left, AListNode <K, T> right, int maxNodeSize)
     : base(left, right, maxNodeSize)
 {
     _highestKey    = new K[_children.Length - 1];
     _highestKey[0] = GetHighestKey(left);
 }
Ejemplo n.º 11
0
        protected new AListInnerBase <K, T> HandleChildSplit(int i, AListNode <K, T> splitLeft, ref AListNode <K, T> splitRight, IAListTreeObserver <K, T> tob)
        {
            // Update _highestKey. base.HandleChildSplit will call LLInsert
            // which will update _highestKey for the newly inserted right child,
            // but we must manually update the left child at _highestKey[i],
            // unless i == _childCount-1.
            if (i < _childCount - 1)
            {
                _highestKey[i] = GetHighestKey(splitLeft);
            }

            return(base.HandleChildSplit(i, splitLeft, ref splitRight, tob));
        }
Ejemplo n.º 12
0
        internal override int DoSingleOperation(ref AListSingleOperation <K, T> op, out AListNode <K, T> splitLeft, out AListNode <K, T> splitRight)
        {
            Debug.Assert(!IsFrozen || op.Mode == AListOperation.Retrieve);

            AssertValid();
            var tob = GetObserver(op.List);
            int i   = BinarySearchK(op.Key, op.CompareKeys);

            if (op.Mode != AListOperation.Retrieve)
            {
                AutoClone(ref _children[i].Node, this, tob);
                if (op.Mode >= AListOperation.Add && _children[i].Node.IsFullLeaf)
                {
                    TryToShiftAnItemToSiblingOfLeaf(i, tob);
                    // Binary search result might now be off-by-1
                    i = BinarySearchK(op.Key, op.CompareKeys);
                }
            }
            AssertValid();
            op.BaseIndex += _children[i].Index;
            int sizeChange = _children[i].Node.DoSingleOperation(ref op, out splitLeft, out splitRight);

            if (sizeChange != 0)
            {
                AdjustIndexesAfter(i, sizeChange);
            }

            // Handle child split / undersized / highest key changed
            if (splitLeft != null)
            {
                if (splitRight != null)
                {
                    splitLeft = HandleChildSplit(i, splitLeft, ref splitRight, tob);
                }
                else
                {
                    // Node is undersized and/or highest key changed
                    bool flagParent = false;

                    if (op.AggregateChanged != 0)
                    {
                        if (i < _childCount - 1)
                        {
                            _highestKey[i]      = op.AggregateKey;
                            op.AggregateChanged = 0;
                        }
                        else
                        {
                            // Update highest key in parent node instead
                            flagParent = true;
                        }
                    }

                    if (splitLeft.IsUndersized)
                    {
                        flagParent |= HandleUndersized(i, tob);
                    }

                    if (flagParent)
                    {
                        splitLeft = this;
                    }
                    else
                    {
                        splitLeft = null;
                    }
                }
            }
            AssertValid();
            return(sizeChange);
        }
Ejemplo n.º 13
0
        private int DoInsert(ref AListSparseOperation <T> op, int index0, out AListNode <int, T> splitLeft, out AListNode <int, T> splitRight)
        {
            Debug.Assert(_totalCount + op.SourceCount >= _totalCount);             // caller ensures list size does not overflow

            if (op.WriteEmpty)
            {
                // SourceIndex will be 0 because inserting empty space always finishes on the first try.
                Debug.Assert(op.SourceIndex == 0);
                InsertSpace((uint)index0, op.SourceCount);
                op.SourceIndex = op.SourceCount;
                splitLeft      = splitRight = null;
                return(op.SourceCount);
            }

            uint index = (uint)(index0 + op.SourceIndex);
            int  i;

            BinarySearch(index, out i);

            int leftHere = _maxNodeSize - _list.Count;

            if (leftHere == 0)
            {
                SplitLeaf(out splitLeft, out splitRight, i == _list.Count);
                return(0);                // return without inserting anything
            }

            if (op.Source == null)
            {
                // Special case: insert a single item
                Debug.Assert(op.SourceCount == 1);
                _list.AutoRaiseCapacity(1, _maxNodeSize);

                _list.Insert(i, new Entry(index, op.Item));
                AdjustOffsetsStartingAt(i + 1, ref _list, 1);
                _totalCount++;
                op.SourceIndex++;
                splitLeft = splitRight = null;
                return(1);
            }

            splitLeft = splitRight = null;

            if (op.SparseSource != null)
            {
                var source   = op.SparseSource;
                var tempList = new InternalList <Entry>(leftHere);

                int?si;
                T   item;
                for (int prev = op.SourceIndex - 1; ; prev = si.Value)
                {
                    si   = prev;
                    item = source.NextHigherItem(ref si);
                    if (si == null)
                    {
                        break;
                    }
                    tempList.Add(new Entry {
                        Offset = (uint)(index0 + si.Value),
                        Item   = item
                    });
                    if (tempList.Count == leftHere)
                    {
                        break;
                    }
                }
                _list.InsertRangeHelper(i, tempList.Count);
                for (int j = 0; j < tempList.Count; j++)
                {
                    _list[i + j] = tempList[j];
                }

                int newSourceIndex       = si == null ? source.Count : si.Value + 1;
                int virtualItemsInserted = newSourceIndex - op.SourceIndex;
                op.SourceIndex = newSourceIndex;

                AdjustOffsetsStartingAt(i + tempList.Count, ref _list, virtualItemsInserted);
                _totalCount += (uint)virtualItemsInserted;
                return(virtualItemsInserted);
            }
            else
            {
                int c            = op.SourceCount;
                int leftToInsert = c - op.SourceIndex;
                Debug.Assert(leftToInsert > 0);
                int amtToIns = System.Math.Min(leftHere, leftToInsert);
                _list.AutoRaiseCapacity(amtToIns, _maxNodeSize);
                _list.InsertRangeHelper(i, amtToIns);
                for (int j = 0; j < amtToIns; j++)
                {
                    _list[i + j] = new Entry(index + (uint)j, op.Source[op.SourceIndex + j]);
                }
                AdjustOffsetsStartingAt(i + amtToIns, ref _list, amtToIns);
                _totalCount += (uint)amtToIns;

                op.SourceIndex += amtToIns;
                //if (tob != null) tob.AddingItems(slice, this, false);
                return(amtToIns);
            }
        }
Ejemplo n.º 14
0
        private int DoReplace(ref AListSparseOperation <T> op, int index, out AListNode <int, T> splitLeft, out AListNode <int, T> splitRight)
        {
            if (op.WriteEmpty)
            {
                int  i1, i2;
                uint leftToReplace = (uint)(op.SourceCount - op.SourceIndex);
                uint startAt       = (uint)(index + op.SourceIndex);
                i1 = GetSectionRange(startAt, leftToReplace, out i2);
                _list.RemoveRange(i1, i2 - i1);

                uint amtReplaced = System.Math.Min(leftToReplace, _totalCount - startAt);
                op.SourceIndex += (int)amtReplaced;

                splitLeft = splitRight = null;
                if (IsUndersized)
                {
                    splitLeft = this;
                }

                return(0);
            }

            // Currently there is only one other replacement operation exposed on
            // SparseAList, namely changing the value of a single item. I'll
            // include code for changing multiple items at once, but not optimize
            // that case. And no sparse support.
            Debug.Assert(op.SparseSource == null);

            splitLeft = splitRight = null;
            if (op.Source != null)
            {
                for (; op.SourceIndex < op.SourceCount; op.SourceIndex++)
                {
                    op.Item = op.Source[op.SourceIndex];
                    if (!ReplaceSingleItem(ref op, (uint)(index + op.SourceIndex)))
                    {
                        SplitLeaf(out splitLeft, out splitRight, false);
                        return(0);
                    }
                }
            }
            else
            {
                Debug.Assert(op.SourceIndex == 0 && op.SourceCount == 1);
                if (!ReplaceSingleItem(ref op, (uint)(index + op.SourceIndex)))
                {
                    SplitLeaf(out splitLeft, out splitRight, false);
                    return(0);
                }
                op.SourceIndex++;
            }
            return(0);
        }
Ejemplo n.º 15
0
        /// <summary>Called by DoSingleOperation to split a full node, then retry the add operation.</summary>
        /// <remarks>Same arguments and return value as DoSingleOperation.</remarks>
        internal virtual int SplitAndAdd(ref AListSingleOperation <K, T> op, out AListNode <K, T> splitLeft, out AListNode <K, T> splitRight)
        {
            // Tell DoSingleOperation not to send notifications to the observer
            op.AggregateChanged |= 2;

            int divAt = _list.Count >> 1;
            var mid   = _list[divAt];
            var left  = new BListLeaf <K, T>(_maxNodeSize, _list.CopySection(0, divAt));
            var right = new BListLeaf <K, T>(_maxNodeSize, _list.CopySection(divAt, _list.Count - divAt));
            int sizeChange;

            if (op.CompareToKey(mid, op.Key) >= 0)
            {
                sizeChange = left.DoSingleOperation(ref op, out splitLeft, out splitRight);
            }
            else
            {
                op.BaseIndex += left.TotalCount;
                sizeChange    = right.DoSingleOperation(ref op, out splitLeft, out splitRight);
            }

            op.AggregateChanged &= unchecked ((byte)~2);

            // (splitLeft may be non-null, meaning that the highest key changed, which doesn't matter here.)
            Debug.Assert(splitRight == null);
            Debug.Assert(sizeChange == 1);
            splitLeft  = left;
            splitRight = right;
            return(sizeChange);
        }
Ejemplo n.º 16
0
 protected K GetHighestKey(AListNode <K, T> node)
 {
     return(GetKey(node.GetLastItem()));
 }
Ejemplo n.º 17
0
        internal override int DoSingleOperation(ref AListSingleOperation <K, T> op, out AListNode <K, T> splitLeft, out AListNode <K, T> splitRight)
        {
            T   searchItem = op.Item;
            int index      = _list.BinarySearch(op.Key, op.CompareToKey, op.LowerBound);

            if (op.Found = (index >= 0))
            {
                op.Item = _list[index];                 // save old value
                if (op.RequireExactMatch && (searchItem == null ? op.Item == null : !searchItem.Equals(op.Item)))
                {
                    op.Found = false;
                }
            }
            else
            {
                index = ~index;
            }

            splitLeft     = splitRight = null;
            op.BaseIndex += (uint)index;

            if (op.Mode == AListOperation.Retrieve)
            {
                return(0);
            }

            if (op.Mode >= AListOperation.Add)
            {
                // Possible operations: Add, AddOrReplace, AddIfNotPresent, AddOrThrow
                if (_list.Count >= _maxNodeSize && (op.Mode == AListOperation.Add || !op.Found))
                {
                    op.BaseIndex -= (uint)index;
                    op.Item       = searchItem;
                    return(SplitAndAdd(ref op, out splitLeft, out splitRight));
                }

                if (op.Found && op.Mode != AListOperation.Add)
                {
                    if (op.Mode == AListOperation.AddOrThrow)
                    {
                        throw new KeyAlreadyExistsException();
                    }
                    else if (op.Mode == AListOperation.AddIfNotPresent)
                    {
                        return(0);
                    }
                }
                else                 // add new item
                {
                    if (HasListChanging(op.List))
                    {
                        CallListChanging(op.List, new ListChangeInfo <T>(NotifyCollectionChangedAction.Add, (int)op.BaseIndex, 1, ListExt.Single(searchItem)));
                    }

                    if (index == _list.Count)
                    {                           // Highest key may change
                        splitLeft            = this;
                        op.AggregateChanged |= 1;
                        op.AggregateKey      = op.List.GetKey(searchItem);
                    }

                    _list.AutoRaiseCapacity(1, _maxNodeSize);
                    _list.Insert(index, searchItem);

                    if (GetObserver(op.List) != null)
                    {
                        if ((op.AggregateChanged & 2) == 0)
                        {
                            GetObserver(op.List).ItemAdded(searchItem, this);
                        }
                    }
                    return(1);
                }
                Debug.Assert(op.Mode == AListOperation.AddOrReplace);
            }
            else if (op.Found)
            {
                // Possible operations: ReplaceIfPresent, Remove
                if (op.Mode == AListOperation.Remove)
                {
                    if (HasListChanging(op.List))
                    {
                        CallListChanging(op.List, new ListChangeInfo <T>(NotifyCollectionChangedAction.Remove, (int)op.BaseIndex, -1, null));
                    }

                    _list.RemoveAt(index);

                    if (index == _list.Count)
                    {                           // Highest key may change
                        splitLeft = this;
                        if (_list.Count != 0)
                        {
                            op.AggregateChanged |= 1;
                            op.AggregateKey      = op.List.GetKey(_list.Last);
                        }
                    }
                    else if (IsUndersized)
                    {
                        splitLeft = this;
                    }

                    if (GetObserver(op.List) != null)
                    {
                        Debug.Assert((op.AggregateChanged & 2) == 0);
                        GetObserver(op.List).ItemRemoved(op.Item, this);
                    }

                    return(-1);
                }
                Debug.Assert(op.Mode == AListOperation.ReplaceIfPresent);
            }
            else
            {
                Debug.Assert(op.Mode == AListOperation.Remove || op.Mode == AListOperation.ReplaceIfPresent);
                return(0);                // can't remove/replace because item was not found.
            }

            // Fallthrough action: replace existing item
            Debug.Assert(op.Found);
            if (HasListChanging(op.List))
            {
                CallListChanging(op.List, new ListChangeInfo <T>(NotifyCollectionChangedAction.Replace, (int)op.BaseIndex, 0, ListExt.Single(searchItem)));
            }

            _list[index] = searchItem;

            if (index + 1 == _list.Count)
            {                   // Highest key may change
                splitLeft            = this;
                op.AggregateChanged |= 1;
                op.AggregateKey      = op.List.GetKey(searchItem);
            }

            if (GetObserver(op.List) != null)
            {
                GetObserver(op.List).ItemRemoved(op.Item, this);
                GetObserver(op.List).ItemAdded(searchItem, this);
            }
            return(0);
        }
Ejemplo n.º 18
0
 public override AListNode <int, T> Insert(uint index, T item, out AListNode <int, T> splitRight, IAListTreeObserver <int, T> tob)
 {
     throw new NotSupportedException();
 }