/// <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(); }
/// <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);
/// <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(); }
/// <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(); }
/// <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);
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)); } }
/// <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(); }
public BDictionaryInner(AListNode <K, KeyValuePair <K, V> > left, AListNode <K, KeyValuePair <K, V> > right, int maxNodeSize) : base(left, right, maxNodeSize) { }
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)); }
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); }
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)); }
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); }
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); } }
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); }
/// <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); }
protected K GetHighestKey(AListNode <K, T> node) { return(GetKey(node.GetLastItem())); }
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); }
public override AListNode <int, T> Insert(uint index, T item, out AListNode <int, T> splitRight, IAListTreeObserver <int, T> tob) { throw new NotSupportedException(); }