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); return(0); } } } else { Debug.Assert(op.SourceIndex == 0 && op.SourceCount == 1); if (!ReplaceSingleItem(ref op, (uint)(index + op.SourceIndex))) { SplitLeaf(out splitLeft, out splitRight); return(0); } op.SourceIndex++; } return(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)); } }
private bool ReplaceSingleItem(ref AListSparseOperation <T> op, uint index) { int i; if (BinarySearch(index, out i)) { _list.InternalArray[_list.Internalize(i)].Item = op.Item; } else { if (_list.Count >= _maxNodeSize) { return(false); } _list.Insert(i, new Entry(index, op.Item)); } return(true); }
internal override int DoSparseOperation(ref AListSparseOperation <T> op, int index, out AListNode <int, T> splitLeft, out AListNode <int, T> splitRight) { Debug.Assert(!IsFrozen); Debug.Assert(op.Source == null || op.SourceCount == op.Source.Count); AssertValid(); Entry e = default(Entry); // Perform the insert/replace int change = 0, i = 0; do { if (change == 0) { // runs once for insert operations, once or multiple times for replace i = BinarySearchI((uint)(index + op.SourceIndex)); AutoClone(ref _children[i].Node, this, op.tob); e = _children[i]; } change += e.Node.DoSparseOperation(ref op, index - (int)e.Index, out splitLeft, out splitRight); } while (op.SourceIndex < op.SourceCount && splitLeft == null && index + op.SourceIndex < TotalCount); // Adjust base index of nodes that follow if (change != 0) { AdjustIndexesAfter(i, change); } // Handle child split/undersize if (splitLeft == null) { return(change); } else if (splitRight != null) { splitLeft = HandleChildSplit(i, splitLeft, ref splitRight, op.tob); return(change); } else { splitLeft = HandleUndersized(i, op.tob) ? this : null; return(change); } }
/// <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(); }
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); } int leftHere = _maxNodeSize - _list.Count; if (leftHere == 0) { SplitLeaf(out splitLeft, out splitRight); return(0); // return without inserting anything } uint index = (uint)(index0 + op.SourceIndex); int i; BinarySearch(index, out i); 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); } }