4using System.Diagnostics;
6using System.Threading.Tasks;
51 [DebuggerDisplay(
"Count = {Count}")]
52 [DebuggerTypeProxy(typeof(ChunkedListDebugView<>))]
55 private const int initialChunkSize = 16;
57 private readonly
int maxChunkSize;
58 private readonly
int minChunkSize;
59 private Chunk firstChunk;
60 private Chunk lastChunk;
61 private int chunkSize;
63 private bool? nullable;
79 : this(initialChunkSize, int.MaxValue)
88 : this(InitialChunkSize, InitialChunkSize)
99 if (InitialChunkSize <= 0)
100 throw new ArgumentException(
"Chunk size must be positive.", nameof(InitialChunkSize));
102 if (MaxChunkSize < InitialChunkSize)
103 throw new ArgumentException(
"Max chunk size must be greater than or equal to initial chunk size.", nameof(MaxChunkSize));
105 this.chunkSize = InitialChunkSize;
106 this.maxChunkSize = MaxChunkSize;
107 this.minChunkSize = InitialChunkSize;
110 this.firstChunk = this.lastChunk =
new Chunk(InitialChunkSize);
112 this.chunkSize <<= 1;
113 if (this.chunkSize > this.maxChunkSize || this.chunkSize <= 0)
114 this.chunkSize = this.maxChunkSize;
123 : this(InitialElements, int.MaxValue)
135 if (InitialElements is
null)
136 throw new ArgumentNullException(nameof(InitialElements));
140 this.chunkSize = this.count = InitialElements.Length;
142 if (this.chunkSize == 0)
144 this.chunkSize = initialChunkSize;
145 Chunk =
new Chunk(this.chunkSize);
148 Chunk =
new Chunk(InitialElements);
150 if (MaxChunkSize < this.chunkSize)
151 throw new ArgumentException(
"Max chunk size must be greater than or equal to initial chunk size.", nameof(MaxChunkSize));
153 this.maxChunkSize = MaxChunkSize;
154 this.minChunkSize = this.chunkSize;
156 this.firstChunk = this.lastChunk = Chunk;
158 this.chunkSize <<= 1;
159 if (this.chunkSize > this.maxChunkSize || this.chunkSize <= 0)
160 this.chunkSize = this.maxChunkSize;
173 public Chunk(
int Size)
175 this.Elements =
new T[Size];
183 public Chunk(
int Size, Chunk Previous)
186 this.Prev = Previous;
187 Previous.Next =
this;
190 public Chunk(T[] Elements)
192 this.Elements = Elements;
193 this.Size = this.Pos = this.Elements.Length;
199 public override string ToString()
201 StringBuilder sb =
new StringBuilder();
204 sb.Append(this.Size);
205 sb.Append(
", Start: ");
206 sb.Append(this.Start);
207 sb.Append(
", Pos: ");
209 sb.Append(
", Count: ");
210 sb.Append(this.Pos - this.Start);
211 sb.Append(
", HasNext: ");
212 sb.Append(!(this.Next is
null));
213 sb.Append(
", HasPrev: ");
214 sb.Append(!(this.Prev is
null));
216 return sb.ToString();
219 public ChunkNode<T> Node
223 if (this.node is
null)
224 this.node =
new ChunkNode<T>(
this);
230 public T
this[
int Index]
234 if (Index < this.Start || Index >= this.Pos)
235 throw new IndexOutOfRangeException();
237 return this.Elements[Index];
242 if (Index < this.Start || Index >= this.Pos)
243 throw new IndexOutOfRangeException();
245 this.Elements[Index] = value;
253 return "Count = " + this.count.ToString();
266 #region ICollection<T>
274 if (this.lastChunk.Pos <
this.lastChunk.Size)
275 this.lastChunk.Elements[this.lastChunk.Pos++] = Item;
276 else if (this.lastChunk.Start > 0)
278 if (this.lastChunk.Start <
this.lastChunk.Pos)
280 Array.Copy(this.lastChunk.Elements,
this.lastChunk.Start,
281 this.lastChunk.Elements, 0,
this.lastChunk.Pos -
this.lastChunk.Start);
284 this.lastChunk.Pos -= this.lastChunk.Start;
285 this.lastChunk.Start = 0;
287 this.lastChunk.Elements[this.lastChunk.Pos++] = Item;
291 this.lastChunk =
new Chunk(this.chunkSize, this.lastChunk);
293 this.chunkSize <<= 1;
294 if (this.chunkSize > this.maxChunkSize || this.chunkSize <= 0)
295 this.chunkSize = this.maxChunkSize;
297 this.lastChunk.Elements[this.lastChunk.Pos++] = Item;
308 this.lastChunk = this.firstChunk;
310 this.firstChunk.Next =
null;
311 this.firstChunk.Start = 0;
312 this.firstChunk.Pos = 0;
313 this.chunkSize = this.firstChunk.Size;
315 Array.Clear(this.firstChunk.Elements, 0,
this.firstChunk.Size);
326 Chunk Loop = this.firstChunk;
328 while (!(Loop is
null))
330 if (Loop.Start < Loop.Pos &&
331 Array.IndexOf(Loop.Elements, Item, Loop.Start, Loop.Pos - Loop.Start) >= 0)
347 public void CopyTo(T[] Destination,
int DestinationIndex)
349 this.
CopyTo(0, Destination, DestinationIndex, this.count);
359 Chunk Loop = this.firstChunk;
362 while (!(Loop is
null))
364 c = Loop.Pos - Loop.Start;
367 i = Array.IndexOf(Loop.Elements, Item, Loop.Start, c);
376 Array.Copy(Loop.Elements, i + 1, Loop.Elements, i, c - i);
381 if (Loop.Start == Loop.Pos)
386 if (Loop.Prev is
null)
387 this.firstChunk = Loop.Next ?? Loop;
389 Loop.Prev.Next = Loop.Next;
391 if (Loop.Next is
null)
392 this.lastChunk = Loop.Prev ?? Loop;
394 Loop.Next.Prev = Loop.Prev;
399 this.chunkSize >>= 1;
400 if (this.chunkSize < this.minChunkSize)
401 this.chunkSize = this.minChunkSize;
422 return new ChunkedListEnumerator(this.firstChunk);
429 IEnumerator IEnumerable.GetEnumerator()
434 private class ChunkedListEnumerator : IEnumerator<T>
437 private Chunk current;
441 public ChunkedListEnumerator(Chunk
FirstChunk)
453 if (this.current is
null)
454 throw new InvalidOperationException(
"Enumeration must be started or reset.");
456 return this.current.Elements[this.pos];
460 object IEnumerator.Current => this.Current;
462 public void Dispose()
469 public bool MoveNext()
471 if (this.current is
null)
476 this.current = this.first;
477 this.pos = this.current.Start - 1;
480 while (++this.pos >= this.current.Pos)
482 this.current = this.current.Next;
483 if (this.current is
null)
489 this.pos = this.current.Start - 1;
505 #region ForEach Optimization
516 if (Callback is
null)
517 throw new ArgumentNullException(nameof(Callback));
519 Chunk Loop = this.firstChunk;
522 while (!(Loop is
null))
524 for (i = Loop.Start, c = Loop.Pos; i < c; i++)
526 if (!Callback(Loop.Elements[i]))
545 if (Callback is
null)
546 throw new ArgumentNullException(nameof(Callback));
548 Chunk Loop = this.firstChunk;
551 while (!(Loop is
null))
553 for (i = Loop.Start, c = Loop.Pos; i < c; i++)
555 if (!await Callback(Loop.Elements[i]))
574 if (Callback is
null)
575 throw new ArgumentNullException(nameof(Callback));
577 Chunk Loop = this.firstChunk;
580 while (!(Loop is
null))
586 if (!Callback(Loop.Elements, i, c))
605 if (Callback is
null)
606 throw new ArgumentNullException(nameof(Callback));
608 Chunk Loop = this.firstChunk;
611 while (!(Loop is
null))
617 if (!await Callback(Loop.Elements, i, c))
629 #region Update Optimization
642 if (Callback is
null)
643 throw new ArgumentNullException(nameof(Callback));
645 Chunk Loop = this.firstChunk;
648 bool Continue =
true;
649 bool Deleted =
false;
651 while (!(Loop is
null))
653 for (i = Loop.Start, c = Loop.Pos; i < c; i++)
655 Continue = Callback(ref Loop.Elements[i], out
bool Keep);
665 Array.Copy(Loop.Elements, i + 1, Loop.Elements, i, d);
686 if (Loop.Start == Loop.Pos)
691 if (Loop.Prev is
null)
692 this.firstChunk = Next ?? Loop;
694 Loop.Prev.Next = Next;
697 this.lastChunk = Loop.Prev ?? Loop;
699 Next.Prev = Loop.Prev;
704 this.chunkSize >>= 1;
705 if (this.chunkSize < this.minChunkSize)
706 this.chunkSize = this.minChunkSize;
721 #region Members corresponding to LinkedList<T> interface.
726 public bool HasLastItem => !(this.lastChunk is
null) && this.lastChunk.Pos >
this.lastChunk.Start;
735 if (this.lastChunk is
null || this.lastChunk.Pos ==
this.lastChunk.Start)
737 if (!this.nullable.HasValue)
738 this.nullable = typeof(T).IsClass;
740 if (this.nullable.Value)
743 throw new InvalidOperationException(
"No last item in the collection.");
746 return this.lastChunk.Elements[this.lastChunk.Pos - 1];
751 if (this.lastChunk is
null)
753 this.firstChunk = this.lastChunk =
new Chunk(this.chunkSize);
755 this.chunkSize <<= 1;
756 if (this.chunkSize > this.maxChunkSize || this.chunkSize <= 0)
757 this.chunkSize = this.maxChunkSize;
759 this.lastChunk.Pos = 1;
760 this.lastChunk.Elements[0] = value;
763 else if (this.lastChunk.Pos ==
this.lastChunk.Start)
765 this.lastChunk.Start = 0;
766 this.lastChunk.Pos = 1;
767 this.lastChunk.Elements[0] = value;
771 this.lastChunk.Elements[this.lastChunk.Pos - 1] = value;
778 public bool HasFirstItem => !(this.firstChunk is
null) && this.firstChunk.Pos >
this.firstChunk.Start;
787 if (this.firstChunk is
null || this.firstChunk.Pos ==
this.firstChunk.Start)
789 if (!this.nullable.HasValue)
790 this.nullable = typeof(T).IsClass;
792 if (this.nullable.Value)
795 throw new InvalidOperationException(
"No first item in the collection.");
798 return this.firstChunk.Elements[this.firstChunk.Start];
803 if (this.firstChunk is
null)
805 this.firstChunk = this.lastChunk =
new Chunk(this.chunkSize);
807 this.chunkSize <<= 1;
808 if (this.chunkSize > this.maxChunkSize || this.chunkSize <= 0)
809 this.chunkSize = this.maxChunkSize;
811 this.firstChunk.Pos = 1;
812 this.firstChunk.Elements[0] = value;
815 else if (this.firstChunk.Pos ==
this.firstChunk.Start)
817 this.firstChunk.Start = 0;
818 this.firstChunk.Pos = 1;
819 this.firstChunk.Elements[0] = value;
823 this.firstChunk.Elements[this.firstChunk.Start] = value;
834 if (this.firstChunk.Start > 0)
835 this.firstChunk.Elements[--this.firstChunk.Start] = Value;
836 else if (this.firstChunk.Pos == 0)
838 this.firstChunk.Start = this.firstChunk.Pos = this.firstChunk.Size;
839 this.firstChunk.Elements[--this.firstChunk.Start] = Value;
843 Chunk NewChunk =
new Chunk(this.chunkSize)
845 Next = this.firstChunk,
848 this.chunkSize <<= 1;
849 if (this.chunkSize > this.maxChunkSize || this.chunkSize <= 0)
850 this.chunkSize = this.maxChunkSize;
852 this.firstChunk.Prev = NewChunk;
853 this.firstChunk = NewChunk;
855 this.firstChunk.Start = this.firstChunk.Pos = this.firstChunk.Size;
856 this.firstChunk.Elements[--this.firstChunk.Start] = Value;
878 if (this.firstChunk.Start <
this.firstChunk.Pos)
880 T Result = this.firstChunk.Elements[this.firstChunk.Start++];
883 if (this.firstChunk.Start ==
this.firstChunk.Pos)
885 this.firstChunk.Start = 0;
886 this.firstChunk.Pos = 0;
888 if (!(this.firstChunk.Next is
null))
890 Chunk Temp = this.firstChunk;
891 this.firstChunk = this.firstChunk.Next;
892 this.firstChunk.Prev =
null;
895 this.chunkSize >>= 1;
896 if (this.chunkSize < this.minChunkSize)
897 this.chunkSize = this.minChunkSize;
904 throw new InvalidOperationException(
"No first item to remove.");
913 if (this.lastChunk.Pos >
this.lastChunk.Start)
915 T Result = this.lastChunk.Elements[--this.lastChunk.Pos];
918 if (this.lastChunk.Pos ==
this.lastChunk.Start)
920 this.lastChunk.Start = 0;
921 this.lastChunk.Pos = 0;
923 if (!(this.lastChunk.Prev is
null))
925 Chunk Temp = this.lastChunk;
926 this.lastChunk = this.lastChunk.Prev;
927 this.lastChunk.Next =
null;
930 this.chunkSize >>= 1;
931 if (this.chunkSize < this.minChunkSize)
932 this.chunkSize = this.minChunkSize;
939 throw new InvalidOperationException(
"No last item to remove.");
952 public T
this[
int Index]
956 if (Index < 0 || Index >= this.count)
957 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
959 Chunk Loop = this.firstChunk;
962 while (!(Loop is
null))
964 c = Loop.Pos - Loop.Start;
967 return Loop.Elements[Loop.Start + Index];
974 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
979 if (Index < 0 || Index >= this.count)
980 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
982 Chunk Loop = this.firstChunk;
985 while (!(Loop is
null))
987 c = Loop.Pos - Loop.Start;
991 Loop.Elements[Loop.Start + Index] = value;
1000 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1011 return this.IndexOf(Item, 0, this.count);
1022 return this.IndexOf(Item, Index, this.count - Index);
1034 if (Index < 0 || Index > this.count)
1035 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1037 if (Count < 0 || Count > this.count - Index)
1038 throw new ArgumentOutOfRangeException(
"Count out of bounds.", nameof(Count));
1040 Chunk Loop = this.firstChunk;
1041 int i, c, c0, Result = 0;
1043 while (!(Loop is
null) && Count > 0)
1045 c = c0 = Loop.Pos - Loop.Start;
1058 if ((i = Array.IndexOf(Loop.Elements, Item, Loop.Start + Index, c)) >= 0)
1059 return Result + i - Loop.Start;
1081 if (this.count == 0)
1084 return this.LastIndexOf(Item, this.count - 1, this.count);
1095 if (this.count == 0)
1100 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1103 return this.LastIndexOf(Item, Index, Math.Min(
this.count, Index + 1));
1115 if (this.count == 0)
1117 if (Index == -1 && Count == 0)
1120 if (Index < 0 || Index >= this.count)
1121 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1123 throw new ArgumentOutOfRangeException(
"Count out of bounds.", nameof(Count));
1126 if (Index < 0 || Index >= this.count)
1127 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1129 if (Count < 0 || Count > Index + 1)
1130 throw new ArgumentOutOfRangeException(
"Count out of bounds.", nameof(Count));
1135 Chunk Loop = this.firstChunk;
1136 int i = 0, j = 0, c;
1138 while (!(Loop is
null) && Index > 0)
1140 c = Loop.Pos - Loop.Start;
1158 Loop = this.lastChunk;
1159 i = Loop.Pos - Loop.Start;
1162 j += Loop.Pos - Loop.Start;
1164 while (!(Loop is
null) && Count > 0)
1166 c = Loop.Pos - Loop.Start;
1175 i = Array.LastIndexOf(Loop.Elements, Item, Loop.Pos - 1, c);
1181 i = Array.LastIndexOf(Loop.Elements, Item, Loop.Start + i, c);
1185 return j + i - Loop.Start;
1198 #region Members corresponding to List<T> interface.
1207 if (Index < 0 || Index > this.count)
1208 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1210 if (Index == this.count)
1216 Chunk Loop = this.firstChunk;
1219 while (!(Loop is
null))
1221 c = Loop.Pos - Loop.Start;
1228 Array.Copy(Loop.Elements, Loop.Start, Loop.Elements, Loop.Start - 1, Index);
1230 Loop.Elements[--Loop.Start + Index] = Item;
1232 else if (Loop.Pos < Loop.Size)
1234 if (Index < Loop.Pos)
1235 Array.Copy(Loop.Elements, Index, Loop.Elements, Index + 1, Loop.Pos - Index);
1237 Loop.Elements[Index] = Item;
1242 Chunk Temp = Loop.Next;
1243 Chunk NewChunk =
new Chunk(Loop.Size, Loop)
1248 if (!(Temp is
null))
1249 Temp.Prev = NewChunk;
1251 this.lastChunk = NewChunk;
1257 NewChunk.Elements[0] = Loop.Elements[0];
1260 Loop.Elements[0] = Item;
1265 NewChunk.Pos = Loop.Size - c;
1266 Array.Copy(Loop.Elements, c, NewChunk.Elements, 0, NewChunk.Pos);
1267 Array.Copy(Loop.Elements, Index, Loop.Elements, Index + 1, c - Index);
1268 Loop.Elements[Index] = Item;
1275 NewChunk.Pos = Loop.Size - c + 1;
1279 Array.Copy(Loop.Elements, c, NewChunk.Elements, 0, Index);
1283 NewChunk.Elements[Index++] = Item;
1286 Array.Copy(Loop.Elements, c, NewChunk.Elements, Index, Loop.Size - c);
1299 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1308 if (Index < 0 || Index >= this.count)
1309 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1311 Chunk Loop = this.firstChunk;
1314 while (!(Loop is
null))
1316 c = Loop.Pos - Loop.Start;
1324 Index += Loop.Start;
1328 Array.Copy(Loop.Elements, Index + 1, Loop.Elements, Index, c - Index);
1333 if (Loop.Start == Loop.Pos)
1338 if (Loop.Prev is
null)
1339 this.firstChunk = Loop.Next ?? Loop;
1341 Loop.Prev.Next = Loop.Next;
1343 if (Loop.Next is
null)
1344 this.lastChunk = Loop.Prev ?? Loop;
1346 Loop.Next.Prev = Loop.Prev;
1351 this.chunkSize >>= 1;
1352 if (this.chunkSize < this.minChunkSize)
1353 this.chunkSize = this.minChunkSize;
1364 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1373 if (Collection is
null)
1374 throw new ArgumentNullException(nameof(Collection));
1375 else if (ReferenceEquals(Collection,
this))
1376 this.AddRange(this.ToArray());
1377 else if (Collection is T[] A)
1381 else if (Collection is ICollection<T> C)
1390 foreach (T Item
in Collection)
1393 this.AddRange(Temp.ToArray());
1403 if (Collection is
null)
1404 throw new ArgumentNullException(nameof(Collection));
1406 if (ReferenceEquals(Collection,
this))
1407 this.AddRange(this.ToArray());
1410 Chunk Loop = Collection.firstChunk;
1412 while (!(Loop is
null))
1414 this.AddRange(Loop.Elements, Loop.Start, Loop.Pos - Loop.Start);
1426 if (Collection is
null)
1427 throw new ArgumentNullException(nameof(Collection));
1429 this.AddRange(Collection, 0, Collection.Length);
1438 public void AddRange(T[] Collection,
int Index,
int Count)
1440 if (Collection is
null)
1441 throw new ArgumentNullException(nameof(Collection));
1443 if (Index < 0 || Index > Collection.Length)
1444 throw new ArgumentOutOfRangeException(nameof(Index));
1446 if (Count < 0 || Count > Collection.Length - Index)
1447 throw new ArgumentOutOfRangeException(nameof(Count));
1449 int End = Index + Count;
1451 if (this.lastChunk.Start > 0)
1453 if (this.lastChunk.Start <
this.lastChunk.Pos)
1455 Array.Copy(this.lastChunk.Elements,
this.lastChunk.Start,
1456 this.lastChunk.Elements, 0,
this.lastChunk.Pos -
this.lastChunk.Start);
1459 this.lastChunk.Pos -= this.lastChunk.Start;
1460 this.lastChunk.Start = 0;
1465 if (this.lastChunk.Pos >=
this.lastChunk.Size)
1467 this.lastChunk =
new Chunk(this.chunkSize, this.lastChunk);
1469 this.chunkSize <<= 1;
1470 if (this.chunkSize > this.maxChunkSize || this.chunkSize <= 0)
1471 this.chunkSize = this.maxChunkSize;
1474 int d = Math.Min(this.lastChunk.Size -
this.lastChunk.Pos, End - Index);
1476 Array.Copy(Collection, Index, this.lastChunk.Elements,
this.lastChunk.Pos, d);
1480 this.lastChunk.Pos += d;
1490 this.CopyTo(0, Destination, 0, this.count);
1500 public void CopyTo(
int Index, T[] Destination,
int DestinationIndex,
int Count)
1502 if (Index < 0 || Index > this.count)
1503 throw new ArgumentOutOfRangeException(nameof(Index));
1505 if (Count < 0 || Count > this.count - Index)
1506 throw new ArgumentOutOfRangeException(nameof(Count));
1508 if (Destination is
null)
1509 throw new ArgumentNullException(nameof(Destination));
1511 if (DestinationIndex < 0 || DestinationIndex > Destination.Length)
1512 throw new ArgumentOutOfRangeException(nameof(DestinationIndex));
1514 if (Count > Destination.Length - DestinationIndex)
1515 throw new ArgumentException(
"Destination array is too small.", nameof(Destination));
1517 Chunk Loop = this.firstChunk;
1519 bool Offset = Index > 0;
1521 while (!(Loop is
null) && Count > 0)
1524 if ((c = Loop.Pos - i) > 0)
1543 Array.Copy(Loop.Elements, i, Destination, DestinationIndex, c);
1544 DestinationIndex += c;
1553 Array.Copy(Loop.Elements, i, Destination, DestinationIndex, c);
1554 DestinationIndex += c;
1569 T[] Result =
new T[this.count];
1570 Chunk Loop = this.firstChunk;
1573 while (!(Loop is
null))
1575 if ((c = Loop.Pos - Loop.Start) > 0)
1577 Array.Copy(Loop.Elements, Loop.Start, Result, i, c);
1587 private void MakeOneChunk(
bool Trimmed)
1589 if (!(this.firstChunk.Next is
null) ||
1590 Trimmed && (
this.firstChunk.Start > 0 ||
1591 this.firstChunk.Pos <
this.firstChunk.Size))
1595 if (this.count == 0)
1596 Chunk =
new Chunk(this.chunkSize);
1598 Chunk =
new Chunk(this.ToArray());
1600 this.firstChunk = this.lastChunk = Chunk;
1609 if (this.count <= 1)
1613 this.MakeOneChunk(
false);
1614 Array.Sort(this.firstChunk.Elements,
this.firstChunk.Start,
1615 this.firstChunk.Pos -
this.firstChunk.Start);
1622 public void Sort(IComparer<T> Comparer)
1624 if (this.count <= 1)
1628 this.MakeOneChunk(
false);
1629 Array.Sort(this.firstChunk.Elements,
this.firstChunk.Start,
1630 this.firstChunk.Pos -
this.firstChunk.Start, Comparer);
1637 public void Sort(Comparison<T> Comparison)
1639 if (Comparison is
null)
1640 throw new ArgumentNullException(nameof(Comparison));
1642 if (this.count <= 1)
1646 this.MakeOneChunk(
true);
1647 Array.Sort(this.firstChunk.Elements, Comparison);
1656 public void Sort(
int Index,
int Count, IComparer<T> Comparer)
1658 if (Index < 0 || Index > this.count)
1659 throw new ArgumentOutOfRangeException(nameof(Index));
1661 if (Count < 0 || Count > this.count - Index)
1662 throw new ArgumentOutOfRangeException(nameof(Count));
1668 this.MakeOneChunk(
false);
1669 Array.Sort(this.firstChunk.Elements,
this.firstChunk.Start + Index,
1679 this.MakeOneChunk(
false);
1680 Array.Reverse(this.firstChunk.Elements,
this.firstChunk.Start,
1681 this.firstChunk.Pos -
this.firstChunk.Start);
1691 if (Index < 0 || Index > this.count)
1692 throw new ArgumentOutOfRangeException(nameof(Index));
1694 if (Count < 0 || Count > this.count - Index)
1695 throw new ArgumentOutOfRangeException(nameof(Count));
1701 this.MakeOneChunk(
false);
1702 Array.Reverse(this.firstChunk.Elements,
this.firstChunk.Start + Index, Count);
1707 #region AddRangeFirst/AddRangeLast
1715 this.AddRange(Collection);
1724 this.AddRange(Collection);
1733 if (Collection is
null)
1734 throw new ArgumentNullException(nameof(Collection));
1736 if (Collection is T[] A)
1737 this.AddRangeFirst(A);
1738 else if (Collection is ICollection<T> C)
1742 this.AddRangeFirst(A);
1748 foreach (T Item
in Collection)
1749 Temp.AddLastItem(Item);
1751 this.AddRangeFirst(Temp.ToArray());
1761 if (Collection is
null)
1762 throw new ArgumentNullException(nameof(Collection));
1764 int c = Collection.Length;
1767 if ((d = this.firstChunk.Size -
this.firstChunk.Pos) > 0)
1769 Array.Copy(this.firstChunk.Elements, 0,
this.firstChunk.Elements, d,
this.firstChunk.Pos);
1770 this.firstChunk.Start += d;
1771 this.firstChunk.Pos = this.firstChunk.Size;
1774 if (this.firstChunk.Start > 0)
1776 d = Math.Min(this.firstChunk.Start, c);
1778 Array.Copy(Collection, c - d, this.firstChunk.Elements,
this.firstChunk.Start - d, d);
1780 this.firstChunk.Start -= d;
1786 Chunk Temp = this.firstChunk;
1787 this.firstChunk =
new Chunk(this.chunkSize);
1788 Temp.Prev = this.firstChunk;
1789 this.firstChunk.Next = Temp;
1791 this.chunkSize <<= 1;
1792 if (this.chunkSize > this.maxChunkSize || this.chunkSize <= 0)
1793 this.chunkSize = this.maxChunkSize;
1795 this.firstChunk.Start = this.firstChunk.Pos = this.firstChunk.Size;
1797 d = Math.Min(this.firstChunk.Start, c);
1799 Array.Copy(Collection, c - d, this.firstChunk.Elements,
this.firstChunk.Start - d, d);
1801 this.firstChunk.Start -= d;
1817 if (Collection is
null)
1818 throw new ArgumentNullException(nameof(Collection));
1820 if (Index < 0 || Index > this.count)
1821 throw new ArgumentOutOfRangeException(
"Index out of bounds.", nameof(Index));
1825 if (!(Collection is T[] A))
1827 if (ReferenceEquals(Collection,
this))
1831 else if (Collection is ICollection<T> C)
1839 foreach (T Item
in Collection)
1846 foreach (T Item
in A)
1847 this.Insert(Index++, Item);
Node referencing a chunk in a ChunkedList<T>
A chunked list is a linked list of chunks of objects of type T .
void Clear()
Clears the collection.
ChunkedList(int InitialChunkSize, int MaxChunkSize)
A chunked list is a linked list of chunks of objects of type T .
IEnumerator< T > GetEnumerator()
Returns an enumerator for the collection.
int IndexOf(T Item, int Index)
Determines the index of a specific item
void AddFirstItem(T Value)
Adds a new item first in the collection.
void AddRangeFirst(T[] Collection)
Adds a range of elements first to the list.
async Task< bool > ForEachChunkAsync(ForEachChunkAsyncCallback< T > Callback)
Iterates through all chunks of elements in the collection, and calls the callback method in Callback ...
bool Remove(T Item)
Removes an element from the collection.
void AddRange(T[] Collection)
Adds a range of elements (last) to the list.
T LastItem
Last item in the collection.
void AddRange(IEnumerable< T > Collection)
Adds a range of elements (last) to the list.
void Reverse()
Reverses the order of the elements in the collection.
ChunkNode< T > FirstChunk
First chunk
void Sort()
Sorts the collection.
void RemoveAt(int Index)
Removes the item at the specified index.
void Sort(Comparison< T > Comparison)
Sorts the collection.
ChunkedList(T[] InitialElements, int MaxChunkSize)
A chunked list is a linked list of chunks of objects of type T , initially filled with elements in In...
bool Contains(T Item)
Checks if an item is a member of the collection.
bool ForEach(Predicate< T > Callback)
Iterates through all elements in the collection, and calls the callback method in Callback for each ...
void CopyTo(T[] Destination, int DestinationIndex)
Copies the contents of the collection to an array.
void AddRange(T[] Collection, int Index, int Count)
Adds a range of elements (last) to the list.
override string ToString()
int LastIndexOf(T Item)
Determines the last index of a specific item
bool HasLastItem
If there is a last item in the collection
bool IsReadOnly
If collection is read-only (false).
int IndexOf(T Item)
Determines the index of a specific item
ChunkedList()
A chunked list is a linked list of chunks of objects of type T .
bool Update(UpdateCallback< T > Callback)
Iterates through all elements in the collection, and calls the callback method in Callback for each ...
void CopyTo(T[] Destination)
Copies the contents of the collection to an array.
int IndexOf(T Item, int Index, int Count)
Determines the index of a specific item
void Insert(int Index, T Item)
Inserts an item to the list at the specified index.
int Count
Number of elements in collection.
ChunkNode< T > LastChunk
Last chunk
int LastIndexOf(T Item, int Index, int Count)
Determines the last index of a specific item
ChunkedList(int InitialChunkSize)
A chunked list is a linked list of chunks of objects of type T .
bool ForEachChunk(ForEachChunkCallback< T > Callback)
Iterates through all chunks of elements in the collection, and calls the callback method in Callback ...
int LastIndexOf(T Item, int Index)
Determines the last index of a specific item
void AddRangeLast(IEnumerable< T > Collection)
Adds a range of elements last to the list.
void InsertRange(int Index, IEnumerable< T > Collection)
Inserts a range of elements at a given index.
void AddRangeFirst(IEnumerable< T > Collection)
Adds a range of elements first to the list.
void CopyTo(int Index, T[] Destination, int DestinationIndex, int Count)
Copies the contents of the collection to an array.
void Reverse(int Index, int Count)
Reverses the order of a subset of elements in the collection.
T RemoveFirst()
Removes the first item in the collection.
T RemoveLast()
Removes the last item in the collection.
void Add(T Item)
Adds an item to the collection.
void AddLastItem(T Value)
Adds a new item last in the collection.
void AddRange(ChunkedList< T > Collection)
Adds a range of elements (last) to the list.
T[] ToArray()
Returns an array containing all elements of the collection.
void Sort(int Index, int Count, IComparer< T > Comparer)
Sorts a part of the collection.
void Sort(IComparer< T > Comparer)
Sorts the collection.
async Task< bool > ForEachAsync(PredicateAsync< T > Callback)
Iterates through all elements in the collection, and calls the callback method in Callback for each ...
ChunkedList(params T[] InitialElements)
A chunked list is a linked list of chunks of objects of type T , initially filled with elements in In...
void AddRangeLast(T[] Collection)
Adds a range of elements last to the list.
delegate Task< bool > ForEachChunkAsyncCallback< T >(T[] Chunk, int Offset, int Count)
Asynchronous callback method for the ForEachChunkAsync method.
delegate Task< bool > PredicateAsync< in T >(T Arg)
Asynchronous predicate function with one argument.
delegate bool UpdateCallback< T >(ref T Value, out bool Keep)
Delegate for callback methods that update the elements of a ChunkedList<T>.
delegate bool ForEachChunkCallback< T >(T[] Chunk, int Offset, int Count)
Callback method for the ForEachChunk method.