private NodeCursor FindInsertNodeCursorImpl(long index) { if (Count == 0 || ReferenceEquals(HeadNode.Next, TailNode)) { return(HeadCursor); } if (TailCursor.Contains(index)) { return(TailCursor); } var cursor = Cursor; if (cursor.Contains(index)) { return(cursor); } if (index >= cursor.Index) { while (cursor.Node != null) { var next = cursor.GetNext(); if (cursor.Contains(index, true)) { return((next.Contains(index) ? next : cursor).WithIndex(index)); } cursor = next; } } else { while (cursor.Node != null) { var prev = cursor.GetPrev(); if (cursor.Contains(index, true)) { return((prev.Contains(index) ? prev : cursor).WithIndex(index)); } cursor = prev; } } return(NodeCursor.Empty); }
private protected void InsertCleanRangeImpl(long index, long count) { try { EnterStructureChange(); if (ReferenceEquals(HeadNode.Next, TailNode)) { HeadNode.Size += count; LongCount += count; return; } if (index == 0 || HeadCursor.Contains(index)) { HeadNode.Size += count; LongCount += count; return; } if (index == LongCount || TailCursor.Contains(index)) { TailNode.Size += count; LongCount += count; return; } var cursor = FindInsertNodeCursorImpl(index); var node = cursor.Node; var realizedNode = node as RealizedNode; var prevNode = node.Prev; var nextNode = node.Next; if (prevNode is GapNode prevGapNode && cursor.GetPrev().NodeOffset == index) { prevGapNode.Size += count; LongCount += count; return; } if (realizedNode == null) { node.Size += count; LongCount += count; return; } var splitIndex = (int)(index - cursor.NodeOffset); var splitCount = (int)(realizedNode.Size - splitIndex); if (count <= NodeCapacity - realizedNode.Size) { //Array.Copy(realizedNode.Items, splitIndex, realizedNode.Items, splitIndex + count, splitCount); var sourceSpan = realizedNode.Span.Slice(splitIndex, splitCount); var targetSpan = realizedNode.Span.Slice((int)(splitIndex + count), splitCount); sourceSpan.CopyTo(targetSpan); //Array.Clear(realizedNode.Items, splitIndex, count); var clearSpan = realizedNode.Span.Slice(splitIndex, (int)count); clearSpan.Clear(); realizedNode.Size += count; LongCount += count; return; } var gapNode = Manager.GetGapNode(); gapNode.Size = count; if (index == cursor.NodeOffset) { gapNode.Prev = prevNode; gapNode.Next = realizedNode; prevNode.Next = gapNode; realizedNode.Prev = gapNode; } else { var nextRealizedNode = Manager.GetRealizedNode(); node.Next = gapNode; gapNode.Prev = node; gapNode.Next = nextRealizedNode; nextRealizedNode.Size = splitCount; nextRealizedNode.Prev = gapNode; nextRealizedNode.Next = nextNode; nextNode.Prev = nextRealizedNode; realizedNode.Size = splitIndex; //Array.Copy(realizedNode.ItemsPrivate, splitIndex, nextRealizedNode.ItemsPrivate, 0, splitCount); var sourceSpan = realizedNode.Span.Slice(splitIndex, splitCount); var targetSpan = nextRealizedNode.Span.Slice(0, splitCount); sourceSpan.CopyTo(targetSpan); //Array.Clear(realizedNode.ItemsPrivate, splitIndex, splitCount); sourceSpan.Clear(); } LongCount += count; } finally { LeaveStructureChange(); } }