/// <summary> /// Removes items from the instance. /// </summary> /// <param name="itemCount">Number of items to remove</param> /// <returns></returns> /// <remarks>DO NOT dispose the original and then slice. Either the original or the sliced instance can be disposed, but not both.</remarks> public Multispan <T> Slice(int itemCount) { var result = new Multispan <T>(); var first = GetAt(0); // if the only thing needing slicing is the head if (first.Count > itemCount) { result._head = _head.Slice(itemCount); result._count = _count; if (Count > 1) { EnsureTailCapacity(ref result, _count - 1); Array.Copy(_tail, result._tail, _count - 1); } return(result); } // head will be removed; this computes how many tail segments need to be removed // and how many items from the first segment that is not removed var itemsLeftToRemove = itemCount - first.Count; int tailSegmentsToRemove = 1; // one is moved to the head for (int tailIndex = 0; tailIndex < _count - 1; tailIndex++) { if (itemsLeftToRemove == 0) { break; } var segment = _tail[tailIndex]; if (segment.Count >= itemsLeftToRemove) { break; } else { tailSegmentsToRemove++; itemsLeftToRemove -= segment.Count; } } result._head = _tail[tailSegmentsToRemove - 1].Slice(itemsLeftToRemove); result._count = _count - tailSegmentsToRemove; if (result._count == 1) { return(result); // we don't need tail; this multispan has just head } EnsureTailCapacity(ref result, result._count - 1); Array.Copy(_tail, tailSegmentsToRemove, result._tail, 0, result._count - 1); return(result); }
private static void EnsureTailCapacity(ref Multispan <T> ms, int count) { int desired = (ms._tail == null) ? 4 : ms._tail.Length * 2; while (desired < count) { desired = desired * 2; } var newSegments = ArrayPool <ArraySegment <T> > .Shared.Rent(desired); if (ms._tail != null) { ms._tail.CopyTo(newSegments, 0); ArrayPool <ArraySegment <T> > .Shared.Return(ms._tail); } ms._tail = newSegments; }
internal Enumerator(Multispan <T> buffer) { _buffer = buffer; _index = -1; }