2 // System.Collections.Generic.List
5 // Ben Maurer (bmaurer@ximian.com)
6 // Martin Baulig (martin@ximian.com)
7 // Carlos Alberto Cortez (calberto.cortez@gmail.com)
9 // (C) 2004 Novell, Inc.
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Collections;
38 using System.Runtime.InteropServices;
40 namespace System.Collections.Generic
43 public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
49 const int DefaultCapacity = 4;
53 data = new T [DefaultCapacity];
56 public List (IEnumerable <T> collection)
58 AddRange (collection);
61 public List (int capacity)
63 data = new T [capacity];
66 public void Add (T item)
68 if (size == data.Length)
69 Capacity = Math.Max (Capacity * 2, DefaultCapacity);
71 data [size ++] = item;
74 public void CheckRange (int idx, int count)
77 throw new ArgumentOutOfRangeException ("index must be equal or larger than zero");
79 if (count < 0 || idx > size - count)
80 throw new ArgumentOutOfRangeException ("Count must refer to an element in the list");
83 [MonoTODO ("PERFORMANCE: fix if it is an IList <T>")]
84 public void AddRange(IEnumerable<T> collection)
86 foreach (T t in collection)
90 public IList<T> AsReadOnly ()
92 return new ReadOnlyList<T>(this);
95 public int BinarySearch(T item)
97 return BinarySearch (item, Comparer <T>.Default);
100 public int BinarySearch(T item, IComparer<T> comparer)
102 return BinarySearch (0, size, item, comparer);
105 public int BinarySearch(int index, int count, T item, IComparer<T> comparer)
107 CheckRange (index, count);
108 return Array.BinarySearch (data, index, size, item, comparer);
113 Array.Clear (data, 0, data.Length);
116 public bool Contains (T item)
118 return IndexOf (item) != -1;
121 public List <U> ConvertAll <U> (Converter<T, U> converter)
123 List <U> u = new List <U> (size);
125 foreach (T t in this)
126 u [i ++] = converter (t);
131 public void CopyTo (T [] array)
136 public void CopyTo (T [] array, int arrayIndex)
138 CopyTo (0, array, arrayIndex, size);
141 public void CopyTo (int index, T[] array, int arrayIndex, int count)
143 CheckRange (index, count);
144 Array.Copy (data, index, array, arrayIndex, count);
147 public bool Exists (Predicate<T> match)
149 foreach (T t in this)
156 public T Find (Predicate<T> match)
158 foreach (T t in this)
165 // Maybe we could make this faster. For example, you could
166 // make a bit set with stackalloc for which elements to copy
167 // then you could size the array correctly.
168 public List<T> FindAll (Predicate<T> match)
170 List <T> f = new List <T> ();
172 foreach (T t in this)
179 public int FindIndex (Predicate <T> match)
181 return FindIndex (0, match);
184 public int FindIndex (int startIndex, Predicate <T> match)
186 return FindIndex (startIndex, size - startIndex, match);
189 public int FindIndex (int startIndex, int count, Predicate <T> match)
191 CheckRange (startIndex, count);
193 for (int i = startIndex; i < startIndex + count; i ++)
194 if (match (data [i]))
200 public T FindLast (Predicate <T> match)
202 int i = FindLastIndex (match);
203 return i == -1 ? default (T) : this [i];
206 public int FindLastIndex (Predicate <T> match)
208 return FindLastIndex (0, match);
211 public int FindLastIndex (int startIndex, Predicate <T> match)
213 return FindLastIndex (startIndex, size - startIndex, match);
216 public int FindLastIndex (int startIndex, int count, Predicate <T> match)
218 CheckRange (startIndex, count);
219 for (int i = startIndex + count; i != startIndex;)
220 if (match (data [--i]))
226 public void ForEach (Action <T> action)
228 foreach (T t in this)
232 public Enumerator GetEnumerator ()
234 return new Enumerator (this);
237 public List <T> GetRange (int index, int count)
239 CheckRange (index, count);
240 List<T> result = new List<T> (count);
243 for (int i = 0; i < count; i++)
244 result.data [i] = data [i+index];
249 public int IndexOf (T item)
251 return IndexOf (item, 0);
254 public int IndexOf (T item, int index)
256 return IndexOf (item, index, size - index);
259 public int IndexOf (T item, int index, int count)
261 CheckRange (index, count);
262 return Array.IndexOf (data, item, index, count);
265 void Shift (int start, int delta)
270 Array.Copy (data, start, data, start + delta, size - start);
275 public void Insert (int index, T item)
277 if ((uint) index > (uint) size)
278 throw new ArgumentOutOfRangeException ("index");
280 if (size == data.Length)
281 Capacity = Math.Max (Capacity * 2, DefaultCapacity);
286 [MonoTODO ("Performance for collection")]
287 public void InsertRange (int index, IEnumerable<T> collection)
289 foreach (T t in collection)
290 Insert (index ++, t);
293 public int LastIndexOf (T item)
295 return LastIndexOf (item, 0);
298 public int LastIndexOf (T item, int index)
300 return LastIndexOf (item, index, size - index);
303 public int LastIndexOf (T item, int index, int count)
305 CheckRange (index, count);
306 return Array.LastIndexOf (data, item, index, count);
309 public bool Remove (T item)
311 int loc = IndexOf (item);
318 [MonoTODO ("I can make it faster than this...")]
319 public int RemoveAll (Predicate<T> match)
323 while ((index = FindIndex (index, match)) != -1) {
331 public void RemoveAt (int index)
333 RemoveRange (index, 1);
336 public void RemoveRange (int index, int count)
338 CheckRange (index, count);
339 Shift (index, -count);
342 public void Reverse ()
346 public void Reverse (int index, int count)
348 CheckRange (index, count);
349 Array.Reverse (data, index, count);
354 Sort (Comparer <T>.Default);
356 public void Sort (IComparer<T> comparer)
358 Sort (0, size, comparer);
363 public void Sort (Comparison<T> comparison)
365 throw new NotImplementedException ();
369 public void Sort (int index, int count, IComparer<T> comparer)
371 CheckRange (index, count);
372 throw new NotImplementedException ();
375 public T [] ToArray ()
377 T [] t = new T [size];
379 Array.Copy (data, t, size);
384 public void TrimToSize ()
389 public bool TrueForAll (Predicate <T> match)
391 foreach (T t in this)
398 public int Capacity {
403 if ((uint) value < (uint) size)
404 throw new ArgumentOutOfRangeException ();
406 Array.Resize (ref data, value);
414 public T this [int index] {
416 if ((uint) index >= (uint) size)
417 throw new IndexOutOfRangeException ();
421 if ((uint) index >= (uint) size)
422 throw new IndexOutOfRangeException ();
423 data [index] = value;
427 #region Interface implementations.
428 IEnumerator <T> IEnumerable <T>.GetEnumerator()
430 return GetEnumerator ();
433 void ICollection.CopyTo (Array array, int arrayIndex)
435 Array.Copy (data, 0, data, arrayIndex, size);
438 IEnumerator IEnumerable.GetEnumerator()
440 return GetEnumerator ();
443 int IList.Add (object item)
449 bool IList.Contains (object item)
451 return Contains ((T) item);
454 int IList.IndexOf (object item)
456 return IndexOf ((T) item);
459 void IList.Insert (int index, object item)
461 Insert (index, (T) item);
464 void IList.Remove (object item)
469 bool ICollection <T>.IsReadOnly {
470 get { return false; }
472 bool ICollection.IsSynchronized {
473 get { return false; }
476 object ICollection.SyncRoot {
479 bool IList.IsFixedSize {
480 get { return false; }
483 bool IList.IsReadOnly {
484 get { return false; }
487 object IList.this [int index] {
488 get { return this [index]; }
489 set { this [index] = (T) value; }
494 internal class ReadOnlyList<I> : IList<I>, ICollection<I>, IEnumerable<I>
498 internal ReadOnlyList (IList<I> list)
503 public void Add (I item)
505 throw new NotSupportedException ();
510 throw new NotSupportedException ();
513 public bool Contains (I item)
515 return list.Contains (item);
518 public void CopyTo (I [] array, int index)
520 list.CopyTo (array, index);
523 public IEnumerator<I> GetEnumerator ()
525 return list.GetEnumerator ();
528 IEnumerator IEnumerable.GetEnumerator ()
530 return ((IEnumerable) list).GetEnumerator ();
533 public int IndexOf (I item)
535 return list.IndexOf (item);
538 public void Insert (int index, I item)
540 throw new NotSupportedException ();
543 public bool Remove (I item)
545 throw new NotSupportedException ();
548 public void RemoveAt (int index)
550 throw new NotSupportedException ();
559 public bool IsReadOnly {
565 public I this [int index] {
570 throw new NotSupportedException ();
575 public struct Enumerator : IEnumerator <T>, IDisposable {
576 const int NOT_STARTED = -2;
578 // this MUST be -1, because we depend on it in move next.
579 // we just decr the size, so, 0 - 1 == FINISHED
580 const int FINISHED = -1;
586 internal Enumerator (List <T> l)
593 // for some fucked up reason, MSFT added a useless dispose to this class
594 // It means that in foreach, we must still do a try/finally. Broken, very
596 public void Dispose ()
601 public bool MoveNext ()
603 if (ver != l.version)
604 throw new InvalidOperationException ();
606 if (idx == NOT_STARTED)
609 return idx != FINISHED && -- idx != FINISHED;
615 throw new InvalidOperationException ();
617 return l.data [l.size - 1 - idx];
621 void IEnumerator.Reset ()
623 if (ver != l.version)
624 throw new InvalidOperationException ();
629 object IEnumerator.Current {
630 get { return Current; }